WS-Security using Cert Authentication with Spring-WS V: How to implement a Message Signing Client

The previous installment set the stage for our WebService Clients’ Security Inftrastucture, that is the Keystore which will provide the Clients private Key in order to build the digital Signature (the encrypted Hash for the messages’ payload) and the related – now signed – Certificate, which will be included within the Request Message (so the receiver – among other things – is able to decrypt the embedded digital Signature in order to compare it with the  Hash rebuilded by himself for the sake of data integrity).

With that at hand, we’re now in a position to implement the WebService Client, which should sign any outgoing message, adhering to the given Security Constraints of our WebService.
We’ll again leverage Spring-WS’ potential and use org.springframework.ws.client.core.support.WebServiceGatewaySupport for implementing our Gateway class, which will encapsulate the whole procedure of Message Signing and Message Sending.


public class WebServiceGateway  extends WebServiceGatewaySupport{
  ...
  public void callService( Resource payload ){...}
}

Using WebServiceGatewaySupport gives us the chance to provide some of the crucial information (like the
WebServices’ location) via Springs’ application context:

...
<bean id="wsGateway" class="ffb.fsm.ws.gateway.WebServiceGateway">
<property name="defaultUri"
      value="http://www.myWebserviceProviderUrl.de/ws/auction"/>
<property name="messageFactory" ref="soap11MessageFactory"/>
<property name="defaultRequest"
      value="classpath:com/mgi/ws/resource/placeBidRequest.xml"/>
  ...
</bean>
...
<bean id="soap11MessageFactory"
      class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
<property name="messageFactory">
    <bean class="com.sun.xml.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl" />
  </property>
</bean>
...

As you can see, we provide the WebServices’ Location in form of property defaultUri (so we don’t have to pass the URI within every single request). Further, we’re explicitly using SOAP 1.1 as the ‘communication protocoll’ for the information structure and statically refer to a resource that will hold the payload of the Request Message.
Please note, that i’m not going into any further details on how to implement a ‘standard’ WebService Client via Spring-WS, since there are some good resources on that topic out there – instead we want to focus mainly on Message Signing.

A simple Message Signer

Signing of the ‘original’ (unsigned) Message is best encapsulated within a class of its own – let’s call it MessageSigner. Although Message Signing can be done more or less completely by configuration, i’m going to implement the process of Message Signing here for the sake of clarity.
Our MessageSigner will deliver an org.springframework.ws.client.core.WebServiceMessageCallback which in turn is responsible for securing the outgoing message. This WebServiceMessageCallback will be used by our WebServiceGateway to ‘intercept’ the Message Sending Process and manipulate the outgoing request message right before its final delivery (as we’ll see later).

Like on the server side – we’ll also rely on XWSS when it comes to securing the outgoing message, thus our MessageSigner will behave according to some given XWSS Security Constraints. This time we have to provide those Security Constraints on client side, forcing the MessageSigner to sign the outgoing Message. Therefore, we’ll use an instance of com.sun.xml.wss.XWSSProcessor which gets fed with the Policy File (which will hold the Configuration to sign the outgoing message) and the related Keystore, holding the Key-Pair used for message Signing.

import java.io.IOException;
import java.io.InputStream;
import javax.xml.soap.SOAPMessage;
import org.springframework.core.io.Resource;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler;
import com.sun.xml.wss.ProcessingContext;
import com.sun.xml.wss.XWSSProcessor;
import com.sun.xml.wss.XWSSProcessorFactory;

public class XwssMessageSigner {

  private final XWSSProcessor processor;

  public XwssMessageSecurer( Resource policyFile, KeyStoreCallbackHandler keystoreHandler ) throws Exception {

    InputStream in = policyFile.getInputStream();
    XWSSProcessorFactory factory = XWSSProcessorFactory.newInstance();
    processor = factory.createProcessorForSecurityConfiguration( in, keystoreHandler );
    in.close();
  }

  public WebServiceMessageCallback getCallback() {

    return       
      new WebServiceMessageCallback() {
        public void doWithMessage( WebServiceMessage message ) throws IOException {

          SaajSoapMessage origSaajMessage = (SaajSoapMessage) message;
          SOAPMessage origSoapMessage = origSaajMessage.getSaajMessage();

         ProcessingContext context = new ProcessingContext();

          try {
            context.setSOAPMessage( origSoapMessage );
            SOAPMessage securedSoapMessage = processor.secureOutboundMessage( context );
            origSaajMessage.setSaajMessage( securedSoapMessage );
          }
          catch (Exception exc) {
            exc.printStackTrace();
            throw new IOException( exc.getMessage() );
          }
        }
      };
   }
}

As you can see, our Signer relies on a policy File (containing the Security Constraints) and a KeyStoreCallbackHandler, which is responsible for handling the key /certificate requests. Both Dependencies will be injected into XwssMessageSigner via constructor injection (as we’ll see later).

