Introduction:
In a requirement where we need to connect SAP Cloud Integration( SAP CPI) with ServiceNow Instance for creation of case/Incident. We need to call the ServiceNow APIs to authenticate via several authentication mechanism few of them are Basic Authentication(username and password) and Oauth Authentication.
Now, in this blog , I am going to demonstrate how we can use
Oauth Connectivity between SAP Cloud Integration (SAP CPI) and ServiceNow using
grant_type = "Password".
While demonstrating the step by step process, we may go through few important technical aspects as below:
- Leveraging Security Artifacts--> User Credential type to store Username,Password,Client ID and Client Secret which I have used as a trick to avoid exposure of connectivity details over iflow build steps.
- Setting up of Authorization Header body using credentials from above step1 and setting content type "application/x-www-form-urlencoded" through a groovy script.
- Use of Authentication bearer token by setting up Auth Token Header using a groovy script which will be used to send data/file attachment to ServiceNow API for incident creation.
- Capturing HTTP response body received from ServiceNow incident/case creation using a groovy script.
This sample process can be leveraged by developers to edit, modify and enhanced according to other business requirements as well.
Prerequisites:
You should have CPI tenant access and have understanding on Integration flow development.
You should have ServiceNow OAuth details like Username,Password,ClientID,Client Secret to be configured on CPI tenant.
Design approach: To explain these scenario, I have created sample iflow
:
Below Figure1 will show the high level steps performed on the iflow development
Figure 1 : Iflow Steps
Step1(Figure1) : Sender System(Participants) : This System name is defined to connect to Sender system SFTP to poll the file.
Step2(Figure1) : Sender SFTP Channel to Poll the files to be sent to ServiceNow API for incident creation. Files to be picked up from Sender SFTP folder path as configured.
Step3(Figure1) : Content Modifier in this usecase used to set properties for below externalized parameters like:
Filename : To get the polled filename
FilePath : Archive folder path for polled files to move.
SYS_ID : for ServiceNow API parameter
SnowCredential : To specify the security artifact name
inputfilepayload : To store input file payload body.
Content Modifier - Externalization of Parameters
Here Property
SnowCredential : "
testServiceNow2" is defined on Security artifacts as User Credential type to avoid exposure of password,clientid and client secret to be hardcoded on the Iflow.(this is one of the trick I have used to configure and retrieved on groovy script on next step).
Developers can explore more ways of hiding secure connectivity credentials details and post as blog comments.
Security Artifacts - User Credential Type
Step4(Figure1) :Groovy Script : This step is used to retrieve Username, Client_Id, Client_Secret from Deployed Security Artifact
" testServiceNow2" and
prepare an authorization body for
Oauth grant_type = "Password" connectivity and this body will be passed on the next step via HTTP channel for authentication request with ServiceNow instance.
On this groovy script message header
Content-type is also set to
"application/x-www-form-urlencoded" which is required for making successful authentication.
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
import com.sap.it.api.ITApiFactory;
import com.sap.it.api.securestore.SecureStoreService;
import com.sap.it.api.securestore.UserCredential;
def Message processData(Message message) {
//Credentials // the same user credentials needs to be avaliable in secure material.
//def user = "YOUR_UserCredentials";
def user = message.getProperty("SnowCredential");// externalise to provide different name configured in other instances on transport
message.setHeader("Content-type", "application/x-www-form-urlencoded");
//service to get the credentials
def service = ITApiFactory.getApi(SecureStoreService.class, null);
//get user credential
def userCred = service.getUserCredential(user);
if (userCred == null){
throw new IllegalStateException("No User credential found for alias" + user);
}
String username = userCred.getUsername();
String password = new String(userCred.getPassword());
//store password parameters i.e password client id and client secret delimited with * symbol as mentioned on respective security artifact
String[] entry = password.split("\\*");
password = entry[0].trim();// retrive password
client_id = entry[1].trim(); // retrive cleint Id
client_secret = entry[2].trim(); // retrive Client_secret
//HTTP Parameters value
String grant_type = "password"; // Service Now grant type
//Query
def query = "";
query = query + "client_id=" + client_id + "&";
query = query + "client_secret=" + client_secret + "&";
query = query + "grant_type=" + grant_type + "&";
query = query + "username=" + username + "&";
query = query + "password=" + password;
message.setBody(query);
return message;
}
Groovy Script Code Snippet (Prepare Authentication Body and set content-type message header)
Step5/Step6/and Step7 (Figure1) : Request Reply/ServiceNow Receiver component/HTTP Channel: These steps are used to call ServiceNow system using HTTP adapter which tries to authenticate with prepared Authentication body and prepared Content-Type on step 4:
HTTP Channel for OAuth Authentication Request
Here, Http Address format is "
https://<ServiceNowInstance-Address>/Oauth_token.do
Where,
<ServiceNowInstance-Address> = Service now instance connectivity address.
Step8(Figure1) :Groovy Script : This step is used to retrieve the the response from ServiceNow and store the Auth bearer token generated and configured as Authorization Header parameter after successful authentication from last step.
ServiceNow session remains open for this authenticated token until timeout. This token authenticate directly for further data transfer(in our case sending incoming file) through ServiceNow API until token session expired at ServiceNow side.
import groovy.json.*;
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
def Message processData(Message message) {
//Body
def body = message.getBody(String.class);
def jsonSlurper = new JsonSlurper()
def list = jsonSlurper.parseText(body)
def token="Bearer "+list.access_token.toString();
//Headers
def map = message.getHeaders();
message.setHeader("Authorization", token);
return message;
}
Groovy Script Code Snippet (Prepare Authorization Header from generated authentication Token)
Step9(Figure1) : Content Modifier : This step is used to retrieve incoming payload body of the polled file.
Content Modifier - Get Incoming payload
Step10/Step6/and Step11 (Figure1) : Request Reply/ServiceNow Receiver component/HTTP Channel: These steps are used to call the actual ServiceNow API for incident creation.
It will internally make use of set
Token Authorization Header to authenticate and pass the incoming payload/data to ServiceNow system.
Sending File to ServiceNow API for incident/Case creation
Here, URL configured is :
https://
<ServiceNow-Address>/api/now/attachment/file?
table_name={property.SYS_tablename}&
table_sys_id=${property.SYS_ID}&
file_name=${property.Filename}
Where:{property.SYS_tablename} , ${property.SYS_ID},${property.Filename} are externalized parameter for user inputs screen.
Step12/Step13(Figure1) :Groovy Script/end : This step is used to retrieve the the response from ServiceNow final API call and log the HTTP response and end the process.
import com.sap.gateway.ip.core.customdev.util.Message;
import java.util.HashMap;
def Message processData(Message message)
{
def body = message.getBody(java.lang.String) as String;
def messageLog = messageLogFactory.getMessageLog(message);
if(messageLog != null)
{
messageLog.addAttachmentAsString("HTTP Response after attachment upload:", body, "text/plain");
}
return message;
}
Conclusion:
In this blog post, I demonstrated how to make use of Oauth grant_type = password based connectivity leveraging below points:
- How to retrieve Oauth credential parameters using groovy script from Security artifacts User Credential type and a trick used to maintain password as combination of password, clientId, client_secret delimited with character(in my usecase it's a "*" star-symbol).
- Set Authentication Body and Content- type using script for initial ServiceNow instance authentication.
- Creating an Authorization header from Service Now Bearer token retrieved.
- Calling the ServiceNow API for transmitting data using Authorization Token header .
- Capturing the HTTP response from ServiceNow API call.
Hope this blog post will help CPI developers to achieve similar functionality and this can be enhanced more to meet the technical business requirements.