Aug 21, 2009

Identity Delegation in WS Trust 1.4

With the introduction of "ActAs" element, WS Trust 1.4 specification facilitates identity delegation. The best way to understand the usage of this element is through a practical scenario. Following use case demonstrates an application of "ActAs".

There are two services called service 1 and service 2. Service 2 contains the actual business logic and Alice(service consumer) is interested about it. There is a Security Token Service(STS) which is trusted by both services.

Screenshot

  1. Alice sends a RST to the STS authenticating herself to the STS. This is a normal RST.

  2. STS returns a SAML Token to Alice in the RSTR. The subject of this SAML token is “Alice”. Let's refer to this SAML token as token1.

  3. Alice forwards the token1 with its soap request to service 1. Up to this message transfer, this is same as a usual trust brokering scenario.

  4. Then service1 sends a RST to STS again authenticating itself to the STS. But this time the RST contains the token1 inside the “ActAs” element. (This ActAs element is introduced in the WS Trust 1.4.)

  5. Now the STS issues a SAML token(referred to as token2). The subject of this token is “service1”. But it contains an attribute called “ActAs” with the value of “Alice”.

  6. Then the service1 sends the token2 to “Service2”. Now the service2 understands that the original requester is “Alice” and “Service1” is acting as the original requester by processing the token2.

  7. Then Service1 sends the response to Service2.

  8. Finally, Service1 forwards the response to Alice.


Apache Rampart will be supporting WS-Trust 1.4 specification soon. So stay tuned..

How does the SOAP Message Encryption work?

WS Security Specification describes enhancements to SOAP messaging to provide message integrity, confidentiality, non-repudiation etc. It does not introduce new information security concepts, rather it is based on the existing security concepts like XML encryption, XML signatures, etc. It sets the foundation to secure web services by adapting these existing technologies accordingly.



This post is intended to provide a simplified explanation on how XML encryption works with SOAP messages as per the WS Security Specification.
WS Security Specification recommends to use symmetric keys for encryption. This is mainly due to the low performance factor of asymmetric key based encryption. Even if the asymmetric binding is used, it is advised to use symmetric keys for encryption. In such scenarios, the PKI is used to establish the symmetric keys. Initiator can come up with the symmetric and encrypt it using the public key of the recipient. Then the recipient can decrypt this key and find out the symmetric key which is used for encryption.

It is possible to encrypt the whole XML element or  just the content of it. WS Security Specification enforces not to encrypt <S11:Header>, <S12:Header>, <S11:Envelope>, <S12:Envelope>,or <S11:Body>, <S12:Body> elements. But encrypting the sub elements of those elements are allowed.


If a particular element or content of it is supposed to be encrypted, then that element should be replaced by the <xenc:EncryptedData> element which is the result of encrypting the original element.

Ex :
...

Symmetric keys used for the encryption operations should be embedded inside <xenc:EncryptedKey> elements. Each <xenc:EncryptedKey> element should contain a <ds:KeyInfo> element that contains information about the key used to encrypt the symmetric key. Then there can be a <xenc:ReferenceList> which is the manifest of the elements which are encrypted. If a <xenc:ReferenceList> element is appearing inside a <xenc:EncryptedKey> element, it implies that the symmetric key resulted by decrypting the cipher value of the <xenc:EncryptedKey> element should be used decrypt the elements specified in that refernce list. <xenc:ReferenceList> is comprised of a list of <xenc:DataReference> elements which contains refernces to the elements which are encrypted using this key. If we put this in a simplified manner, <xenc:ReferenceList> inside a <xenc:EncryptedKey> element refers to all the <xenc:EncryptedData> elements which are encrypted using the symmetric key contained in that  <xenc:EncryptedKey> element. Each <xenc:EncryptedData> element should be referred using <xenc:DataReference> element.


