Monday, July 14, 2014

Customizing the login page for different SAML SSO Service Providers in WSO2 Identity Server 5.0

Usecase

Usually WSO2 Identity Server displays a default login page for all the SAML SSO Service Providers (SP) that are sending authentication requests to it. However, there might be a need to display different login pages for each SP.

This post explains how it can be done using IS 5.0.0 [1]

Please refer [2] for how to achieve this in IS 4.5.0 and 4.6.0.

Configuring 2 SPs - Travelocity.com & Avis.com

1.  Copy travelocity.com.war [3] and avis.com.war [4] to your application server (I used Tomcat 7)

2. Start the application server and access following URLs to make sure both apps are running:

Travelocity.com = http://localhost:8080/travelocity.com/index.jsp


Avis.com = http://localhost:8080/avis.com/index.jsp




Registering the 2 SPs at IS

1. Download WSO2 Identity Server and extract it (wso2is-5.0.0.zip).

2. Run the server by executing wso2is-5.0.0/bin/wso2carbon.sh if on a Unix based systems, or /bin/wso2carbon.bat if on Windows.

3. On the home page, under Identity -> Service Providers, click 'Add'. Then give "travelocity.com" as the 'Service Provider Name' and press 'Register'.



4. In the next page click 'Configure' under 'SAML2 Web SSO Configuration' in Inbound Authentication Configuration.


5. Fill following details on the next page:
  • Issuer: travelocity.com 
  • Assertion Consumer URL: http://localhost:8080/travelocity.com/samlsso-home.jsp
  • Select Enable Response Signing 
  • Select Enable Assertion Signing 
  • Select Enable Single Logout
6. Similarly, register Avis.com as a new Service Provider:
  • Issuer: avis.com 
  • Assertion Consumer URL: http://localhost:8080/avis.com/samlsso-home.jsp
  • Select Enable Response Signing 
  • Select Enable Assertion Signing  
  • Select Enable Single Logout
Now if you try to "login with SAML from WSO2 Identity Server" in Travelocity.com and Avis.com, you would get landed in the following default page.



Configuring the login pages at IS

The default login page you saw earlier is located at:

wso2is-5.0.0/repository/deployment/server/webapps/authenticationendpoint/login.jsp

A quick look at authenticationendpoint web application...

The login page that gets displayed during SAMLSSO, OAuth, OpenID and Passive-STS flows are located inside the webapp named authenticationendpoint.

The rational behind having it in a web app is:
  • to easily customize the page according to user requirements
  • if needed, place that whole web application in an external application server.
So how does IS know where this web application is located? It is pointed in the following configuration file:

wso2is-5.0.0/repository/conf/security/application-authentication.xml

<AuthenticationEndpointURL>/authenticationendpoint/login.do</AuthenticationEndpointURL>

By default it points to a location inside IS itself, thus the relative path is given. If it is needed to point to an external application, the full path should be given instead.

A very important note, if this web app is moved outside, we must ensure that no one can take a peek at the login credentials getting passed between this app and IS. Which means, that external location should be either inside a secured Intranet or transport should be HTTPS or take any other precaution needed to secure the communication.

Following is the structure of this web app...


In the default web application, when a request comes to the login page, it's first served by AuthenticationEndpoint servlet. After checking this is a SAMLSSO related request it's forwarded to SAMLSSOLogin servlet which finally forwards to the login.jsp. If you look inside the web.xml you would see how these are mapped.

The beauty is, all of these are customizable...the servlets...pages and everything!

You can get the source for authenticationendpoint webapp from [5]

The only restriction is to submit to IS what is already sent back by the pages inside the default web app. And of cause to point to the correct location via application-authentication.xml

Now to customize the pages..

There can be many ways to do this as you might have discerned from the overview of authenticationendpoint web app. Following are two such methods, first one: easy and quick, second one: not so easy and involves some code compiling, but neater.

Some important points first:

When a request comes to the said default login page, if you check the address bar you would notice several parameters are getting passed. Out of them, for this customization we are going to focus on the following two:

sessionDataKey : This is an identifier used by IS to maintain state information related to this particular request by the SP.

relyingParty : This is the value we gave for the "Issuer" field when we registered the SAML SSO SP (e.g. travelocity.com). This value will be used to display different login pages to different SPs.

