Oct 20, 2009

How to use SAML 2.0 Token Profile Support in Rampart 1.5

From 1.5 release onwards Apache Rampart supports SAML 2.0 Token Profile. With this new feature, it allows web service consumers to obtain SAML 2.0 tokens from Security Token Services(STS) and use those tokens to consume other services which impose the presence of a SAML 2.0 token in a SOAP request. In this post, I am explaining how to use a SAML 2.0 token using Apache Rampart in a WS Trust scenario.

1. As the first step you need to set up Apache Axis2 + Rampart. You can download Axis2 1.5 from here and Rampart 1.5 from here.(Since Rampart 1.5 is not released yet, I have hosted the binaries built from the 1.5 branch) I am using an Axis2 deployment on Apache Tomcat to host services in this post.
  • You can simply download Axis2 webapp and deploy it in Apache Tomcat. (I am referring the tomcat installation directory as TOMCAT_HOME from here onwards)
  • Copy the set of jars inside the lib directory of Rampart binary distribution into $TOMCAT_HOME/webapps/axis2/WEB-INF/lib and copy the rampart and rahas module archives(.mar) files into $TOMCAT_HOME/webapps/axis2/WEB-INF/modules directory. Rampart makes use of WSS4J for SAML token validation. Because WSS4J release with the SAML 2.0 token validation support is yet to be released, I am using a custom WSS4J implementation in this scenario. Please download wss4j-1.5.7.wso2v2.jar from here and replace the wss4j-1.5.8.jar which is shipped with Rampart.
  • To use SAML 2.0 support, it is required to endorse the default JAXP implementation of the JDK with Apache Xerces and Xalan. You can find more information on how to endorse the JDK in the README file of Rampart binary distribution. Since Tomcat uses its own endorsed directory, it is required to endorse the Tomcat deployment. You can copy the same set of jar files which is used to endorse the JDK to $TOMCAT_HOME/endorsed directory. For convenience, I have hosted the necessary endorsing jars here. You can download this set of jars and copy them to $JAVA_HOME/jre/lib/endorsed directory.

2. As the second step you need to set up the STS and the relying party service. I am using the SAML 1.1 sample shipped with Apache Rampart with some modifications to make it use SAML 2.0. We are using a service archive which contains both relying party service and configurations for STS. STS is implemented inside Rampart and it is sufficient to provide only the configuration. You can download the this service archive named "samlple05.aar" from here. This service archive will contain a service group where STS and Sample05 are the members of that service group.
  • It is possible to configure STS according to the user requirements. STS configuration of this sample can be found in services.xml file inside the META-INF directory of the extracted service archive. These configurations are available in the <parameter name="saml-issuer-config"> element. Lets go through some of the important parameters of this configuration.



    • issuerName - This is used to identify the issuer, this could be the end point of the issuer or any other identifier used by the relying party services.
    • issuerKeyAlias - This is the alias of the certificate that STS will be using for signing SAML Assertions.
    • issuerKeyPassword - Private key password of the certificate of the STS
    • cryptoProperties - The child elements of this configuration element is used to identify the keystore which is used by the STS. Location of the keystore, keystore type and keystore password are specifed as child elements of this parameter.
    • timeToLive - Validity period of a SAML assertion(mentioned in seconds)
    • trusted-services - Under this parameter, you can specify the EPRs of the trusted relying party services for which users are obtaining SAML tokens. It is possible to specify a wildcard character, so that STS trusts any relying party service. In this sample, we have used a wildcard character. But in real world scenarios, it is recommended not to use this and mention the trusted services specifically.




  • STS is a web service, hence it is possible to publish its requirement as a policy. Please note that, it is better if STS can express its authentication requirements for the user in its policy. In this case, we are using a security policy which contains a Asymmetric Binding. So the X.509 certificate of the client is used to authenticate him.
  • Then it contains the policy and configuration required for the relying party service (sample05) which has a 'echo' operation. The security policy of the relying party service imposes the presence of a SAML 2.0 token in the SAML request.


    
        
            
                
