November 26, 2012

Jetty support added in Apache CXF Fediz

Initial support for Jetty in Apache CXF Fediz added

Apache CXF Fediz is a subproject of Apache CXF. Fediz helps you to secure your web applications and delegate security enforcement to the underlying application server. With Fediz, authentication is externalized from your web application to an identity provider installed as a dedicated server component. The supported standard is WS-Federation Passive Requestor Profile.

Fediz 1.0.2 supports the following features:

  • WS-Federation 1.0/1.1/1.2
  • SAML 1.1/2.0 Tokens
  • Custom token support
  • Publish WS-Federation Metadata document
  • Role information encoded as AttributeStatement in SAML 1.1/2.0 tokens
  • Claims information provided by FederationPrincipal interface

New features are going to be added in the next version 1.1. The first feature ready for testing is the support for the Open Source Servlet Container Jetty for version 7 and 8.

You can either download the sources here:

git clone git://git.apache.org/cxf-fediz.git

or

svn co https://svn.apache.org/repos/asf/cxf/fediz/trunk

or download it from the snapshot maven repository.

As Jetty can easily be embedded in your application you might be interested to look at the Unit test for the Jetty module how to configure the FederationAuthenticator. If you download the Jetty distribution the configuration for Fediz is described here. Please post feedback and ideas to the CXF mailing list or the Jira task FEDIZ-5.

Thank you for all support and feedback!

July 31, 2012

Add End-To-End monitoring to Your CXF application with Open Source

This is the second blog I mentioned here.

I'd like to show how to add end-to-end monitoring to your CXF based applications. End-to-end monitoring means that you can follow the message flow which has been triggered by a user across several web services nodes (consumer/provider). Context information of a message and its content are pushed by every web service node to a central server component. The communication style is asynchronous to not delay message processing.

To show how this can be achieved I'll also use the example wsclientWebapp of the Apache CXF Fediz project which I already used to illustrate how to add load balancing and failover. Further information is available here.

This example already supports Web SSO (IDP), WS-Security and STS. The architecture is described in a previous blog.

A web appliation is federation enabled with Fediz to support SSO. As part of the login of the browser user, a SAML token is issued which contains the claims information which are relevant to the web application. The web application calls a web service on behalf of the logged in user. This is accomplished by the CXF STS which is shipped as part of the Fediz in the IDP/STS component. The Web Service Consumer (Web Application) requests a new token based on the WS-SecurityPolicy of the Web Service Provider on behalfof of the security token issued as part of the Web Login. In this example, the security tokens are SAML tokens.

More information on how to build, deploy and test the demo are described in the README.

This example has the following gaps to be deployed in a distributed environment:

  • URL's of the web service provider is configured on the service consumer side which is difficult to manage across the environments and for all web service consumers
  • If an error occurs you have to analyze log files of all involved nodes in the message flow to drill down the root cause of the issue. Usually, the log files of all involved applications are distributed in the network. It's difficult to correlate the messages in the different log files.
These issues might be manageable within the scope of a project but not on the enterprise level as your application might consume several services which are used by other applications as well. As mentioned at the beginning, the first gap is addressed in the previous blog. This blog will address how to add end-to-end monitoring.

Talend built Apache licensed open source components to add load balancing, failover and end-to-end monitoring to your CXF/Camel based applications. This blog shows you how easily you can integrate this component into your application.

Update your CXF application

Talend built a SAM (Service Activity Monitoring) server component where service participants (consumer/provider) can send information about incoming and outgoing messages. The SAM server is Apache licensed. Besides the server component, the SAM agent is deployed as part of the CXF application which hooks into the interceptor chain to collect all required information about the message and pushes it to the SAM server asynchronously.

What do you have to do in your application?

A) Web Service Provider

Make the following changes in the maven project wsclientWebapp/webservice/service

1) add POM dependency for the Talend SAM agent library

This library hooks into the CXF interceptor chain to send service activity information to the SAM server.

  <dependency>
    <groupId>org.talend.esb</groupId>
    <artifactId>sam-agent</artifactId>
    <version>5.1.1</version>
  </dependency>
2) add a file agent.properties to your maven project src/main/resources

This file contains information where the SAM agent is running and what kind of information should be sent.

collector.scheduler.interval=500
collector.maxEventsPerCall=10
collector.lifecycleEvent=false

log.messageContent=true
log.maxContentLength=-1
log.enforceMessageIDTransfer=false

service.url=http://localhost:8040/services/MonitoringServiceSOAP
service.retry.number=3
service.retry.delay=5000
3) Update Spring configuration file applicationContext.xml

The highlighted lines must be added to the example application.

...
   <import resource="classpath:META-INF/cxf/cxf.xml" />
   <import resource="classpath:META-INF/tesb/locator/beans.xml" />
   <import resource="classpath:META-INF/tesb/agent-context.xml" /> 
...
   <!-- GreeterService -->
   <jaxws:endpoint id="GreeterService"
      implementor="org.apache.cxf.fediz.examples.service.GreeterImpl"
      wsdlLocation="WEB-INF/wsdl/hello_world.wsdl"
      serviceName="svc:GreeterService"
      xmlns:svc="http://apache.org/hello_world_soap_http"
      address="/GreeterService">

      <jaxws:properties>
         <entry key="ws-security.signature.properties" value="stsKeystore.properties" />
         <entry key="org.talend.tesb.endpoint.secured" value="true"/>
      </jaxws:properties>

      <!-- Talend feature -->
      <jaxws:features>
         <bean class="org.talend.esb.servicelocator.cxf.LocatorFeature" />
         <ref bean="eventFeature"/>
      </jaxws:features>
   </jaxws:endpoint>
4) Run "mvn clean install"

Maven builds a new WAR package. This package is now able to send service activity information to the SAM server.

B) Web Service Consumer

Make the following changes in the maven project wsclientWebapp/webapp

1) add POM dependency for the Talend SAM agent library

This library hooks into the CXF interceptor chain to send service activity information to the SAM server.

  <dependency>
    <groupId>org.talend.esb</groupId>
    <artifactId>sam-agent</artifactId>
    <version>5.1.1</version>
  </dependency>
2) add a file agent.properties to your maven project src/main/resources

This file contains information where the SAM agent is running and what kind of information should be sent.

collector.scheduler.interval=500
collector.maxEventsPerCall=10
collector.lifecycleEvent=false

log.messageContent=true
log.maxContentLength=-1
log.enforceMessageIDTransfer=false

service.url=http://localhost:8040/services/MonitoringServiceSOAP
service.retry.number=3
service.retry.delay=5000
There are different options to configure what kind of information should be pushed to the SAM server. Please check the Talend_ESB_InfrastructureServices manual for all configuration options like:
  • Send message content
  • Configure maximum length of content to be sent
  • filters to find/replace in message content
  • add custom context information
  • ...
3) Update Spring configuration file applicationContext.xml

The highlighted lines must be added to the example application.

...
   <import resource="classpath:META-INF/cxf/cxf.xml" />
   <import resource="classpath:META-INF/tesb/locator/beans.xml" />
   <import resource="classpath:META-INF/tesb/agent-context.xml" /> 
