How to secure a WebService using Spring-WS and Certificate Authentication

Implementing a plain WebService with Spring-WS is rather easy and straight forward: Following the ‘contract first‘ approach, you mainly have to come up with an xsd schema for defining the types and elements, constituting
the structure of your request and response messages (including the so called wrapper elements which are in compliance with the WS-I Basic Profile and also used to designate the different operations offered by the
WebService). The rest (not REST ;o)) is more or less a matter of configuration.

A simple configuration could look like the following example (extract):

...
<beans>
  <bean id="payloadMapping"
        class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="mappings">
<props>
<prop key="{http://www.mg-informatik.de/ws/auction}PlaceBidRequest">placeBidEndpoint</prop>
<prop key="{http://www.mg-informatik.de/ws/auction}CancelBidRequest">cancelBidEndpoint</prop>
        ...
      </props>
    </property>
    ...
  </bean>

  <bean id="placeBidEndpoint" ... />
  <bean id="cancelBidEndpoint" ... />
  ...
</beans>

I assume that you have some basic knowledge on how to set up a WebService based on Spring-WS. Since there are many great Resources on how to construct a WebService using Spring-WS out there, i’m not going into greater details here.
Instead, i will focus on how to secure such a given WebService using Certificate Authentification, since i haven’t found any detailed information on that specific topic. There are some good examples on how to secure WebServices using plain Text Username Authentication or Digest Username Authentication, but regarding Certificate Authentication, i had to wade through some deeper swamps of security related stuff while applying its Security model to my Services.

This entry will be the first one within a series, providing a step by step tutorial on how to secure a WebService based on Spring-WS using Certificate Authentification. We will not only secure our WebService, but also implement an appropriate WebService-Client which will adhere to the given security constraints, (also using Spring-WS and
its WebServiceTemplate).
The series will provide some basic security concepts like ‘Public Key Infrastructure’, ‘Message Signing’, ‘WS-Security’ and the like. Therefore it will not only show you how to extend Spring-WS’ application context for ‘WebService-Security’ (mainly within this post), but also give detailed step by step instructions on how to work with OpenSSL and Java Keystores in order to properly set up and supply the needed infrastructure to Spring-WS.

Libraries

Spring-WS provides two different implementations for securing your WebServices. One is based on Apache’s WSS4J.
I will use SUN’s WS-Security implementation – the XML and Web Services Security package (XWSS), which is part of the Java Web Services Developer Pack (Java WSDP).

All in all, you have to add the following Libraries to your classpath for proper work with XWSS:

  • xmlsec-2.0.jar (provided with Spring-WS with dependencies)
  • xws-security-2.0-FCS.jar (provided with Spring-WS with dependencies)
  • spring-security-core-2.0.2.jar (provided with Spring-WS with dependencies)
  • xmldsig-1.0.jar (provided within Java WSDP)
  • saaj-api.jar
  • saaj-impl.jar

Finally, XWSS requires SUN 1.5 JDK, so be sure to comply with the given conditions at Runtime.

Security Interceptor

In order to activate WS-Security, we have to add a so called Security Interceptor to our Endpoint Mapping(s). As the name says, every request to these endpoints gets intercepted and validated due to some security constraints (which we also have to configure).
Adding a Security Interceptor is as easy as adding any other Endpoint Interceptor:

...
<bean id="payloadMapping"
      class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="mappings">
     ...
  </property>
<property name="interceptors">
	<list>
      <ref local="wsSecurityInterceptor"/>
    </list>
  </property>
</bean>

<bean id="wsSecurityInterceptor"
      class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
  ...
</bean><
...
&#91;/sourcecode&#93;

As you can see, we added bean <em>wsSecurityInterceptor</em> as a new Interceptor to our Endpoint mapping and used class
<em>XwsSecurityInterceptor </em>as its implementation.
<h3>Security Policies</h3>
We now have to define some concrete Security Policies, which will tell our Security Interceptor what constraints to put on incoming requests (and - if wanted - also for outgoing responses).

Let's say we need the clients <a title="certificate" href="http://en.wikipedia.org/wiki/Public_key_certificate&#93;" target="_blank">certificate</a> (or at least some identity information that is bound to the clients public key within the certificate) for some custom authentication or authorisation purposes, so we want our Security Interceptor to check every incoming Message, if there's a so called Security Header present (placed inside the <a title="SOAP" href="http://www.w3.org/TR/soap/" target="_blank">SOAP</a>s Message Envelope), which will contain at least the clients certificate
Every Request Message which doesn't comply with that policy will be rejected by the Security Interceptor.

