SAP Webservice connector Rule error

In Prod I’m seeing the below error when performing modify operation for SAP webservice connector. The same code is working fine in sandbox env. Can you please identify the issue?.

Error: Incomplete items. Please contact your administrator.

Provisioning

Exception occurred while performing 'Modify' operation on identity '011233': Error: Error executing before operation rule for endpoint 'Modify Access': The application script threw an exception: org.json.JSONException: JSONObject["requesterIdentitySummary"] not found. BSF info: CPGRC Before Operation Rule at line: 0 column: columnNo

************ code for BeforeOperationRule ******************

String tokenUrl = idnMainURL+"/oauth/token";	
	String access_token = "";
	String finalToken1 = "NOFINALTOKEN1FOUND";			
	String requesterId = "NOREQUESTERIDFOUND";
	String requesterName = "NOREQUESTERNAMEFOUND";		
	List accessProfileList = new ArrayList();
	
	
	/** This method returns SailPoint IDN access token **/
	String getSailPointAccessToken (){	
	 //calling the Http Request to fetch the Berear Token
   
		HttpRequest request = HttpRequest.newBuilder()
		.uri(URI.create(tokenUrl+"?grant_type=client_credentials&client_id="+clientId+"&client_secret="+clientSecret))	
		.method("POST", HttpRequest.BodyPublishers.noBody())
		.build();
		
		HttpResponse response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());
		String finalToken = response.body();
		log.info("HTTP RESPONSE : "+response.body());
		JSONObject json = new JSONObject(finalToken.toString());
		log.info("JSON BODY TO STRING :"+json);
		access_token = (String) json.get("access_token");
		log.info("accessTokenValue :"+access_token);
		
		return access_token;
	}
        