...
  <jaxws:client id="HelloServiceClient" serviceName="svc:GreeterService"
    xmlns:svc="http://apache.org/hello_world_soap_http"
    serviceClass="org.apache.hello_world_soap_http.Greeter"
    address="locator://whatever"
    wsdlLocation="WEB-INF/wsdl/hello_world.wsdl">
    <jaxws:properties>
      <entry key="ws-security.sts.client">
        <bean class="org.apache.cxf.ws.security.trust.STSClient">
          <constructor-arg ref="cxf" />
          <property name="wsdlLocation" value="https://localhost:9443/fedizidpsts/STSServiceTransport?wsdl" />
          <property name="serviceName"
            value="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}SecurityTokenService" />
          <property name="endpointName"
            value="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}Transport_Port" />
          <property name="onBehalfOf" ref="delegationCallbackHandler" />
          <property name="enableAppliesTo" value="true" />
        </bean>
      </entry>
    <entry key="ws-security.cache.issued.token.in.endpoint" value="false" />
    </jaxws:properties>
    <jaxws:features>
      <bean class="org.talend.esb.servicelocator.cxf.LocatorFeature" />
      <ref bean="eventFeature"/>
    </jaxws:features>
  </jaxws:client>
4) Run "mvn clean install"

Maven builds a new WAR package. This package is now able to send service activity information to the SAM server.

Deploy SAM server

Last but not least, the Talend SAM server must be deployed and started which is shipped as part of the Talend ESB. Follow these steps to start the SAM server (if you have run already the demo for the Service Locator you only have to run tesb:start-all):
  1. Download the Talend ESB Standard Edition (SE) here. The Standard Edition has full functionality and is Apache licensed.
  2. Unzip the file
  3. Run <install-dir>/container/trun
  4. Execute the following command in the console

    tesb:start-all

  5. You can log the most recent logs with the command

    log:display

The SAM server (and Service Locator) are running now.

More information about the Talend ESB is available here:

Test the application

You can test the application as described in the README of the Fediz example wsclientWebapp.

Enter the URL https://localhost:8443/fedizhelloworld/secure/service.jsp and click on the button Call Service after login (User: alice, Password: ecila). This triggers a web service call.

You will also see that messages are sent to the SAM server from the service consumer and service provider:

...
Jul 5, 2012 11:21:09 PM org.talend.esb.sam.agent.collector.EventCollector sendEvents
INFO: Put events(2) to Monitoring Server.
...

You can use any DB Visualizer Tool to show the data of the messages exchanged in the web services network. In this example, the data is written to Apache Derby.

You find more information where this DB is located in Talend_ESB_InfrastructureServices in chapter 4.3.

This is not a very nice UI to see which messages are part of a flow triggered by a user. In my next blog I'll describe the Talend Administration Console (TAC) which allows to see the messages exchanged and the registered service in a graphical way.

This blog showed how easy it is to add end-to-end monitoring capabilities to your CXF application with open source components and without changing a single line of code.

July 12, 2012

Add Failover and Load balancing to Your CXF application with Open Source

In the next blogs I'd like to describe how easy it is to add other enterprise features to your existing CXF based applications. My previous blogs were always very focused on security. The enterprise features I'd like to talk are:
  • load-balancing
  • failover
  • end-to-end monitoring
In this blog, I'll address load-balancing and failover whereas end-to-end monitoring is addressed in the next blog.

The assumption is that the web services are deployed on several machines. You want to either load balance the requests among the deployed services dynamically or failover in case a service is not reachable anymore.

To show how this can be implemented I'll use the example wsclientWebapp of the Apache CXF Fediz project which has been released recently.

This example already supports Web SSO (IDP), WS-Security and STS. The architecture is described in a previous blog. More information on how to build, deploy and test the wsclientWebapp example are described in its README.

This example has the following gaps to be deployed in a distributed environment:

  • URL's of the web service is configured on the service consumer side which is difficult to manage across the environments and for all web service consumers
  • If an error occurs you have to analyze log files to drill down the root cause of the issue. Usually, the log files of all involved applications are distributed in the network. It's difficult to correlate the messages in the different log files.
These issues might be manageable within the scope of a project but not on the enterprise level as your application might consume several services which are used by other applications as well. As mentioned at the beginning, the second gap will be addressed by implementing end-to-end monitoring which is described in the next blog.

Talend built Apache licensed open source components which address the previously mentioned gaps and add load balancing and failover capabilities to your CXF application.

Update your CXF application

Service Providers register its endpoints (URL) at the Talend Service Locator and service consumer can lookup for an service endpoint (compare to DNS or UDDI). The Service Locator is Apache licensed and re-uses other proven open source projects like Zookeeper. Besides the server component, the CXF Failover/Clustering feature has been extended to integrate with the Service Locator.

What do you have to do in your application?

A) Web Service Provider

Make the following changes in the maven project wsclientWebapp/webservice/service

1) add POM dependency to Talend Locator library

This library hooks into the CXF Failover/Load Balancing functionality to integrate with the Service Locator server.

  <dependency>
    <groupId>org.talend.esb</groupId>
    <artifactId>locator</artifactId>
    <version>5.1.1</version>
  </dependency>

2) add a file locator.properties to your maven project src/main/resources

This file contains information where the Service Locator server is running.

# Configured zookeeper instances (divided by a comma if several instances uses). 
# The service locator client will pick an instance
# to connect to the service locator until a connection is established. 
locator.endpoints=localhost:2181

# Endpoint prefix property is needed because the services
# in a container where the endpoints
# are relative to the container.
endpoint.https.prefix=https://localhost:10443/fedizservice

connection.timeout=5000
session.timeout=5000
3) Update Spring configuration file applicationContext.xml

The highlighted lines must be added to the example application.

...
   <import resource="classpath:META-INF/cxf/cxf.xml" />
   <import resource="classpath:META-INF/tesb/locator/beans.xml" />
...
   <!-- GreeterService -->
   <jaxws:endpoint id="GreeterService"
      implementor="org.apache.cxf.fediz.examples.service.GreeterImpl"
      wsdlLocation="WEB-INF/wsdl/hello_world.wsdl"
      serviceName="svc:GreeterService"
      xmlns:svc="http://apache.org/hello_world_soap_http"
      address="/GreeterService">

      <jaxws:properties>
         <entry key="ws-security.signature.properties" value="stsKeystore.properties" />
         <entry key="org.talend.tesb.endpoint.secured" value="true"/>
      </jaxws:properties>

      <!-- Talend feature -->
      <jaxws:features>
         <bean class="org.talend.esb.servicelocator.cxf.LocatorFeature" />
      </jaxws:features>
   </jaxws:endpoint>
4) Run "mvn clean install"

Maven builds a new WAR package. This package is now able to register its endpoint at the service locator.

B) Web Service Consumer

Make the following changes in the maven project wsclientWebapp/webapp

1) add POM dependency to Talend Locator library

This library hooks into the CXF Failover/Load Balancing functionality to integrate with the Service Locator server.

Some transitive dependencies have to be excluded as they are already part of the fediz package which is available in the parent classloader of tomcat.

  <dependency>
    <groupId>org.talend.esb</groupId>
    <artifactId>locator</artifactId>
    <version>5.1.1</version>
      <exclusions>
        <exclusion>
          <artifactId>xmlsec</artifactId>
          <groupId>org.apache.santuario</groupId>
        </exclusion>
        <exclusion>
          <artifactId>wss4j</artifactId>
          <groupId>org.apache.ws.security</groupId>
        </exclusion>
        <exclusion>
          <artifactId>ehcache-core</artifactId>
          <groupId>net.sf.ehcache</groupId>
        </exclusion>
      </exclusions>
    </dependency>
2) add a file locator.properties to your maven project src/main/resources

This file contains the network address where the Service Locator server is running.

# Configured zookeeper instances (divided by a comma if several instances uses). 
# The service locator client will pick an instance
# to connect to the service locator until a connection is established. 
locator.endpoints=localhost:2181

connection.timeout=5000
session.timeout=5000
There are different options to configure the cache of endpoints. Please check the Talend_ESB_InfrastructureServices manual for all configuration options.

3) Update Spring configuration file applicationContext.xml

The highlighted lines must be added to the example application.

...
   <import resource="classpath:META-INF/cxf/cxf.xml" />
   <import resource="classpath:META-INF/tesb/locator/beans.xml" />
...
  <jaxws:client id="HelloServiceClient" serviceName="svc:GreeterService"
    xmlns:svc="http://apache.org/hello_world_soap_http"
    serviceClass="org.apache.hello_world_soap_http.Greeter"
    address="locator://whatever"
    wsdlLocation="WEB-INF/wsdl/hello_world.wsdl">
    <jaxws:properties>
      <entry key="ws-security.sts.client">
        <bean class="org.apache.cxf.ws.security.trust.STSClient">
          <constructor-arg ref="cxf" />
          <property name="wsdlLocation" value="https://localhost:9443/fedizidpsts/STSServiceTransport?wsdl" />
          <property name="serviceName"
            value="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}SecurityTokenService" />
          <property name="endpointName"
            value="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}Transport_Port" />
          <property name="onBehalfOf" ref="delegationCallbackHandler" />
          <property name="enableAppliesTo" value="true" />
        </bean>
      </entry>
    <entry key="ws-security.cache.issued.token.in.endpoint" value="false" />
    </jaxws:properties>
    <jaxws:features>
      <bean class="org.talend.esb.servicelocator.cxf.LocatorFeature" />
    </jaxws:features>
  </jaxws:client>
4) Run "mvn clean install"

Maven builds a new WAR package. This package is now able to lookup the endpoint at the service locator.

You can also apply the following patch to the sources of the fediz example which enables the integration with the Talend Service Locator.

Deploy Service Locator

Last but not least, the Talend Service Locator must be deployed and started which is shipped as part of the Talend ESB. Follow these steps to start the Service Locator:
  1. Download the Talend ESB Standard Edition (SE) here. The Standard Edition is Apache licensed.
  2. Unzip the file
  3. Run <install-dir>/container/trun
  4. Execute the following command in the console

    tesb:start-all

  5. You can log the most recent logs with the command

    log:display

The Service Locator is running now.

More information about the Talend ESB is available here:

Test the application

You can test the application as described in the README of the Fediz example wsclientWebapp.

Enter the URL https://localhost:8443/fedizhelloworld/secure/service.jsp and click on the button Call Service after login (User: alice, Password: ecila). This triggers a web service call where the web service consumer will lookup the service provider URL at the Talend Service Locator (and caches this information). You will see log statements like this:

