October 20, 2011

How to enable an interceptor without configuration in CXF

Imagine you develop an interceptor within your company which is for general use and not for a specific business project. There are different ways to configure an interceptor as described in more detail here. In summary:
  • by programming
  • configure the interceptor on the bus, client or endpoint level
  • configure a feature which registers interceptor(s)
  • configure a policy which registers interceptors
There might be use cases where you want to enable an interceptor just because the interceptor is available in the classpath. This means, you developed an interceptor, built a Jar and published to the maven repository. Another project should only add a dependency to your jar in their POM to enable the interceptor automatically. Done.

This blog will explain how this works and an example can be downloaded here.

CXF 2.4 introduced a new feature called bus extension which are loaded during the initialization phase of a bus automatically. Thus, your interceptor registration code must get notified whenever a new client or server is created to be able to add the interceptor. CXF provides three LifecycleListners:
This example shows the usage of the Server- and ClientLifecycleListner. A lifecycle listener is registered by the corresponding lifecycle manager which can be resolved using the CXF bus as illustrated in the following code snippet:

public class DemoListener implements ClientLifeCycleListener, ServerLifeCycleListener {

 public DemoListener(Bus bus) {
    ServerLifeCycleManager slm = bus.getExtension(ServerLifeCycleManager.class);
    slm.registerListener(this);

This class implements the lifecycle listener methods and registers itself to the lifecycle manager. The interceptor could be registered as illustrated in the following code snippet:

public void startServer(Server server) {
  System.out.println("--------- startServer");
  server.getEndpoint().getInInterceptors().add(new DemoInterceptor());
  server.getEndpoint().getOutInterceptors().add(new DemoInterceptor());
}

public void clientCreated(Client client) {
  System.out.println("--------- clientCreated");
  client.getOutInterceptors().add(new DemoInterceptor());
  client.getInInterceptors().add(new DemoInterceptor());
}

So far so good, but there must be a way to trigger the instantiation of the class DemoListener. One option is to use Spring and make this class a spring managed component or you register this bean as a CXF bus extension.

I'll explain how to register this bean as a bus extension thus it gets instantiated when the bus is created which means that the lifecycle listeners are registered in the startup phase too.
Your Jar file must contain a file called bus-extensions.xml at the following location in the Jar:
META-INF/cxf/bus-extensions.txt

The content of this text file is very simple. You just list the classname:
org.talend.ps.examples.busextension.DemoListener::false

The last parameter is false which tells the bus whether the instantiation of the bean should be defered or not. If deferred is true, (default) the bus doesn't create the beans during startup. However, if something specifically asks for one of those beans, it will be created and loaded.

If the class provides a constructor with the Bus argument, CXF will pass the bus during initialization.

Where else is this feature used? In CXF itself.

This was a very simple example how to instantiate beans during bus startup without the requirement for Spring. A lot of the advanced and WS-* features in CXF 2.3 and earlier required that you explicitly imported resources like:

<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-jms.xml" />

This was required to import the spring configuration files which contained bean definitions which usually implemented lifecycle listeners or support for policy. This is not required any more in CXF 2.4 and above. You only have to import the following resource now:

<import resource="classpath:META-INF/cxf/cxf.xml" />

With CXF 2.4, these features are not plugged into the bus using a spring mechanism but instead the bus extension mechnism as illustrated in the simple example above.

If you want to see more advanced usage of bus extension have a look to the sources of some of these CXF modules:

An interesting interceptor example can be found in the Talend Service Factory.

October 18, 2011

Configure LDAP directory for CXF STS

I explained in my previous blog how to set up the CXF STS where you manage your users and claims in a file.This blog explains the required changes to integrate the CXF STS with a LDAP directory.

You can attach an LDAP directory either for username/password validation or for retrieving the claims data or both.

1. Username and password authentication

WSS4j supports username/password authentication against a JAAS based backend since version 1.6.3.

The JDK provides a JAAS LoginModule for LDAP which can be configured as illustrated here in a sample jaas configuration (jaas.config):
  
myldap {
 com.sun.security.auth.module.LdapLoginModule REQUIRED
 userProvider=ldap://ldap.mycompany.org:389/OU=Users,DC=mycompany,DC=org"
 authIdentity="cn={USERNAME},OU=Users,DC=mycompany,DC=org"
 useSSL=false
 debug=true;
};

You can get more information about this LoginModule here.

In this example, all the users are stored in the organization unit Users within mycompany.org. The configuration filename can be chosen, i.e. jaas.config. The filename must be configured as a JVM argument. I recommend to set JVM related configurations for Tomcat in the setenv.sh/bat file located in tomcat/bin directory. This script is called by catalina.bat/sh implicitly and might look like this for UNIX:

#!/bin/sh 
JAVA_OPTS="-Djava.security.auth.login.config=/opt/tomcat/conf/jaas.config"
export JAVA_OPTS

Now, the LDAP LoginModule is configured. Next we have to configure the JAASUsernameTokenValidator for the STS endpoint.

<bean
  class="org.apache.ws.security.validate.JAASUsernameTokenValidator"
      id="jaasUTValidator">
   <property name="contextName" value="myldap"/>
</bean>

<jaxws:endpoint id="transportSTSUT"
  endpointName="ns1:TransportUT_Port"
  serviceName="ns1:SecurityTokenService"
  xmlns:ns1=http://docs.oasis-open.org/ws-sx/ws-trust/200512/
  wsdlLocation="/WEB-INF/wsdl/ws-trust-1.4-service.wsdl"
  address="/STSServiceTransportUT"
  implementor="#transportSTSProviderBean">

  <jaxws:properties>
    <entry key="ws-security.ut.validator"
         value-ref="jaasUTValidator"/>
  </jaxws:properties>
</jaxws:endpoint>


The property contextName must match with the context name defined in the JAAS configuration file which is "myldap" in this example.
<
 2. Claims management

When a STS client requests a claim, the ClaimsManager in the STS checks every registered ClaimsHandler who can provide the data of the requested claim.  The CXF STS provides a claims handler implementation which allows to add claims which are stored as user attributes in a LDAP directory. You can configure which claim URI maps to which LDAP user attribute. The implementation uses the spring ldap module (LdapTemplate).

<util:list id="claimHandlerList">
  <ref bean="ldapClaimsHandler" />
</util:list>

<bean id="contextSource"
   class="org.springframework.ldap.core.support.LdapContextSource">
  <property name="url" value="ldap://ldap.mycompany.org:389" />
  <property name="userDn"
    value="CN=techUser,OU=Users,DC=mycompany,DC=org" />
  <property name="password" value="mypassword" />
</bean>

<bean id="ldapTemplate"
   class="org.springframework.ldap.core.LdapTemplate">
  <constructor-arg ref="contextSource" />
</bean>

<util:map id="claimsToLdapAttributeMapping">
  <entry
key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
value="givenName" />
  <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
value="sn" />
  <entry
key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
value="mail" />
  <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country"
value="c" />
</util:map>

<bean id="ldapClaimsHandler"
    class="org.apache.cxf.sts.claims.LdapClaimsHandler">
  <property name="ldapTemplate" ref="ldapTemplate" />
  <property name="claimsLdapAttributeMapping"
            ref="claimsToLdapAttributeMapping" />
  <property name="userBaseDN"
      value="OU=Users,DC=mycompany,DC=org" />
</bean>


The claim id's are configured according to chapter 7.5 in the specification Identity Metasystem Interoperability. You can add as many entries in the map claimsToLdapAttributeMapping as you want. Thus you can add any user attribute from your LDAP directory to the issued SAML token.

October 13, 2011

Configure and deploy Identity Provider (IdP) - Part II

In my previous blog I talked about setting an STS which supports username/password authentication and the issuance of a SAML 2.0 token which contains additional claims information.
We need these claims information to provide the application (called Relying Party in WS-Federation specification) the information like application roles for role based access control. Claims based authorization goes one step further and provides other claims data of the authenticated entity (SAML subject).

Introduction

This blog is about the Identity Provider (IDP) implementation which is referenced in the WS-Federation specification. Therefore, I'm giving a short introduction. This blog series looks at the passive requestor profile only of WS-Federation.

The following picture is used by Microsoft which supports WS-Federation in their Windows Identity Foundation framework.


(C) Microsoft



The key principals of WS-Federation are:
  • Externalize authentication process from the application container
  • Provide the claims/attributes of the authenticated identity to the application for role based and fine grained authorization
WS-Federation gives you the following benefits:
  • Applications can benefit of stronger security mechanism without changes
  • Identities/users don't have to be provisioned in all security domains to propagate identities across the security domains
  • B2B partners can be integrated without changing the application (includes programming and configuration)
  • Audit-Trail end-to-end


    Deploy Identity Provider (IdP)



    This sample IDP will support the following functionality:
    • Authentication based on username/password (Basic Authentication)
    • The authentication store is configured in the STS and can be file based (part of this example) or LDAP
    • Following federation parameters are supported:
      • wtrealm
      • wreply
      • wctx
      • wresult
    • Required claims can be configured per Relying Party (based on wtrealm value)
    Jürg Portmann and myself have put together this IDP. You can download the maven project services/idp here.


    1. Claims configuration per relying party

    The required claims per relying party are configured in the WEB-INF/RPClaims.xml. The XML file has the following structure. The key of each map entry must match with the wtrealm paramater in the redirect triggered by the relying party.
    (the set up of the relying part will be covered in the next blog).


        <util:map id="realm2ClaimsMap">
            <entry key="http://localhost:8080/wsfedhelloworldother/"
                value-ref="claimsWsfedhelloworld" />
            <entry key="http://localhost:8080/wsfedhelloworld/"
                value-ref="claimsWsfedhelloworldother" />
        </util:map>

        <util:list id="claimsWsfedhelloworld">
            <value>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
            </value>
            <value>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
            </value>
        </util:list>

        <util:list id="claimsWsfedhelloworldother">
            <value>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
            </value>
            <value>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
            </value>
            <value>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
            </value>
        </util:list>   


    You group the required claims in beans which are a list of String as illustrated in claimsWsfedhelloworld and claimsWsfedhelloworldother.

    The map bean must be named realm2ClaimsMap and maps the different relying parties (applications) to one of the claim lists.


    In a further release, this information will be pulled from a WS-Federation Metadata document published by the replying party.


    2. Project dependencies
     
    The IDP reuses a lot of existing projects like Apache CXF to communicate with the STS for instance and provides an adaption of the WS-Trust interface to pure HTTP functionality as it is supported by a browser. The IDP has the following dependencies in the Maven project:


        <properties>
          <cxf.version>2.5.2</cxf.version>
       </properties>

       <dependencies>
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-transports-http</artifactId>
                <version>${cxf.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-frontend-jaxws</artifactId>
                <version>${cxf.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-ws-policy</artifactId>
                <version>${cxf.version}</version>
            </dependency>
            <dependency>
                <groupId>
    org.apache.cxf</groupId>
                <artifactId>
    cxf-rt-ws-security</artifactId>
                <version>${cxf.version}</version>
            </dependency>

       </dependencies>  


    3. IDP web application configuration

    Setting up the IDP involves a few steps only. If you you don't deploy the IDP in the same servlet container as the STS you must first download Tomcat 7 and update server.xml. If you deploy the IDP in the same servlet container you can skip 3.1

    3.1 Configure HTTP/S connector in Tomcat

    The HTTP connector should be configured with port 9080.


    The HTTPS connector in Tomcat is configured in conf/server.xml. Deploy the tomcatkeystore.jks of the example project  to the Tomcat root directory if the Connector is configured as illustrated:

        <Connector port="9443" protocol="HTTP/1.1" SSLEnabled="true"
                   maxThreads="150" scheme="https" secure="true"
                   keystoreFile="tomcatKeystore.jks"
                   keystorePass="tompass" sslProtocol="TLS" />

    This connector configures a self-signed certificate which is used for simplification only. You should get a certificate signed by a Certificate Authority for production usage.

    3.2 Configure Username/password authentication


    As described in section 1. the requested claims per relying party are managed in the file WEB-INF/RPclaims.xml.

    3.3 IDP and STS distributed
     
    If the IDP and STS are not deployed on the same machine (likewise in production) you have to update the following configuration:






    1) The remote WSDL location of the STS:

    WEB-INF/web.xml:

      <init-param>
        <param-name>sts.wsdl.url</param-name>
        <param-value>https://localhost:9443/wsfedidpsts/STSService?wsdl</param-value>
      </init-param>


    2) the transport conduit to enable the truststore as described in more detail here:


    WEB-INF/beans.xml

      <http:conduit name="https://localhost:9443/.*">
        <http:tlsClientParameters disableCNCheck="true">
          <sec:trustManagers>
            <sec:keyStore type="jks" password="cspass" resource="clientstore.jks"/>
          </sec:trustManagers>
        </http:tlsClientParameters>
      </http:conduit>




    3) fully qualified realm in realm2ClaimsMap