Inside the WebServiceMessageCallback, we’ll receive the original message in a state just before sending it to the receiver. The message already conists of the whole Soap structure (Payload Body and Envelope), so that we can refer to all parts of it. After retrieving the original Soap Message (extracted from Spring-WS’ SaajSoapMessage wrapper), XWSSProcessor is going to secure it according to the given Security Constraints. The outgoing message is than replaced by our newly secured Soap Message.

Security Policies

In order to get our MessageSigner to really sign the Message, we have to come up with an accordant policy File. Like we did on the server side, we also have to configure it for Message Signing. Note, that we could have placed every possible type of Security Configuration within the Policy file and our MessageSigner would behave accordant to that policy (under that point of view, ‘MessageSecurer’ would be a better, more general name for our MessageSigner).

<xwss:SecurityConfiguration dumpMessages="true"
  xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
    <xwss:Sign id="signature">
      <xwss:X509Token certificateAlias="wstestclient"/>
    </xwss:Sign>
</xwss:SecurityConfiguration>

As you can see, we force Message Signing by placing xwss:Sign within theSecurity Configuration, further arranging, that the Signing should be based on X509 Certificates. Note, that we also define the alias Name of the Key-Pair which should be used for building the digital Signature (when refering to the Keystore, which we’ve assigned to our instance of XWSSProcessor).

Configuration

Now we’re able to configure our MessageSigner also within the application context, supplying the conning Security Constraints and the underlying Keystore (via the before mentioned KeyStoreCallbackHandler) which holds our Key-Pair for Message Signing:

<bean id="xwssMessageSigner" class="com.mgi.xwss.XwssMessageSigner">
  <constructor-arg value="classpath:com/mgi/xwss/securityPolicy.xml"/>
  <constructor-arg>
    <bean class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="keyStore" ref="clientKeystore" />
<property name="defaultAlias" value="wstestclient"/>
<property name="privateKeyPassword" value="keyPairPasswd"/>
    </bean>
  </constructor-arg>        
</bean>

<bean id="clientKeystore" class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="classpath:com/mgi/xwss/XWSSClientKeystore.jks"/>
<property name="password" value="keystorePasswd"/>
</bean>

With our MessageSigner ready to go, we’ll extend the configuration of WebServiceGateway. It will now accept the MessageSigner as an additional Dependency:

<bean id="wsGateway" class="ffb.fsm.ws.gateway.WebServiceGateway">
  ...
<property name="xwssMessageSigner" ref="xwssMessageSigner"/>
</bean

Delegation

With the MessageSigner injected, WebServiceGateway will now delegate the Signing of outgoing messages to that MessageSigner simply by requesting an instance of the provided WebServiceMessageCallback and let him do its job (of course we could have requested an instance of WebServiceMessageCallback only once and reuse that instance for every Request):

public class WebServiceGateway  extends WebServiceGatewaySupport{
  ...
  private XwssMessageSigner xwssMessageSigner = null;
  ...
  public void setXwssMessageSigner( XwssMessageSigner signer ){
    this.xwssMessageSigner = signer;
  }

  public void callService() throws IOException{
    callService( defaultRequest );
  }

  public void callService( Resource request ) throws IOException{

    Source requestSource = new ResourceSource( request );

    try{

      getWebServiceTemplate()
        .sendSourceAndReceive(
          requestSource,
          xwssMessageSecurer.getCallback(),
          new MySourceExtractor() );        
    }
    catch( SoapFaultClientException e ){
      // error handling
    }
  }

  public class MySourceExtractor implements SourceExtractor{
    public Object extractData( Source src ) throws IOException, TransformerException {

    DOMSource dom = (DOMSource) src;
      // process response     
      return ... // processed response;
    }
  }
  ...
}

You see, that there’s nothing magic about it at all. WebServiceGateway gets called in order to send a new request to our WebService (which is configured via the clients’ application context, as we’ve seen before).  In the easiest case, we could simply call callService(), so that the configured default message used, signed and send. Of course, you could also call callService( Resource request ), passing an individual payload that is to be signed and send over the wire.

Summary

Message Signing on the client side is also done by leveraging XWSS in form of an XWSSProcessor which is configured accordingly (using an appropriate Security Policy File). The Signing Process is encapsulated within a class of its own – MessageSigner. The client is able to use MessageSigner in that it request a WebServiceMessageCallback which in fact does the job of securing the outgoing message. In our case, according to the given Security Policies, a Hash is build based on the message payload (also including the Timestamp, which is also regarded by default, if not specified otherwise) which gets encrypted afterwards. Encryption is done by using the private Key of a Key-Pair, whose alias name is also defined within the Policy File – the underlying Keystore is configured via Spring-WS’ application config, which in turn is passed to the responsible XWSSProcessor. The encrypted Hash is in fact the digital Signature which is embedded within the outgoing message. In order to give the receiver a chance to detect some unwanted payload manipulation, it will also build a Hash, also based on the payload and Timestamp. To compare that Hash with the digital Signature which is embedded within the message, the receiver has to decrypt the Signature again. This can only be done with the related Public Key (contained within the clients certificate) which therefore also has to be passed to the receiver. Once you’ve retrieved the certificate (also embedded within the message), you can perform whatever kind of logic you want to do based on the client certificate (as seen in episode two).