try {
	//checking for provisioning plan
	if(null != provisioningPlan){
		//getCsrfTokenAndCookie();	//get csrf-token and session cookie and set it in the requestEndPoint header

	//BEGIN SETTING up the csrft token and the sessionID cookie
	String url_str = sapMainURL+"/sap/bc/rest/sap/zsec_selectusr/GetUsers?sap-client=200&include_details=X&search=AARONDAILEY";
	URL url = new URL(url_str);	
	
	log.info("KDEBUG: SAP username from app " + application.getAttributes());
	
	
	log.info("CHECK URL : "+url.toString());
	HttpURLConnection conn = (HttpURLConnection) url.openConnection();
	conn.setRequestMethod("GET");
	conn.setRequestProperty("Content-Type","application/json");
	conn.setRequestProperty("x-csrf-token","fetch");
	log.info("CHECK CONN");
	log.info("CHECK CONNECTION1 :"+conn.toString());
	String encoded = Base64.getEncoder().encodeToString((username+":"+password).getBytes(StandardCharsets.UTF_8));  
	conn.setRequestProperty("Authorization", "Basic "+encoded);
	log.info("CHECK CONNECTION2 :"+conn.toString());
	conn.connect();
	log.info("REQUEST SENT SUCCESSFULLY");
	if (conn.getResponseCode() != 200) {
		throw new RuntimeException("FAILED CONNECTION: "  + conn.getResponseCode());
	}
	log.info("SUCCESS RESPONSE : "+conn.getResponseCode());
	
	/*Map map = conn.getHeaderFields();
	log.info("PRINTING ALL RESPONSE HEADERS FOR THE URL: ");
	for (Map.Entry entry : map.entrySet()) {
		log.info("RESPONSE HEADER "+entry.getKey() + " : RESPONSE KEY" + entry.getValue());
	}*/
	
	String x_csrf_token = conn.getHeaderField("x-csrf-token");
	log.info("NEW CSRF TOKEN : "+x_csrf_token);
	
	String cookie = conn.getHeaderField("set-cookie");
	log.info("NEW COOKIE : "+cookie);
	
	conn.disconnect();
	log.info("CSRF TOKEN VALUE AFTER CONNECTION DISCONNECT : "+x_csrf_token);

	Map requestHeader = requestEndPoint.getHeader();
	requestHeader.put("Content-Type","application/json");
	requestHeader.put("Authorization","Basic "+encoded);
	requestHeader.put("x-csrf-token", x_csrf_token);
	requestHeader.put("Cookie", cookie);
	requestEndPoint.setHeader(requestHeader);
	log.info("REQUEST END POINT WITH EXISTING METHOD: " +requestEndPoint.toString());
	log.info("KDEBUG: Request Endpoint is set with cookie and csrf-token");
	log.info("KDEBUG: x-csrf-token: " +  x_csrf_token);
	log.info("KDEBUG: Cookie: " +  cookie);
	requestEndPoint.setHttpMethodType("POST");
	//END OF SETTING CSRFT TOKEN AND SESSIONID COOKIE
		
		//Checking for provisioningPlan operation
		//CREATE OPERATION
		if((ProvisioningPlan.ObjectOperation.Create).equals(provisioningPlan.getAccountRequests().get(0).getOp()) || (ProvisioningPlan.ObjectOperation.Modify).equals(provisioningPlan.getAccountRequests().get(0).getOp()) || (ProvisioningPlan.ObjectOperation.Disable).equals(provisioningPlan.getAccountRequests().get(0).getOp())){
			//do create operation related modification
			log.info("INSIDE create/Modify/Disable operation");			
			
			List accRequests = provisioningPlan.getAccountRequests();
			AccountRequest accReq = accRequests.get(0);
			log.info("ACCOUNT REQUEST:"+accReq);
			List entitlementList = new ArrayList();
			if (accReq != null) {
				//The next line, replace "role" with your entitlement schema attribute
				AttributeRequest attributes = accReq.getAttributeRequest("logsys_agr");
				
				if (attributes != null) {
					Object entList = attributes.getValue();					

					//if single entitlement, add it to list, if array, iterate and add to list
					if (entList instanceof String) {
						entitlementList.add((String) entList);
						log.info("======getAttributeValue has single Entitlement: " + entList);
					}
					else if (entList instanceof List){
						log.info("======getAttributeValue has list of: " + entList);
						for (String entitlement : entList){
							log.info("++++Adding entitlement value " + entitlement + " to entitlements array list.");
							entitlementList.add((String)entitlement);
						}
					}
				}
			}
			//AttributeRequest attrReq = accReq.getAttributeRequest("logsys_agr");
			//String logsys_agrname = attrReq.getValue();			
			log.info("ROLE REQUESTED VALUE : "+entitlementList);
								
			Map postBodyMap = (Map) requestEndPoint.getBody();
			// String postBodyMap = (String) requestEndPoint.getBody();
			String jsonBody = (String) postBodyMap.get("jsonBody");
			log.info("postBodyMap :::"+postBodyMap);
			List listOfMap = new ArrayList();
			

			for (String entitlementValue : entitlementList){
				String logsys,agr_name;
				//Splitting Entitlement name into logsys and agr_name
				String[] splitstr = entitlementValue.split("_", 2);
				logsys = splitstr[0];
				agr_name = splitstr[1];
				Map entitlementMap = new HashMap();
				//Map itemMap = JsonUtil.toMap(jsonBody);
				entitlementMap.put("logsys", logsys);
				entitlementMap.put("agr_Name", agr_name);				
				
				//Checking the attributeRequest operation and setting remove entitlement flag
				AttributeRequest attributes = accReq.getAttributeRequest("logsys_agr");
				if((ProvisioningPlan.Operation.Remove).equals(attributes.getOperation())){
					log.info("KDEBUG: AttributeRequest OPERATION is remove");
					entitlementMap.put("remove", "X");
				}else{
					entitlementMap.put("remove", "");
				}
				entitlementMap.put("to_dat", "");
				listOfMap.add(entitlementMap); 
			}
			log.info("listOfMap size1: "+listOfMap.size());
			log.info("listOfMap size1 Content: "+listOfMap);
			log.info("NEW LOGSYS : "+logsys+ " - NEW AGR_NAME : "+agr_name);
			log.info("NEW LOGSYS Entitlement: "+logsys+ " - NEW AGR_NAME : "+agr_name);
			
			String accnt = accReq.getNativeIdentity();
			log.info("EMPLOYEE NUMBER : "+accnt);
			String ticket1 = "TICKETNOTFOUND";
			String requester = "REQUESTERNOTFOUND";
			if(null != provisioningPlan.getArguments()){
				Map ticket= provisioningPlan.getArguments().getMap();
				ticket1 = (String) ticket.get("identityRequestId");
				requester = (String) ticket.get("requester");
				log.info("REQUESTER : "+requester);
				log.info("TICKET : "+ticket);
				log.info("TICKET1 : "+ticket1);
			}
			
			
			access_token = getSailPointAccessToken();
			log.info("accessTokenValue :"+access_token);
			
			//Calling the SailPoint API to get requesterId
			String id = ticket1;
			
			HttpRequest request1 = HttpRequest.newBuilder()
			.uri(URI.create(idnMainURL+"/v3/account-activities/"+id))
			.header("Authorization", "Bearer " + access_token)
			.method("GET", HttpRequest.BodyPublishers.noBody())
			.build();
			
			
			HttpResponse response1 = HttpClient.newHttpClient().send(request1, HttpResponse.BodyHandlers.ofString());
			log.info("HTTP RESPONSE BODY FOR SAILPOINT : "+response1.body());
			finalToken1 = "NOFINALTOKEN1FOUND";			
			requesterId = "NOREQUESTERIDFOUND";
			requesterName = "NOREQUESTERNAMEFOUND";
			//receIpientIdentity = "NORECIPIENTIDENTITYFOUND";			
			JSONObject json1 = new JSONObject();
			//JSONArray jsonArray = new JSONARRAY();
			
			finalToken1 = response1.body();
			json1 = new JSONObject(finalToken1.toString());
			//log.info("RECEIPIENT Identity:"+json1.get("targetIdentitySummary"));
			//receIpientIdentity = json1.get("targetIdentitySummary").get("id");
			//log.info("RECEIPIENTIDENTITY :"+receIpientIdentity);			
			if(null != json1.get("requesterIdentitySummary")){
				log.info("RECEIPIENT :"+json1.get("requesterIdentitySummary"));
				
				if((null != json1.get("requesterIdentitySummary").get("id")) && (null != json1.get("requesterIdentitySummary").get("name"))){
				//if(null != requesterIdentitySummary && ""!=requesterIdentitySummary){
				requesterId = json1.get("requesterIdentitySummary").get("id");
				requesterName = json1.get("requesterIdentitySummary").get("name");
				}
				if("David Knight".equals(requesterName)){
					requesterName = json1.get("clientMetadata").get("requestedBy");
				}
				log.info("requesterName :"+requesterName);
				log.info("requesterId :"+requesterId);
				log.info("JSON BODY TO STRING1 :"+json1);
				JSONArray jsonArray = (JSONArray) json1.get("items");
				log.info("JSON ARRAY  :"+jsonArray);
					
				for(int i=0;i<jsonArray.length();i++){
					JSONObject json2 = jsonArray.getJSONObject(i);
					log.info("JSON OBJECT :"+json2);					
					if(json2.get("accountRequestInfo").toString() != null && json2.get("accountRequestInfo").toString() != "" && json2.get("accountRequestInfo").toString() != "null") {
					log.info("ACCOUNTREQUESTINFO:"+json2.get("accountRequestInfo"));
						Map accessProfileMap = new HashMap();
						accessProfileMap.put("name", json2.get("accountRequestInfo").get("requestedObjectName"));
						log.info("This map is adding into the list:"+ accessProfileMap);
						accessProfileList.add(accessProfileMap);
						//log.info("REQUESTED OBJECT:"+json2.get("accountRequestInfo").get("requestedObjectName"));
						log.info("ACCESS PROFILE List:"+accessProfileList);
					}
					else {
						log.info("ACCOUNTREQUESTINFO1: null");
					}

				}
				log.info("KDEBUG: FINAL ACCESS PROFILE LIST:"+accessProfileList);
			}
	
			//calling the sailpoint API to get the requester emailaddress
			String requesterId = requesterId;
			String emailAddress = "NOEMAILFOUND";
			if(!"NOREQUESTERIDFOUND".equals(requesterId)){
				HttpRequest request2 = HttpRequest.newBuilder()
				.uri(URI.create(idnMainURL+"/beta/identities/"+requesterId))
				.header("Authorization", "Bearer " + access_token)
				.method("GET", HttpRequest.BodyPublishers.noBody())
				.build();
			
				
				HttpResponse response2 = HttpClient.newHttpClient().send(request2, HttpResponse.BodyHandlers.ofString());
				log.info("HTTP RESPONSE BODY FOR SAILPOINT Identity: "+response2.body());
				String finalToken2 = response2.body();
				JSONObject jsonIdentity = new JSONObject(finalToken2.toString());
				log.info("REQUESTER Email :"+jsonIdentity.get("emailAddress"));
				emailAddress = jsonIdentity.get("emailAddress");
				log.info("REQUESTER EmailAddress :"+emailAddress);
				log.info("CHECK CONNECTION FOR Sailpoint");
				//check if it is coming from SmartSheet and assign the appropriate email.
				if(requesterName.contains("@")){
					emailAddress = requesterName;
					log.info("New EmailAddress :"+emailAddress);
				}
				
			}
						
			//Adding identity request id to Ticket
			Map jsonMap = JsonUtil.toMap(jsonBody);
			jsonMap.put("ticket", ticket1);		
			
			
			 //Remove access profile/entitlement use case
			 //check for attribute request operation = remove
			/*if ((ProvisioningPlan.ObjectOperation.Modify).equals(provisioningPlan.getAccountRequests().get(0).getOp()))
			{

			   log.info("Removing Attributes:"+attributes);
				if(attributes != null && attributes != "") 
				{
				  log.info("Removing Access:"+accReq.remove(attributes));
				  
				}
			}*/
			
			if((ProvisioningPlan.ObjectOperation.Disable)!=(provisioningPlan.getAccountRequests().get(0).getOp()) ) {							
				jsonMap.put("requestorname", requesterName);
				jsonMap.put("requestoremail", emailAddress);
				jsonMap.put("access_profile", accessProfileList);
				jsonMap.remove("roleassignment");
			}
			/*if((ProvisioningPlan.ObjectOperation.Remove)!=(provisioningPlan.getAccountRequests().get(0).getOp())) {
				jsonMap.put("requestorname", "SLPT_LS1_200");
				jsonMap.put("access_profile", accessProfileList);
				jsonMap.remove("roleassignment");
			}*/
			else {
			  jsonMap.put("requestorname", "SLPT_LS1_200");	
			}
			
			//Specific to CREATE and MODIFY use case. 
			//Disable use case, we don't need to add roleassignment.
			if((ProvisioningPlan.ObjectOperation.Disable)!=(provisioningPlan.getAccountRequests().get(0).getOp())) {
			
				List roleassignment = new ArrayList();
				log.info("listOfMap size2: "+listOfMap.size());
				for(Map itemMap : listOfMap){
					roleassignment.add(itemMap);
				}
				jsonMap.put("roleassignment", roleassignment);
			}
			String finalBody = JsonUtil.render(jsonMap);
			postBodyMap.put("jsonBody", finalBody);
			requestEndPoint.setBody(postBodyMap);
			log.info("postBodyMap 2 :::"+finalBody);					
		}
		
		else{
			log.info("else case");
		}		
	}
	else {
	}
	
}catch(MalformedURLException e){
	log.info("MalformedURLException : " + e);
}
catch (IOException e){
	log.info("IOException : " + e);
}
catch (IllegalStateException e){
	log.info("IllegalStateException : " + e);
}	
log.info("EXITING CPGRC BEFORE OPR RULE");
return requestEndPoint;