...
Jul 5, 2012 11:21:08 PM org.apache.cxf.clustering.FailoverTargetSelector setStrategy
INFO: Using failover strategy org.talend.esb.servicelocator.cxf.internal.EvenDistributionSelectionStrategy@9235c2
Jul 5, 2012 11:21:08 PM org.talend.esb.servicelocator.cxf.internal.LocatorClientEnabler enable
INFO: Client enabled with strategy org.talend.esb.servicelocator.cxf.internal.EvenDistributionSelectionStrategy.
Jul 5, 2012 11:21:08 PM org.talend.esb.servicelocator.cxf.internal.LocatorTargetSelector prepare
INFO: Found address with locator protocol, mapping it to physical address.
Jul 5, 2012 11:21:08 PM org.talend.esb.servicelocator.cxf.internal.LocatorTargetSelector prepare
INFO: Using strategy org.talend.esb.servicelocator.cxf.internal.EvenDistributionSelectionStrategy.
Jul 5, 2012 11:21:08 PM org.talend.esb.servicelocator.cxf.internal.ReloadSelectionStrategy getPrimaryAddress
INFO: Get address for service {http://apache.org/hello_world_soap_http}GreeterService using strategy org.talend.esb.servicelocator.cxf.internal.EvenDistributionSelectionStrategy selecting from [https://localhost:10443/fedizservice/GreeterService] selected = https://localhost:10443/fedizservice/GreeterService
...
We removed the endpoint URL https://localhost:10443/fedizservice/GreeterService in the configuration of the service consumer. Instead a lookup at the Service Locator resolves this URL.

How can you see which services are registered at the Service Locator

You can use the Zookeeper Client shipped with the Talend ESB to access the Service Locator (Zookeeper Service) which is illustrated next:
/projects/talend/TESB_SE-V5.1.1/zookeeper/bin$ ./zkCli.sh
[zk: localhost:2181(CONNECTED) 0] ls /
[cxf-locator, zookeeper]
[zk: localhost:2181(CONNECTED) 1] ls /cxf-locator
[{http:%2F%2Fapache.org%2Fhello_world_soap_http}GreeterService]
[zk: localhost:2181(CONNECTED) 2] ls /cxf-locator/{http:%2F%2Fapache.org%2Fhello_world_soap_http}GreeterService
[https:%2F%2Flocalhost:10443%2Ffedizservice%2FGreeterService]
[zk: localhost:2181(CONNECTED) 3] 

This is not a very nice UI to see the registered services. After the blog about End-to-End monitoring I'll describe the Talend Administration Console (TAC) which allows to see the registered service and the messages exchanged in a graphical way.

This blog showed how easy it is to add failover and load-balancing capabilities to your CXF application with open source components and without changing a single line of code. I very much like the approach convention over configuration.

July 2, 2012

Apache CXF Fediz

First release of Apache CXF Fediz available

Apache CXF Fediz is a subproject of Apache CXF. Fediz helps you to secure your web applications and delegate security enforcement to the underlying application server. With Fediz, authentication is externalized from your web application to an identity provider installed as a dedicated server component. The supported standard is WS-Federation Passive Requestor Profile.

Fediz supports Claims Based Access Control beyond Role Based Access Control (RBAC).

Fediz supports the following features:

  • WS-Federation 1.0/1.1/1.2
  • SAML 1.1/2.0 Tokens
  • Custom token support
  • Publish WS-Federation Metadata document
  • Role information encoded as AttributeStatement in SAML 1.1/2.0 tokens
  • Claims information provided by FederationPrincipal interface

Release notes are available here.

For more information see:


Features to come in the upcoming releases:
  • Fediz IDP supports RP IDP use case
  • SAML Holder-Of-Key support
  • Support for encrypted SAML tokens
  • Support for Jetty Container
  • Integration with Spring Security
  • Integration with CXF JAX-RS
  • SAML-P support
Feel free to raise enhancement requests and issues here

Thank you for all support and feedback!

April 16, 2012

SSO across Web Applications and Web Services - Part IV b

This blog describes how to implement the solution described in my previous blog which you must have read before.

I'd like to structure the blog into the following sections:


I've prepared this demo to run the different components in three tomcat instances. The reason is to get closer to a real scenario.

  1. tomcat-idp

    This tomcat instance hosts the security infrastructure components which are the IDP and the STS.

    HTTPS: 9443, HTTP: 9080

  2. tomcat-rp

    This tomcat instance hosts the Web Application.

    HTTPS: 8443, HTTP: 8080

  3. tomcat-svc

    This tomcat instance hosts the Web Services provider which is usually not hosted on the same instance as the frontend.

    HTTPS: 10443, HTTP: 10080

All three tomcat instances use the same certificate tomcatkeystore.jksfor HTTPS which can be downloaded here.

The Tomcat HTTPS connector 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="10443" protocol="HTTP/1.1"
    SSLEnabled="true"
    maxThreads="150" scheme="https" secure="true"
    keystoreFile="tomcatKeystore.jks"
    keystorePass="tompass" sslProtocol="TLS"
  />

Extend the STS...

We use the same STS instance prepared for the Web SSO. The initial set up of this STS is described in my first blog. You can find the updated sources here.

The previous STS supported only one policy which says the communication with the STS must be secured on the transport level using HTTPS (TransportBinding) and UsernameToken is used as a "SupportingToken".

We have to configure a new policy which supports the TransportBinding but doesn't enforce a UsernameToken (SupportingToken assertion is missing). The new policy is added to the wsdl file ws-trust-1.4-service.wsdl.

Right now, everybody who gets into the possession of a signed SAML token could request a new security token from the STS. This risk is mitigated using HTTPS (You could authenticate the requestor also who requests a token on behalf of someone else).


The new endpoint is configured in WEB-INF/cxf-transport.xml as illustrated here:

<jaxws:endpoint id="transportSTS2"
   implementor="#transportSTSProviderBean"
   address="/STSServiceTransport"
   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:Transport_Port">
</jaxws:endpoint>
You can see all updates here.


Protect the Web Services provider...


The Web Service provider is a new component. You can find the sources of this example here. It supports a basic Web Services operation called "greetMe" with no input parameters but one output parameter. The response contains the authenticated user id which is retrieved from the JAX-WS WebServiceContext. In this use case, the authenticated user id must be the same as the one used by the browser user when login to the Web Application.

The following code snippet shows the implementation of the operation greetMe:

@Resource
    WebServiceContext context = null;

    public String greetMe() {
        LOG.info("Executing operation greetMe");
        System.out.println("Executing operation greetMe");
        if (context == null) {
           return "Unknown user";
        }
        else {
           Principal p = context.getUserPrincipal();
           if (p == null) {
             return "Principal null";
           }
           return p.getName();
        }
    }

The WSDL of the service provider contains a WS-SecurityPolicy which defines that:
  • HTTPS must be used
  • a SAML token must be sent issued by an STS
  • the SAML token is a SupportingToken
<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>
  ...
 </wsp:Policy>
</sp:TransportBinding>
<sp:SupportingTokens
 xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
 <wsp:Policy>
  <sp:IssuedToken
   sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
   <sp:RequestSecurityTokenTemplate>
    <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</t:TokenType>
    <t:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</t:KeyType>
   </sp:RequestSecurityTokenTemplate>
   ...
  </sp:IssuedToken>
 </wsp:Policy>
</sp:SupportingTokens>

The service provider trusts an STS which means that it accepts every SAML token which has been signed/issued by its trusted STS. This trust is established based on the certificate (stsstore.jks) which must be configured in the service provider in the JAX-WS property ws-security.signature.properties.

<jaxws:endpoint id="GreeterService"
   implementor="org.apache.cxf.fediz.examples.service.GreeterImpl"
   wsdlLocation="WEB-INF/wsdl/hello_world.wsdl"
   serviceName="svc:GreeterService"
   xmlns:svc="http://apache.org/hello_world_soap_http"
   address="/GreeterService">
   <jaxws:properties>
     <entry key="ws-security.signature.properties" value="stsKeystore.properties" />
   </jaxws:properties>
</jaxws:endpoint>

You must ensure to add the Maven dependencies for security and policy because the policy engine is not initialized otherwise.
<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>

The demo is prepared to deploy the Web Service to Tomcat instance tomcat-svc using Maven.

You don't have to change the tomcat URL if you have set up a Tomcat instance with HTTP port 10080 and HTTPS port 10443. Otherwise you must update the tomcat plugin in the POM:

<plugin>
  <groupId>org.codehaus.mojo</groupId>
  <artifactId>tomcat-maven-plugin</artifactId>
  <version>1.1</version>
  <configuration>
    <server>myTomcat</server>
    <url>http://localhost:10080/manager</url>
    <path>/${project.build.finalName}</path>
  </configuration>
</plugin>

Add the server with username and password to your Maven settings.xml
Ensure that this user has the role "manager-script" in Tomcat as described here

Run...

mvn clean install tomcat:redeploy
I recommend to use redeploy as deploy works the first time only

You can download the published WSDL with the following url:
https://localhost:10443/fedizservice/GreeterService?wsdl


Integrate the Web SSO and Web Services stack...

The Web Application fediz-tomcat-example has been extended and slightly changed. You can find the new version here. A key change is the URL used to access the FederationServlet.
old: https://localhost:8443/fedizhelloworld/secureservlet/fed
new: https://localhost:8443/fedizhelloworld/secure/fedservlet

A simple JSP page has been added which shows the authenticated user and provides a button to call the Web Service. The Web Services is protected by the WS-SecurityPolicy which enforces a SAML token issued by its trusted STS. If the call was successfull a similar page is shown as for the federation servlet but it shows the response of the Web Services provider. The response contains the authenticated username which must be the same as the one for the authenticated user in the Web Application.

The following code snippet shows the code used to call the service provider securely. The JAX-WS proxy is instantiated by Spring and thus just read from the ApplicationContext.

Greeter service = (Greeter)ApplicationContextProvider.getContext().getBean("HelloServiceClient");
String reply = service.greetMe();
out.println("<br><b>Greeter Service Response: " + reply + "</b><p>");
There is no security related code required.

The spring configuration beans.xml contains the bean configuration for the service consumer:

<jaxws:client id="HelloServiceClient" serviceName="svc:GreeterService"
  xmlns:svc="http://apache.org/hello_world_soap_http"
  serviceClass="org.apache.hello_world_soap_http.Greeter"
  address="https://localhost:10443/fedizservice/GreeterService"
  wsdlLocation="WEB-INF/wsdl/hello_world.wsdl">
  <jaxws:properties>
    <entry key="ws-security.sts.client">
      <bean class="org.apache.cxf.ws.security.trust.STSClient">
        <constructor-arg ref="cxf" />
        <property name="wsdlLocation" value="https://localhost:9443/fedizidpsts/STSServiceTransport?wsdl" />
        <property name="serviceName"
          value="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}SecurityTokenService" />
        <property name="endpointName"
          value="{http://docs.oasis-open.org/ws-sx/ws-trust/200512/}Transport_Port" />
        <property name="onBehalfOf" ref="delegationCallbackHandler" />
        <property name="enableAppliesTo" value="true" />
      </bean>
    </entry>
    <entry key="ws-security.cache.issued.token.in.endpoint" value="false" />
  </jaxws:properties>
</jaxws:client>

<bean id="delegationCallbackHandler" class="org.apache.cxf.fediz.example.ThreadLocalCallbackHandler" />

The Web Application must have access to the WSDL which includes the WS-SecurityPolicy assertion. Either you have deployed this WSDL within your Web Application (see configuration wsdlLocation attribute) or you download it from the service provider at runtime (see configuration for wsdlLocation of the ws-security.sts.client). The SecurityPolicy contains an IssuedToken assertion which indicates CXF to call the STS to request a token. The STS configuration is shown above where the STSClient bean is configured at entry ws-security.sts.client.

The information in the SecurityPolicy element RequestSecurityTokenTemplate are added to the SecondaryParameters element in the request to the STS. The service consumer doesn't care about its content. Our example looks like this:

<sp:RequestSecurityTokenTemplate>
  <t:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</t:TokenType>
  <t:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</t:KeyType>
</sp:RequestSecurityTokenTemplate>

You can find more information about the correlation of STS parameters and SAML tokens here.

If you have deployed the service provider to a Tomcat instance with another port than 10443 you must update the attribute address of the bean jaxws:client.

The key thing to bridge Web SSO and Web Services stack CXF is the property onbehalfof in the STSClient bean configuration. This property references a Java CallbackHandler implementation which provides the on-behalf-of token as a DOM element. More information about the CallbackHandler for onbehalfof can be found here.
CXF ships some out-of-the-box CallbackHandler implementations. This demo provides a custom CallbackHandler implementation called ThreadLocalCallbackHandler which provides the SAML token which has been issued by the IDP/STS during the Web login. The following additional classes are required:

  • SecurityTokenThreadLocal

    This is the thread local which contains the SAML token as a DOM element. The ThreadLocalCallbackHandler gets the SAML token from this class.

  • FederationFilter

    This servlet filter reads the SAML token from the session and adds it to SecurityTokenThreadLocal and cleans it after request processing finished

You must also ensure to add the Maven dependencies for security and policy because the policy engine is not initialized otherwise.
<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>

You can deploy this demo with Maven to Tomcat instance tomcat-rp in the same way as for the service provider described above.

You got a bunch of information in the last two blogs and I'd say a great example to illustrate how to SSO enable your Web Applications and Web Services with only a few open source components.

Update: This example is part of the Fediz distribution.

April 12, 2012

SSO across Web Applications and Web Services - Part IV a

As promised in my first blog I talk now about Part IV where an Single Sign On (SSO) enabled Web Application integrates with Web Services in the back office. I've splitted this topic into two blogs. This one describes the design of the solution and the next one describes how to implement it.

This is a list of requirements for this application:

  • Web Application must be SSO enabled using WS-Federation
  • Role Based Access Control (RBAC) required for Web Application
  • users are managed in an LDAP directory
  • security solution integrated without programming
  • industry standards should be used (WS-SecurityPolicy, Servlet- and JAX-WS Security API)
  • Web Services are secured with SAML 2.0 to authenticate the browser user
  • Web Services trust a WS-Trust Security Token Service (STS)
  • SAML token for authentication only (SupportingToken, WS-SecurityPolicy)
  • RBAC might be required for Web services in a future release
  • Confidentiality and Integrity on transport level (HTTPS)
  • prevent man-in-the-middle attack

You might think this are a bunch of very sophisticated requirements and will cost a lot of money to implement. The answer is no. In this blog I'll introduce the architecture and design and in the next blog how to realize that with Apache CXF and Tomcat.

The following diagram illustrate the overall architecture:


The key components are the WS-Trust Security Token Service (STS) and the Identity Provider (IDP) which is part of the WS-Federation Passive Requestor Profile. If you are familiar with my previous blogs about Web SSO...

... there are no new infrastructure components required to integrate SSO with Web Services. Because the STS is used for both Web SSO and Web Services Security.

The sequence of steps can be splitted into two parts the Web login and the security for the Web Services.
The Web login starts when the user access the Web Application the first time. The Web Application redirects the browser to the IDP for authentication. The IDP transforms and delegates the request to the STS. The STS validates the user against the LDAP directory and issues a signed SAML token. The browser posts the SAML token to the Web Application which validates the token and creates the security context. This part is described in more details in the above mentioned blogs.

Role information can be accessed using standard security constraints in web.xml or using the Java Servlet API without worrying about the underlying SAML security token or accessing the LDAP directory explicitly.

The second part is the security for Web Services when the user does a step in the application which requires a call to a Web Services. The Web Services stack processes the WS-SecurityPolicy of the service provider where it is described to send a token issued by the STS. The Web Services stack sends an Issue request to the STS on behalf of the browser user. The STS validates the incoming credentials and issues the requested signed SAML token for the target Web Service. The Web Services stack caches the token and attachs it to the outgoing Web Services call. The service provider trusts the STS and can therefore validate the signed SAML token on its own.

I'd like to describe the second request to the STS in more details where the Web Services stack requests a token on behalf of the browser user. You must be in the possession of the credentials (ex. password) to request a token for the browser user - otherwise, anybody could request a token for someone else without knowing the passwort using a took like SOAPUI. The Web Application itself doesn't know the password because the authentication is externalized to the IDP. Even if the authentication had been done by the Web Application the password wouldn't have been cached by the application server for security reasons. OK, you don't possess the password but you got the signed SAML token which you can only get if you provided the credentials to the STS initially. This token must be protected on the wire when exchanged between browser and IDP, the browser and the Web Application and the Web Application and the STS. The option with the best performance is SSL/TLS.
For further confidentiality protection you could encrypt the token with the certificate of the application thus only the application is able to process the token. This is a supported feature of the CXF STS.

The SAML token is cached by the application server and is provided to the Web Services stack to request a new token when required. This use case is covered by the WS-Trust specification with the OnBehalfOf element (or ActAs) in the request to the STS. The STS validates the SAML token in the OnBehalfOf element and issues a new token based on the requirements of the Web Services which are described in its WS-SecurityPolicy document and send to the STS in the SecondaryParameters element.

There are some service calls before a request is sent to the service provider. The request to the STS is the most expensive as it might require to access some ID stores to read user attributes, roles (so called claims) to add it to the SAML token. Usually, a security token has some sort of lifetime either described in the security token itself (SAML condition) or some out-of-band agreement and known by the STS only. The WS-Trust specifiction defines the Lifetime element in the response to tell the token requestor the lifetime in a security token agnostic way. Thus, the Web Services stack just have to cache the returned security token (XML element) and the LifeTime element to prevent sending an issue request for every outgoing Web Service call.

Going through the requirements above... the solution above covers all of them.

How to implement this solution is described here

March 8, 2012

Packaged Tomcat Instances for Federation/SSO

I've created a ZIP archive which contains two tomcat setups for the replying party (secured web application) and the identity provider (IDP). It's much easier to start with this approach and make the experience how easily a web application can be SSO enabled using SAML tokens according to the Passive Requestor Profile of WS-Federation specification.

You can download the package here.

Installation

Unzip the downloaded archive which contains in each sub-directory a dedicated tomcat instance. The two tomcat instances are described below.


tomcat-idp

Start the Tomcat container:
tomcat-idp/bin/startup.sh (or startup.bat for windows)

Mar 8, 2012 8:59:13 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-9080"]
Mar 8, 2012 8:59:13 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-9443"]
Mar 8, 2012 8:59:13 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 4245 ms

The Tomcat IDP instance creates an HTTPS listener (9443) and HTTP listener (9080). The insecure port is used for remote deployment during the maven build.

This tomcat instance has got two WAR files deployed: fedizidp and fedizidpsts.
You can find more information how to build and deploy the corresponding package here:


tomcat-rp

start the Tomcat container:
tomcat-rp/bin/startup.sh (or startup.bat for windows)

Mar 8, 2012 9:00:05 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Mar 8, 2012 9:00:05 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8443"]
Mar 8, 2012 9:00:05 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 2840 ms

The Tomcat RP instance creates an HTTPS listener (8443) and HTTP listener (8080). The insecure port is used for remote deployment during the maven build.

This tomcat instance has got one WAR file deployed: fedizhelloworld
You can find more information how to build and deploy the package here:



Test

Enter the following URL in the browser:

https://localhost:8443/fedizhelloworld/secureservlet/fed

to access the web application which redirects to the IDP component. The IDP challenges the browser to enter username/password. Next, the IDP/STS issues the SAML token which contains all requested claims information and "redirects" the browser back to the application.

This post describes how to test the fedizhelloworld application. The configured users and their claims are described here.



Secure your own web application

Follow these steps to secure your own web application:

  • If it is another Tomcat instance than tomcat-rp ensure to deploy the federation plugin into this tomcat instance as described here
  • Configure the Tomcat Valve FederationAuthenticator in your META-INF/context.xml or Tomcat server.xml as described here
  • Configure the URL of your web application (including the servlet context name) in the RPClaims.xml (bean realm2ClaimsMap) in <tomcat-idp>/webapps/fedizidp/WEB-INF/RPClaims.xml and update the claims if required
  • You can manage the claims of the users in <tomcat-idp>/webapps/fedizidpsts/WEB-INF/userClaims.xml

March 7, 2012

WS-Federation across several companies

I described a simple scenario about the WS-Federation Passive Requestor Profile in my previous blogs:
Before I describe a more complex scenario, I'd like to summerize the benefits of the simple scenario:
  • Authentication is externalized to IdP/STS
  • New IdP authentication mechanism can be used by all applications
  • Role Based Access control (RBAC) supported in applications
  • Claims/Attrribute based acess control (ABAC) supported in applications
  • IDP and applications deployable in different networks (ex. on-premise and cloud)
  • Easy testing with Mock IdP


Federation with B2B partners in the internet

In most cases, a web application is built for a single user group like internal users with some basic authentication mechanism like username/password against an LDAP system. Over time, the business see some potential to grow in providing this solution to partners. The application is enhanced to support a new kind of authentication mechanism for the users of the partner. The next partner has again a different kind of approach for authentication which must be extended in your application. Very often, the userids of the partner's employees have to be managed within your ID system also. What happens of an employee of the partner leaves the company? Usually, a manual process must be triggered to deprovision the user in your ID system.



How can federation and claims based authorization help here. The simple scenario doesn't support different kind of "user groups". But it's very important to highlight that the authentication mechanism is not tight into the application but instead into the IDP component. The benefit of federation is that you can integrate new partners without having an impact on your application. Just imagine how agile your application is to generate new business with new B2B partners without building a new authentication mechanism within all your applications.


How does this work? Let's look at a concrete example.


Our federation enabled web application should be provided to two new partners (fabrikam.com and adatam.com).


The users of fabrikam.com and adatam.com are managed within their own identity store. The following list provides more context information of the companies:
  • mycompany.com
    - 10000 users

    - five roles (user, manager, sales, accountmanager, admin)

  • adatam.com
    - IDP supported

    - 2000 users

    - three roles (employee, manager, administrator)

  • fabrikam.com
    - IDP supported
    with restrictions (SAML token contains user only)
    - 50 users

    - two roles (user, accountmanager)
The three companies have their own kind of naming for roles but the application must not differentiate between the different kind of role semantic.
fabrikam.com supports an IDP but can't provide the role information. mycompany.com decides to manage the 50 users and its roles within a dedicated ID store within their network (another option would have been to choose a more advanced IDM solution in the cloud). The usernames are different within the ID store at fabrikam.com and the dedicated ID store of mycompany.com due to different naming conventions in place.


The following deployment diagram illustrates the solution:



I haven't drawn any lines between the browser and the relying party which is the first component the browser accesses. The relying party redirects the browser to the RP-IDP (resource IDP) where the home realm discovery mechanism redirects the browser to its (requestor) IDP. The requestor IDP authenticates the browser and issues a SAML token with claims information. The browser sends the SAML token to the RP-IDP which transforms the SAML token into a format which can be validated and processed by the application (RP). This SAML token has the exact same structure independent who the requestor IDP was.


adatam.com 
What happens with the different kind of syntax of the roles?
The RP-IDP transforms the roles from the requestor IDP to the internal set of roles.
  • employee -> user
  • manager -> manager
  • administrator -> admin
fabrikam.com
How can the RP-IDP get the roles of the users?
The RP-IDP maps the userid of fabrikam.com to an internal userid in mycompany.com. The mapped userid is used to retrieve the role information. The roles/claims are not transformed.


mycompany.com
Nothing changes.


Finally, the issued tokens by the RP-IDP have the same syntax and semantic independent whether a user from fabrikam.com, adatam.com or an internal user accesses the application.


There are different kind of relationships between mycompany.com and the partner adatam.com and fabrikam.com. The former relies on federating the claims information whereas the latter federates/maps the userid/identity.




Support for identity mapping and claims transformation in STS


The STS is the key component in the WS-Federation based solution who issues the security tokens. The CXF STS supports identity mapping in the release 2.5.x.


I've finished my work to add support for claims transformation in the CXF STS.

Soon, I'll provide more details how to configure an STS with several realms (security domains) and different federation relationships among them.

March 6, 2012

SAML sender-vouches use case

In my previous blog here I described the different SAML subject confirmation methods (SCM) and how they integrate with an STS. This blog describes the use case for the Sender-Vouches (SV) SCM. As this use case can be solved with an STS also, I compare the two approaches finally.


Use case for SAML Sender-Vouches



The SAML token profile states that the attesting entity is different from the subject. You have such kind of a scenario where a web service proxy/gateway (intermediary) is deployed between your service consumer and service provider. The proxy is the attesting entity and vouches for verification (or authentication) of the subject (service consumer). The proxy signs the SAML token and the soap body to protect against modification by another party.

The following picture illustrate the deployment diagram of this intermediary pattern:


(This kind of intermediary pattern is often referred to as an ESB)

The characteristic of the intermediary is that TCP connections (HTTP) are terminated and new connections are established between the intermediary and the service providers (the term proxy is widely used for settings in your OS or browser which support HTTP tunneling).


The service provider must not accept a SAML SV token unless the token and the SOAP message content being vouched for are protected by the intermediary (attesting entity) who is trusted by the service provider. The protection can be achieved by using XML signature in the WS-Security header by signing the SAML token and the SOAP body. A direct trust is established between service provider and intermediary (service consumer).


The usage of XML Signature has a significant performance impact as most XML security libraries are DOM dependent which means you need an full in-memory representation of the SOAP message. This breaks streaming (StAX parser) and increases memory usage by factors of the original message size. Another issue to consider is the potential lack of support for the STR Dereference transform algorithm  to build the signature (this was not supported two years ago in .NET). This algorithm is described in section 3.4.3 in the SAML Token Profile specification.
(Apache CXF/WSS4J 2.0 is going to support streaming based XML signature and encryption in the near future)


The OASIS WS-SecurityPolicy Examples document describes in 2.3.1.2 a more performant approach. Instead of signing the SOAP message on the XML level it uses a mutual SSL handshake where the service provider requires that the intermediary has configured a client certificate for the HTTPS communication he trusts. The side effect is that this won't be supported by all web service stacks and so you can run into interoperability issues.


SAML SV works fine if the service provider, the intermediary and service consumer are in the same security domain which means that the principal name "jdoe" is processable in all of them. 
  • If the service providers are in different security domains how shall the intermediary map/federate the identity? 
  • If the service provider should support more than one security domain how should the intermediary encode the security domain information into the SAML token? 
  • Do the different web service stacks of your service providers support the same kind of mechanism to decode security domain information or do you have to write code for all your stacks to support that? 
  • If the service provider requires role information in the SAML token how should the intermediary retrieve that and encode it within the SAML token?
  • Do the web service stacks of your service providers support the same kind of mechanism to decode role information thus you can use container managed role based access control?
  • Are the issued security tokens/retrieved authorization information cached?
  • If the service provider requires specific claims information in the SAML token ...
As you can see, you have to consider a few things before deciding to go with the SAML Sender-Vouches subject confirmation method.

If your enviroment can fulfill the following requirements you can consider using SAML Sender-Vouches:
  • there is only one security domain
  • you don't have to authorize your web services and thus don't need additional claims in the token
  • you're using only one Java or .NET web service stack
  • soap message size is small
  • performance is not critical or business logic related processing time is  comparatively higher
By now it should be apparent that  SAML Sender-Vouches is not my favourite subject confirmation method. The main reasons are the underlying pattern of a direct trust (resulting in more administration effort, comparable to the usage of self-signed certificates without a certificate authority) and lots of functionality that should instead be handled by an IDM solution which can be integrated into different kind of contexts (Web Services, Web SSO, B2B gateway, ...).
Is there another solution to address the intermediary case?



Use case "Intermediary" for WS-Trust Security Token Service

The answer to the question in my last paragraph is yes.


The WS-Trust specification defines two ways to address it:
  • OnBehalfOf
  • ActAs
The following blog post provides more information about the differences of OnBehalfOf and ActAs. In both cases, the security token received by the intermediary is sent within one of these elements in the request (RST) to the STS. The STS validates the security token and issues a new one with the information of the original principal.


Is there a standard mechanism to tell the intermediary that the service provider requires a token issued by an STS?
Yes, the service provider's WS-SecurityPolicy defines an IssuedToken assertion.


Is there a standard mechanism to tell the intermediary what kind of security token (saml1, saml2, other) the service provider requires?
Yes,
the service provider's WS-SecurityPolicy defines the TokenType in the RequestSecurityTokenTemplate of the IssuedToken assertion.

Is there a standard mechanism to tell the intermediary from which security domain the service provider requires a token issued?
Yes, the service provider's WS-SecurityPolicy defines the Issuer element in the IssuedToken assertion.

Is there a standard mechanism to tell the intermediary which claims information the service provider requires in the issued token?
Yes,
the service provider's WS-SecurityPolicy defines the Claims element in the IssuedToken assertion.

This logic doesn't have to be coded and managed statically within the intermediary in a non-standard compliant way. It's very flexible by just changing the policy information of the service provider.

In both intermediary solutions (with and without STS), if the intermediary has to communicate with a remote component (ID system or STS) it's recommended to cache issued security tokens for the duration of their lifetimes. This avoids needing to obain a new security token for each web service request issued by the intermediary on behalf of a particular subject.

How does the intermediary know how long should a token be cached?
How should the intermediary know if a security token has been issued for a specific service only?
This is fairly easy, the response of an STS usually returns a Lifetime and AppliesTo element. The cache can be built around the incoming security token id, the subject the token is for, the lifetime and AppliesTo information to build a flexible and token agnostic cache.

Last but not least, is there a web services stack which supports this functionality without having to write a single line of code?
Yes, it's Apache CXF. The intermediary use case is described in the above mentioned blog post. A system test and its configuration for the CXF STS is available too.


CXF is not the only web services stack supporting the intermediary case with an STS as the following article shows:



One question remains: How can the service provider process claims information like roles, etc. which are encoded as an AttributeStatement in the SAML token? Do I have to implement and maintain this for Websphere, Weblogic, Tomcat, JBoss, etc.

This answer is no.
In one of my next posts I will explain how to reduce the complexity and increase interoperability of your web services deployment even you've got different application server stacks in house.



February 27, 2012

SAML tokens and WS-Trust Security Token Service (STS)

I've been working actively in the Apache CXF community with respect to SAML tokens and the WS-Trust SecurityTokenService (STS) since Talend's donation of the STS to the community. I've noticed in various WS-Trust projects that there is a lack of documentation about the different use cases for SAML tokens and the WS-Trust STS.

I'll give a brief introduction into SAML and STS before bringing the two together.


SAML


SAML is an OASIS standard and consists of several specifications. A SAML token is issued by an identity provider. A service provider relies on the identity provider to authenticate a principal (a user). The SAML assertion is provided to the service provider allowing it to make an access control decision. The main problem SAML tries to solve is Web Single Sign On.

There is a clear layering between the SAML specifications thus they can be fairly easy reused in other contexts. Another context besides Web SSO is Web Services communication - which I'll be covering here. Therefore, we only need to look into the SAML Core specification as it describes the syntax and semantics of SAML assertions. The SAML protocols are covered by SAML core too but there are not relevant for Web Services communication. This is also the case for the SAML bindings (how SAML messages are transmitted from one system entity to another) as well as for SAML profile which describes use cases for Web application Single Sign On.

A SAML assertion (also known as SAML security token) contains different kinds of statements: authentication-, attribute- and authorization decision statements. The "authorization decision statement" became deprecated in SAML 2.0 specification as it is covered in XACML and in claims based authorization based on standard SAML attribute statements. The former is quite complex whereas the latter provides already good options for fine grained authorization at less complexity. You can find more information about the latter here.


A SAML assertion contains a subject which identifies the principal. The subject can also contain additional information like key material and the subject confirmation method. One of the main topics in this blog are the different kind of subject confirmation methods and how they correlate to an STS.


As a side note, the subject confirmation method is not defined in the SAML core. Instead, the SAML profile specification defines the following three subject confirmation methods:
  • Holder of Key (HOK)
    The subject must contain key material so the service provider is able to validate that the requestor is in the possession of the key(s)
  • Bearer
    The subject doesn't contain key material and it is up to the service provider to accept the assertion or not
  • Sender vouches (SV)
    The subject doesn't contain key material and it is up to the service provider to accept the assertion or not. The requestor and the identity provider are usually the same.

For more information about SAML I recommend Wikipedia and the documentation at the OASIS committee.

Web Services and SAML

SAML in the context of Web Services is standardized in the SAML token profile here. It describes on the one hand how a SAML token is embedded in a SOAP message and on the other hand what kind of requirements must be met dependent on the SAML version and subject confirmation method.


I can highly recommend the following web services security usecases from OASIS as it describes very interesting use cases by combining transport level and message level security (ex. SAML HOK is very complex and has a performance impact as XML signature is required. This document describes how to use mutual SSL handshake for the proof-of-possession processing)

In 2011, many new security features have been added to CXF. Check the following blog for more information.



WS-Trust STS


The WS-Trust standard introduces a runtime component called Security Token Service (STS). A service consumer requests a security token from the STS which is sent to the service provider. Either the service provider can validate the security token on its own or sends a request to the STS for validation. This pattern is based on an indirect trust relationship between the service provider and the STS instead of between the service provider and service consumer. As long as the service consumer is in the possession of a security token issued by a trusted STS, the service provider accepts the token sent by the service consumer. This is the same pattern as for certificates and certificate authorities. This approach has significant advantages compared to a direct (brokered) trust established between a service provider and service consumer. The specification is an OASIS standard and can be downloaded here.

The STS can issue security tokens based on requirements provided by the service consumer and/or service provider. The requirements of the service provider are either expressed in a WS-Policy document according to WS-SecurityPolicy or out-of-band agreement.


A key benefit of the STS is the reduced complexity for web service consumer. A web service consumer doesn't have to know how to create the various types of security tokens its service providers require. Instead, it sends a request to the STS containing the requirements of the client and the service provider and attaches the returned security token to the outgoing SOAP message to the service provider. One service provider could require a SAML 1.1 token, another a SAML 2.0 token and another a custom binary security token. The service consumer doesn't have to understand SAML 1.1, SAML 2.0 or the custom binary security token. All he has to do is grab the returned token from the STS and attach it to the message. Thus, you can reduce the complexity in your application and move it to a centralized component.


How does a web service consumer know whether it has to go to an STS to request a token? The policy of the service provider contains an IssuedToken assertion with some additional information like the address of the STS, token type, claims, etc.


Now, it's time to explain a few parameters of the request (RST) to the STS.


TokenType
specifies the type of security token requested (ex. SAML 1.1, 2.0, X.509, ...). URIs are defined for all standard security tokens.

KeyType
specifies the type of key desired in the security token. There are three URIs defined:
  • PublicKey
  • SymmetricKey
  • Bearer

Claims
specifies the required and optional claims in the security token. A claim can be the email address, role information, country, etc.


AppliesTo
specifies the scope for which the security token is required. This can be the URL of the service provider.


Lifetime
specifies the creation and expiration time of the security token. The STS is not obligated to honor this range.

These parameters can be retrieved from the WS-SecurityPolicy document also. In that case, they are added as child elements of the SecondaryParameters element in the RST.



SAML and STS 


How does a SAML token and the parameters sent to the STS match with each other. How does the STS know which subject confirmation method should be used? OK, let's start with the more obvious one.

1) TokenType
the token type is either SAML 1.1 or SAML 2.0. The STS creates the corresponding SAML assertion