That’s it

You’ve seen how to configure Certificate Authentification using Spring-WS on client and server side and hopefully got some introduction to the underlying ideas like Message Signing, Certificate Authorities and Public Key Infrastructure.
Of course, Certificate Authentification might only be a reasonable instrument for some use cases which heavily rely on
some given Security concerns.
As always, you have to be clear about your projects goals, the given Security context your WebService is acting in and the knowledge about the given trade offs (extended configuration vs. increased Security) and consequences when leveraging WS-Security using Certificate Authentification.
Maybe this series could gave some useful information on that topic or at least some helpful suggestions.

About these ads

16 Responses to “WS-Security using Cert Authentication with Spring-WS V: How to implement a Message Signing Client”

  1. Morag Says:

    First blog I read after wakeup from sleep today!

    —————————-

  2. A Gambler Says:

    Well writen, really!

  3. Cross Site Scripting » Blog Archive » Ws-Security Using Cert Authentication with Spring-Ws V: How To … Says:

    [...] Both Dependencies will be injected into XwssMessageSigner via constructor injection (as we’ll see later). Inside the WebServiceMessageCallback, we’ll receive the original message in a state just before sending it to the receiver. …Continue Reading… [...]

  4. Cheap Airline Tickets Says:

    Niсе blоg! It’s a pitу thаt thеrе’s nоt а lot of commеnts. Best rеgards, Cheap airline tickets

  5. Flex bath house Says:

    Seems good to me.

  6. angelborroy Says:

    I’m developing a Web Service client using Spring WS 1.0.3 and XWSS 3.0 against WebSphere 6.1. It works fine with XMLBeans 2.3 marshalling, but Castor 1.1.1 marshalling generates following error:

    [com.ibm.wsspi.wssecurity.SoapSecurityException: WSEC5620E: Error verifying signature]

    The code is just the same for both test, just only changing Marshaller and Unmarshaller setter.

    Maybe I’m missing something?

    Thanks in advance.

  7. Slbruce Says:

    Hi

    This has been a fantastic series of articles. However I am stuck on adding encryption to the equation. The moment I add on the client side I receive different errors such as X509 Certificate Not found.

    Would it be possible to add a new installment of this excellent series to help with this problem or give me some pointers?

    Thanks

  8. sridhar Says:

    just excellant write-up. I read the whole 5 parts of the article in one sitting.

    really well written (wish i could do write such articles).

    Thanks a lot !!!

  9. Alfredo Says:

    Thank you for the excellent series of articles. Are very comprehensive and well written.

    Just a question:
    You said in this article “Although Message Signing can be done more or less completely by configuration…”.
    Could you please include how this configuration could be done?

    Thanks a lot.

  10. josh Says:

    Thanks a heap for this article.

    Can you attach the contents of the securityPolicy.xml file of the server and the client. It is not clear to me how to set up this file. What properties you defined in the file and how did you specify what hashing technique is to be used for hashing the message to be encrypted by the client and also at the server end for comparing with the decrypted hash message. This is the missing information to me. As a newbie it would help if you also add the contents of both securityPolicy.xml files for both the client and server.

  11. Alx P Says:

    This articles have been really clear and usefull to me.

    I’m wondering if could you write an article about working with certificate encryption and managing several concurrent clients??

    Thanks a lot!!

  12. Kandhla Venkat Reddy Says:

    nice article about message signing.

  13. Manav Says:

    I am also implementing Spring WS security using XWS but I am getting an exception : “Cannot create inner bean ‘wsSecurityInterceptor’ of type [org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor] while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘wsSecurityInterceptor’ defined in ServletContext resource [/WEB-INF/spring-ws-servlet.xml]: Invocation of init method failed; nested exception is com.sun.xml.wss.XWSSecurityException: org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element ‘xwss:SecurityConfiguration’.” I am using JDK1.6 in NetBeans. Can you please let me know if XWS works with JDK1.6

  14. Sathish Murugesan Says:

    Wonderful Article about webservices security using certification authentication

  15. mansionsforsaleinlondon.com Says:

    Thank you for every other fantastic article. The place else
    may anyone get that kind of info in such a perfect means
    of writing? I’ve a presentation subsequent week, and I’m on the look for
    such info.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 42 other followers

%d bloggers like this: