SailPoint IIQ and ServiceNow custom integration using ServiceNow REST APIs (ServiceNow Table API) - PART 2
Published September 6, 2018
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
- Create Service Catalog Request (SR).
- Create Request item (RI)
- Create the custom variable and update its value.
- Correlate the custom variable created in step3 with RI created in step2 using sys_id.
- Correlate the RI back to SR using sys_id
SN object to SN Table mapping
| No. | ServiceNow Object | ServiceNow Table |
| 1 | SN Catalog request | sc_request |
| 2 | SN Catalog request item | sc_req_item |
| 3 | SN Catalog item variable | sc_req_item_option |
| 4 | SN variable and request item correlation | sc_req_item_mtom |
Refer to the table below for SN URIs, operations, and HTTP Verbs.
| No. | Operation | URI | HTTP Verb |
| 1 | Create new Service Catalog Request | https://xxx.service-now.com/api/now/v1/table/sc_request | POST |
| 2 | Get the existing Service Catalog Request from ServiceNow | https://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: 1a451fad4ff3130081630fbf9310c7b0 | GET |
| 3 | Update the Service Catalog Request created earlier | https://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: 1a451fad4ff3130081630fbf9310c7b0 | PUT |
| 4 | Create new Request Item | https://xxx.service-now.com/api/now/v1/table/sc_req_item | POST |
| 5 | Update request item | https://xxx.service-now.com/api/now/v1/table/sc_req_item/sys_id | PUT |
| 6 | Create Variable | https://xxx.service-now.com/api/now/v1/table/sc_item_option | POST |
| 7 | Create Variable correlation with request item | https://xxx.service-now.com/api/now/v1/table/sc_item_option_mtom | POST |
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. | Variable | E.g. Value | Comments |
| 1 | EndpointURL | https://xxx.service-now.com/api/now/v1/table | Common portion of the SN URI. The suffix can be added to base URI to generate table specific URI |
| 2 | Username | admin | Username is used in basic authentication. This user must have the appropriate rights to manage incidents in SN |
| 3 | Password | P#ss&rd134 | Password is used in basic authentication. |
| 4 | CallerID | 1a451fad4ff3130081630fbf933454 | Sys_id of the caller, this is the sys_id of the SN user who will be set as a requester of an incident. |
| 5 | CatalogID | 58d41bad4ff313dfd1630fbf9310cdsfds6 | Sys_id of the service catalog |
| 6 | variableTemplateID | 80sdf4d3ad4ff3130081630fbf9310c7zdf | Sys_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.