Ex :

    
    
        
            
                HYL371NzoOs2+IA24VDkBGcUFQM=
            
        
    
    
        
            H9l+f1lqTvi4W3vaHwXMhhdfOT8t2t75fzgCkUvjX7ae9FLMEm7/hoQCEurJE4SOmPRXUvLV3MSI21Fcr3HW2OFc1SEpAZQwxma03/iG0jlSyAOOO/j9jitTnmvhtMGI9HShrM0cP77U0GDBTIoXqMSOrzMKbSQ8iz7wl5dG+TY=
        
    
    
        
    

Lets come back to the <xenc:EncryptedData> element. Earlier we said that all the elements which should be encrypted must be replaced by a <xenc:EncryptedData> elements. This element might contain a <ds:KeyInfo> element which points to another <ds:KeyInfo> element or an attached security token. But it is not mandatory to have such <ds:KeyInfo> element, if that <xenc:EncryptedData> element is listed in a <xenc:ReferenceList> of a particuar <xenc:EncryptedKey>. It should contain a </xenc:CipherData> element, which contains the cipher data.


Ex :

    
    
        
            
        
    
    
        HTnMneoskQeLew99eIqCLh+8kUAvKozGjsLMfBN8Ji2QDx64Rl53vKqXYybDQeGidWHn9L7OFSEW
            6kWuSsDqB+AWQezNgoACcxrNfn7vGwQidD3Kl6aviSaFALzJJkphk29Cip7vSOFmxJn3qIaA82AD
            rrnPYT57uyPh03XELwrv1Wret3q1uNZ0pnjk6xjYjsQzkAgADUeE/MfWSMdjvpZ6eQ4wwTOmemeh
            HtVLEdIsKoCyXRBMC9Etiu3KoymArNWRAMgQHvSzBmGxuWCALOHYru8OJpmetZacz5KVqWHifRhP
            wXFsWOQF3zfBQhJmf4fRiAXkeJ4ZXn3BjT4dz/BVoDaHJFEwK5KY9GRtg0U7Eu3l5k6RNM3ds56N
            PGP/DhvKJfcFCh4qKVfbWFDVLdeqcRzrHXWuiHTu6BoiwJgzFoQ8vjP6Bw==
        
    

Having said about the optional <ds:KeyInfo> element inside a <xenc:EncryptedData> element, now it is possible to take the <xenc:ReferenceList> element out of the <xenc:EncryptedKey> element if required. In such scenarios, <xenc:EncryptedData> elements should contain the <ds:KeyInfo> elements pointing to the keys that are used for the encryption. With this option, it is possible to use multiple keys for encrypting the elements in the same SOAP message.


So lets bring all the bits and pieces together. Following listing depicts a SOAP message with an encrypted soap body.

    
        
            
                
                
                    
                        
                            HYL371NzoOs2+IA24VDkBGcUFQM=
                        
                    
                
                
                    
                        H9l+f1lqTvi4W3vaHwXMhhdfOT8t2t75fzgCkUvjX7ae9FLMEm7/hoQCEurJE4SOmPRXUvLV3MSI21Fcr3HW2OFc1SEpAZQwxma03/iG0jlSyAOOO/j9jitTnmvhtMGI9HShrM0cP77U0GDBTIoXqMSOrzMKbSQ8iz7wl5dG+TY=
                    
                
                
                    
                
            
        
        http://localhost:8081/axis2/services/sample03
        urn:uuid:EE5C34B1DCEF6DBA991250791000372
        urn:echo
    
    
        
            
            
                
                    
                
            
            
                HTnMneoskQeLew99eIqCLh+8kUAvKozGjsLMfBN8Ji2QDx64Rl53vKqXYybDQeGidWHn9L7OFSEW
                    6kWuSsDqB+AWQezNgoACcxrNfn7vGwQidD3Kl6aviSaFALzJJkphk29Cip7vSOFmxJn3qIaA82AD
                    rrnPYT57uyPh03XELwrv1Wret3q1uNZ0pnjk6xjYjsQzkAgADUeE/MfWSMdjvpZ6eQ4wwTOmemeh
                    HtVLEdIsKoCyXRBMC9Etiu3KoymArNWRAMgQHvSzBmGxuWCALOHYru8OJpmetZacz5KVqWHifRhP
                    wXFsWOQF3zfBQhJmf4fRiAXkeJ4ZXn3BjT4dz/BVoDaHJFEwK5KY9GRtg0U7Eu3l5k6RNM3ds56N
                    PGP/DhvKJfcFCh4qKVfbWFDVLdeqcRzrHXWuiHTu6BoiwJgzFoQ8vjP6Bw==
                
            
        
    

