Implementing an IdP Discovery Service

As discussed earlier, OAM/SP can be configured to use a remote IdP Discovery Service whose function is to determine which IdP to use for the Federation SSO operation.

The “Identity Provider Discovery Service Protocol and Profile” SAML 2.0 specification published by OASIS defines the interaction protocol between a SAML 2.0 SP and an IdP Discovery Service.

This article implements a sample IdP Discovery Service, and then configures OAM/SP to use that service.

IdP Discovery Service Protocol

As mentioned earlier, the IdP Discovery Service flow is described in the specification (http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-idp-discovery.pdf?) and is made of the following steps:

Apart from the protocol exchange, the service can be implemented in any way deemed acceptable by the implementer.

Custom Service

Overview

In this example, write a service that will:

In terms of implementation:

Sample Pages

The custom IdP Discovery Service is made of two JSP pages:

Implementation

Landing Page

<%@ page buaer="5kb" autoFlush="true" session="false"%\> \<%@ page language="java"import="java.util.\*,sun.misc.\*,java.net.\*"%>

<%response.setHeader("Expires", "Sat, 1 Jan 200000:00:00 GMT"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); request.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=UTF-8");

// list of known IdPs, keys being the displayed names,and values the ProviderID/Issuer IDs

Map idps = new HashMap(); idps.put("AcmeIdP", "https://acme.com/fed"); idps.put("IdP1", "https://idp1.com/saml"); idps.put("MyIdentiyProvider.com", "https://myidentityprovider.com/saml2.0");

// entityID of the requesting SP

String entityID = request.getParameter("entityID");

// the query parameter that contains the IdP's ProviderID/Issuer when

// redirecting the user back to the SP

String returnIDParam = request.getParameter("returnIDParam");

// the URL where the user should be redirected at the SP

String returnURL = request.getParameter("return");

// check if the IDPDiscService cookie is set, and if it is a known IdP

Cookie\[\] cookies = request.getCookies();

if (cookies != null && cookies.length \> 0)

{

for (int i = 0; i \< cookies.length; i++)

{

if ("IDPDiscService".equals(cookies\[i\].getName()))

{

// decode the idp

BASE64Decoder b64 = new BASE64Decoder();

String idp = new

String(b64.decodeBuaer(cookies\[i\].getValue()));

if (idps.containsValue(idp))

{

// redirects to the SP

StringBuaer redirectStringBuaer = new

StringBuaer(returnURL);

if (returnURL.indexOf('?') == -1)

redirectStringBuaer.append("?");

else if (returnURL.charAt(returnURL.length() - 1)

!= '&')

redirectStringBuaer.append("&");

redirectStringBuaer.append(returnIDParam);

redirectStringBuaer.append("="); redirectStringBuaer.append(URLEncoder.encode(idp));

response.sendRedirect(redirectStringBuaer.toString());

return;

}

}

}

}

%>

<html>

<head>

<title>Select your Single Sign-On Server</title>

</head>

<body>

<p style="text-align: center;"\>Select your SingleSign-On Server</p>

<form action="/idpdiscoveryservice/submit.jsp" method="post" name="idpselection"/>

<input name="entityID" type="hidden" value="<%=entityID%\>" />

<input name="returnIDParam" type="hidden" value="<%=returnIDParam%\>" />

<input name="return" type="hidden" value="<%=returnURL%>" />

<p style="text-align: center;"\>Single Sign-On Server:

<select name="selectedidp"\>

<%Iterator idpsIterator = idps.keySet().iterator();while(idpsIterator.hasNext())

{

String displayIdP = (String)idpsIterator.next();

String providerIDIdP = (String)idps.get(displayIdP);
%>

<option value="<%=providerIDIdP%>">

<%=displayIdP%><option>

<%

}

%>

</select>

</p>

<p style="text-align: center;">

<input name="submit" type="submit"value="Submit" />

</p>

</form>

</body>

</html>

Submit Page

<%@ page buaer="5kb" autoFlush="true" session="false"%> <%@ page language="java"import="java.util.*,sun.misc.*,java.net.*"%>

<%response.setHeader("Expires", "Sat, 1 Jan 200000:00:00 GMT"); response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); request.setCharacterEncoding("UTF-8"); response.setContentType("text/html; charset=UTF-8");

// list of known IdPs with values being the ProviderID/Issuer IDs

List idps = new ArrayList(); idps.add("https://acme.com/fed"); idps.add("https://idp1.com/saml"); idps.add("https://myidentityprovider.com/saml2.0");

// entityID of the requesting SP

String entityID = request.getParameter("entityID");

// the query parameter that contains the IdP's ProviderID/Issuer when

// redirecting the user back to the SP

String returnIDParam =request.getParameter("returnIDParam");

// the URL where the user should be redirected at the SP

String returnURL = request.getParameter("return");

// the idp selected by the user

String idp = request.getParameter("selectedidp");

// check that the selected IdP is one of the known IdPs

if (!idps.contains(idp))

throw new Exception("Unknown IdP");

// save the idp in the IDPDiscService cookie

BASE64Encoder b64Encoder = new

BASE64Encoder();

response.addHeader("Set-Cookie", "IDPDiscService="

+

b64Encoder.encode(idp.getBytes()) + "; expires=Wed, 01-Jan-2020 00:00:00 GMT; path=/");

// redirects to the SP

StringBuaer redirectStringBuaer = new StringBuaer(returnURL); if (returnURL.indexOf('?') == -1) redirectStringBuaer.append("?");

else if (returnURL.charAt(returnURL.length() - 1) != '&')

redirectStringBuaer.append("&"); redirectStringBuaer.append(returnIDParam); redirectStringBuaer.append("="); redirectStringBuaer.append(URLEncoder.encode(idp));

response.sendRedirect(redirectStringBuaer.toString());

%>

Packaging

Having put the landing.jsp and submit.jsp into a directory only containing those files, create the idpDiscService.war WAR Ale using the JAR tool:

jar cvf idpDiscService.war *.jsp

The content of that WAR file can be seen via the unzip command: ` unzip -l idpDiscService.war Archive: idpDiscService.war`

Length Date Time Name
0 01-09-2014 19:00 META-INF/
76 01-09-2014 19:00 META-INF/MANIFEST.MF
2898 01-09-2014 19:57 landing.jsp
1838 01-09-2014 19:57 submit.jsp
4812     4 files

Then deploy this WAR file on a J2EE container, using /idpdiscoveryservice as the root path. That way both pages are accessible using /idpdiscoveryservice /landing.jsp and /idpdiscoveryservice/submit.jsp.

Configuring OAM/SP

To configure OAM/SP to use an IdP Discovery Service, perform the following steps:

  1. Enter the WLST environment by executing: $IAM_ORACLE_HOME/common/bin/wlst.sh

  2. Connect to the WLS Admin server: connect()

  3. Navigate to the Domain Runtime branch: domainRuntime()

  4. Enable/disable OAM/SP to use an IdP Discovery Service: ` putBooleanProperty(“/spglobal /idpdiscoveryserviceenabled”, “true”)`

  5. Set the location of the remote IdP Discovery Service: putStringProperty("/spglobal /idpdiscoveryserviceurl","http://remote.idp.disc.service.com /idpdiscoveryservice/landing.jsp")

  6. Exit the WLST environment: exit()

Test

When OAM/SP is invoked to start a Federation SSO, it redirects the user to my custom IdP Discovery Service (/idpdiscoveryservice/landing.jsp)

On the first visit, the user is presented with a drop down list and prompted to select an IdP SSO Server:

Description of the illustration IdP_SSO_Server.jpg

Upon submitting the choice to /idpdiscoveryservice /submit.jsp, the page validates the choice, save it into the IDPDiscService cookie and redirect the user to OAM/SP with the IdP’s ProviderID: from there, OAM/SP starts Federation SSO with that IdP.

The next time OAM/SP starts a Federation SSO for that user:

More Learning Resources

Explore other labs on docs.oracle.com/learn or access more free learning content on the Oracle Learning YouTube channel. Additionally, visit education.oracle.com/learning-explorer to become an Oracle Learning Explorer.

For product documentation, visit Oracle Help Center.