SailPoint IIQ and ServiceNow custom integration using ServiceNow REST APIs (ServiceNow Table API) - PART 2

Published September 6, 2018
SailPoint IIQ and ServiceNow custom integration using ServiceNow REST APIs (ServiceNow Table API) - PART 2 Image

Insight summary and table of contents

Summary

Contents

SailPoint IIQ provides many out-of-the-box (OOTB) options to integrate with ServiceNow. Though OOTB integrations are great for most of the common use cases, it lacks the flexibility and provides less control over the entire process.

Many times we come across a requirement where we need total control, and that’s where this custom integration can be very useful.

Note: This is the second part of the series and covers the Service Catalog request management.  Please review Part 1 of this series which covers the pre-reqs, basic configuration, and incident management in detail.

Creating ServiceCatalog request in ServiceNow using REST APIs

ServiceCatalog requests (SR) are different than incidents. Some of the options available for incidents are not available for SR and vice-versa. The process of creating SR is more complicated than the process of creating incidents and involves sending multiple REST calls and useing the output of the first call as the input of subsequent steps.

The example below assumes all the prereqs from Part 1 of this blog series. This example also assumes that Service Catalog is already available on SN (catalog requests will be created under Service Catalog). If the requirement is to set the custom variables in request item, then you must create the variable template in request item before you try to do it through REST APIs.

Process To Create Service Catalog Request

  1.  Create Service Catalog Request (SR).
  2.  Create Request item (RI)
  3.  Create the custom variable and update its value.
  4.  Correlate the custom variable created in step3 with RI created in step2 using sys_id.
  5.  Correlate the RI back to SR using sys_id

SN object to SN Table mapping 

No.ServiceNow ObjectServiceNow Table
1SN Catalog requestsc_request
2SN Catalog request itemsc_req_item
3SN Catalog item variablesc_req_item_option
4SN variable and request item correlationsc_req_item_mtom

Refer to the table below for SN URIs, operations, and HTTP Verbs.

No.OperationURIHTTP Verb
1Create new Service Catalog Requesthttps://xxx.service-now.com/api/now/v1/table/sc_requestPOST
2Get the existing Service Catalog Request from ServiceNowhttps://xxx.service-now.com/api/now/v1/table/sc_request/sys_id Note: sys_id is internal system identifier of SR object created earlier. Examples: Sys_id: 1a451fad4ff3130081630fbf9310c7b0GET
3Update the Service Catalog Request created earlierhttps://xxx.service-now.com/api/now/v1/table/sc_request/sys_id Note: sys_id is internal system identifier of Service Catalog Request object created earlier. Examples: Sys_id: 1a451fad4ff3130081630fbf9310c7b0PUT
4Create new Request Itemhttps://xxx.service-now.com/api/now/v1/table/sc_req_itemPOST
5Update request itemhttps://xxx.service-now.com/api/now/v1/table/sc_req_item/sys_idPUT
6Create Variablehttps://xxx.service-now.com/api/now/v1/table/sc_item_optionPOST
7Create Variable correlation with request itemhttps://xxx.service-now.com/api/now/v1/table/sc_item_option_mtomPOST

ServiceNow exposes multiple ways to authenticate. For this blog, we will use “basic authentication”. You can find more about basic authentication here.

The Pre-Reqs

The following variable values must be gathered before you start the implementation:

No.VariableE.g. ValueComments
1EndpointURLhttps://xxx.service-now.com/api/now/v1/tableCommon portion of the SN URI. The suffix can be added to base URI to generate table specific URI
2UsernameadminUsername is used in basic authentication. This user must have the appropriate rights to manage incidents in SN
3PasswordP#ss&rd134Password is used in basic authentication.
4CallerID1a451fad4ff3130081630fbf933454Sys_id of the caller, this is the sys_id of the SN user who will be set as a requester of an incident.
5CatalogID58d41bad4ff313dfd1630fbf9310cdsfds6Sys_id of the service catalog
6variableTemplateID80sdf4d3ad4ff3130081630fbf9310c7zdfSys_id of the variable template