2) AppliesTo
the AppliesTo element defines the scope and thus match to the SAML AudienceRestriction element in the SAML condition

3) Lifetime
the value of the lifetime or the lifetime choosen by the STS matchs to the SAML conditions NotBefore and NotAfter

4) Claims
the claim values maps to a SAML attribute statement. It's standardized here how claims are encoded as a SAML attribute statement. You can get more information about claims here.


How is the trust between the service provider and the STS established? This is fairly easy. The SAML assertion is signed by the STS. The signing certificate must be configured in the service provider to be trusted.


But how can the STS know whether the subject confirmation method should be HoK, SV or Bearer.
If the KeyType contains the value PublicKey or SymmetricKey, the subject confirmation method is Holder-Of-Key.
If the KeyType contains the value Bearer, the subject confirmation method is Bearer.

The benefit of HoK is that even if somebody gets into the possession of a SAML token he can't 
send requests masquerading as the subject in the SAML token as he doesn't know the key (symmetric or private key). However SAML tokens with Bearer subject confirmation method must be protected. In most cases, Bearer combined with HTTPS is sufficient to prevent that "a man in the middle" can get into the possession of the SAML token.

The subject confirmation methods Bearer and Holder-Of-Key are widely used for all STS use cases as well as for Web Single Sign On in WS-Federation Passive Requestor Profile and SAML Post Profile.