Also, make sure following are applied when customizing the pages:

1. Form submissions should happen to "commonauth" servlet as a POST.
<form id="form" name="form" action="../../commonauth" method="POST">
2. Make sure to send back the "sessionDataKey" with the form submission, by using a hidden input field:
<input type="hidden" name="sessionDataKey" value="<%=request.getParameter("sessionDataKey")%>"/>

With that background let's dive into steps of the two methods:

Method 1: Using a JSP for redirecting to SP relevant pages

1. Rename the existing 'login.jsp' to 'default_login.jsp' 

2. Create a new file with the name 'login.jsp' including the following code:

<%  
String relyingParty = request.getParameter("relyingParty");

if (relyingParty.equals("travelocity.com")) {
 RequestDispatcher dispatcher = request.getRequestDispatcher("travelocity_login.jsp");
 dispatcher.forward(request, response);
} else {
 RequestDispatcher dispatcher = request.getRequestDispatcher("default_login.jsp");
 dispatcher.forward(request, response);
} 
  %>

What this basically does is forward to different login pages by checking the value of relyingParty parameter.

3. Get the 'travelocity_login.jsp' from [6] and place it at the same level as 'login.jsp'. Also, download the contents of 'css' and 'images' folders from that same link and put them inside the respective folders in the authenticationendpoint.

4. Now, try to login into Travelocity.com web app again. You would be presented with a different page this time!


If you try to access Avis.com, it will present the default login page of IS.

Method 2: Using a Servlet for redirecting to SP relevant pages

1. Check out the source code of authenticationendpoint web app from the svn location given above.

2. Modify the existing org.wso2.carbon.identity.application.authentication.endpoint.samlsso.SAMLSSOLogin.java located at src/main/java/org/wso2/carbon/identity/application/authentication/endpoint/samlsso/ as below:

public class SAMLSSOLogin extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {
     
        if(request.getRequestURI().contains("/samlsso_login.do")){
         String relyingParty = request.getParameter("relyingParty");
         
         if (relyingParty != null && !relyingParty.isEmpty()) {
          String rpPage = getServletConfig().getInitParameter(relyingParty);
          
          if (rpPage != null) {
           request.getRequestDispatcher(rpPage).forward(request, response);
           return;
          }
         }
            request.getRequestDispatcher("login.jsp").forward(request, response);
        } else if (request.getRequestURI().contains("/samlsso_redirect.do")){
            request.getRequestDispatcher("samlsso_redirect.jsp").forward(request, response);
        }  else if (request.getRequestURI().contains("/samlsso_notification.do")){
            request.getRequestDispatcher("samlsso_notification.jsp").forward(request, response);
        }
    }
}

3. Build the source and replace the existing authenticationendpoint.war at  wso2is-5.0.0/repository/deployment/server/webapps/ with the new war file. Also, delete the existing expanded authenticationendpoint folder at the same location.

4. Start the server.
 
5. Add init parameters to "SAML2SSO" servlet in web.xml, located in the expanded web app:
<servlet>
        <servlet-name>SAML2SSO</servlet-name>
        <servlet-class>org.wso2.carbon.identity.application.authentication.endpoint.samlsso.SAMLSSOLogin</servlet-class>
        
        <init-param> 
            <param-name>travelocity.com</param-name> 
            <param-value>travelocity_login.jsp</param-value> 
        </init-param> 
        
    </servlet>
You can add any new SP page like that. Just give the issuer as the "param-name" and the customized page location as the "param-value".

6. Do step 3 above Method 1 to get the customized pages and css files.

7. Try to access the Travelocity.com. You will be presented with the customized page!

Ref:
[1] http://wso2.com/products/identity-server/
[2] http://dulanja.blogspot.com/2014/01/wso2-is-samlsso-customizing-login-page.html
[3] https://svn.wso2.org/repos/wso2/people/dulanja/samples/customize_loginpage/travelocity.com.war
[4] https://svn.wso2.org/repos/wso2/people/dulanja/samples/customize_loginpage/avis.com.war
[5] https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/components/identity/org.wso2.carbon.identity.application.authentication.endpoint/4.2.2/  
[6] https://svn.wso2.org/repos/wso2/people/dulanja/samples/customize_loginpage/is-500/

No comments: