Advanced MID Server Series – Part 2 – A Better JavascriptProbe

Introduction

Welcome to the second post in the series of articles looking into Advanced MID Server solutions. At the end of the last post we learned how we can use the JavascriptProbe Script Include to initiate the execution of a script on the MID Server. In this article we will be creating our own version of this Script Include that adds additional functionality and helps us protect our sensitive data in transit.

Fixing what’s broken

OK, so the JavascriptProbe isn’t technically broken, but there are certainly some oversights and some things we can add to make our lives a bit easier. Here’s a list of what we’ll be adding:

  • Encryption of sensitive data
  • Synchronous processing (for development testing)
  • Automatic discovery sensor skipping

Protect your credentials!

The JavascriptProbe provided by ServiceNow includes just one method for adding parameters to our requests addParameter(name, value). Let us take a look at this method.

setSource : function(s) {
    this.source = s;
},

addParameter : function(name, value) {
    var el = this.payloadDoc.createElement("parameter");
    el.setAttribute("name", name);
    el.setAttribute("value", value);
},

setJavascript : function(script) {
    this.addParameter("script", script);
},

What happens if for example we want to send a username and password to the MID server for some sort of integration? Well this is going to send it in plaintext. Yes, you read that right! In practical terms the means the following:

  • The sensitive data will be stored within the ECC queue for any user with enough access to go and steal
  • The sensitive data will be transferred over the public internet in plaintext
  • The sensitive data will be stored on the MID server in plaintext for a time whilst the job is processing

Admittedly, the second point there is of less concern due to the connection between MID Server and ServiceNow instance using SSL/HTTPS, but you just never know…

The good news is that this is reasonably easy to fix. ServiceNow actually provide the AutomationAPI that we can leverage to encrypt this data and have it automatically decrypted in memory on the MID server. I’m not entirely sure why ServiceNow hasn’t implemented this already.

setSource : function(s) {
	  this.source = s;
},

addParameter : function(name, value) {
    var el = this.payloadDoc.createElement("parameter");
    el.setAttribute("name", name);
    el.setAttribute("value", value);
},

addEncryptedParameter : function(name, value) {
    var automationApi = new sn_automation.AutomationAPI();
    var encryptedValue = automationApi.encrypt(value);
    this.addParameter(name, encryptedValue);
},

setJavascript : function(script) {
    this.addParameter("script", script);
},

Testing our new method, we can see the results in the outgoing ecc_queue entry.

Go on, I dare you, refresh that list again.

When developing on ServiceNow, if you’re anything like me, you’ll make good and extensive use of Background Scripts as a simple and quick way to test your script without having to navigate to a specific page, click a specific button, get a flow to trigger etc.

The same can also be said of MID Server scripts, but annoyingly there is then the need to navigate to the ECC queue and refresh the list over and over until you see a response come in for your request. You could be spending this time doing something much more productive, like sipping that sweet oat chai latte that’s slowly leaking through the bottom of the disintegrating takeaway cup. But let’s be honest, you don’t want (or have time) to clean up that mess, so let’s update our script to make this easier for us.

The MID Server is asynchronous by design, meaning that we need to find a way to make it function as though it’s synchronous. What if instead of manually refreshing ECC queue, we could get our script include to do it for us and let us know when a response has come in? We can do exactly that using GlideRecord to look for responses to our instruction and gs.sleep(milliseconds) to place a 2 second delay between “refreshes”. Couple both of those with a do-while loop and we’ve got ourselves a solution.

		egr.topic = "JavascriptProbe";
		egr.name = this.name;
		egr.source = this.source;
		egr.payload = this.payloadDoc.toString();
		return egr.insert();
	},

	createSync: function () {
		var strOutputEccId = this.create();
		var intMaxItterations = 30;
		var intCurrentItteration = 0;
		var intWaitMillis = 2000;
		
		do {
			gs.sleep(intWaitMillis);

			var grEccInput = new GlideRecord('ecc_queue');
			if (grEccInput.get('response_to', strOutputEccId)) {
				return gs.getProperty('glide.servlet.uri') + grEccInput.getLink();
			}

			intCurrentItteration += 1;
		} while (intCurrentItteration < intMaxItterations);

		return 'No response returned within allowed time of ' + ((intWaitMillis * intMaxItterations) / 1000) + ' seconds';
	},

	type: 'BetterJavascriptProbe'
}

My response says there’s been an error πŸ™

Don’t worry, our response probably doesn’t have an error. The state we’re seeing is related to Discovery, the original and sole intended use for the MID Server (how times change). We can easily prevent this from showing an error state by adding a parameter to our request.

var bjp = new BetterJavascriptProbe('PersonalDevMID');
bjp.setJavascript('new MyClass().getMIDDateTime()');
bjp.addParameter('skip_sensor', 'true');
gs.info(bjp.createSync());

That’s great, but now we have to remember to add that parameter in every time we use the MID Server for executing javascript… or we could just add it in automatically. Back to our Script Include, where we can simply add the following into our create method.

  setJavascript: function (script) {
		this.addParameter("script", script);
	},

	create: function () {
		this.addParameter('skip_sensor', 'true');
		var egr = new GlideRecord("ecc_queue");
		egr.agent = "mid.server." + this.midServer;
		egr.queue = "output";
		egr.state = "ready";
		egr.topic = "JavascriptProbe";
		egr.name = this.name;
		egr.source = this.source;
		egr.payload = this.payloadDoc.toString();
		return egr.insert();
	},

	createSync: function () {
		var strOutputEccId = this.create();

And that’s it. We’ve now got ourselves a better JavascriptProbe than the one provided out of the box. If you’ve followed along, you may already have your new Script Include ready to go. If not, see the download below to get your copy.

Share this with your network

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top