Integration with Amazon SQS - how to import AWS SDK or CryptoJS libraries for server side coding?

tamarasylte
Mega Expert

I have a requirement to post a message on to AWS SQS when a certain type of incident occurs. The message payload is in a JSON format, and I have an ACCESS KEY, a SECRET KEY, a username and of course the AWS REGION and URL. What I can't figure out is how to build the v4 signature required to submit a message to AWS SQS.

Does anyone have insight on how to import either the AWS SDK or the CryptoJS libraries into ServiceNow in such a way that they can be used server-side to create such a message?

I attempted the method outlined in Mini-Lab: Adding Underscore.js Into ServiceNow without success, getting a Javascript parse error that prevents the library from being saved.

14 REPLIES 14

josh_nerius
ServiceNow Employee
ServiceNow Employee

Hi Tamara,



This is a topic I've been researching recently, and I have what I think may be a solution for you. This is not well tested and has not been deployed in a production setting, so please keep this in mind if it works for you - the usual caveats about "test this thoroughly" apply . Look for a blog about this some time after the holidays as well.



I've been experimenting with Browserify and Webpack, two build tools that are capable of taking Node.js libraries and packaging them up in a way that makes them usable in browser applications. We can take advantage of what these tools do to make some libraries run server-side in ServiceNow.



Here are the steps I took to get from zero to a working AWS SQS call.



1. Install aws4 Node.js package on your computer

Make a directory somewhere and run npm install aws4



2. Install webpack

Run command sudo npm install -g webpack



This may vary slightly depending on   your Operating System



3. Create a stub .js file and run Webpack against it

Create a file, let's call it aws4_prep.js. Add the following two lines of code:



var aws4 = require('aws4');


global.aws4 = aws4;



Save the file, and from the command line, run webpack aws4_prep.js aws4_built.js



4. Create a script include in ServiceNow

Create a script include with name aws4 (this matches the assignment we did on line 2 of our Node script)



Copy the contents of aws4_built.js into the script include and save it



5. Make any necessary adjustments to that script include

Depending on the library, you may have to make minor adjustments to the code. I think you're in the clear with aws4 though.



6. Build out an SQS call


Adjust the properties below such as AWS keys and Queue URL and run this from a background script:



// Define a method that will help build our RESTMessageV2 call


function prepareRestMessage(rm, options) {


  rm.setHttpMethod(options.method || 'GET');


  rm.setEndpoint('https://' + options.host);



  // Loop through the headers and add them


  for (var h in options.headers) {


      rm.setRequestHeader(h, options.headers[h]);


  }



  // Loop through the query params and add them to the message


  // We'll also build an array of key/value pairs for later use


  var params = [];


  for (var q in options.query) {


      rm.setQueryParameter(q, options.query[q]);


      params.push([q, options.query[q]].join('='));


  }  



  // Get a signature


  var opts = {


      method: options.method,


      host: options.host,


      path: '?' + params.join('&') // We collected these in the last step


  };



  // The only place we actually use the aws4 package


  aws4.sign(opts, options.awsCredentials);



  // Set the headers using the signature we just obtained


  rm.setRequestHeader('Authorization', opts.headers.Authorization);


  rm.setRequestHeader('X-Amz-Date', opts.headers['X-Amz-Date']);


}



// Build out the options we want to apply to the RESTMessageV2 call


var options = {


  awsCredentials: { accessKeyId: '<Your Access Key>', secretAccessKey: '<Your Secret Key>' },


  method: 'POST',


  host: 'sqs.us-east-1.amazonaws.com',


  headers: { 'Accept': 'application/json' },


  query: {


      'Action': 'SendMessage',


      'QueueUrl': 'https://sqs.us-east-1.amazonaws.com/your-queue-url',


      'MessageBody': 'TestFromServiceNow'


  }


}



// Build the REST Message


var rm = new sn_ws.RESTMessageV2();



// Work some magic on the REST Message object (see the method above)


prepareRestMessage(rm, options);



// Let's do this thing!


var response = rm.execute();


var body = response.getBody();


gs.debug(body);




With any luck, you'll get a response like this indicating success!



*** Script: [DEBUG] {"SendMessageResponse":{"ResponseMetadata":{"RequestId":"6c3ce549-259d-57da-9217-b58505f306ec"},"SendMessageResult":{"MD5OfMessageAttributes":null,"MD5OfMessageBody":"73aa0f5998721b11234b56ddaac0a6ad","MessageId":"e64123b5-9b54-4139-9e48-3bfa276774b3"}}}



Getting this working is pretty challenging, but hopefully these steps will give you a general path to follow. This is also not the only way to accomplish this - you could also try to do something similar with webpack and CryptoJS (or some other library) and handle the canonicalization and signing of the URL yourself, but aws4 seems like the "easiest" route.



Let me know how it goes!


Hi, I have been playing around with the solution you outlined - the webpack portion worked great, but I am getting an error with placing the library into a script include:



Could not save record because of a compile error: JavaScript parse error at line (349) column (32) problem = missing ) after condition



This line (number 1, below) looks to be properly enclosed with () except possibly for the regular expression which I am not knowledgeable enough to untangle.



12345678901234567890123456789012


  if (/[^0-9A-Za-z!'()*\-._~%/]/.test(path)) {


      path = path.split('/').map(function(piece) {


          return querystring.escape(querystring.unescape(piece))


      }).join('/')


  }



Did you happen to observe this error?


Hmm, I did not experience this error. What version of ServiceNow are you working on?


We are on Geneva Patch 8 Hot Fix 1.