Thursday, April 16, 2009

Building a Custom Trust Association Interceptor for WebSphere Portal

At one point, I had to develop a custom Single Sign On solution to WebSphere Portal. The general standard for this is to use TAM, but since this wasn't available, I wrote something a little more simple, using a Trust Association Interceptor. Trust Association Interceptors are used when a page in a Web Application has been marked as protected. The TAI can determine if a user should be allowed to access that page.

This multiple part posting explores setting up a simple TAI for WebSphere Portal. It's a collection of information around the web. For an excellent resource on Trust Association Interceptors, see this article (which I wish I had seen when I did this).

As usual, the code has been stripped down to the key parts.

Part I: The code

package test.security.tai;

import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ibm.websphere.security.CustomRegistryException;
import com.ibm.websphere.security.EntryNotFoundException;
import com.ibm.websphere.security.UserRegistry;
import com.ibm.websphere.security.WebTrustAssociationException;
import com.ibm.websphere.security.WebTrustAssociationFailedException;
import com.ibm.wsspi.security.tai.TAIResult;
import com.ibm.wsspi.security.tai.TrustAssociationInterceptor;

/**
* Custom Login Module
*
* Project imports the jar wssec.jar for development purposes.
* Found in the server runtime lib directory ($irad_home$\runtimes\base_v6\)
*
*
**/
public class CustomPortalTAI implements TrustAssociationInterceptor
{
private static final String VERSION = "Custom TAI version 1.0 \n Author: SirCrofty \n " + "Last Updated: March 1, 2008";

private static final String TYPE = "--- Custom TAI --- \n Custom Trust Assocation Interceptor for WebSphere Portal Application";

HashMap sharedState = null;

/**
* Constructor
*
**/
public CustomPortalTAI()
{
sharedState = new HashMap();
}

/**
* (non-Javadoc)
* @see com.ibm.wsspi.security.tai.TrustAssociationInterceptor#initialize(java.util.Properties)
* @param arg0
* @return
* @throws com.ibm.websphere.security.WebTrustAssociationFailedException
*
**/
public int initialize(Properties props) throws WebTrustAssociationFailedException
{
return 0;
}


/**
* (non-Javadoc)
* @see com.ibm.wsspi.security.tai.TrustAssociationInterceptor#isTargetInterceptor(javax.servlet.http.HttpServletRequest)
* @param arg0
* @return
* @throws com.ibm.websphere.security.WebTrustAssociationException
*
**/
public boolean isTargetInterceptor(HttpServletRequest req) throws WebTrustAssociationException
{
System.out.println("*********** Custom TAI ******************");
System.out.println("Determining if this TAI should handle the incoming request...");

if (req.getParameter("customUser") != null)
{
System.out.println("Custom TAI is being used to establish trust!");
return true;
}


System.out.println("Bypassing Custom TAI, did not find a user ID in the request");
return false;
}
/**
* (non-Javadoc)
* @see com.ibm.wsspi.security.tai.TrustAssociationInterceptor#negotiateValidateandEstablishTrust(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
* @param arg0
* @param arg1
* @return
* @throws com.ibm.websphere.security.WebTrustAssociationFailedException
*
**/
public TAIResult negotiateValidateandEstablishTrust(HttpServletRequest req, HttpServletResponse resp)
throws WebTrustAssociationFailedException
{
String userId = req.getParameter("customUser");
if (userId.equals("portalUser"))
{
System.out.println("*********** CustomTAI *****************");
System.out.println("UserID = " + userId);

return TAIResult.create(HttpServletResponse.SC_OK, userId);
}
else
{
return TAIResult.create(HttpServletResponse.SC_FORBIDDEN, userId);
}
}

/**
* @see com.ibm.wsspi.security.tai.TrustAssociationInterceptor#cleanup()
*
*
**/
public void cleanup()
{
sharedState = null;
}


/**
* @see com.ibm.wsspi.security.tai.TrustAssociationInterceptor#getType()
* @return
*
**/
public String getType()
{
return TYPE + " \n " + this.getClass().getName();
}

/**
*
* @see com.ibm.wsspi.security.tai.TrustAssociationInterceptor#getVersion()
* @return
*
**/
public String getVersion()
{
return VERSION;
}
}

We're implementing the com.ibm.wsspi.security.tai.TrustAssociationInterceptor interface provided by IBM. In order to get this to compile, you may need to place some jars in your class path during development. These jars are named wssec.jar and sas.jar, and are found in your server runtime directory.

The two methods of interest above are isTargetInterceptor and negotiateValidateandEstablishTrust. Both of these methods accept an HttpServletRequest as input, and that's how we can accomplish our single sign on.

isTargetInterceptor is called whenever a user requests access to a protected page. The Application server will run through it's list of installed TAIs (see Part II for installing the TAI) and call isTargetInterceptor on each one. This is the servers way of determining if it should use that TAI for the incoming request. In our simple example, if the request has the parameter customUser, we tell the application server to return true, signaling that we want to use this TAI.

Once the server finds a TAI that returns true for it's isTargetInterceptor method, it will proceed to call that TAI's negotiateValidateandEstablishTrust method. This method is in charge of actually checking whether we want to trust the incoming request, and therefore forward the user to the requested page.

In the example, if the userId is equal to "portalUser", we create a TAIResult with a 200 response, indicating that all is good and the user can continue. Otherwise, the access is forbidden.

Since the url path /myportal is protected once security is configured on WebSphere Portal, all requests sent to /myportal will be challenged against this TAI. If the request included a query parameter such as /myportal?customUser=portalUser, the CustomPortalTAI would be invoked, and the user would be passed to the corresponding page in the portal.

Note that we're not creating any Subject information or anything else to create the user credentials. WebSphere Portal will take care of most of the default creation for you, once the success is found in the TAI.

3 comments:

  1. Excellent .. Easily explained the flow..

    Thanks again.
    Sri

    ReplyDelete
  2. In order to determine whether a blog is DoFollow or NoFollow in nature, pick up a name of someone who already commented there, white hat link building

    ReplyDelete
  3. Can you Please explain "How to handle an exception caused in negotiateValidateandEstablishTrust method" for a portal application

    ReplyDelete