Monday, May 2, 2011

Configuring WebLogic IdP initiated SAML2 based SSO

In an IdP-initiated use case, the identity provider is configured with specialized links that refer to the desired service providers. These links actually refer to the local IdP's Single Sign-On Service and pass parameters to the service identifying the remote SP. So instead of visiting the SP directly, the user accesses the IdP site and clicks on one of the links to gain access to the remote SP. This triggers the creation of a SAML assertion that will be transported to the service provider.

Here, I discuss the scenario when:
  • WebLogic is IdP
  • WebLogic is SP

Suppose we have two domains (SrcDom1 and DstDom1) such that:
  • SrcDom1 - (IdP)
- host:27001
- metadata file is idp.xml
  • DstDom1 - (SP)
- host:37001
- metadata file is sp.xml
- service application deployed as "appB.war" with one of the protected urls as:
http://host:37001/appB/admin/services.jsp
- Default URL (defined from admin console at "SERVER_NAME/Configuration/Federation Services/SAML 2.0 Service Provider"):
http://host:37001/appB/index.jsp
After setting up the Identity provider and the Service Provider (both configured for POST profiles), and deploying a service application at service provider we do following to configure IdP first initiated SAML2 SSO:



1)   We import the metadata of two providers at respective ends (to configure partner settings). Suppose we now have partners named as:

  • "sp1"  (from admin console, located at "Security Realms>>myrealm>>Providers>>Credential Mapping/<SAML2_CM>/Management/" on IdP server)
  • "idp1" (from admin console, located at "Security Realms>>myrealm>>Providers>>Authentication/<SAML2_IdentityAsserter>/Management/" on SP server)

The theory behind IdP initiated SSO is that we need to hit /saml2/idp/sso/initiator (a weblogic servlet at IdP end) with attributes "SPName"(identifying the service partner registered at IdP end) and "RequestURL"(identifying the SP URL of resource on which the end user should land at SP end once ACS consumes assertion) , and then post the saml specific data to assertion consumer service(SP) via the browser(using a custom form). The initiator servlet places the unsolicited response (which is typical of a IdP initiated SSO) in request attribute "com.bea.security.saml2.samlContent" and the value of "RequestURL" in "com.bea.security.saml2.relayState".

Hitting the initiator servlet will be done using a protected form(available at IdP end) that will list the services (available at SP end) to end user.

For all this we need to deploy one more application at IdP end having following contents specified in next step.



2)  File names can be anything, the way you like, except for xml files'
appA.war
- WEB-INF
- web.xml
- weblogic.xml
- services.jsp
- post_sp1.jsp

Description as to why we need above files, and their contents are listed in following tables:


"services.jsp" will list the services that are available at SP (like in our example http://host:37001/appB/admin/services.jsp )
<html>
<head>
<h2>Services Available</h2>
</head>
<body>

<form method="post" action="http://host:27001/saml2/idp/sso/initiator">
<br>Service -1 (at host:37001/appB)<br>
<input type="hidden" name="SPName" value="sp1"/>
<input type="hidden" name="RequestURL" value="http://host:37001/appB/admin/services.jsp"/>
<input type="submit" value="submit"/>
</form>

</body>
</html>



"post_sp1.jsp" will be used to put initiator servlet generated values for "com.bea.security.saml2.samlContent" and "com.bea.security.saml2.relayState" into SAML2 specific place holders for SAML Response (SAMLResponse) and target URL (RelayState) respectively.
<html>
<head>
</head>
<body>

<%
String samlResponse = (String) request.getAttribute("com.bea.security.saml2.samlContent");
String relayState = (String) request.getAttribute("com.bea.security.saml2.relayState");
System.out.println(samlResponse);
System.out.println(relayState);
%>

<body onLoad="document.forms[0].submit();">
<FORM METHOD="POST" ACTION="http://host:37001/saml2/sp/acs/post">
<INPUT TYPE="HIDDEN" NAME="RelayState" VALUE="<%=relayState%>"/>
<INPUT TYPE="HIDDEN" NAME="SAMLResponse" VALUE="<%=samlResponse%>">
</FORM>

</body>
</html>



"web.xml" will protect "services.jsp" such that when user hits this jsp he is asked to authenticate (if no security context already exists
for him)
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Saml Source Site Application</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<security-constraint>
<web-resource-collection>
<web-resource-name>SecurePages</web-resource-name>
<description>These pages are only accessible by authorized users.</description>
<url-pattern>/services.jsp</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<description>These are the roles who have access.</description>
<role-name>admin</role-name>
</auth-constraint>
<user-data-constraint>
<description>This is how the user data must be transmitted.</description>
<transport-guarantee>NONE</transport-guarantee>
</user-data-constraint>
</security-constraint>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>myrealm</realm-name>
</login-config>
<security-role>
<description>These are the roles who have access</description>
<role-name>admin</role-name>
</security-role>
</web-app>



"weblogic.xml" will map the role to principal (user/group known to weblogic through any of its authenticators). IdP will generate saml assertion containing the subject based on this principal only.
<?xml version='1.0' encoding='UTF-8'?>
<weblogic-web-app xmlns="http://www.bea.com/ns/weblogic/90"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<security-role-assignment>
<role-name>admin</role-name>
<principal-name>SAML_SSO_GROUP</principal-name>
</security-role-assignment>
<context-root>/appA</context-root>
</weblogic-web-app>


3)   Now, deploy "appA.war" onto IdP (SrcDom1 - host:27001)

4)   Navigate to "Security Realms/myrealm >Providers/Credential Mapping/<SAML2_CM>/Management/sp1", enable it and specify following URI into "POST Binding POST Form:"
/appA/post_sp1.jsp
Save the changes and then activate them

5)   Restart any of the servers (if required)

6)   Now hit the services.jsp, and provide the credentials of the user belonging to group "SAML_SSO_GROUP" (because of weblogic.xml) when challenged:
http://host:27001/appA/services.jsp
7)   Select any service (only one in this example )

8)   You should see yourself landing at:
http://host:37001/appB/admin/services.jsp           (=RequestURL=RelayState)
9)   Please note that if we do not embed "RelayState" in the post form, then end user will land on "Default URL" of SP. Like in our example it will be:

         http://host:37001/appB/index.jsp


2 comments:

  1. Hi,
    as per my requirement I am using weblogic as a idp and OIF(oracle identity federation as a SP) I have configured weblogic and OIF both and exchanged metadata. But i have not deployed any web app(war file). I want to know is there any out of box feature of weblogic (it will create login page etc)or we have to write a seprate java code to enable SAML creation.

    ReplyDelete
  2. If WebLogic is being used as an IdP in "SP initiated SAML2 SSO", all that is needed is exchange of metadata. WebLogic as an IdP would present a dialog box for basic authentication by default.So you don't need to necessarily deploy an application with a login page.

    For IdP initiated SSO where WebLogic is IdP, a setup similar to above is needed on WebLogic side, for this would list/describe services available to client on SP end(and this concept is central to IdP initiated SSO).

    ReplyDelete