An asymmetric key is used for encrption. <xenc:EncryptedKey> element contains a <ds:KeyInfo> element which can be used by the recipient to locate the correct private key from his keystore to decrypt the symmetric key. <wsse:SecurityTokenReference> element inside that <ds:KeyInfo> element specifies a ThumbprintSHA1 value that can be used as a key identifier. Then it contains a <xenc:CipherData> which contains the cipher text of the symmetric key. Decrypting this cipher text using the private key of the recipient with result with the symmetric key.

Then it has the <xenc:ReferenceList> with a single <xenc:DataReference> element. That <xenc:DataReference> element refers to an element using the URI fragment #EncDataId-3. If you carefully observe, you will note that, this URI fragment is the ID of the <xenc:EncryptedData> which is the child element of the soap body. That <xenc:EncryptedData> element contains a <ds:KeyInfo> element which points to the <xenc:EncryptedKey> element mentioned above using a SecurityToken Reference. <xenc:CipherValue> contains the encrypted content of the soap body, which should be decrypted using the symmetric key.


I did not discussed about encrypting SOAP headers, to keep this note short as much as possible.

Refer to WS Security Specification for a comprehensive description about the SOAP message encryption.

Aug 20, 2009

WS Security Policy - Asymmetric Binding Explained...

In this post, I am trying to explain the Assymetric Binding defined in WS Security Policy Specification. First I will explain what the Asymmetric Binding is, and then I will take you through a sample scenario using Apache Rampart.


WS Security Policy Specification defines three security binding assertions, namely Transport Binding, Symmetric Binding and Asymmetric Binding. All these bindings are ideal for different use cases and only the Asymmetric Binding is discussed in detail in this post.



What is Assymetric Binding ?

According to the WS Security Specification, “The AsymmetricBinding assertion is used in scenarios in which message protection is provided by means defined in WSS: SOAP Message Security using asymmetric key (Public Key) technology”. If we put this in a simplified manner, Asymmetric Binding can be used when both parties possess key pairs. For example, if both the parties possess X.509 certificates, then it is possible to use asymmetric binding.


In asymmetric binding, message encryption and signing takes place using the Public Key Infrastructure(PKI), i.e. sender encrypts messages using the public key of the recipient and sign the messages using his private key. Then the recipient can decrypt the received messages using his private key and verify the signature of the message using the public key of the sender. This way, the confidentiality, integrity and the non-repudiation properties of the message exchanges can be assured.



Following diagram explains how asymmetric binding works.

asymmetric

Asymmetric Binding Policy Assertion

Following is a sample Asymmetric Binding policy assertion.

    
        
            
                
                    
                        
                        
                    
                
            
        
        
            
                
                    
                        
                        
                    
                
            
        
        
            
                
            
        
        
            
                
            
        
        
        
    

In asymmetric binding scenario, keys used for signature and encrypting should be clearly specified. This is facilitated in the Assymetric Binding assertion itself. An assymetric binding usually contains two main elements, InitiatorToken and RecipientToken. These tokens provides room for specifying the tokens used in the signing/encrypting operations by the sender(initiator) and recipient respectively. According to the specification, each of these two elements should contain tokens used for signing and encrypting. In this policy, X.509 certificate is used for signing/encrypting at each end. This is specified using a X.509 supporting token.



In addition to those two elements, other properties like Algorithmic Suite, IncludeTimeStamp can also be specified in the Asymmetric Binding element similar to other security binding assertions.

Rampart Configuration

Although we have specified that we are using a X.509 certificates for signing and encrypting in the policy, there should be a way to point to those certificates from both ends. Now the Rampart Configuration element comes into play. Following is the Rampart-Config of the client side. Server side should also contain a RampartConfig element which is almost similar to this.

    client
    service
    org.apache.rampart.asymm.PWCBHandler

    
       
          JKS
          
            /path/to/client.jks
          apache
       
    

