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.

9 comments:

  1. SEVERE: Parse error in context.xml for /manager
    java.lang.ClassNotFoundException: org.apache.fediz.tomcat.FederationAuthenticator
    Caused by: java.lang.ClassNotFoundException: org.apache.fediz.tomcat.FederationAuthenticator
    Mar 6, 2012 3:31:40 PM org.apache.catalina.startup.ContextConfig processContextConfig
    SEVERE: Occurred at line 40 column 44
    Mar 6, 2012 3:31:40 PM org.apache.tomcat.util.digester.Digester endElement
    WARNING: No rules found matching 'Context/Valve/Context'.
    Mar 6, 2012 3:31:40 PM org.apache.catalina.startup.ContextConfig configureStart
    SEVERE: Marking this application unavailable due to previous error(s)
    Mar 6, 2012 3:31:40 PM org.apache.catalina.core.StandardContext startInternal
    SEVERE: Error getConfigured
    Mar 6, 2012 3:31:40 PM org.apache.catalina.core.StandardContext startInternal
    SEVERE: Context [/manager] startup failed due to previous errors
    Mar 6, 2012 3:31:40 PM org.apache.catalina.startup.HostConfig deployDirectory
    INFO: Deploying web application directory C:\apache-tomcat-7.0.25\tomcat-instance2\webapps\ROOT
    Mar 6, 2012 3:31:40 PM org.apache.tomcat.util.digester.Digester startElement
    SEVERE: Begin event threw exception
    java.lang.ClassNotFoundException: org.apache.fediz.tomcat.FederationAuthenticator
    Mar 6, 2012 3:31:40 PM org.apache.catalina.startup.ContextConfig processContextConfig
    SEVERE: Parse error in context.xml for
    java.lang.ClassNotFoundException: org.apache.fediz.tomcat.FederationAuthenticator

    Caused by: java.lang.ClassNotFoundException: org.apache.fediz.tomcat.FederationAuthenticator

    Mar 6, 2012 3:31:40 PM org.apache.catalina.startup.ContextConfig processContextConfig
    SEVERE: Occurred at line 40 column 44
    Mar 6, 2012 3:31:40 PM org.apache.catalina.startup.ContextConfig configureStart
    SEVERE: Marking this application unavailable due to previous error(s)
    Mar 6, 2012 3:31:40 PM org.apache.catalina.core.StandardContext startInternal
    SEVERE: Error getConfigured
    Mar 6, 2012 3:31:40 PM org.apache.catalina.core.StandardContext startInternal
    SEVERE: Context [] startup failed due to previous errors
    Mar 6, 2012 3:31:40 PM org.apache.coyote.AbstractProtocol start
    INFO: Starting ProtocolHandler ["http-apr-8282"]
    Mar 6, 2012 3:31:40 PM org.apache.coyote.AbstractProtocol start
    INFO: Starting ProtocolHandler ["http-apr-8283"]
    Mar 6, 2012 3:31:40 PM org.apache.coyote.AbstractProtocol start
    INFO: Starting ProtocolHandler ["http-nio-8222"]
    Mar 6, 2012 3:31:40 PM org.apache.coyote.AbstractProtocol start
    INFO: Starting ProtocolHandler ["ajp-apr-8209"]
    Mar 6, 2012 3:31:40 PM org.apache.catalina.startup.Catalina start
    INFO: Server startup in 11208 ms

    ReplyDelete
  2. when ever I insert this code to the context.xml file , it gives me the above errors.. especially this error
    java.lang.ClassNotFoundException: org.apache.fediz.tomcat.FederationAuthenticator
    where am i suppose to get this class?

    META-INF/context.xml

    ReplyDelete
  3. I haven't updated the classname on this blog - only the example. The correct class name is: org.apache.cxf.fediz.tomcat.FederationAuthenticator
    will update this now. Thanks for the hint.

    ReplyDelete
  4. HTTP Status 403 - Requesting security token failed

    type Status report

    message Requesting security token failed

    description Access to the specified resource (Requesting security token failed) has been forbidden



    https://localhost:8222/fedizidp/?wa=wsignin1.0&wreply=http%3A%2F%2Flocalhost%3A8282%2Fmanager%2Fhtml&wtrealm=http%3A%2F%2Flocalhost%3A8282%2Fmanager%2F


    how do i pass this stage , because Class Not Found Exception is ok now , the web page is complaining about the certificate


    Thanks a lot

    ReplyDelete
    Replies
    1. The Federation plugin is called and the redirect to the IDP triggered.

      Could you please raise this with the CXF user list (http://cxf.apache.org/mailing-lists.html) as it is much easier to attach log files?

      Could you send me the logfile of both tomcat instances?

      The browser makes the following checks when establishing an HTTPS connection:
      - certificate of server (self-signed) or the CA certificate must be in the truststore of the browser
      - verifies whether the subject CN of the certificate matchs with the hostname of the Url
      - the certificate must be valid

      Otherwise, the browser shows a warning message.

      Delete
  5. i'm not sure if you have seen it, but i have posted it .......


    http://cxf.547215.n5.nabble.com/HTTP-Status-403-Requesting-security-token-failed-td5543684.html

    ReplyDelete
  6. I've prepared a zip file which contains two tomcat instances:
    - tomcat-idp
    - tomcat-rp (contains the application)

    You can download it here:
    https://docs.google.com/open?id=0B39bWm6JgpkfMDZDVkFZemdTX202YlVWM2xMUjEwdw

    After starting the two tomcat instances, open a browser and enter the following url:
    https://localhost:8443/fedizhelloworld/secureservlet/fed

    The following usernames are configured:
    user: alice password:ecila
    user: bob password:bob
    user: ted password:det

    ReplyDelete
  7. when I enter this URL https://localhost:8443/fedizhelloworld/secureservlet/fed, it says

    The server localhost:9443 requires a username and password

    The server says :IDP

    and I have tried the configured usernames and passwords

    user: alice password:ecila
    user: bob password:bob
    user: ted password:det

    but it returns HTTP Status 403 - Requesting security token failed

    ReplyDelete
  8. I want to have different services such that I’m able to use single sign on across all the services using certificate

    Not as In the case of SAML Sender-Vouches, where there is one security (trust) domain

    ReplyDelete