Hi @sambathpalaniswamy

org.json.JSONException: JSONObject[“requesterIdentitySummary”] - Throwing during the JSON deserilization.

Based on your logic below, you are trying to read ``requesterIdentitySummary``` from the response payload:

HttpRequest request1 = HttpRequest.newBuilder()
			.uri(URI.create(idnMainURL+"/v3/account-activities/"+id))
			.header("Authorization", "Bearer " + access_token)
			.method("GET", HttpRequest.BodyPublishers.noBody())
			.build();
			
			
			HttpResponse response1 = HttpClient.newHttpClient().send(request1, HttpResponse.BodyHandlers.ofString());
finalToken1 = response1.body();
json1 = new JSONObject(finalToken1.toString());

When you try this endpoint "/v3/account-activities/"+id in Postman or outside the ISC, what is the value of response1, does that have requesterIdentitySummary, If I guess based on the information you provided, it is missing in the payload.

To do a check, you must replace null != json1.get("requesterIdentitySummary")
with
json1.has("requesterIdentitySummary") && !json1.isNull("requesterIdentitySummary")

has("requesterIdentitySummary") This will ensure you have this attribute in the object and !isNull("requesterIdentitySummary") checks the attribute value is NOT null.

json1.get("requesterIdentitySummary") throws a JsonException when json payload does not have the attribute requesterIdentitySummary

For more information on JSOnObject:
https://stleary.github.io/JSON-java/org/json/JSONObject

1 Like

Hi Raghu,

Thanks for analyzing the code a d the solution.

I agree the JSON payload does not have value for requesterIdentitySummary attribute. But my question is why it is not available in Prod ?. configuration wise both Prod and Sandbox are same.

This code works as it is in Sandbox without any errors. This means the JSON object in Sandbox has this attribute value and it is getting processed.

In your provisioning plan arguments, How are you passing the identityRequestId, is the account-activity type is same in both sandbox and prod? If type is Identity Refresh, I always noticed this value as null.

Map ticket= provisioningPlan.getArguments().getMap();
ticket1 = (String) ticket.get("identityRequestId");

As per this document attribute requesterIdentitySummary must be part of the payload. The value might be a null but attribute must exist in the response.

If attribute requesterIdentitySummary exists but the value is null, It can be nullable. If this attribute is not part of the payload, you have to open a support ticket.

This value can be null as per documentation. I am assuming, when the account activity is triggred by system actions like “Identity Refresh” this value will be null.

Yes, I think both sandbox and prod are same(ideally). But due to the error on requesterIdentitySummary

I’m beginning to think, they might be different. I’d like your guidance to figure that out. Because if it worked in sandbox, it should also work in prod as well.

@sambathpalaniswamy -|

Happy to help!.

  1. To troubleshoot further as I requested in my prervious response. Please share, How are you passing identityRequestId in provisioing plan arguments?
  2. Could you please confirm what is the “type” of account-activity and check in postman if both the environments have the same type in postman? - Please remove any sensitive information and share the account-activty response in prod and sandbox.

@anneragh

how to fetch / look in for identityRequestId ?

@osmanmohammed That is my question in my previous response!. It depends on what is passed into provisioning plan.

@sambathpalaniswamy - Could you please explain what is your business case and what you are achieving in this rule?

Hi Raghu,

The code is trying to get the request and bundle all the entitlements into a single approval request for SAP since SAP has it’s own approval process.

The provisioning plan comes as the payload to the rule. However, not sure why the identityRequestId is not sent along.

I want to look into the logs. Where to i check for those logs?

provisioningPlan.getArguments().getMap();
ticket1 = (String) ticket.get(“identityRequestId”);

thanks

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.