    As described in 1) the key of an entry in the map realm2ClaimsMap must match with the  parameter wtrealm in the redirect triggered by the relying party. If you access the relying party using a fully qualified URL, you must use the fully qualified URL in the IDP too.  


    WEB-INF/RPclaims.xml


        <util:map id="realm2ClaimsMap">
            <entry key="http://localhost:8080/wsfedhelloworldother/"
                value-ref="claimsWsfedhelloworld" />
            <entry key="http://localhost:8080/wsfedhelloworld/"
                value-ref="claimsWsfedhelloworld2" />
        </util:map>



    4. Deploy the IDP to Tomcat

    To deploy the IDP using Maven you have to follow these steps:
    • Configuring the following maven plugin
          <plugin>
              <groupId>org.codehaus.mojo</groupId>
              <artifactId>tomcat-maven-plugin</artifactId>
              <version>1.1</version>
              <configuration>
                   <server>myTomcat</server>
                   <url>http://localhost:9080/manager/text</url>
                   <path>/${project.build.finalName}</path>
              </configuration>
          </plugin>
    • Add the server with username and password to your settings.xml
    • Ensure the user has the role "manager-script" as described here
    • Run mvn tomcat:redeploy
      (I recommend to use redeploy as deploy works the first time only)
    If you use Tomcat 6, you must change the url of the tomcat maven plugin:
        <url>http://localhost:9080/manager</url>


    4. Test the IDP

    As long as you don't have a relying party in place you can't easily test the IDP. The following post explains the set up of the relying party using Tomcat 7.


    If you like you can test the IDP by using an HTTP client and pass the following request parameters (urls must be encoded):

    wa       wsignin1.0
    wreply   http://localhost:8080/wsfedhelloworld/secureservlet/fed
    wtrealm  http://localhost:8080/wsfedhelloworld/


    The browser will get a HTML form back (auto-submit). The action of the form is equal to the value of wreply which doesn't exist. You see the response of the STS escaped in the form parameter wresult.

    October 11, 2011

    Configure and deploy CXF 2.5 STS - Part I

    Talend has donated an STS implementation to the Apache CXF community as posted already on this here

    This is the first part of a series of blogs on using WS-Federation Passive Requestor Profile to implement a Web and Web Services SSO solution from a web application to a target Web Service. The used technologies are CXF 2.5 (to be released soon) and Tomcat 7.

    • Part I
      Configure and deploy CXF STS using Claims
    • Part II
      Configure and deploy Identity Provider (IdP)
    • Part III
      Configure and deploy Tomcat Relying Party (RP)
    • Part IV
      Enhance Tomcat RP to call a target web services which delegates the identity
    • Part V
      Interoperability testing with Microsoft Windows Identity Foundation

    The STS in this part is configured to support the following functionality:
    • STS WSDL is enriched with the WS-SecurityPolicy information
    • STS issues a signed SAML 2.0 token
    • STS is secured using HTTPS
    • STS validates an incoming UsernameToken against a local file store
    • STS adds claims information to the SAML token in an attribute statement
    You can find a running maven project called services/sts here.


    1. Username and password management

    The users and passwords are configured in a spring configuration file in WEB-INF/passwords.xml. The XML file has the following structure:

        <util:map id="passwords">
            <entry key="alice"
                value="ecila" />
            <entry key="bob"
                value="bob" />
            <entry key="ted"
                value="det" />
        </util:map>

    The intention of this STS example is to illustrate how to set up an STS. If you have an LDAP directory in place or any other JAAS based LoginModule you can also plug in the WSS4J JAASUsernameTokenValidator.

    2. Claims management

    The claims for each user are configured in a spring configuration file also in WEB-INF/userClaims.xml. The XML file has the following structure:

        <util:map id="userClaims">
            <entry key="alice"
                value-ref="aliceClaims" />
            <entry key="bob"
                value-ref="bobClaims" />
            <entry key="ted"
                value-ref="tedClaims" />
        </util:map>
       
        <util:map id="aliceClaims">
            <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"
                value="Alice" />
            <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"
                value="Smith" />
            <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
                value="alice@mycompany.org" />
            <entry key="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role"
                value="user" />
               
        </util:map>


    The claim id's are configured according to chapter 7.5 in the specification Identity Metasystem Interoperability. The mapping of claims to a SAML attribute statement are described in chapter 7.2.
    There is no standard URI for role. Therefore, I reuse Microsoft's role URI which is used by ADFS (Active Directory Federation Service) and Windows Identity Foundation (WIF). If the STS issues claims using the same role URI, you get role-based access control (or claims based authorization support for WIF based applications out-of-the-box).

    The intention of this STS example is to illustrate how to set up an STS. If you have an LDAP directory in place you can configure the LdapClaimsHandler where you configure the mapping of the claim id (URI) to an LDAP user attribute. 

    3. Project dependencies
     
    The STS has the following dependencies in the Maven project.

        <properties>
          <cxf.version>2.5.2</cxf.version>

       </properties>

       <dependencies>
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-transports-http</artifactId>
                <version>${cxf.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-frontend-jaxws</artifactId>
                <version>${cxf.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-ws-policy</artifactId>
                <version>${cxf.version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.cxf.services.sts</groupId>
                <artifactId>cxf-services-sts-core</artifactId>
                <version>${cxf.version}</version>
            </dependency>

       </dependencies>  


    4. STS endpoint configuration

    Setting up the STS involves several steps. The STS is configured using the spring framework. First step is to download Tomcat 7.

    4.1 Configure HTTP/S connector in Tomcat


    The HTTP connector should be configured with port 9080.

    The HTTPS connector in Tomcat is configured in conf/server.xml. Deploy the tomcatkeystore.jks of the example project  to the Tomcat root directory if the Connector is configured as illustrated:

        <Connector port="9443" protocol="HTTP/1.1" SSLEnabled="true"
                   maxThreads="150" scheme="https" secure="true"
                   keystoreFile="tomcatKeystore.jks"
                   keystorePass="tompass" sslProtocol="TLS" />

    Update: Have a read through the following blog here which describes how to generate a keystore.

    4.2 Configure the WS-SecurityPolicies of the STS endpoint

    The following policies must be added to the WSDL. CXF provides other ways to correlate policies with a wsdl subject (port type, service, port, ...). I've chosen the simplest one where the policies are embedded into the wsdl for illustration purposes. The WSDL can be found in WEB-INF/wsdl/ws-trust-1.4-service.wsdl

    The following policy defines a transport binding (https) and expects a UsernameToken be present in the WS-Security header. The UsernameToken must be signed which is implicitly supported by HTTPS:

        <wsp:Policy wsu:Id="Transport_policy">
          <wsp:ExactlyOne>
             <wsp:All>
                <wsap10:UsingAddressing/>
                <sp:TransportBinding
                   xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
                   <wsp:Policy>
                      <sp:TransportToken>
                         <wsp:Policy>
                            <sp:HttpsToken RequireClientCertificate="false"/>
                         </wsp:Policy>
                      </sp:TransportToken>
                      <sp:AlgorithmSuite>
                         <wsp:Policy>
                            <sp:TripleDesRsa15 />
                         </wsp:Policy>
                      </sp:AlgorithmSuite>
                      <sp:Layout>
                         <wsp:Policy>
                            <sp:Lax />
                         </wsp:Policy>
                      </sp:Layout>
                      <sp:IncludeTimestamp />
                   </wsp:Policy>
                </sp:TransportBinding>
                <sp:SignedSupportingTokens
                   xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
                   <wsp:Policy>
                      <sp:UsernameToken
                         sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
                         <wsp:Policy>
                            <sp:WssUsernameToken10 />
                         </wsp:Policy>
                      </sp:UsernameToken>
                   </wsp:Policy>
                </sp:SignedSupportingTokens>
                <sp:Wss11
                   xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
                   <wsp:Policy>
                      <sp:MustSupportRefKeyIdentifier />
                      <sp:MustSupportRefIssuerSerial />
                      <sp:MustSupportRefThumbprint />
                      <sp:MustSupportRefEncryptedKey />
                   </wsp:Policy>
                </sp:Wss11>
                <sp:Trust13
                   xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
                   <wsp:Policy>
                      <sp:MustSupportIssuedTokens />
                      <sp:RequireClientEntropy />
                      <sp:RequireServerEntropy />
                   </wsp:Policy>
                </sp:Trust13>
             </wsp:All>
          </wsp:ExactlyOne>
       </wsp:Policy>



    4.3 Configure TokenProvider

    This STS endpoint configuration only supports to issue SAML tokens (2.0 or 1.1). For a full list of the supported features by the STS check this blog.

    The configuration related to issuing a token is located in the following spring configuration file (cxf-transport.xml):

    <bean id="transportIssueDelegate"
    class="org.apache.cxf.sts.operation.TokenIssueOperation">

        <property name="tokenProviders" ref="transportTokenProviders"/>
        <property name="services" ref="transportService"/>
        <property name="stsProperties" ref="transportSTSProperties"/>
        <property name="claimsManager" ref="claimsManager"/>
    </bean>

    <util:list id="transportTokenProviders">

        <ref bean="transportSamlTokenProvider"/>
    </util:list>
     

    <bean id="transportSamlTokenProvider" class="org.apache.cxf.sts.token.provider.SAMLTokenProvider">
        <property name="attributeStatementProviders" ref="attributeStatementProvidersList" />
    </bean>


    <util:list id="attributeStatementProvidersList">
        <ref bean="claimsAttributeProvider"/>

    </util:list>
       
    <bean id="claimsAttributeProvider"
            class="org.apache.cxf.sts.claims.ClaimsAttributeStatementProvider">
    </bean>


    The last bean claimsAttributeProvider is described in section 4.5



    4.4 Configure Username/password authentication


    As described in section 1. the user and passwords are managed in the file WEB-INF/passwords.xml.


    To configure username/password authentication in CXF/WSS4J you must provide a CallbackHandler. The CallbackHandler is part of this example project.


    The configuration is located in the following spring configuration file (cxf-transport.xml):

         <import resource="passwords.xml" />
      
        <bean id="upCallBackHandler"
            class="org.talend.security.sts.UsernamePasswordCallbackHandler">
            <property name="passwords" ref="passwords" />
        </bean>

        <jaxws:endpoint id="transportSTS1"
            implementor="#transportSTSProviderBean"
            address="/STSService"
            wsdlLocation="/WEB-INF/wsdl/ws-trust-1.4-service.wsdl"
            xmlns:ns1="http://docs.oasis-open.org/ws-sx/ws-trust/200512/"
            serviceName="ns1:SecurityTokenService"
            endpointName="ns1:TransportUT_Port">
            <jaxws:properties>
                <entry key="ws-security.callback-handler" value-ref="upCallBackHandler"/>
            </jaxws:properties>
        </jaxws:endpoint>


    The bean upCallBackHandler implements the CallbackHandler which is configured as a jaxws property ws-security.callback-handler in jaxws:properties of the jaxws:endpoint configuration. 



    4.5 Configure ClaimsManager

    Claims data can be stored in different kind of ID systems which can be accessed using LDAP, Web Services, REST whatever. The retrieval of claims is independent of any specific security token type and group in a list of claimshandler. Each claims handler must implement what kind of claims he can provide. It's the responsibility of the ClaimsManager to call the corresponding ClaimsHandler if a specific claim is requested by a STS client.

    The claims related configuration is summerized in the following spring configuration file (cxf-transport.xml):

        <import resource="userClaims.xml" />
       
        <bean id="claimsManager"
            class="org.apache.cxf.sts.claims.ClaimsManager">
            <property name="claimHandlers" ref="claimHandlerList" />
        </bean>
       
        <util:list id="claimHandlerList">
            <ref bean="fileClaimsHandler"/>
        </util:list>
       
        <bean id="fileClaimsHandler"
            class="org.talend.security.sts.FileClaimsHandler">
           
            <property name="userClaims" ref="userClaims" />
        </bean>

    The bean userClaims is defined in the imported spring configuration file userClaims.xml.

    5. Deploy the STS to Tomcat

    To deploy the STS using Maven you have to follow these steps:
    • Configuring the following maven plugin
          <plugin>
              <groupId>org.codehaus.mojo</groupId>
              <artifactId>tomcat-maven-plugin</artifactId>
              <version>1.1</version>
              <configuration>
                   <server>myTomcat</server>
                   <url>http://localhost:9080/manager/text</url>
                   <path>/${project.build.finalName}</path>
              </configuration>
          </plugin>
    • Add the server with username and password to your settings.xml
    • Ensure the user has the role "manager-script" as described here
    • Run mvn tomcat:redeploy
      (I recommend to use redeploy as deploy works the first time only)
    If you use Tomcat 6, you must change the url of the tomcat maven plugin:
        <url>http://localhost:9080/manager</url>


    6. Test the STS with SoapUI

    This is a sample request (called RST) to the STS:

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
       <soap:Header>
          <wsse:Security soap:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
             <wsse:UsernameToken wsu:Id="UsernameToken-1">
                <wsse:Username>alice</wsse:Username>
                <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">ecila</wsse:Password>
             </wsse:UsernameToken>
          </wsse:Security>
       </soap:Header>
       <soap:Body>
          <wst:RequestSecurityToken xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
             <wst:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</wst:TokenType>
             <wst:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</wst:KeyType>
             <wst:Claims Dialect="http://schemas.xmlsoap.org/ws/2005/05/identity" xmlns:ic="http://schemas.xmlsoap.org/ws/2005/05/identity">
                <ic:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"/>
                <ic:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"/>
                <ic:ClaimType Uri="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"/>
             </wst:Claims>
             <wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</wst:RequestType>
             <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
                <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
                   <wsa:Address>https://localhost:8081/doubleit/services/doubleittransportsaml1claims</wsa:Address>
                </wsa:EndpointReference>
             </wsp:AppliesTo>
          </wst:RequestSecurityToken>
       </soap:Body>
    </soap:Envelope>



    and this the expected response (called RSTR):

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
       <soap:Header/>
       <soap:Body>
          <RequestSecurityTokenResponseCollection xmlns="http://docs.oasis-open.org/ws-sx/ws-trust/200512" xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:ns3="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:ns4="http://www.w3.org/2005/08/addressing" xmlns:ns5="http://docs.oasis-open.org/ws-sx/ws-trust/200802">
             <RequestSecurityTokenResponse>
                <TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</TokenType>
                <RequestedSecurityToken>
                   <saml2:Assertion ID="_ACF774CE2C8F387D9413183197088603" IssueInstant="2011-10-11T07:55:08.860Z" Version="2.0" xsi:type="saml2:AssertionType" xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                      <saml2:Issuer>DoubleItSTSIssuer</saml2:Issuer>
                      <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                         <ds:SignedInfo>
                            <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                            <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                            <ds:Reference URI="#_ACF774CE2C8F387D9413183197088603">
                               <ds:Transforms>
                                  <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                                  <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                                     <ec:InclusiveNamespaces PrefixList="xs" xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                                  </ds:Transform>
                               </ds:Transforms>
                               <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
                               <ds:DigestValue>YIHAnHYol0pOs1Mc4MWhgwTP540=</ds:DigestValue>
                            </ds:Reference>
                         </ds:SignedInfo>
                         <ds:SignatureValue>Mb3WfLefs0KziHe7NjhLUBsgfD2spr8M3HpqqhpO+yzIqMrw9eY1r7nFIh3nWeDOHY4odPBa0w06XDpzPGSzdmm9k/Ay+S6trtkgS/Hoi3sL8CGAmAHEPWSO4+td6MNrucdVhG9P+do6JflXDOppDroGh/YjvxpdosM55G2TbL0=</ds:SignatureValue>
                         <ds:KeyInfo>
                            <ds:X509Data>REMOVED</ds:X509Certificate>
                            </ds:X509Data>
                         </ds:KeyInfo>
                      </ds:Signature>
                      <saml2:Subject>
                         <saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" NameQualifier="http://cxf.apache.org/sts">alice</saml2:NameID>
                         <saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/>
                      </saml2:Subject>
                      <saml2:Conditions NotBefore="2011-10-11T07:55:08.860Z" NotOnOrAfter="2011-10-11T08:00:08.860Z">
                         <saml2:AudienceRestriction>
                            <saml2:Audience>https://localhost:8081/doubleit/services/doubleittransportsaml1claims</saml2:Audience>
                         </saml2:AudienceRestriction>
                      </saml2:Conditions>
                      <saml2:AttributeStatement>
                         <saml2:Attribute Name="givenname" NameFormat="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
                            <saml2:AttributeValue xsi:type="xs:string">Alice</saml2:AttributeValue>
                         </saml2:Attribute>
                         <saml2:Attribute Name="surname" NameFormat="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
                            <saml2:AttributeValue xsi:type="xs:string">Smith</saml2:AttributeValue>
                         </saml2:Attribute>
                         <saml2:Attribute Name="emailaddress" NameFormat="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
                            <saml2:AttributeValue xsi:type="xs:string">alice@mycompany.org</saml2:AttributeValue>
                         </saml2:Attribute>
                      </saml2:AttributeStatement>
                   </saml2:Assertion>
                </RequestedSecurityToken>
                <RequestedAttachedReference>
                   <ns3:SecurityTokenReference wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd">
                      <ns3:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">#_ACF774CE2C8F387D9413183197088603</ns3:KeyIdentifier>
                   </ns3:SecurityTokenReference>
                </RequestedAttachedReference>
                <RequestedUnattachedReference>
                   <ns3:SecurityTokenReference wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd">
                      <ns3:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_ACF774CE2C8F387D9413183197088603</ns3:KeyIdentifier>
                   </ns3:SecurityTokenReference>
                </RequestedUnattachedReference>
                <wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
                   <wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
                      <wsa:Address>https://localhost:8081/doubleit/services/doubleittransportsaml1claims</wsa:Address>
                   </wsa:EndpointReference>
                </wsp:AppliesTo>
                <Lifetime>
                   <ns2:Created>2011-10-11T07:55:08.872Z</ns2:Created>
                   <ns2:Expires>2011-10-11T08:00:08.872Z</ns2:Expires>
                </Lifetime>
             </RequestSecurityTokenResponse>
          </RequestSecurityTokenResponseCollection>
       </soap:Body>
    </soap:Envelope>



    Have fun!