In case of using <em>XwsSecurityInterceptor</em>, we can configure those Security Policies by injecting an appropriate xml file
(let's name it <em>securityPolicy.xml</em>) to its property <em>policyConfiguration</em>:


<bean id="wsSecurityInterceptor"
      class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
<property name="policyConfiguration" value="/WEB-INF/securityPolicy.xml"/>
  ...
</bean>

Message Signing

Our goal is to force clients to include their certificate within the Request Message – for more than one reason:
As said, we may want to retrieve some identity information (e.g. the Common Name of the client) from the clients certificate for further processing.
Concerning WS-Security, we also want to allow only a group of accredited clients to utilise our WebService – access should be denied for all other ‘unknown’ clients (we’ll get back to that topic when looking at the Public Key Infrastructure (PKI) in greater detail).

In order to force clients to put their certificate into the request message, we have to take a little ‘detour’: Message Signing. Message Signing is a way to guarantee data integrity for the message content (mainly its payload), ensuring that the payload isn’t altered (un)intentionally by a third party (while the message may be on its way from client to server).
This is done by adding a Digital Signature to the message. In short, a hash is built based on the message body (so that any alteration of the content would result into a different hash) and is then turned into its final form – the digital Signature – by encrypting the hash value using the Signers Private Key.
The receiver of the message will also calculate the hash from the message body and compare it to the hash value that is transmitted within the message (if the message isn’t altered, they must be equal).
In order to read the transmitted hash value, the receiver has to decrypt it now, which can be done with the Signers (which is the client of our WebService) public key.
Hence, the clients public key have to be passed along with the digital Signature within the message, too. This is done in form of the clients certificate (which contains the clients public key).

Consequently, if we want to configure our Security Interceptor forcing clients to pass their certificate, we have to ‘activate’ Message Signing.
This can be done by providing the following security configuration within our security policy file (securityPolicy.xml):

<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config">
  <xwss:RequireSignature requireTimestamp="true" />
</xwss:SecurityConfiguration>

As you may have noticed, we’ve also required to add a Timestamp within the security Header of the message, so that a timestamp must be included in the signature of the incoming message.

Accredited Clients, Certificate Chains and Truststores

So far, we only accept signed Messages which – in accordance to that fact – have to carry the Signers certificate, too.
Hence, every potential client could use our WebService simply by creating an arbitrary Key-Pair (a private key with its associated public key).
It would be no problem to come up with a ‘self made’ certificate of that public key (which is self signed in that case), so that we could generate a signed message (using the clients private key), including the related, self signed certificate and still statisfy our security policy.

Now, if we only want to allow a small set of ‘accredited’ clients to use our WebService (and reject all other client calls), we have to be able to detect if a certain client is in fact accredited. To do so, we have to ‘tag’ those certificates that belong to the ‘good’ clients. This ‘Tagging’ is achieved by signing the clients certificate by a so called Certificate Authority (CA) we trust (we’ll take a detailed look on how to create a CA Key-Pair and signing a client certificate in one of the following parts of this tutorial).
In effect, we trust all clients from which we’ll receive incoming messages that contain a certificate which itself is signed by the CA we trust. The idea to ‘trust’ a client whose certificate is signed by another certificate that we finally trust is called ‘Certificate Chaining‘. In fact, you could have a Certificate Chain of an arbitrary depth. In case of validating WebServices with Spring-WS, it’s ‘recommended’ to rely on a direct chain between the CA and the client certificate (in that the client certificate is directly signed by the CA).

The only thing left is to tell Spring-WS where to find the CA certificate that we trust (whose digital signature have to be embedded within the clients certificate as its Signer, in order to recognize them as accredited). Therefore we have to provide a so called Truststore (a common Java Keystore) where we have to import the CA’s certificate. Now, whenever a message arrives, the included client certificate is tested, in that it have to be signed by the trusted CA certificate which is contained within the given Truststore.
For that purpose, we have to extend the configuration of our Security Interceptor, in that we provide a so called KeyStoreCallbackHandler, which points to the accordant Truststore:

<bean id="wsSecurityInterceptor"
      class="org.springframework.ws.soap.security.xwss.XwsSecurityInterceptor">
<property name="policyConfiguration" value="/WEB-INF/securityPolicy.xml"/>
<property name="callbackHandlers">
	<list>
      <ref bean="keyStoreHandler"/
    </list>
  </property>
</bean>

<bean id="keyStoreHandler"
      class="org.springframework.ws.soap.security.xwss.callback.KeyStoreCallbackHandler">
<property name="trustStore" ref="trustStore"/>
</bean>

<bean id="trustStore"
      class="org.springframework.ws.soap.security.support.KeyStoreFactoryBean">
<property name="location" value="/WEB-INF/MyTruststore.jks"/>
<property name="password" value="MyJavaKeyStorePassword"/></pre>
<pre></bean>

That’s it, considering Spring-WS configuration in order to secure our WebService.

Summary

Incoming request messages may get intercepted by a Security Interceptor, which is configured by an appropriate Security Policy. In order to achieve Certificate Authentification we have to require Message Signing, which automatically force the client to include its certificate into the message, so that the receiver is able to decrypt the digital Signature in order to retrieve and compare the payloads hash value.
If we want to restrict access to our WebService to a limited set of accredited clients, their certificate have to be signed by a CA we trust. We inform the Security Interceptor about that trusted CA in that we place the CAs certificate in a Java Keystore which is then introduced to our Security Interceptor as a so called Truststore.

One last fact that might be noteworthy is the level of processing Certificate Authentification, which is completely done at message level, not at transport level! For this is the case, you can call the secured WebService via ordinary http. It’s completely decoupled from Certificate Authentification that might be applied at transport level, when using secured http connections via SSL (maybe in order to ‘hide’ the transmitted request message on its way from client to server from the eyes of a third party).

So far, we only looked at the configuration details for Spring-WS on the server side. In the next parts, we’ll extend our WebService in oder to retrieve some of the clients certificate content (like the certificates Common Name, e.g. for the sake of authorisation) and take a closer look on how to set up our needed Public Key Infrastructure, e.g. how to create a CA Key-Pair with OpenSSL and import the related CA certificate into a Java KeyStore (which will act as the TrustStore).
On a further episode, we’ll see on how to sign a client certificate with the CAs private Key, how to prepare the clients Keystore to work with that signed certificate and of course how to write a WebService-Client that will sign its request messages accordingly (also using Spring-WS) and call our secured WebService.

Advertisements

21 Responses to “How to secure a WebService using Spring-WS and Certificate Authentication”

  1. Ron Says:

    Thanks for that fantastic explanation as i’ve also searched the web for exactly that kind of information without success.

    I’m desperately looking forward to your next episodes! Please don’t let us wait to long!

    Greetings

    Ron

  2. Technology » Blog Archive » How To Secure a Webservice Using Spring-Ws and Certificate … Says:

    […] It’s completely decoupled from Certificate Authentification that might be applied at transport level, when using secured http connections via SSL (maybe in order to ‘hide’ the transmitted request message on its way from client to server …[Continue Reading] […]

  3. WS-Security using Cert Authentification with Spring-WS II: Accessing the certificate « brain driven development Says:

    […] Spring-WS II: Accessing the certificate January 22, 2009 — Mario Gleichmann In the last episode, we’ve introduced the Security Interceptor and its Collaborators (KeyStoreHandler, […]

  4. Timur I. Alhimenkov Says:

    Great! Thank you!
    I always wanted to write in my site something like that. Can I take part of your post to my site?
    Of course, I will add backlink?

    Sincerely, Timur I.

  5. Mario Gleichmann Says:

    Timur,

    thanks for your feedback.

    I’ve got no problems if you want to refer to this post within your articles. Just go ahead :o)

    Greetings

    Mario

  6. WS-Security using Cert Authentication with Spring-WS III: Setting up the Security infrastructure « brain driven development Says:

    […] the first episodes, we configured Spring-WS for rejecting incoming Messages which were sent from […]

  7. Alexwebmaster Says:

    Hello webmaster
    I would like to share with you a link to your site
    write me here preonrelt@mail.ru

  8. troll Says:

    Great tutorial! Although I have just another request… can you provide some guidelines refering to the securityPolicy.xml file? I’m new with all this things and besides this I’m kind of short with time :D. 10q best regards.

  9. troll Says:

    Sorry…before I just parsed the page.

  10. Anonymous Says:

    Can you share some sample application for the security implementation which would give more roof to undertand the concept.

    Thanks,
    Santhosh

  11. Nelutu Sabau Says:

    Here ( http://forum.springsource.org/showthread.php?t=72858 ) you will find further discussions on the topic. Also one of the responds has attached also an
    example.

    Cheers

  12. abc Says:

    will you plz share the source here..

  13. Mike Says:

    Yeah, XWSS is really great.
    Just debugged a couple of hours to find out the xws-security-2.0-FCS.jar has a Thread/TimerTask/ClassLoader leak which will prevent your webapps from shutting down cleanly. Thanks, Sun 😦

  14. Asaf Says:

    Spring Web Services seems to miss out on the fantastic code generation and annotation provided by JAX-WS. How can that be?
    Is there any way to specify EndPointInterceptor for authentication while using JAX-WS?

  15. Hugo Says:

    Hi I just wanted to say thank you for the fantastic explanation you just have cleared my mind.

  16. Antonio Gomez Says:

    Fantastic !!! Thanks for your great articles….

  17. Doraz Says:

    This is great! Do you happen to have the client-side code as well? Running into issues w/ signing the request with XWS Security Configuration:

    And I get this exception:

    [XwsSecurityInterceptor] Could not validate request: com.sun.xml.wss.XWSSecurityException: More Receiver requirements [ SignaturePolicy ] specified than present in the message; nested exception is com.sun.xml.wss.XWSSecurityException: com.sun.xml.wss.XWSSecurityException: More Receiver requirements [ SignaturePolicy ] specified than present in the message

  18. Anonymous Says:

    Please enter a comment

  19. Anonymous Says:

    Can you please create a download link for this as a maven project?

  20. Certificate Authentication Says:

    Thanks for your marvelous posting! I quite enjoyed reading it, you are a great author.I will be sure to bookmark your blog and definitely will come back from now on. I want to encourage that you continue your great job, have a nice day.

  21. 数字证书的原理与实现 | Life in USA Says:

    […] HERE is a good series of how to secure webservice […]


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

%d bloggers like this: