Showing posts with label idp. Show all posts
Showing posts with label idp. Show all posts

March 4, 2013

SSO and Fine Grained Authorization in the Cloud

In February 2013, I was at ApacheCon NA 2013 in Portland, Oregon, US where I learned a lot about several Apache projects.

My presentation was about SSO and Fine Grained Authorization in the Cloud. I gave an introduction about application security 10-15 years ago and how to address challanges with Cloud deployment using Apache CXF Fediz.

Here are the slides from my talk:

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

November 2, 2011

Configure Tomcat for federation - Part III


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

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

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

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


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

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



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

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

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

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


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

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

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

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

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


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



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

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


5) Configure the CA certificates

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

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


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

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

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

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



Encoding of roles in SAML token

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

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

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

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.