How to support multiple delegated authentication service in one Salesforce Organisation ?

Problem

How can we support multiple delegated authentication service in one Salesforce Organisation ?

Background

As you may noticed, we can configure only one Delegated Authentication URL Service in the Single Sign On Setting of your Org. Now what’s happened if you have multiple different portal (with their own security mechanism) to integrate with Salesforce when you have only one Org instance and want to benefit from the delegated authentication Service provided by Salesforce ?

Answer

We can derive the facade pattern to implement this service. This service can be located anywhere in your network and must be publicly available (HTTPS is recommended here). You can even host this service in your Salesforce’s Org by exposing this service as a SOAP Service.

The delegated authentication Service

Please refer to the following documentation to understand the delegated authentication service:

Salesforce provide top-down approach by providing the WSDL interface for this service. It is available in your Org (Setup| Develop | API | Download Delegated Authentication WSDL).

Multiple Authentication Service - SE - Delegated Authentication SOAP Request-Response (1)

Proof of Concept

Let’s validate this by mocking a SOAPUI Service based on the WSDL provided by Salesforce, and use Groovy scripting functionality to route dynamically the request to the real implementation of this delegated service. For the purpose of this demo, I will used the sourceIp element in my SOAP request to identify the caller of this service. I would recommend to use either SOAP Header or HTTP header to store this “routing” information.

Below the screensot of my SOAPUI Settings:
MockDelegatedAuthenticationService_2015-08-23_14-21-05

Below groovy code i have used to this purpose. I have used the groovy-wslite as a WS client (just download the JAR and put it in your SOAPUI library extension to made to available: C:\Program Files\SmartBear\SoapUI-5.1.3\bin\ext\groovy-wslite-1.1.2.jar).

import wslite.soap.*
import wslite.http.*
import wslite.soap.SOAPClient
import wslite.http.HTTPClientException
import wslite.http.HTTPRequest
import wslite.http.HTTPResponse
import wslite.soap.SOAPClient
import wslite.soap.SOAPFaultException
import wslite.soap.SOAPResponse


log.info "context=" + context
def groovyUtils = new com.eviware.soapui.support.GroovyUtils( context )
log.info  "groovyUtils=" +groovyUtils
log.info  "mockRequest.requestContent=" + mockRequest.requestContent

// create XmlHolder for request content
def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
def _username = holder["//*:username"]
def _password = holder["//*:password"]
def _sourceip = holder["//*:sourceIp"]
log.info "_username=" + _username
log.info "_password=" + _password
log.info "_sourceip=" + _sourceip
def DELEGATED_AUTH_URL_PORTAL1 = "http://PORTAL1/wsGCSBFO/DAuth.asmx"
def DELEGATED_AUTH_URL_PORTAL2 = "https://PORTAL2/IMS-IdentityManager/services/AuthenticationService"
def DELEGATED_AUTH_URL_PORTALDEFAULT = "https://PORTALDEFAULT/services/AuthenticationService"

switch (_sourceip) {
        case ~/^PORTAL1$/:
            log.info "Routing to PORTAL1 Portal Delegated AuthN Service"          
            context.myContentResponse = call_DelegatedAuthenticationFacade(DELEGATED_AUTH_URL_PORTAL1, _username, _password, _sourceip)   
            return "SCRIPT_RESPONSE"
            break
        case ~/^PORTAL2$/:
            log.info "Routing to PORTAL2 Portal Delegated AuthN Service"          
            context.myContentResponse = call_DelegatedAuthenticationFacade(DELEGATED_AUTH_URL_PORTAL2, _username, _password, _sourceip)   
            return "SCRIPT_RESPONSE"
            break
        default:
            log.info "Routing to DEFAULT Portal Delegated AuthN Service"          
            context.myContentResponse = call_DelegatedAuthenticationFacade(DELEGATED_AUTH_URL_PORTALDEFAULT, _username, _password, _sourceip)   
            return "SCRIPT_RESPONSE"
            break
}    

String call_DelegatedAuthenticationFacade(String serviceLocationUrl, String _username, String _password, String _sourceip) {
	def String defaultResponse = '''
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <AuthenticateResult xmlns="urn:authentication.soap.sforce.com">
         <AuthenticateResult>
            <Authenticated>false</Authenticated>
         </AuthenticateResult>
      </AuthenticateResult>
   </soap:Body>
</soap:Envelope>
'''
	try {
		SOAPClient client = new SOAPClient(serviceLocationUrl)
	  	def response = client.send(SOAPAction:'') {  
	      body {
	          Authenticate('xmlns':'urn:authentication.soap.sforce.com') {
	              username(_username)
	              password(_password)
	              sourceIp(_sourceip)
	          }
	      }
	 	}
	  	HTTPRequest myRequest = response?.httpRequest
	  	HTTPResponse myResponse = response?.httpResponse
	  	return debug(defaultResponse, myRequest, myResponse)
	  		 
	} catch (SOAPFaultException soapEx) {
	    return debug(defaultResponse, soapEx.httpRequest, soapEx.httpResponse)
	} catch (HTTPClientException httpEx) {
	    return debug(defaultResponse, httpEx.request, httpEx.response)
	} catch (Exception Ex) {
	    return debug(defaultResponse, Ex.request, Ex.response)
	}		
}

String debug(String defaultResponse, HTTPRequest request, HTTPResponse response) {
  log.info("*****************************************************************************************************")
  log.info("HTTPRequest $request with formatted content:\n${request?.contentAsString}")
  log.info("HTTPResponse $response with formatted content:\n${response?.contentAsString}")
  defaultResponse = "${response?.contentAsString}"
  log.info("RETURNED RESPONSE TO FACADE\n${defaultResponse}")
  return defaultResponse
  
}

The script response content SOAP response generated by the groovy SCRIPT.

${myContentResponse}

Thanks for reading.

Advertisements

About Chenda Mok

19 years of hands on experience in software design and development with emphasis on Enterprise Application Integration (EAI), Services Oriented Architecture (SOA) and Identity Management (IDM) solutions. I’m a software engineer, member of the professional service delivery team working for Salesforce. Prior to this, I worked for Oracle as Solution Architect, through SeeBeyond(06/2005), then SUN’s acquisition (04/2009). After my master’s degree in computer science in 1997; I always delivered consulting on architecture, design, implementation on integration’s field. I’m interested in architecture using EAI/SOA/IDM/BPM/Cloud technologies, software development and Java’s related technologies. I may blog about my work/activities at Salesforce, but I do not speak for my employer, past, present or future.
This entry was posted in Salesforce and tagged , , , , , , . Bookmark the permalink.