This example expects the custom IIQ object which holds the ServiceNow connection details. Please refer Part 1 of this blog series to add the CatalogID, variableTemplateID

The Implementation

Workflow implementation can be anything, for detailed information and variable details, please refer to Part 1 of this blog series.

The following script is responsible for creating the service requests in SN. Code comments should help understanding overall flow of the request.

        import java.io.BufferedReader;
        import java.io.InputStreamReader;
        import java.io.OutputStreamWriter;
        import java.net.URL;
        import java.net.URLConnection;
        import java.util.Base64;
        import java.util.List;
        import java.util.Map;
        import org.json.simple.JSONObject;
        import org.json.simple.parser.JSONParser;
        import java.util.*;
        import sailpoint.object.*;
        log.info("Creating serviceNow Service Request");
        try
        {
			//Get Credentials
			String baseEndPointURL = ServiceNowCredsMap.get("EndpointURL");
			String username = ServiceNowCredsMap.get("Username");
			String encryptedPassword = ServiceNowCredsMap.get("Password");
			String CatalogID = ServiceNowCredsMap.get("CatalogID");
			String CallerID = ServiceNowCredsMap.get("CallerID");
			String variableTemplateID = ServiceNowCredsMap.get("variableTemplateID");
			
			//variable to hold sys_ids
			String sc_req_item_id = "";
			String sc_item_option_id = "";
			String sc_request_id = "";
			String sc_item_option_mtom_id = "";
			String reqNumber = "" ;
			
			
			//SN table names 
			String requested_item_table = "sc_req_item";
			String service_request_table = "sc_request";
			String variable_table = "sc_item_option";
			String variable_requestItem_correlation_table = "sc_item_option_mtom";
			
			//service request json
			String sr_request = "{'short_description':'IAM request for #UserName#','assignment_group':'Service Desk','urgency':'3','impact':'3','contact_type':'email','sys_created_by':'admin','opened_by':'admin','description':'#Description#','approval':'approved','request_state':'in_process','price':'0','opened_by':'#CallerID#'}";
			
			//requested item json
			String sr_requestitem_request = "{'state':'1','sys_created_by':'admin','impact':'3','active':'true','priority':'4','short_description':'TIPS','description':'#Description#','urgency':'3','comments':'','approval':'approved','comments_and_work_notes':'','cat_item':'#CatalogID#','upon_approval':'proceed','upon_reject':'cancel','request':'#ServiceRequestID#','price':'0'}";
			
			//variable request json
			String sr_requestitem_variable_request = "{'item_option_new':'#variableTemplateID#','value':'#WorkNotes#','sys_created_by':'admin','order':'1'}";
			
			//variable to request item correlation json
			String requestItem_variable_correlation_request = "{'request_item':'#RequestedItemID#','sc_item_option':'#VariableID#','sys_created_by':'admin'}";
			
			//check password and decrypt it
			if(encryptedPassword == null || encryptedPassword.isEmpty())
			{
				log.error("ServiceNow Error:Password can not be null or empty");
				return;
			}
			String decryptedPassword ="";
			try{
				decryptedPassword = context.decrypt(encryptedPassword);
			}
			catch(Exception e)
			{
				log.error("Error while decrypting password" + e);
			}
			
			log.error("Creating service request....");
			
			//create ServiceRequest
			URL serviceRequestURL = new URL(baseEndPointURL + "/" + service_request_table);
			URL requestItemURL = new URL(baseEndPointURL + "/" + requested_item_table);
			URL variableURL = new URL(baseEndPointURL + "/" + variable_table);
			URL correlationURL = new URL(baseEndPointURL + "/" + variable_requestItem_correlation_table);
			
			//open connection
			HttpURLConnection c = (HttpURLConnection) serviceRequestURL.openConnection();
			
			//Set Auth information
			String authStr = Base64.getEncoder().encodeToString((username +":"+ decryptedPassword).getBytes());

			//setting Authorization header
			c.setDoOutput(true);
			c.setRequestMethod("POST");
			c.setRequestProperty("Authorization", "Basic " + authStr);
			c.setRequestProperty("Content-Type", "application/json");

			//Create Description
			//Add request details
			//Here you can add as many attributes you want.
			String desc = "This is SN notification for " + requestMap.get("username") + "rn" + "User Information";
			for (String key : UserAttributeToDisplayNameMap.keySet())
			{
				if(key != null)
				{
					if(!desc.isEmpty())
					desc = desc + "rn";

					desc = desc + UserAttributeToDisplayNameMap.get(key) + ": " + requestMap.get(key);
				}
			}

			//Replace tokens
			sr_request = sr_request.replace("#UserName#",requestMap.get("username")).replace("#Description#",desc).replace("#CallerID#", CallerID).replace("rn","n");

			//Write to output stream
			OutputStream os = c.getOutputStream();
			os.write(sr_request.getBytes());
			os.flush();

			//Common variables
			BufferedReader bf;
			StringBuilder stringBuilder;
			String line;
			String response;
			JSONParser parse = new JSONParser();
			JSONObject jobj;
			JSONObject result;
			
			
			//Send Request and get response code
			if (c.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
			throw new RuntimeException("Failed : HTTP error code : " +
			c.getResponseCode());

			} else {
				bf = new BufferedReader(new InputStreamReader(c.getInputStream()));
				stringBuilder = new StringBuilder();
				
				while ((line = bf.readLine()) != null) {
				stringBuilder.append(line);
				}
				response = stringBuilder.toString();

				//return response;
				System.out.println("response : " + response);

				//Type caste the parsed json data in json object
				jobj = (JSONObject) parse.parse(response);
				result = (JSONObject) jobj.get("result");

				//Retrieve service request sys_id
				reqNumber = result.get("number");
				sc_request_id = result.get("sys_id");
				
				log.error("Service Request created Successfully. sys_id:"+ sc_request_id);
				
			}
			
			if(!sc_request_id.isEmpty())
			{
				//setting Authorization header
				HttpURLConnection c1 = (HttpURLConnection) requestItemURL.openConnection();
				
				c1.setDoOutput(true);
				c1.setRequestMethod("POST");
				c1.setRequestProperty("Authorization", "Basic " + authStr);
				c1.setRequestProperty("Content-Type", "application/json");
				
				//replace tokens
				sr_requestitem_request = sr_requestitem_request.replace("#ServiceRequestID#",sc_request_id).replace("#Description#",desc).replace("#CatalogID#", CatalogID).replace("rn","n");
				
				//Write to output stream
				os = c1.getOutputStream();
				os.write(sr_requestitem_request.getBytes());
				os.flush();
				
				//Send Request and get response code
				if (c1.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
				throw new RuntimeException("Failed : HTTP error code : " +
				c1.getResponseCode());

				} else {
					bf = new BufferedReader(new InputStreamReader(c1.getInputStream()));
					stringBuilder = new StringBuilder();

					while ((line = bf.readLine()) != null) {
					stringBuilder.append(line);
					}
					response = stringBuilder.toString();

					//return response;
					System.out.println("response : " + response);

					//Type caste the parsed json data in json object
					jobj = (JSONObject) parse.parse(response);
					result = (JSONObject) jobj.get("result");

					//Retrieve service request sys_id
					sc_req_item_id = result.get("sys_id");
				
					log.error("Service Request item created Successfully. sys_id:"+ sc_req_item_id);
				}
				
			}
			else
			{
				throw new RuntimeException("Error while creating service request, aborting..");
			}
			
			if(!sc_req_item_id.isEmpty())
			{
				//setting Authorization header
				HttpURLConnection c2 = (HttpURLConnection) variableURL.openConnection();
				
				c2.setDoOutput(true);
				c2.setRequestMethod("POST");
				c2.setRequestProperty("Authorization", "Basic " + authStr);
				c2.setRequestProperty("Content-Type", "application/json");
				
				//replacing tokens
				sr_requestitem_variable_request = sr_requestitem_variable_request.replace("#variableTemplateID#",variableTemplateID).replace("rn","n");
				
				//Write to output stream
				os = c2.getOutputStream();
				os.write(sr_requestitem_variable_request.getBytes());
				os.flush();
				
				//Send Request and get response code
				if (c2.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
				throw new RuntimeException("Failed : HTTP error code : " +
				c2.getResponseCode());

				} else {
					bf = new BufferedReader(new InputStreamReader(c2.getInputStream()));
					stringBuilder = new StringBuilder();

					while ((line = bf.readLine()) != null) {
					stringBuilder.append(line);
					}
					response = stringBuilder.toString();

					//return response;
					System.out.println("response : " + response);

					//Type caste the parsed json data in json object
					jobj = (JSONObject) parse.parse(response);
					result = (JSONObject) jobj.get("result");

					//Retrieve service request sys_id
					sc_item_option_id = result.get("sys_id");
				
					log.error("Variable created Successfully. sys_id:"+ sc_item_option_id);
				}
			}
			else
			{
				throw new RuntimeException("Error while creating service request item, aborting..");
			}
			
			if(!sc_item_option_id.isEmpty())
			{
				//setting Authorization header
				HttpURLConnection c3 = (HttpURLConnection) correlationURL.openConnection();
				
				c3.setDoOutput(true);
				c3.setRequestMethod("POST");
				c3.setRequestProperty("Authorization", "Basic " + authStr);
				c3.setRequestProperty("Content-Type", "application/json");
				
				//replacing tokens
				requestItem_variable_correlation_request = requestItem_variable_correlation_request.replace("#RequestedItemID#",sc_req_item_id).replace("#VariableID#", sc_item_option_id).replace("rn","n");
				
				//Write to output stream
				os = c3.getOutputStream();
				os.write(requestItem_variable_correlation_request.getBytes());
				os.flush();
				
				//Send Request and get response code
				if (c3.getResponseCode() != HttpURLConnection.HTTP_CREATED) {
				throw new RuntimeException("Failed : HTTP error code : " +
				c3.getResponseCode());

				} else {
					bf = new BufferedReader(new InputStreamReader(c3.getInputStream()));
					stringBuilder = new StringBuilder();

					while ((line = bf.readLine()) != null) {
					stringBuilder.append(line);
					}
					response = stringBuilder.toString();

					//return response;
					System.out.println("response : " + response);

					//Type caste the parsed json data in json object
					jobj = (JSONObject) parse.parse(response);
					result = (JSONObject) jobj.get("result");

					//Retrieve service request sys_id
					sc_item_option_mtom_id = result.get("sys_id");
				
					log.error("Variable correlation created Successfully. sys_id:"+ sc_item_option_mtom_id);
				}
			}
			else
			{
				throw new RuntimeException("Error while creating variable correlation, aborting..");
			}
			
			workflow.put("incidentid",reqNumber);
			
			//Store incidentid on cube : Optional
			Identity idObj = context.getObjectByName(Identity.class,identityName);
			idObj.setAttribute("IncidentNo",sc_request_id);
			context.saveObject(idObj);
			
			log.info("ServiceNow ServiceRequest created..");
        }
        catch(Exception ex)
        {
			log.error("Unable to create serviceNow ServiceRequest:" + ex);
        }

Closing request is the same as that of closing incidents. Please refer Part 1 of this blog series for the code. Just replace the value of variable "input" with field relevant to your implementation.

Bonus Information: Okta OIN is an enterprise grade identity management service. It connects anyone on any application regardless of the device. It is cloud-based offering security, reliability, and the power to integrate with on premise directories, applications, and identity management systems.