[vc_row][vc_column][vc_column_text]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.[/vc_column_text][/vc_column][/vc_row]