November 2, 2011

Configure Tomcat for federation - Part III


I described in the previous blogs how to set up the IDP which plays a key role in Web SSO based on the Passive requestor profile of WS-Federation and the CXF STS to issue security tokens. The IDP delegates authentication requests to the STS.

In WS-Federation, the authentication process is externalized to the IDP/STS. It provides you a SAML token (or another security token, WS-Federation is not tight to SAML) which contains all information of the authenticated user you need to implement finer grained authorization requirements without being tight to the user name.

The information in the SAML token must be integrated in Tomcat in such a way that application developers can use J2EE security as they are used to.
Example:
  • HttpServletRequest.getUserPrincipal()
  • HttpServletRequest.isUserInRole()
  • security constraints in web.xml
There is no need to configure any security related servlets/filters in the web.xml. This is managed on the Tomcat container level to benefit of container managed security.

It's standardized here how claim information (firstname, lastname, email, etc) must be represented in an AttributeStatement of a SAML token (assertion) but there is no Java API standard how this information could be accessed by programming. The federation plugin provides an extension of the Tomcat principal class which provides all these information.


This blog addresses two topics:
  • how to build and deploy the federation plugin into Tomcat
  • how to build and deploy a federation enabled web application into Tomcat

The plugin has been tested with JDK 1.6 and Tomcat 7.0.



Build and deploy the federation plugin into Tomcat
The source code is bundled as maven plugins which can be downloaded here and contains the following maven modules:
  • plugins/core
    This module contains the core ws-federation functionality which is container agnostic. The core functionality includes SAML 1.1/2.0 token validation (signature verification), lifetime and audience restriction validation. The FederationProcessor returns all information like roles, claims and authenticated user.
  • plugins/tomcat
    This module contains the tomcat authenticator which integrates the ws-federation functionality into Tomcat. It hydrates the tomcat security context
  • examples/simpleWebapp/
    This is a sample web application where the federation plugin is configured and makes use of security constraints and the Servlet Security API.
    This module is described in section "Build and deploy the federation sample application".

Run mvn clean install in each module to build the jar file.
After the build, please follow these steps to deploy and configure the federation plugin.

1) Create sub-directory fediz in ${catalina.home}/lib

2) Update calatina.properties in ${catalina.home}/conf
add the previously created directory to the common loader:
common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar,${catalina.home}/lib/fediz/*.jar


3) Deploy the built libraries and dependencies to the directory created in (1)
The built libraries and their dependencies can be found in the zip file located in fediz-tomcat/target/...zip-with-dependencies.zip

4) Configure Federation plugin
The current release of the federation plugin requires to configure the FederationAuthenticator which is configured like any other Valve as described here.

You can either configure the context in the server.xml or in META-INF/context.xml as part of your WAR file.

server.xml
  <Context path="/fedizhelloworld" docBase="fedizhelloworld">
    <Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator"

      issuerURL="https://localhost:9443/fedizidp/"
      truststoreFile="conf/stsstore.jks"
      truststorePassword="stsspass"
      trustedIssuer=".*CN=www.sts.com.*" />
  </Context>
       
META-INF/context.xml


  <Context> 
    <Valve className="org.apache.cxf.fediz.tomcat.FederationAuthenticator"
      issuerURL="https://localhost:9443/fedizidp/"
      truststoreFile="conf/stsstore.jks"
      truststorePassword="stsspass"
      trustedIssuer=".*CN=www.sts.com.*" />
  </Context>



The attribute issuerURL tells the plugin where to redirect unauthenticated requests which access a protected resource (security constraint matches URI pattern).
The current release of the federation plugin supports SAML 1.1/2.0 tokens. The SAML token is signed to provide a way to establish a trust. The federation plugin must validated the SAML token. The validation process includes verifying whether the certificate has been issued by a trusted CA and whether the certificate subject is trusted. The certificate subject identifies the IDP/STS.
You can have more than one IDP/STS in your company. As soon as you grant B2B partners access (internet) to your web application you have at least 2 IDP/STS instances. Usually, you create a chain of IDP instances where the RP trusts only the internal IDP/STS instance and the internal IDP (so called Relying Party IDP) trusts the external IDP. This scenario is addressed in one of the next blogs.
The attribute truststoreFile tells the plugin where the truststore is located (Java Keystore format) and the password is configured in the attribute truststorePassword. The trusted IDP/STS is configured as a regular expression in the attribute trustedIssuer.

It's not yet possible to configure a custom security token validator.


5) Configure the CA certificates

If you use the STS as described here you can copy the keystore from fediz-idp-sts/src/test/resources/stsstore.jks to the configured location in the attribute truststoreFile.

(you can ignore the fact in this demo that the private key is contained in this keystore also which must not be the case for production. The certificate is sufficient for signature validation)


Build and deploy the federation sample application
I've chosen the META-INF/context.xml approach to configure the federation plugin for ease of use.

This web application provides three accessible resources:
  • index.html
    This static page is not secured by a security constraint
  • secure/test.html
    This static page is secured by a security constraint in the web.xml
  • /secureservlet/fed
    This servlet provides information about the authenticated user like username, roles and claims as illustrated in the following picture:
    
The user and role information can be retrieved using standard J2EE security API. Unfortunately, there is no standard API to retrieve claims information thus the federation plugin provides an extension of the principal which can be accessed as illustrated here:

  Principal p = request.getUserPrincipal();
  if (p instanceof FederationPrincipal) {
     FederationPrincipal fp = (FederationPrincipal)p;
     ClaimCollection claims = fp.getClaims();
     ...
  }

Every security constraint must define at least one role in auth-constraint as defined in the Servlet specification. There are use cases where you might want to give access to resources to everybody who is authenticated. Therefore, the plugin can add a default role if no roles are provided as part of the SAML token. If not explicitly configured, the default role name is Authenticated.



Encoding of roles in SAML token

The federation authenticator provides the following attributes to customize where and how the role information is encoded in the SAML token. The role is like any other claim represented within the attribute statement.

The IDP/STS in this example uses the following URI for the role claim:
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role

If your IDP/STS stores the role information in another claim, configure the attribute roleClaimURI in the FederationAuthenticator. The value of the attribute is a string where the list of roles are delimited by a character. The IDP/STS in this example use "," as the default delimiter. If you want to use another delimiter configure the attribute roleDelimiter in the FederationAuthenticator.