Lets go through each of these elements.

<ramp:userCertAlias> - alias of the key used for signing.

<ramp:encryptionUser> - used to identify the key that is used to encrypt, i.e. alias of the recipient's certificate.

<ramp:passwordCallbackClass> - used to get the password of the private key that is used for signing.

<ramp:signatureCrypto> - information about the key store that contains the necessary keys. Here, we are providing the keystore type, location and keystore password. This element only defines the keystore that contains the keys used for signing. Similarly there can be a another element called encryptionCypto containg keystore information used for encryption. In Rampart, if this element is not specified, properties defined in ramp:signatureCrypto element is used for encryption operations.



Policy

Following listing is the policy I have used in this sample. Since the Asymmetric Binding assertion is provided before I have removed that assertion from the policy for the brevity.

    
      
         
               ....
         
         
            
                
                
            
         
         
            
         
       
   

The body of the soap message should be singed according to the policy.

Please note that the corresponding RampartConfig elements should also be appended to the policy. The complete policy.xml and the services.xml files can be found in the resources.

Service

I am using a simple echo service in this sample. The service class looks similar to this.
public class SimpleService {
  public String echo(String arg) {
    return arg;
  }
}

This service file can be found in the resources.

Client
package org.apache.rampart.asymm;

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.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.rampart.RampartMessageData;

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

        String repo = "/path/to/repo";
        String EPR = "http://localhost:8080/axis2/services/sample02";
        String policyPath = "/path/to/policy.xml";

// instantiating a ConfigurationContext object pointing to a Axis2 repository.
        ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(repo, null);

        ServiceClient client = new ServiceClient(ctx, null);

//Setting the properties to the service client.
        Options options = new Options();
        options.setAction("urn:echo");
        options.setTo(new EndpointReference(EPR));
        options.setProperty(RampartMessageData.KEY_RAMPART_POLICY, loadPolicy(policyPath));
        client.setOptions(options);

// engage modules
        client.engageModule("addressing");
        client.engageModule("rampart");

//invoke the web service
        OMElement response = client.sendReceive(getPayload("Hello world"));

        System.out.println(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://sample02.policy.samples.rampart.apache.org", "ns1");
        OMElement elem = factory.createOMElement("echo", ns);
        OMElement childElem = factory.createOMElement("param0", ns);
        childElem.setText(value);
        elem.addChild(childElem);

        return elem;
    }
}

Since we have used policy based configuration, most of the rampart configuration is done at the policy. So this class is simple. If you have already gone through my previous post about using username token + HTTPS to secure a web service, it is easy to understand this code.



Request and Response

You can find both the request and response generated in this service invocation in the resources. You will see that the body of the SOAP message is signed using the private key of the sender. So the recipient can verify that signature using the ppublic key of the sender.


Image Courtesy : Understanding WS – Security Policy Language by Nandana Mihindukulasooriya.


Aug 18, 2009

Securing a Web Service with Username Token + HTTPS with Apache Rampart

This is the first of a series of blogs about using Rampart effectively for securing web services. In this blog, I am explaining how to use an Username Token with transport level security to secure a web service. You can find all the resources related to this post here.

Securing Approach

Username Token is a Signed Supporting token that can be used to send the username/password to the other end. Then the recipient can check whether this is coming from a valid user. In this example we are are achieving transport level security through HTTPS. In HTTPS the service and the client are communicating through a pre-established a secured tunnel. So the confidentiality and the integrity of the messages are protected.

Security Policy Used


Following listing is the security policy that we are using in this blog.

    
        
            
                
                    
                        
                            
                        
                    
                    
                        
                            
                        
                    
                    
                        
                            
                        
                    
                    
                
            
            
                
                    
                
            
        
    

If you observe this security policy carefully, you will notice that two main policy assertions are specified. TransportBinding assertion is used to enforce the transport level security. HttpsToken inside the Transport Token declares the requirement of using HTTPS. SignedSupportingTokens assertion contains the UsernameToken assertion which establishes the requirement of providing a username token.

