Forum Discussion

mhashemi's avatar
2 years ago

Trouble Authenticating to LogicMonitor REST API from ServiceNow

I am trying to convert a PowerShell script to run from ServiceNow and found “Using REST API from ServiceNow Scripting” from two years ago. Since then, ServiceNow has added GlideDigest() which, among other things, should allow me to create a message digest from a string using the SHA256 algorithm, with the result being a Base64 string.

However, I am getting back: 

"{"errorMessage":"Authentication failed","errorCode":1401,"errorDetail":null}"

The PowerShell script looks like this:

[string]$sandboxaccessid = 'abc'
[securestring]$sandboxaccesskey = '123' | ConvertTo-SecureString -AsPlainText -Force
[string]$AccountName = 'portalname'
[int]$Id = 2
$httpVerb = "GET"
$resourcePath = "/device/devices/$id"
$AllProtocols = [System.Net.SecurityProtocolType]'Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols

$time = (Get-Date).ToUniversalTime()
$epoch = [Math]::Round((New-TimeSpan -Start (Get-Date -Date "1/1/1970") -End $time).TotalMilliseconds)

$requestVars = $httpVerb + $epoch + $resourcePath
$hmac = New-Object System.Security.Cryptography.HMACSHA256
$hmac.Key = [Text.Encoding]::UTF8.GetBytes([System.Runtime.InteropServices.Marshal]::PtrToStringAuto(([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($sandboxaccesskey))))
$signatureBytes = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($requestVars))
$signatureHex = [System.BitConverter]::ToString($signatureBytes) -replace '-'
$signature = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($signatureHex.ToLower()))

$headers = @{
"Authorization" = "LMv1 $sandboxaccessid`:$signature`:$epoch"
"Content-Type" = "application/json"
"X-Version" = 3
}
$url = "https://$AccountName.logicmonitor.com/santaba/rest$resourcePath"

$response = Invoke-RestMethod -Uri $url -Method $httpVerb -Header $headers -ErrorAction Stop
$resposne

And JavaScript looks like this (at the moment):

var ACCESS_ID = 'abc';
var ACCESS_KEY = '123';
var ACCOUNT_NAME = 'portalname';
var resourcePath = '/device/devices';
var time = new Date().getTime();
var epoch = Math.round((time - new Date("1/1/1970").getTime()));
var id = 2;

var requestVars = 'GET' + epoch + resourcePath;

// Compute the HMACSHA256 hash using GlideDigest
var gd = new GlideDigest();
var signature = gd.getSHA256Base64(ACCESS_KEY, requestVars);

// Remove hyphens from the signature
signature = signature.replace(/-/g, '');

var token = 'LMv1 ' + ACCESS_ID + ':' + signature + ':' + epoch;

var httpRequest = new GlideHTTPRequest('https://' + ACCOUNT_NAME + '.logicmonitor.com/santaba/rest/device/devices/' + id);
httpRequest.addHeader('Content-Type', 'application/json');
httpRequest.addHeader('Authorization', token);
httpRequest.addHeader('X-Version', '3');
var response = httpRequest.get();

gs.info('Response status code: ' + response.getStatusCode());
gs.info('Devices = ' + response.body);

Anyone know how to make this authentication work, without the customer convertByteArrayToHex() utility?

  • Anonymous's avatar
    Anonymous
    2 years ago

    Why not use the Postman pre-request script? It’s already in javascript (this one is modified from that one to do just what you were wanting):

    var http_verb = "GET";
    var resource_path = "/device/devices";
    var epoch = (new Date()).getTime();
    var request_vars = (http_verb == 'GET'||http_verb == 'DELETE') ? http_verb + epoch + resource_path : http_verb + epoch + request.data + resource_path;
    var signature = btoa(CryptoJS.HmacSHA256("API_KEY").toString());
    var auth = "LMv1 " + "API_ID" + ":" + signature + ":" + epoch;
    return auth;
  • I was able to solve it.

    HMAC Signature on client side was not an issue it was generating the correct auth token.

    Issue was with resource path not matching with what we had in the URL.

    Thanks

    Ashish

  • Hello All,

    I am so sorry for using this topic after 10 months but this is exactly the challenge I am facing now with REST API V3.

    Good News is that I am able to filter based on properties not only that I could also filter using multiple properties using advance filtering with Rest API V3 for /device/devices/

    json_key_parameter and escaped json_value_parameter (Ref)

    But I am facing a challenge where I cannot create HMAC signature as per the new requirement mentioned here where we have to concatenate request details to form a string, and use Access Key to calculate the HMAC-SHA256 of that string. You then need Base64 to encode the result. 

    I am using Logic Monitor Dashboard “Text” widget for HTML Embedded JavaScript.

    I cannot access CryptoJS nor I can use the library at the top of my script as Logic Monitor automatically removes it, has anyone attempted to do something like this.

    The following does not work with V3   // Create our API signature...

            window.crypto.subtle.importKey(

                "raw", // raw format of the key - should be Uint8Array

                enc.encode(apiKey), ………..

    @Kevin Ford you are creating signature using this… in 

    https://community.logicmonitor.com/product-discussions-22/dynamic-dashboards-2476

    Any help would be appreciated!

    Similar issues was reported here on stack overflow few years ago

    Thanks

    Ashish

  • The application itself inside of ServiceNow for LogicMonitor uses this

                var signature = new CryptoJS.HmacSHA256(request_vars, api_key).toString();
    var auth = ("LMv1 " + api_id + ":" + gs.base64Encode(signature) + ":" + epoch).toString();

    Works very much like the python or powershell auth method. You stated you don’t have the CryptoJS library currently. You can add libraries into ServiceNow under an application. Otherwise you can take the library and just put it at the top of your script.

  • Anonymous's avatar
    Anonymous

    I don’t seem to have access to CryptoJS.

    You’ve reached the limit of my JS knowledge. Sorry.

  • I don’t deal with ServiceNow anymore, but I recall that if you add the LM/SN integration SN store app, it will add several functions (including sha256) that can be used in SN code. But it might be server-side only. I don’t recall and it was a few years ago.

  • Anonymous's avatar
    Anonymous

    Why not use the Postman pre-request script? It’s already in javascript (this one is modified from that one to do just what you were wanting):

    var http_verb = "GET";
    var resource_path = "/device/devices";
    var epoch = (new Date()).getTime();
    var request_vars = (http_verb == 'GET'||http_verb == 'DELETE') ? http_verb + epoch + resource_path : http_verb + epoch + request.data + resource_path;
    var signature = btoa(CryptoJS.HmacSHA256("API_KEY").toString());
    var auth = "LMv1 " + "API_ID" + ":" + signature + ":" + epoch;
    return auth;