Scenario :
You need to send a complex JSON payload in the SAML. The payload would depend upon the contextual data requested through a querystring . Below is the SP connection would look like:-
The input context is in the querystring which is a JSON:-
{“Param1″:”9999″,”Param2″:”8787879″,”Param3″:”Test”}
Above request JSON when passed to a service will give a JSON response like below :-
"data": { "level1": "some data", "level2": "some data11", "level3": { "level131": "some data 13", "level132": [{ "level1321": { "level13211": { "level132111": "False", "level132112": "True" }, "level13212": "some data", "level13213": "some data" }, "level1322": "some data" }, ], "level133": "test data", "level134": "test data", } }
The output needs to be included in the SAML as a value for a SAML attribute. In this case the attribute is named as “Payload”. When we have implemented the solution, below is the part of the SAML response what It would like showing the attribute key “Payload” and the value from the service.
<saml:AttributeStatement> <saml:Attribute Name="Payload" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"> <saml:AttributeValue xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> "data": { "level1": "some data", "level2": "some data11", "level3": { "level131": "some data 13", "level132": [{ "level1321": { "level13211": { "level132111": "False", "level132112": "True" }, "level13212": "some data", "level13213": "some data" }, "level1322": "some data" }, ], "level133": "test data", "level134": "test data", } } </saml:AttributeValue> </saml:Attribute> </saml:AttributeStatement>
Now on a first thought one would think this could be done using a custom data-source in PingFederate. However, a custom data-source does not have access to the HTTP request context and therefore cannot access the querystring.
One way to solve this to use an OGNL expression for the “Payload” attribute. The OGNL expression has access to the HttpRequest. So – not only we can get the querystring, but also can get the authentication cookies from the request which may be required by the payload service.
#ServiceURL="http://example.com/payloadservice", //Get all the cookies #cookies=#this.get("context.HttpRequest").getObjectValue().getCookies(), #cookiesMap=new java.util.HashMap(), #cookies.{ #cookie=#this, #cookiesMap.put(#cookie.getName(),#cookie.getValue()) }, // Get the querystring #querystring = #this.get("context.HttpRequest").getObjectValue().getQueryString(), #indexOfPayLoadKey = #querystring.indexOf("&Request_Payload="), #actualPayload=#querystring.substring(#indexOfPayLoadKey), // Get the actual payload request #actualPayload=#actualPayload.replace("&Request_Payload=",""), /* Via a service call, call the service with the payload request and get the payload response*/ #restPayloadServiceHelper = new com.pingfederate.utils.payloadservices.RESTPayloadServiceHelper(#ServiceURL), restPayloadServiceHelper.GetServiceResponsePayload(#actualPayload, #cookiesMap)
Below is the skeleton of the helper class the OGNL expression is using. The jar file for the class needs to be put in the “\pingfederate\server\default\deploy” folder and the PingFederate service needs to be restarted.
/* The constructor takes the URL. The method GetServiceResponse takes the payload and also the cookie collection */ public class RESTPayloadServiceHelper { String serviceURL = ""; JSONObject jsonPayloadRequest = null; public RESTPayloadServiceHelper(String serviceURL) { if(serviceURL!= null || serviceURL.length() > 0) { this.serviceURL = serviceURL; } else { throw new IllegalArgumentException(" The supplied service URL " + serviceURL + " is not valid"); } } public String GetServiceResponsePayload(String adhocPayloadString, HashMap<String,String> cookieCollection) throws UnknownHostException, IOException { // Call the service and return the payload response } }
#1 by Matt Tebo on June 21, 2018 - 3:35 pm
Ashish – great post. I’m going to try and implement this for a project I’m working on. Do you have any sample code for the RESTPayloadServiceHelper?