How to send Outbound REST Messages using AWS Signature Version 4?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-13-2018 07:27 AM
Currently trying to send outbound REST messages using AWS sigv4 authentication. I have everything working in POSTMan but when I try to implement the same headers within ServiceNow, I end up with 502 errors. Can anyone assist?
Thanks!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
09-16-2019 05:14 AM
As of now is there any method to implement Outbound REST Messages using AWS Signature Version 4?

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
08-14-2019 01:21 PM
Here is a script I have used to download a file from a non-public bucket in Amazon AWS S3. Pay close attention to the "REPLACE_ME" comments to make sure you put the correct value there and take a look at the "GeneralAWSAuthorization.test" static method for execution example.
/*
* Constructs the Authentication Header for Amazon AWS S3.
*
* @see https://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html#ConstructingTheAuthenticationHeader
* @author SERVICE-NOW.COM\walter.brame
*/
var GeneralAWSAuthorization = Class.create( );
GeneralAWSAuthorization.prototype = {
initialize: function ( ) {
this.stringToSign = null;
this.canonicalizedAmzHeaders = null;
this.contentMD5 = null;
this.contentType = null;
this.date = null;
this.digest = null;
this.yourSecretAccessKeyID = ''; // REPLACE_ME
this.awsAccessKeyId = ''; // REPLACE_ME
this.canonicalizedResource = ''; // REPLACE_ME, Relative URI E.g. /walter.brame/a+test.xlsx
this.httpVerb = 'GET'; // REPLACE_ME, E.g. GET, POST, PUT, etc.
},
getCanonicalizedAmzHeaders : function ( ) {
return this.canonicalizedAmzHeaders;
},
setCanonicalizedAmzHeaders : function (canonicalizedAmzHeaders) {
this.canonicalizedAmzHeaders = canonicalizedAmzHeaders;
},
getCanonicalizedResource : function ( ) {
return this.canonicalizedResource;
},
setCanonicalizedResource : function (canonicalizedResource) {
this.canonicalizedResource = canonicalizedResource;
},
getHTTPVerb : function () {
if ( gs.nil(this.httpVerb) ) {
this.httpVerb = 'GET';
}
return this.httpVerb;
},
setHTTPVerb : function (httpVerb) {
this.httpVerb = httpVerb;
},
getContentMD5 : function () {
return this.contentMD5;
},
setContentMD5 : function (contentMD5) {
this.contentMD5 = contentMD5;
},
getContentType : function () {
return this.contentType;
},
setContentType : function (contentType) {
this.contentType = contentType;
},
getYourSecretAccessKeyID : function ( ) {
return this.yourSecretAccessKeyID;
},
setYourSecretAccessKeyID : function (yourSecretAccessKeyID) {
this.yourSecretAccessKeyID = yourSecretAccessKeyID;
},
getAWSAccessKeyId : function ( ) {
return this.awsAccessKeyId;
},
setAWSAccessKeyId : function (awsAccessKeyId) {
this.awsAccessKeyId = awsAccessKeyId;
},
getDate : function ( ) {
if ( gs.nil(this.date) ) {
var gdt = new GlideDateTime( );
var time = gdt.getTime( );
var t = time.getByFormat("HH:mm:ss");
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 = gdt.getDayOfMonthUTC( );
var m = (function ( ) {
var map = {
'1' : 'Jan',
'2' : 'Feb',
'3' : 'Mar',
'4' : 'Apr',
'5' : 'May',
'6' : 'Jun',
'7' : 'Jul',
'8' : 'Aug',
'9' : 'Sep',
'10' : 'Oct',
'11' : 'Nov',
'12' : 'Dec'
};
return map[gdt.getMonthUTC( ) + ''];
})();
var y = gdt.getYearUTC( );
this.date = wd + ', ' + d + ' ' + m + ' ' + y + ' ' + t + ' +0000';
gs.print('date = ' + this.date);
}
return this.date;
},
setDate : function (date) {
this.date = date;
},
_getStringToSign : function ( ) {
if ( gs.nil(this.stringToSign) ) {
if ( gs.nil(this.getHTTPVerb( )) ) {
throw 'HTTP Verb is required';
}
if ( gs.nil(this.getCanonicalizedResource( )) ) {
throw 'CanonicalizedResource is required';
}
this.stringToSign = this.getHTTPVerb( ) + '\n';
if ( !gs.nil(this.getContentMD5( )) ) {
this.stringToSign += this.getContentMD5( ) + '\n';
} else {
this.stringToSign += '\n';
}
if ( !gs.nil(this.getContentType( )) ) {
this.stringToSign += this.getContentType( ) + '\n';
} else {
this.stringToSign += '\n';
}
this.stringToSign += this.getDate( ) + '\n';
if ( !gs.nil(this.getCanonicalizedAmzHeaders( )) ) {
this.stringToSign += this.getCanonicalizedAmzHeaders( );
}
this.stringToSign += this.getCanonicalizedResource( );
gs.print('stringToSign = ' + this.stringToSign);
}
return this.stringToSign;
},
_getDigest : function( ) {
if ( gs.nil(this.digest) ) {
if ( gs.nil(this.getYourSecretAccessKeyID( )) ) {
throw 'YourSecretAccessKeyID is required';
}
try {
var data = this._getStringToSign( );
var fkey = this.getYourSecretAccessKeyID( );
// default to something JDK 1.4 has
var MAC_ALG = "HmacSHA1";
this.digest = SncAuthentication.encode(data, fkey, MAC_ALG);
} catch (e) {
gs.print(e.toString( ));
throw 'failed_missing_requirement';
}
}
return this.digest;
},
getAuthorization : function ( ) {
if ( gs.nil(this.authorization) ) {
if ( gs.nil(this.getAWSAccessKeyId( )) ) {
throw 'AWSAccessKeyId is required';
}
this.authorization = "AWS" + " " + this.getAWSAccessKeyId( ) + ":" + this._getDigest( );
gs.print('authorization = ' + this.authorization);
}
return this.authorization;
},
type: 'GeneralAWSAuthorization'
};
GeneralAWSAuthorization.test = function ( ) {
try{
// step 1: get the file
var request = new sn_ws.RESTMessageV2( );
request.setHttpMethod('get');
request.setEndpoint('https://s3-us-west-1.amazonaws.com/.../a+test.xlsx'); // REPLACE_ME
var auth = new GeneralAWSAuthorization( );
request.setRequestHeader('Authorization', auth.getAuthorization( ));
request.setRequestHeader('Date', auth.getDate( ));
// step 2 : save the file to a data source.
// The "data source" record should be manually created prior
// to doing this
var tablename = 'sys_data_source';
var recordSysId = 'sys_data_source_sys_id'; // REPLACE_ME
var filename = 'file_name'; // REPLACE_ME
request.saveResponseBodyAsAttachment(tablename, recordSysId, filename);
var response = request.execute( );
var httpResponseStatus = response.getStatusCode( ) + '';
gs.print(" http response status_code: " + httpResponseStatus);
if ( httpResponseStatus != '200' ) {
gs.print(" http response : " + response.getBody( ));
}
// step 3 : Run the import and transform for the data source.
// the "import set table" and "transform map",
// and "scheduled data import" records
// should be manually created prior to doing this
var scheduledDataLoad = new GlideRecord('scheduled_import_set');
scheduledDataLoad.get('scheduled_import_set_sys_id'); // REPLACE_ME
SncTriggerSynchronizer.executeNow(scheduledDataLoad);
}
catch(ex){
gs.print(ex);
}
};
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-07-2022 03:55 AM
This is a long shot, and considering this post was 3 years ago, I hope you are still around and can assist me.
I have followed your instructions from the code and have replaced the various objects with what is applicable to me, but when I execute the GeneralAWSAuthorization function, I get an error stating the following:
Request not sent to uri= https://<host>/<bucket>/<file> : java.net.ConnectException: Connection refused (Connection refused)
*** Script: http response status_code: 0
*** Script: http response :
I've checked the credentials to make sure they are ok and I can access the host URL.
I would really appreciate your assistance in solving this.
Thank you in advance
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-10-2023 04:19 AM
Hi,
Bit late to the party, but i'm also looking to authenticate rest messages with AWS Signature Version 4. I came across this SNow doc article that looks promising: https://docs.servicenow.com/en-US/bundle/utah-platform-security/page/product/credentials/task/config...
Haven't tried it yet, but i'm guessing its one native way to authenticate with AWS_IAM and AWS Signature Version 4