OK, what about sender-vouches? Even it is not clearly stated it makes no sense to request a SAML token from an STS with sender-vouches subject confirmation method.


You might know this paper from IBM which describes how to get a SAML token from the STS with sender-vouches. Even though it's from IBM, I won't change my opinion ;-)

Let's step back once and have a look what the differences are between a SAML token with subject confirmation method Bearer and Sender-Vouches. Utlimately, it is just a string in the ConfirmationMethod element. Of course, an STS can put the string for Sender-Vouches into the SAML token - not a big deal.

The WS-Security SAML token profile defines the processing rules for HoK and Sender Vouches. In the case of Sender-Vouches it says that the attesting entity, (presumed to be) different from the subject, vouches for the verification of the subject. The receiver MUST have an existing trust relationship with the attesting entity. The attesting entity MUST protect the assertion in combination with the message content against modification by another party. The trust is established based on certificates where the attesting entity (service consumer) creates a signature which protects the SAML token and the SOAP body. The service provider verifies the signature to have the confirmation that nobody made changes either to the token or the SOAP body. The receiver (service provider) must have imported the certificate of the service consumer.
A SV SAML token itself is not signed in contrast to Bearer and HoK because there is no third party like an STS. It wouldn't make sense for an STS to issue unsigned SAML tokens as there would be no way to protect against other entities adding additional statements.

Therefore, Sender-Vouches doesn't make sense in the context of STS.

Where is SAML Sender-Vouches used? I blogged about this topic here.