https://kirillgdev04/Security_Federation_SecurityTokenService_Indigo/Symmetric.svc/Scenario_1_IssuedTokenOverTransport_UsernameOverTransport
urn:oasis:names:tc:SAML:2.0:assertion http://schemas.xmlsoap.org/ws/2005/02/trust/SymmetricKey 256

This policy assertion establishes the requirement for a SAML 2.0 assertion which uses a symmetric key with a length of 256 bit for SAML subject confirmation. These requirements are specified in the RequestSecurityTemplate policy assertion.


  • Then lets deploy this service archive in Axis2. You can simply copy sample05.aar file into $TOMCAT_HOME/webapps/axis2/WEB-INF/services/ directory and restart Tomcat if you haven't enable hot deployment.

3. Now lets look at the client code.
package org.wso2.sts;                                                                            

import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axis2.addressing.AddressingConstants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.Options;
import org.apache.axis2.client.ServiceClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.ConfigurationContextFactory;
import org.apache.neethi.Policy;
import org.apache.neethi.PolicyEngine;
import org.apache.rahas.RahasConstants;
import org.apache.rahas.Token;
import org.apache.rahas.TokenStorage;
import org.apache.rahas.TrustException;
import org.apache.rahas.TrustUtil;
import org.apache.rahas.client.STSClient;
import org.apache.rampart.RampartMessageData;
import org.apache.ws.secpolicy.SP11Constants;
import org.apache.ws.secpolicy.SPConstants;
import org.opensaml.XML;

import javax.xml.namespace.QName;

public class Client {

  public static void main(String[] args) throws Exception {

     //TODO : replace with the local paths in your machine
     String epr = "http://localhost:8081/axis2/services/sample05";
     String repo = "/path/to/repo";
     String servicePolicy = "/path/to/service-policy.xml";
     String stsPolicy = "/path/to/sts-policy.xml";

     ConfigurationContext ctx =      configurationContextFactory.createConfigurationContextFromFileSystem(repo, null);

     STSClient stsClient = new STSClient(ctx);

     stsClient.setRstTemplate(getRSTTemplate());
     stsClient.setVersion(RahasConstants.VERSION_05_12);
     String action = TrustUtil.getActionValue(RahasConstants.VERSION_05_02, RahasConstants.RST_ACTION_ISSUE);
     stsClient.setAction(action);

      //Obtain the token
     Token responseToken = stsClient.requestSecurityToken(loadPolicy(servicePolicy),
      "http://localhost:8081/axis2/services/STS", loadPolicy(stsPolicy), epr);

     System.out.println("\n------------------------------ Requested Token   ---------------------------------------\n");
     System.out.println(responseToken.getToken().toString());

     TokenStorage store = TrustUtil.getTokenStore(ctx);
     store.add(responseToken);

     //Call the relying party service
     ServiceClient client = new ServiceClient(ctx, null);

     Options options = new Options();
     options.setAction("urn:echo");
     options.setTo(new EndpointReference(epr));
     options.setProperty(RampartMessageData.KEY_RAMPART_POLICY, loadPolicy(servicePolicy));
     options.setProperty(RampartMessageData.KEY_CUSTOM_ISSUED_TOKEN, responseToken.getId());
     client.setOptions(options);

     client.engageModule("addressing");
     client.engageModule("rampart");

     OMElement response = client.sendReceive(getPayload("Hello world1"));
     System.out.println("Response  : " + response);

  }

  private static Policy loadPolicy(String xmlPath) throws Exception {
    StAXOMBuilder builder = new StAXOMBuilder(xmlPath);
    return PolicyEngine.getPolicy(builder.getDocumentElement());
  }

  private static OMElement getPayload(String value) {
    OMFactory factory = OMAbstractFactory.getOMFactory();
    OMNamespace ns = factory.createOMNamespace("http://sample05.policy.samples.rampart.apache.org", "ns1");
    OMElement elem = factory.createOMElement("echo", ns);
    OMElement childElem = factory.createOMElement("param0", null);
    childElem.setText(value);
    elem.addChild(childElem);

    return elem;

  }

