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?
- Anonymous2 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;