Fabian Kunzke
Kilo Sage
Kilo Sage

This blog entry is a short tutorial of how to create a REST call within the flow designer as the Mid-Server as running instance. Note: This is how i did it. I did not find any available documentation for this, nor any content on the community. This may not be the way to go, but i (personally) did not find any other way.

Why do this?

Just to be clear: This is a very specific and very niece use case. Usually you are fie with using the "REST" step or even scripting with the RESTMessageV2() API. Therefore, the first question should be: Why?

Let's set the stage: You have a provisioning workflow, which triggers an automatic creation of user groups and roles within your user-management system. Or maybe you have another system, which manages some infrastructure components you need access to. Or your want to change a configuration there. Or...

Usually, when looking at the integrationhub, first thing to do is: Check for an existing spoke. There are many and we don't need to reinvent the wheel. But sometimes, there isn't. Next thing to check: How is the REST API configured. You got a header based authentication? Great, no need to read any further. You don't. Then this may be the exact case.

In the example where i used it, the REST API needed an authentication token for further interactions. And the place where you can get it returned the token if:

1) you gave the correct username and password combo
2) you gave the correct secret

Now here is the issue: This had to be done within the body of the REST call. Why is this an issue? Whenever the body for a "REST step" is created it is automatically logged within the integration hub log. When using the RESTMessageV2() API the ECC queue contains the REST body as well. In both cases the password as well as the secret would be either logged or stored within the ECC queue unencrypted. And that my friends is what we call a security no-go.

Building a HTTP REST Message on the Mid-Server

Now, this can be solved by doing 2 things:

1) create a step which takes the password fields as an input variable and runs on the Mid-Server
2) Decrypt the encrypted values on the Mid-Server, then execute a HTTP Request from there

The downside here is, that logging is very restrictive and any error handling is more or less absent. But no decryption of values outside of the Mid-Server runtime - noice.

The script for the execution itself then look pretty unspectacular, if you know what you are looking for:

(function execute(inputs, outputs) {
// ... code ...
  
  var HTTPRequest = Packages.com.glide.communications.HTTPRequest; // -> loading the HTTP package
  var Encrypter = Packages.com.glide.util.Encrypter; // -> loading the Encrypter package
 
  var username = inputs.user_name;
  var password = new Encrypter().decrypt(inputs.password); // -> this decrypts any password field
  var client_id = inputs.client_id;
  var client_secret = new Encrypter().decrypt(inputs.client_secret); // -> this decrypts any password field
  
  var request = new HTTPRequest('Endpoint URL here');
  request.addHeader('Content-Type', 'application/x-www-form-urlencoded'); //-> add whatever headers you need
  
  var body = 'grant_type=password&client_id=' + client_id
+ '&client_secret=' + client_secret
+ '&username=' + username
+ '&password=' + password;
  
  var response = request.post(body);
  outputs.body = response.getBody();
  

})(inputs, outputs);

Aaaaaand you are done. Note that the HTTPRequest and Encrypter at the top are packages provided by servicenow. Further: This can be incorporated into a Mid-Server-Script include as well, allowing you to essentially utilise it outside of the integration hub - but thats for another story. (Note: The example used here is common for command line APIs)

Thats it. This script will be executed on the Mid-Server (Note: ensure that your "Script-Step" required runtime is set to "Mid-Server"). 

 

Update for newer instance versions and using the encryption/decryption in a custom action for the flow designer

@Daniel Gurney1 I've now managed to get it to work in a scoped custom spoke action with a bit of fiddling:

 

1) For any password value, get the encrypted value and decrypt on the instance, then encrypt it with the automation api:

 

var clearSecret = secret.getDecryptedValue();
var automation = new sn_automation.AutomationAPI();
var encryptedSecret = automation.encrypt(clearSecret);
return encryptedSecret;

 

2) Within an instance action put the encrypted value into an output variable of the string type. Within the script parse it as a JSON string (any other way will always result in a serialization error):

 

var customIntegrationUtils= new customIntegrationUtils(); // -> calling the script from step 1)
var secret = customIntegrationUtils.getSecret();
if(!secret)
    return;
    
outputs.group_key = JSON.stringify(secret); // -> otherwise we cannot pass it to a output variable

 

3) Within the MID server script action, parse the JSON string, the use the ParameterEncrypter package (the Encrypter Packages DOES NOT WORK) to decrypt the secret

 

var secret = JSON.parse(inputs.secret);
var secretDecrypted = Packages.com.snc.commons.ParameterEncrypter.get().decrypt(secret); // -> this decrypts the secret field

 

And now you are good to go. Archives the "don't have any variables logged in clear text" issue while still being able to execute the HTTP call.

Thank you @Daniel Gurney1 for the help on this one.

9 Comments