  private static OMElement getRSTTemplate() throws Exception {
    OMFactory fac = OMAbstractFactory.getOMFactory();
    OMElement elem = fac.createOMElement(SP11Constants.REQUEST_SECURITY_TOKEN_TEMPLATE);
    TrustUtil.createTokenTypeElement(RahasConstants.VERSION_05_12,  elem).setText(RahasConstants.TOK_TYPE_SAML_20);
    TrustUtil.createKeyTypeElement(RahasConstants.VERSION_05_12, elem,  RahasConstants.KEY_TYPE_SYMM_KEY);
    TrustUtil.createKeySizeElement(RahasConstants.VERSION_05_12, elem, 256);

    return elem;
  }
}

Above listing depicts the complete version of the Client code. In order to make this work, you need to make some changes in the paths to repos, policies etc. Modify the repo, epr, servicePolicy and stsPolicy accordingly. I am explaining some of the important code segments of the above code for the sake of completion.
  • After instantiating the STSClient object, we set its RSTTemplate. In this code, getRSTTemplate() method is used to create the RSTTemplate. The SAML version, key type and the key size are set to the RST(Request Security Token) inside this method. Following code snipped sets the SAML version, Key type and key length in RST.

TrustUtil.createTokenTypeElement(RahasConstants.VERSION_05_12, elem).setText(RahasConstants.TOK_TYPE_SAML_20);
TrustUtil.createKeyTypeElement(RahasConstants.VERSION_05_12, elem, RahasConstants.KEY_TYPE_SYMM_KEY);
TrustUtil.createKeySizeElement(RahasConstants.VERSION_05_12, elem, 256);

  • Then we set the RST action. In this scenario, we are requesting a token from the STS. So the corresponding trust action is ISSUE.

String action = TrustUtil.getActionValue(RahasConstants.VERSION_05_02, RahasConstants.RST_ACTION_ISSUE);
stsClient.setAction(action);

  • Then the RST is sent to the STS. Here, we are passing the EPR of the RP service as a parameter. This is going to be checked against the set of trusted services we specified in the sts-configuration.

Token responseToken = stsClient.requestSecurityToken(loadPolicy(servicePolicy), "http://localhost:8081/axis2/services/STS", loadPolicy(stsPolicy), epr);

  • After obtaining the token, we are storing it in the trust store and then sending it to the RP service.

You can download the source code, policy files and client site key store from here. Please note that you have to change the rampart-config parameters in both policy files to reflect your local settings.

In this sample, we are using a password callback handler to load the passwords of the private keys. In the client's end, we are using the following password callback handler.
package org.wso2.sts;

import org.apache.ws.security.WSPasswordCallback;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import java.io.IOException;

public class PWCBHandler  implements CallbackHandler{
      public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
          for (int i = 0; i < callbacks.length; i++) {
              WSPasswordCallback pwcb = (WSPasswordCallback)callbacks[i];
              String id = pwcb.getIdentifer();
              if("client".equals(id)) {
                 pwcb.setPassword("apache");
              } else if("service".equals(id)) {
                pwcb.setPassword("apache");
              }
         }
    }
}

To get the client code up and running you need to add certain set of jars to your classpath. Most straight forward approach is adding the Axis2 'lib' into your classpath. It contains all the jars required to compile and run this sample.

Following listing depicts the RST sent from Client to STS.

    http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue
    
        
            http://localhost:8081/axis2/services/sample05
        
    
    
        2009-10-20T13:15:51.739Z
        2009-10-20T13:20:51.739Z
    
    http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0
    http://docs.oasis-open.org/ws-sx/ws-trust/200512/SymmetricKey
    256
    
        
            g5WVRpUl7bKno8LYFC9JUGLpe1NZpkZ/
        
    
    http://docs.oasis-open.org/ws-sx/ws-trust/200512/CK/PSHA1

In this RST, RequestType is set to "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue". We have passed EPR of the RP service as a parameter when requesting the token. If you carefully observe  AppliesTo element, you will note the EPR we have passed has been set as the value of this element. Similarly the token type, key type and the key size are also appearing in the RST as we have set them in the RSTTemplate. The "Entopy" element is used pass a binary secret which is used to derive keys. I am not going into further details about key derivation is WS Trust. Plese refer to the WS Trust specification for further details.

Following is the resulting RSTR(Request Security Token Response) returned by the STS.

    
        http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0
        256
        
            
                
            
        
        
            
                
            
        
        
            
                http://localhost:8081/axis2/services/sample05
            
        
        
            2009-10-20T15:13:26.138Z
            2009-10-20T15:13:56.138Z
        
        
            
                SAMPLE_STS
                    ...
               
        
        
            http://docs.oasis-open.org/ws-sx/ws-trust/200512/CK/PSHA1
        
        
            
                r/JgXgGMFb4afwRQpggqky8q4TQm7pdXm8RQq9IgCzI=
            
        
    

SAML assertion contained in the RSTR is removed for brevity.

In this post, we have looked about the STS Configuration of Apache Rampart, how to obtain a SAML 2.0 Token, and how to use it to consume a web service. If you faced any issues, do not hesitate to post them here.

Oct 12, 2009

WSO2 SOA Workshop - Santa Clara, CA

Are you ready to get beyond the hype surrounding Service Oriented Architecture, and learn how to actually implement a real SOA solution?

In this full-day interactive workshop, you will learn how to map specific business requirements to concrete SOA development patterns. If you’re ready to gain insight into real-world best practices for SOA, this session is for you.

us-soa-workshop-banner


Topics Covered



  • ESBs and SOA



  • SOA Security



  • Mashups and Business Process Management for SOA



  • SOA Governance



  • SOA with C, C++, PHP and more



  • SOA Enterprise Architecture Patterns


Date and Time


November 3 2009
9:00 am to 5:00 pm (Registration at 8:30 am)

Location


Network Meeting Center at Techmart
5201 Great America Parkway
Santa Clara, California 95054

Get registered today.

Oct 9, 2009

WSO2 Identity Server 2.0.1 Released

The WSO2 Identity Server team is pleased to announce the release of
version 2.0.1 of the Open Source WSO2 Identity Server (IS).

IS 2.0.1 release is available for download at [1].

This is based on revolutionary the WSO2 Carbon [2] framework, Middleware
a la carte'.

All the major features have been developed as pluggable Carbon components.

New Features
---------------
1. SAML 2.0 Token Profile support
2. Passive STS
3. Equinox P2 based provisioning support
4. Improved Support for deploying on top of WebSphere, WebLogic, and
JBoss.
5. Various bug fixes and enhancements including architectural
improvements to Apache Axis2, Apache Rampart, Apache Sandesha2, WSO2
Carbon and other projects

Other Key Features
---------------------
1. Entitlement Engine with XACML 2.0 support.
2. Claim based Security Token Service.
3. Extension points for SAML assertion handling.
4. OpenID Provider
5. Information Card Provider

How to Run
------------------
1. Extract the downloaded zip.
2. Go to the bin directory in the extracted folder.
3. Run the wso2server.sh or wso2server.bat as appropriate.
4. Point your browser to the URL https://localhost:9443/carbon
5. Use "admin", "admin" as the user name and password.
6. If you need to start the OSGi console with the server use the
property -DosgiConsole when starting the server

Known issues
----------------------
All the known issues have been filed here [3]. Please report any other
issues you find as JIRA entries.

Contact us
-----------------
WSO2 Identity Server developers can be contacted via the mailing lists:
For Users: carbon-user@wso2.org
For Developers: carbon-dev@wso2.org

Alternatively, questions can also be raised in the Identity Server forum
at http://wso2.org/forum/308

Training
---------------
WSO2 Inc. offers a variety of professional Training Programs, including
training on general Web services as well as WSO2 Identity Server,
Apache Axis2, Data Services and a number of other products. For
additional support information please refer to
http://wso2.com/training/course-catalog/


Support
--------------
WSO2 Inc. offers a variety of development and production support
programs, ranging from Web-based support up through normal business
hours, to premium 24x7 phone support. For additional support information
please refer to http://wso2.com/support/


For more information on WSO2 Identity Server, visit the WSO2 Oxygen Tank[4].

Thank you for your interest in WSO2 Identity Server.

-The WSO2 Identity Server team

[1]: http://wso2.org/downloads/identity
[2]: http://wso2.org/projects/carbon
[3]: https://wso2.org/jira/browse/CARBON
[4]: http://wso2.org