In the client side, a custom tag is appended to the policy.

   alice
 org.apache.rampart.utSample.PWDCBHandler


Here I am using the policy based configuration approach instead of programmatically setting the parameters. I am setting the alice as the user and org.apache.rampart.utSample.PWDCBHandler as the password callback handler. So the alice and the password returned from the password callback handler will be sent to the server as the username/password pair.

In the server side I am setting the Password Callback handler to be used for verifying the password.

    org.apache.rampart.utSample.PWDCBHandler


These custom assertions will not be appearing in the WSDL. They are used within Rampart to get the configuration details.

Creating the service

We are using a simple "echo" service as the service. The service class that we are using in this blog is given below.
public class SimpleService {
  public String echo(String arg) {
    return arg;
  }
}

You can find the sample01.aar file that contains this service in the resources. Deploy it in Tomcat + Axis2 or in WSO2 Web Services Application Server (WSO2 WSAS). If you are using Tomcat, you must enable SSL first. This guide will take you through the steps required to enable SSL in Tomcat.

Client Code
package org.apache.rampart.utSample;

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.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.rampart.RampartMessageData;

public class UTClient {

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

        String repo = "/path/to/repo";
        String trustStore = "/path/to/server's_keystore";
        String storePass = "keyStore_passwprd";
        String policyFile = "/path/to/UT-Policy.xml";
        String EPR = "https://localhost:8443/axis2/services/sample01";

        System.setProperty("javax.net.ssl.trustStore", trustStore);
        System.setProperty("javax.net.ssl.trustStorePassword", storePass);

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

        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(policyFile));
        client.setOptions(options);

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

        OMElement response = client.sendReceive(getPayload("Hello world"));

        System.out.println(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://sample01.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;
    }

}

Lets walk through the important code segments of the Client.

Following code lines are used to set the trust store properties. Since we are using HTTPS as the transport, we need to trust the certificate used by the server. So I am adding the keystore used by the server as a trusted store.
System.setProperty("javax.net.ssl.trustStore", trustStore);
System.setProperty("javax.net.ssl.trustStorePassword", storePass);

Then you need to specify a repository in order to locate the module archives of Rampart, Addressing and Rahas. This tutorial explains how to create a Axis2 Repository.
ConfigurationContext ctx = ConfigurationContextFactory.createConfigurationContextFromFileSystem(repo, null);

You should engage Rampart and Addressing modules in the client side. You should point to a valid repository in the previous step in order to successfully engage these modules.
client.engageModule("addressing");
client.engageModule("rampart");

Following is the Password Callback handler  I am using at the client side.
package org.apache.rampart.utSample;

import org.apache.ws.security.WSPasswordCallback;

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

public class PWDCBHandler implements CallbackHandler {
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        WSPasswordCallback cb = (WSPasswordCallback) callbacks[0];
        if ("alice".equals(cb.getIdentifier())) {
            cb.setPassword("bobPW");
        } else {
            cb.setPassword("bobPW");
        }
    }
}

This class implements the javax.security.auth.callback.CallbackHandler interface .

All these source codes can be found with the resources.

Request & Response

Since we are using SSL, only the encrypted form of the request and response can be captured. But the request and response in plain text should appear as follows.

Request


    
        
            
                2009-08-18T15:12:58.053Z
                2009-08-18T15:17:58.053Z
            
            
                alice
                
                    bobPW
                
            
        
        http://localhost:8081/axis2/services/sample01
        urn:uuid:B429936843779AAE931250608376908
        urn:echo
    
    
        
            Hello world
        
    


Observe the UsernameToken element in the security header. It contains the username/password pair.

Response


    
        
            
                2009-08-18T15:12:58.544Z
                2009-08-18T15:17:58.544Z
            
        
        urn:echoResponse
        urn:uuid:B429936843779AAE931250608376908
    
    
        
            Hello world
        
    


Now we have gone through all the steps required to invoke a service with username token over HTTPS.

All the source files, policy files, and other resources can be found here.