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.

<sp:AsymmetricBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
    <wsp:Policy>
       <sp:InitiatorToken>
          <wsp:Policy>
             <sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient">
                 <wsp:Policy>
                     <sp:RequireThumbprintReference/>
                     <sp:WssX509V3Token10/>
                 </wsp:Policy>
            </sp:X509Token>
          </wsp:Policy>
       </sp:InitiatorToken>
       <sp:RecipientToken>
          <wsp:Policy>
             <sp:X509Token sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Never">
                 <wsp:Policy>
                     <sp:RequireThumbprintReference/>
                     <sp:WssX509V3Token10/>
                 </wsp:Policy>
            </sp:X509Token>
        </wsp:Policy>
       </sp:RecipientToken>
       <sp:AlgorithmSuite>
          <wsp:Policy>
             <sp:TripleDesRsa15/>
          </wsp:Policy>
       </sp:AlgorithmSuite>
       <sp:Layout>
          <wsp:Policy>
             <sp:Strict/>
          </wsp:Policy>
       </sp:Layout>
       <sp:IncludeTimestamp/>
       <sp:OnlySignEntireHeadersAndBody/>
     </wsp:Policy>
 </sp:AsymmetricBinding>

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.

<ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy">
    <ramp:userCertAlias>client</ramp:userCertAlias>
    <ramp:encryptionUser>service</ramp:encryptionUser>
    <ramp:passwordCallbackClass>org.apache.rampart.asymm.PWCBHandler</ramp:passwordCallbackClass>

    <ramp:signatureCrypto>
       <ramp:crypto provider="org.apache.ws.security.components.crypto.Merlin">
          <ramp:property name="org.apache.ws.security.crypto.merlin.keystore.type">JKS</ramp:property>
          <ramp:property name="org.apache.ws.security.crypto.merlin.file">
            /path/to/client.jks</ramp:property>
          <ramp:property name="org.apache.ws.security.crypto.merlin.keystore.password">apache</ramp:property>
       </ramp:crypto>
    </ramp:signatureCrypto>
</ramp:RampartConfig>

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.

?xml version="1.0" encoding="UTF-8"?>
<wsp:Policy wsu:Id="SigOnly"  xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
          xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
    <wsp:ExactlyOne>
      <wsp:All>
         <sp:AsymmetricBinding xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
               ....
         </sp:AsymmetricBinding>
         <sp:Wss10 xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
            <wsp:Policy>
                <sp:MustSupportRefKeyIdentifier/>
                <sp:MustSupportRefIssuerSerial/>
            </wsp:Policy>
         </sp:Wss10>
         <sp:SignedParts xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy">
            <sp:Body/>
         </sp:SignedParts>
       </wsp:All>
   </wsp:ExactlyOne>
</wsp:Policy>

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.

Advertisements

About this entry