The CreatorCon Call for Content is officially open! Get started here.

Run Python Script from Service Now Workflow

sachin_namjoshi
Kilo Patron
Kilo Patron

Hello,

I have developed python script to create users in DUO application for assigning them DUO token.

As per DUO documentation, we can consume DUO REST API only via python, perl or ruby clients. Service now can not consume DUO REST API directly due to security constraints.

I need to consume this python script from service now workflow.

What is the best way to call python script from service now platform?

Regards,

Sachin

 

15 REPLIES 15

It works via postman using a pre-request script to generate a HMAC signature which uses crypto-js library. But while making a call from servicenow to duo we are using "

GlideCertificateEncryption".

Following is the postman script: 

let pc = require('postman-collection');
let cryptoJS = require('crypto-js');
let moment = require('moment');

let DATE = (moment().format("ddd, DD MMM YYYY HH:mm:ss ZZ"));
pm.environment.set("duo-DATE", DATE)

let METHOD = request.method;

let URL_OBJECT = new pc.Url(request.url);

//HOST is retrieved from the environment variable itself, since parsing the hostname using
//postman-collection's URL object will just give you the variable name.
let HOST = pm.environment.get("duo-API-HOST")

let PATH = URL_OBJECT.getPath();
let QUERY = URL_OBJECT.getQueryString();

let HMAC_STRING = DATE + "\n"
                + METHOD + "\n"
                + HOST + "\n"
                + PATH + "\n"
                + QUERY
               
let HMACd = cryptoJS.HmacSHA1(HMAC_STRING, pm.environment.get("admin-skey")).toString();

pm.environment.set("duo-admin-HMAC", HMACd)

Dhravesh,

     I am needing to use the DUO api within Servicenow to add and remove people from groups when a task comes due.  I am having trouble with the authentication piece in web services with Duo as I don't see how to do the HMAC authentication.  Can you help me at all?  Thanks.

 

-paul

Hi Paul,

 

I sucessfully implemented Service now DUO integration.

I created blog with all necesssary steps for this integration.

 

https://community.servicenow.com/community?id=community_blog&sys_id=14e958a0db7be7402be0a851ca9619f9

 

Please use this blog to resolve your query.

 

Regards,

Sachin

Hi Dhravesh Murpana,

I'm facing authentication issue when calling duo sec api in servicenow.

Can you help me out in this

Dhravesh Murpan
Mega Expert
_skey_int : function(){
	var skey_int ="XXXXXXXXXXXXXXXXXXXXXXXX";
		return skey_int;
	},
	
	_ikey_int : function(){
	var ikey_int ="XXXXXXXXXXXXXXXXXXXXXX";
		return ikey_int;
	},
	
	_host_int : function(){
	var host_int = "XXXXXXXXX.duosecurity.com";
		return host_int;
	},
	
	call_API : function(endpoint,method,path,params){
		var date = this.returndata();
		var skey = this._skey_int();
		var ikey = this._ikey_int();
		var host = this._host_int();
		var auth = this._returnAuth(method, host, path, params, skey, ikey,date);
		 var restMessage = new sn_ws.RESTMessageV2();
			
			restMessage.setHttpMethod(method);
			restMessage.setEndpoint(endpoint);
			restMessage.setRequestHeader('Date', date);
			restMessage.setRequestHeader('Authorization', auth);
			//restMessage.setRequestHeader("Content-Length", "35");
		if(method == 'POST' || method == 'PUT'){
			restMessage.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			var encodedParam = this._createQueryString(params+",");
			gs.info(encodedParam);
			restMessage.setRequestBody(encodedParam);
		}
		else
			restMessage.setRequestHeader("Content-Type", "application/json");
		
		
		
		var response = restMessage.execute();
		 var responseBody = response.getBody();
		 var httpStatus = response.getStatusCode();
	
		gs.info("httpStatus: "+httpStatus);
		gs.info("responseBody: "+responseBody);
		return response;
	},
	
	_returnAuth : function(method, host, path, params, skey, ikey,date){
		method = method.toUpperCase();
		host = host.toLowerCase();

		var msg = this._canonData(date,method,host,path,params);
		var sig = new x_zh_duo.Hashes.SHA1().hex_hmac(skey,msg);
		var d = ikey +":"+sig;
		var enc = gs.base64Encode(d);
		return "Basic "+enc;
		
	},
	
	_canonData : function(date,method,host,path,params){
		// 		var msg = date +"\n"+method+"\n"+host+"\n"+path+"\n"+params;
		 var canon = "";
		canon += date + "\n";
        canon += method.toUpperCase() + "\n";
        canon += host.toLowerCase() + "\n";
        canon += path + "\n";
        canon += this._createQueryString(params+",");
		//gs.info(canon);
        return canon;
	},
	
	_createQueryString : function(params){
		var args = [];
      var keys = [];
		
		function convertUTF(data){
			var da = encodeURIComponent(data);
			var fi = da.replace("+", "%20").replace("*", "%2A") .replace("%7E", "~");
			return fi;
		}
		//gs.info(params);
		var split = params.split(",");
		//gs.info(split);
		split.sort();
		for(i=0;i<split.length;i++){
			if(split[i] != ''){
				var dat = split[i].split(":");
			var name = convertUTF(dat[0]);
			var value = convertUTF(dat[1]);
				
			 args.push(name + "=" + value);
			}
			
		}
      //gs.info(args.join("&"));
	   return args.join("&");
	},
	
	getUser_byParam : function(param){
		var method ="GET";
		var encodedParam = this._createQueryString(param+",");
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/users?"+encodedParam;
		var path = "/admin/v1/users"; // ?"+encodedParam;
		var params = param;
		var data = this.call_API(endpoint,method,path,params);
		return data;
	},
	
	createUser_byParam : function(param){
		var method ="POST";
		//var encodedParam = this._createQueryString(param+",");
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/users"; //?"+encodedParam;
		var path = "/admin/v1/users";
		var params = param;
		var data = this.call_API(endpoint,method,path,params);
		return data;
	},
	
	createPhone_byParam : function(param){
		var method ="POST";
		//var encodedParam = this._createQueryString(param+",");
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/phones"; //?"+encodedParam;
		var path = "/admin/v1/phones";
		var params = param;
		var data = this.call_API(endpoint,method,path,params);
		return data;
	},
	
	activatePhone_byPhoneID : function(phoneid){
	// /admin/v1/phones/[phone_id]/activation_url
		var method ="POST";
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/phones/"+phoneid+"/activation_url";
		var path = "/admin/v1/phones/"+phoneid+"/activation_url";
		var params = '';
		var data = this.call_API(endpoint,method,path,params);
		return data;
	},
	
	_associatePhonewithUser : function(userid,phoneid){
	// /admin/v1/users/[user_id]/phones
		var method ="POST";
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/users/"+userid+"/phones";
		var path = "/admin/v1/users/"+userid+"/phones";
		var params = "phone_id:"+phoneid;
		var data = this.call_API(endpoint,method,path,params);
		return data;
	},
	
	_disassociatePhonewithUser : function(userid,phoneid){
	// /admin/v1/users/[user_id]/phones/[phone_id]
		var method ="DELETE";
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/users/"+userid+"/phones/"+phoneid;
		var path = "/admin/v1/users/"+userid+"/phones/"+phoneid;
		var params = '';
		var data = this.call_API(endpoint,method,path,params);
		return data;
	},
	
	modifyUser_byUserIDandParam : function(userid,param){
		var method ="POST";
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/users/"+userid;
		var path = "/admin/v1/users/"+userid;
		var params = param;
		var data = this.call_API(endpoint,method,path,params);
		return data;
	},
	
	getUser_byUserID : function(userid){
		var method ="GET";
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/users/"+userid;
		var path = "/admin/v1/users/"+userid;
		var params = "";
		var data = this.call_API(endpoint,method,path,params);
		return data;
	},
	
	deleteUser_byUserID : function(userid){
		var method ="DELETE";
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/users/"+userid;
		var path = "/admin/v1/users/"+userid;
		var params = "";
		var data = this.call_API(endpoint,method,path,params);
		return data;
	},
	
	deletePhone_byPhoneID : function(phoneid){
		// /admin/v1/phones/[phone_id]
		var method ="DELETE";
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/phones/"+phoneid;
		var path = "/admin/v1/phones/"+phoneid;
		var params = "";
		var data = this.call_API(endpoint,method,path,params);
		return data;
	},

	getUsers : function(){
		 try { 

		
		var method ="GET";
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/users";
		var path = "/admin/v1/users";
		var params = "";
		var data = this.call_API(endpoint,method,path,params);
		return data;	
			 }
		catch(ex) {
		 var message = ex.getMessage();
			gs.info(message);
		}	
	},
	
	getPhones : function(){
		 try { 

		
		var method ="GET";
		var endpoint = "https://api-XXXXXXXXX.duosecurity.com/admin/v1/phones"; // /admin/v1/phones
		var path = "/admin/v1/phones";
		var params = "";
		var data = this.call_API(endpoint,method,path,params);
		return data;	
			 }
		catch(ex) {
		 var message = ex.getMessage();
			gs.info(message);
		}	
	},
	
	returndata : function(){
		var month =  ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
		var week =  [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat','Sun'];

		var gdt = new GlideDateTime();
// 		gs.info(gdt.getTime());
		var tim = gdt.getTime().getByFormat('HH:mm:ss');
		var yea = gdt.getYearUTC();
		var datt = gdt.getDate().getByFormat('dd');
		
		var da = week[gdt.getDayOfWeekUTC()-1]+", "+datt+" "+month[gdt.getMonthUTC()-1] +" "+yea +" "+tim+" -0000";
		return da;
	},

I faced same issue but was able to figure out correct code by understanding the Python scripts provided by DUO. Let me know if you have any query.