How to Integrate with AWS EC2 Web Service using REST API
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-05-2020 11:41 PM
Currently trying to integrate with AWS EC2 web service using REST APIs. I have everything working in 'Postman' but when I try to implement the same headers(Authentication) within ServiceNow, I end up with 401 error.
Below is the code which I am using, can anyone suggest that I am using the correct values for variables : uri, CanonicalURI, CanonicalQueryString, CanonicalResource.
// SETTING VARABILES
var accessID = ''; // This come from AWS
var yourSecretAccessKeyID = ''; // This comes from AWS
var CanonicalResource = 'us-east-1'; // The file name that you want to retrive
var region = 'us-east-1'; //region of bucket
var service = 'ec2'; // service type
var bucket = '<CHANGE ME>'; //bucket name
var uri = 'https://ec2.amazonaws.com/?';
var CanonicalURI = encodeURIComponent(uri);
var CanonicalQueryString = 'Action=StopInstances&Version=2016-11-15';
var CanonicalHeaders = '';
var SignedHeaders = '';
var digest = new GlideDigest();
var HashedPayload = digest.getSHA256Hex(''); //ServiceNow's method for SHA256 hex
var hash = HashedPayload.toLowerCase();
var date = getDate();
//var jshash = x_snc_key_master.CryptoJS.SHA256(''); // using the crypto js way to SHA256 hex
//var hash = jshash.toLowerCase(); // uncomment out if you use the crytpo js method
//Headers
var header1 = 'host';
var headValue1 = 'ec2.amazonaws.com';
var header2 = 'x-amz-date';
var headValue2 = hash;
// Date converter for AWS date format
function getDate() {
var date; {
var gdt = new GlideDateTime();
var time = gdt.getTime();
var t = time.getByFormat("HHmmss");
var wd = (function() {
var map = {
'1': 'Mon',
'2': 'Tue',
'3': 'Wed',
'4': 'Thu',
'5': 'Fri',
'6': 'Sat',
'7': 'Sun'
};
return map[gdt.getDayOfWeekUTC() + ''];
})();
var d = (function() {
var map = {
'1': '01',
'2': '02',
'3': '03',
'4': '04',
'5': '05',
'6': '06',
'7': '07',
'8': '08',
'9': '09',
'10': '10',
'11': '11',
'12': '12',
'13': '13',
'14': '14',
'15': '15',
'16': '16',
'17': '17',
'18': '18',
'19': '19',
'20': '20',
'21': '21',
'22': '22',
'23': '23',
'24': '24',
'25': '25',
'26': '26',
'27': '27',
'28': '28',
'29': '29',
'30': '30',
'31': '31'
};
return map[gdt.getDayOfMonthUTC() + ''];
})();
var m = (function() {
var map = {
'1': '01',
'2': '02',
'3': '03',
'4': '04',
'5': '05',
'6': '06',
'7': '07',
'8': '08',
'9': '09',
'10': '10',
'11': '11',
'12': '12'
};
return map[gdt.getMonthUTC() + ''];
})();
var y = gdt.getYearUTC();
date = y + m + d + 'T' + t + 'Z';
}
return date;
}
// gs.print('date = ' + date);
//Task 1: Create a Canonical Request
//<HTTPMethod>\n
//<CanonicalURI>\n
//<CanonicalQueryString>\n
//<CanonicalHeaders>\n
//<SignedHeaders>\n
//<HashedPayload>
// Creating the Canonical Header
CanonicalHeaders = header1.toLowerCase() + ':' + headValue1.trim() + '\n' +
header2.toLowerCase() + ':' + headValue2;
gs.print('CanonicalHeaders:' + CanonicalHeaders);
//Signed Headers
SignedHeaders = header1.toLowerCase() + ';' + header2.toLowerCase();
//Create CanonicalRequest
var CanonicalRequest = 'GET' + '\n' +
uri + '\n' +
CanonicalQueryString + '\n' +
CanonicalHeaders + '\n' + '\n' +
SignedHeaders + '\n' +
hash;
gs.print('CanonicalRequest: ' + CanonicalRequest);
//Task 2: Create a String to Sign
//"AWS4-HMAC-SHA256" + "\n" +
//timeStampISO8601Format + "\n" +
//<Scope> + "\n" +
//Hex(SHA256Hash(<CanonicalRequest>))
// Setting Variables needed for String to Sign
var date_sub = date.substring(0, 8);
var scope = date_sub + '/' + region + '/' + service + '/' + 'aws4_request';
var hashCanonical = digest.getSHA256Hex(CanonicalRequest);
var hashLower = hashCanonical.toLowerCase();
//var jshashCanonical = x_snc_key_master.CryptoJS.SHA256(CanonicalRequest);// using the crypto js way to hex
var stringToSign = 'AWS4-HMAC-SHA256' + '\n' +
date + '\n' +
scope + '\n' +
hashLower;
//gs.print('StringToSign: ' + stringToSign);
//Task 3: Calculate Signature
//DateKey = HMAC-SHA256("AWS4"+"<SecretAccessKey>", "<YYYYMMDD>")
//DateRegionKey = HMAC-SHA256(<DateKey>, "<aws-region>")
//DateRegionServiceKey = HMAC-SHA256(<DateRegionKey>, "<aws-service>")
//SigningKey = HMAC-SHA256(<DateRegionServiceKey>, "aws4_request")
//Signature = HMAC-SHA256(SigningKey, StringToSign)
var signature = getSig(yourSecretAccessKeyID, date_sub, region, service);
//gs.print('Signature: ' + signature);
// This Function creates the encoding of the Signature
function getSig(yourSecretAccessKeyID, date_sub, region, service) {
try {
var kSecret = yourSecretAccessKeyID;
gs.log('@@ kSecret'+ kSecret);
gs.log('@@ Before DateSub: '+ date_sub);
var kDate = global.CryptoJS.HmacSHA256(date_sub, 'AWS4' + kSecret);
gs.log('@@ After kDate : '+kDate);
gs.log('@@ Before Region: '+ region);
var kRegion = global.CryptoJS.HmacSHA256(region, kDate);
gs.log('@@ After kRegion: '+ kRegion);
gs.log('@@ Before Service: '+ service);
var kService = global.CryptoJS.HmacSHA256(service, kRegion);
gs.log('@@ After kService: '+ kService);
var kSigning = global.CryptoJS.HmacSHA256('aws4_request', kService);
gs.log('@@ After kSigning: '+ kSigning);
var kSignature = global.CryptoJS.HmacSHA256(stringToSign, kSigning);
gs.log('@@ After kSignature: '+ kSignature);
//gs.print('kSignature: ' + kSignature);
return kSignature;
} catch (e) {
gs.log(e.string());
throw 'failed_missing_requirement';
}
}
//Create Authorization String
var authorization = 'AWS4-HMAC-SHA256 Credential=' + accessID + '/' + scope + ', SignedHeaders=' + SignedHeaders + ', Signature=' + signature;
gs.log('@@ Signature : '+signature);
//gs.print('authorization: ' + authorization);
gs.log('@@ Authorization : '+authorization);
gs.log('@@ Date: '+date);
//Authorization header
getS3(authorization, date, headValue2);
// Creating the GET REST API
function getS3(auth, date, headValue2) {
try {
var r = new sn_ws.RESTMessageV2();
r.setHttpMethod('GET');
r.setEndpoint('https://ec2.us-east-1.amazonaws.com/?Action=StopInstances&Version=2016-11-15&InstanceId=i-0cedd3f1defebd299'); // TAGET S3 BUCKET URL
gs.log('@@ Auth : '+auth);
gs.log('@@ Date : '+date);
r.setRequestHeader('Authorization', auth);
r.setRequestHeader('Date', date);
// r.setRequestHeader('x-amz-date', headValue2);
// r.saveResponseBodyAsAttachment('sys_data_source','<SYS_ID TO DATA SOURCE>','<NAME FILE YOU WANT ATTACHED>');
var response = r.execute();
var httpResponseStatus = response.getStatusCode() + '';
gs.log("@@ http response status_code: " + httpResponseStatus);
if (httpResponseStatus != '200') {
gs.log("@@ http response : " + response.getBody());
}
} catch (ex) {
var message = ex.message;
gs.print(message);
}
//gs.print('This is the Body: ' + response.getBody()); // IF you do not get a code 200 , this might tell you whats wrong
//gs.print('Status: ' + response.getStatusCode()); // code 200 is what you want
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-05-2020 11:57 PM
Hi,
error 401 means authentication issue i.e. username and password is incorrect.
please compare the configuration changes of Postman and ServiceNow and check what is the difference
Regards
Ankur
Ankur
✨ Certified Technical Architect || ✨ 9x ServiceNow MVP || ✨ ServiceNow Community Leader

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-06-2020 10:08 AM
Cool code, I wonder where you got it from?!?!?! You didn't read the part in my post where i mentioned that the only way for this to work is the CryptoJS library HAS TO BE IN A SCOOPED APPLICATION. It will not work if you put the CryptoJS at the Global level. THERE IS NO WAY AROUND IT.
global.CryptoJS.HmacSHA256
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
10-07-2020 01:38 AM