Showing posts with label WS-Security. Show all posts
Showing posts with label WS-Security. Show all posts
, , , , , ,

Spring WS 2: Client-side WS-Security Using WSS4J

In this tutorial we will implement a client-side WS-Security using WSS4J. We will based our client application on an existing web service client which can be found at Spring WS - MVC: Implementing a Client Tutorial. It's imperative that you've read that first to understand the client application.

Our web service provider will be based from the Spring-WS 2: WS-Security Using WSS4J tutorial. We can also use the web service provider from the Spring-WS 2: WS-Security Using XWSS tutorial. This means you will be required to setup two servers with different ports, i.e two Tomcat instances (which is trivial to setup in Eclipse), one for the client and one for the provier. This also means you've read those articles first to understand what security tokens are required from the client.

We actually just need to edit a single file from our current web service client, the spring-ws.xml config. I'll show you the new config and the old config for comparison purposes.

Here's the new config:

spring-ws.xml (new)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:sws="http://www.springframework.org/schema/web-services"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/web-services
http://www.springframework.org/schema/web-services/web-services-2.0.xsd
http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd">

<!--
* The WebServiceTemplate requires a messageSender and messageFactory
* In order to facilitate the sending of plain Java objects, the WebServiceTemplate requires a marshaller and unmarshaller.
* The WebServiceTemplate class uses an URI as the message destination.
See: http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template
-->
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"
p:marshaller-ref="jaxbMarshaller"
p:unmarshaller-ref="jaxbMarshaller"
p:defaultUri="http://localhost:8081/spring-ws-wss4j/krams/ws"
p:messageSender-ref="messageSender">
<constructor-arg ref="messageFactory"/>
<property name="interceptors">
<list>
<ref local="wss4jSecurityInterceptor"/>
</list>
</property>
</bean>

<!--
References
Chapter 7. Securing your Web services with Spring-WS
- http://static.springsource.org/spring-ws/sites/2.0/reference/html/security.html
7.3. Wss4jSecurityInterceptor
- http://static.springsource.org/spring-ws/sites/2.0/reference/html/security.html#security-wss4j-security-interceptor
Apache WSS4J
- http://ws.apache.org/wss4j/
Example of SOAP request authenticated with WS-UsernameToken
- http://stackoverflow.com/questions/3448498/example-of-soap-request-authenticated-with-ws-usernametoken -->
<!-- This is not documented in the Spring WS Reference but the API shows that we can add interceptors -->
<bean id="wss4jSecurityInterceptor"
class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<!-- The web service provider requires us to pass a timestamp,
username, and password -->
<property name="securementActions" value="Timestamp UsernameToken" />
<property name="securementUsername" value="admin" />
<property name="securementPassword" value="secret" />
<!-- When the web service replies, it will send a timestamp,
username, and password as well. We want to verify that it is still
the same provider -->
<property name="validationActions" value="Timestamp UsernameToken"/>
<property name="validationCallbackHandler" ref="callbackHandler" />
</bean>

<!-- Simple callback handler that validates passwords against a in-memory Properties object.
Password validation is done on a case-sensitive basis -->
<bean id="callbackHandler" class="org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler">
<property name="users">
<props>
<prop key="mojo">mojopass</prop>
<prop key="user">pass</prop>
</props>
</property>
</bean>

<!--
There are two implementations of the WebServiceMessageSender:
HttpUrlConnectionMessageSender and CommonsHttpMessageSender.

The CommonsHttpMessageSender provides advanced and easy-to-use functionality
(such as authentication, HTTP connection pooling, and so forth).
This uses the Jakarta Commons HttpClient.
See http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template
-->
<bean id="messageSender" class="org.springframework.ws.transport.http.CommonsHttpMessageSender"/>

<!--
There are two message factories for SOAP: SaajSoapMessageFactory and AxiomSoapMessageFactory.
If no message factory is specified (via the messageFactory property), Spring-WS will use
the SaajSoapMessageFactory by default.
See: http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template
-->
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<!-- Here we use the Jaxb2 marshaller to marshall and unmarshall our Java objects -->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"
p:contextPath="org.krams.tutorial.oxm"/>

</beans>

Here's the old config:

spring-ws.xml (old)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:sws="http://www.springframework.org/schema/web-services"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/web-services
http://www.springframework.org/schema/web-services/web-services-2.0.xsd
http://www.springframework.org/schema/oxm
http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd">

<!--
* The WebServiceTemplate requires a messageSender and messageFactory
* In order to facilitate the sending of plain Java objects, the WebServiceTemplate requires a marshaller and unmarshaller.
* The WebServiceTemplate class uses an URI as the message destination.
See: http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template
-->
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate"
p:marshaller-ref="jaxbMarshaller"
p:unmarshaller-ref="jaxbMarshaller"
p:defaultUri="http://localhost:8081/spring-ws-standalone/krams/ws"
p:messageSender-ref="messageSender">
<constructor-arg ref="messageFactory"/>
</bean>

<!--
There are two implementations of the WebServiceMessageSender:
HttpUrlConnectionMessageSender and CommonsHttpMessageSender.

The CommonsHttpMessageSender provides advanced and easy-to-use functionality
(such as authentication, HTTP connection pooling, and so forth).
This uses the Jakarta Commons HttpClient.
See http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template
-->
<bean id="messageSender" class="org.springframework.ws.transport.http.CommonsHttpMessageSender"/>

<!--
There are two message factories for SOAP: SaajSoapMessageFactory and AxiomSoapMessageFactory.
If no message factory is specified (via the messageFactory property), Spring-WS will use
the SaajSoapMessageFactory by default.
See: http://static.springsource.org/spring-ws/sites/2.0/reference/html/client.html#client-web-service-template
-->
<bean id="messageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory"/>

<!-- Here we use the Jaxb2 marshaller to marshall and unmarshall our Java objects -->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"
p:contextPath="org.krams.tutorial.oxm"/>

</beans>

Notice we still have the same basic bean declaration:
webServiceTemplate
messageSender
messageFactory
jaxbMarshaller

However the webServiceTemplate bean now has a reference to the interceptors property:
<property name="interceptors">
<list>
<ref local="wss4jSecurityInterceptor"/>
</list>
</property>
This is the property that's responsible for all the client-side WS-Security using WSS4J. It's really a simple addition to our existing web service client.

We also have to modify the defaultUri to match our current web service provider:
http://localhost:8081/spring-ws-wss4j/krams/ws
You may need to modify this property depending on how you setup your provider.

The Client-side WSS4J WS-Security
Let's examine further the wss4jSecurityInterceptor bean. Notice it contains a couple of properties. If you have read the Spring-WS 2: WS-Security Using WSS4J, you will find the following settings familiar because we're using the same exact interceptor!

<bean id="wss4jSecurityInterceptor"
class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<!-- The web service provider requires us to pass a timestamp,
username, and password -->
<property name="securementActions" value="Timestamp UsernameToken" />
<property name="securementUsername" value="admin" />
<property name="securementPassword" value="secret" />
<!-- When the web service replies, it will send a timestamp,
username, and password as well. We want to verify that it is still
the same provider -->
<property name="validationActions" value="Timestamp UsernameToken"/>
<property name="validationCallbackHandler" ref="callbackHandler" />
</bean>

<!-- Simple callback handler that validates passwords against a in-memory Properties object.
Password validation is done on a case-sensitive basis -->
<bean id="callbackHandler" class="org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler">
<property name="users">
<props>
<prop key="mojo">mojopass</prop>
<prop key="user">pass</prop>
</props>
</property>
</bean>
The configuration defines policies pertaining to client-side WS-Security. It contains two parts:

1. The elements that the client must provide when sending a request message.
  • securementActions: When the client sends a message, a Timestamp and UsernameToken elements (including the username and password) will be added in the SOAP Header section.
  • securementUsername: The username that the provider expects
  • securementPassword: The password that the provider expects

2. The elements that the provider must provide when sending a response message.
  • validationActions: When the provider sends a reply, it should contain the actions we specified in the validationActions. If it doesn't contain the actions, then the reply is invalid. For our current configuration, we expect a Timestamp and UsernameToken as well from the provider. This is like a dual verification on both sides. The provider requires a Timestamp and UsernameToken. The client requires the same
  • validationCallbackHandler: When the provider sends a reply, it adds a username and password attributes. To validate these values in the client-side, we provide a callback handler, a SimplePasswordValidationCallbackHandler (see below) . In our current configuration, the client expects that the provider will send either of the following username/password pair:
    mojo/mojopass
    user/pass
<bean id="wss4jSecurityInterceptor"
<!-- Simple callback handler that validates passwords against a in-memory Properties object.
Password validation is done on a case-sensitive basis -->
<bean id="callbackHandler" class="org.springframework.ws.soap.security.wss4j.callback.SimplePasswordValidationCallbackHandler">
<property name="users">
<props>
<prop key="mojo">mojopass</prop>
<prop key="user">pass</prop>
</props>
</property>
</bean>

Run the Client Application
Let's run our client application and examine the actual SOAP request message sent by the client:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" SOAP-ENV:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-2" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>admin</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">1pN5RLpgXRhZxlYwHovlstf75do=</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">TOvp53qb3mPvX4YMi+Ac8g==</wsse:Nonce>
<wsu:Created>2011-01-13T14:17:59.486Z</wsu:Created>
</wsse:UsernameToken>
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-1">
<wsu:Created>2011-01-13T14:17:59.473Z</wsu:Created>
<wsu:Expires>2011-01-13T14:22:59.473Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns2:subscriptionRequest xmlns:ns2="http://krams915.blogspot.com/ws/schema/oss">
<ns2:id>1234567</ns2:id>
<ns2:name>John Smith</ns2:name>
<ns2:email>john@dummy.com</ns2:email>
</ns2:subscriptionRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Notice the SOAP Header has been augmented with a Timestamp and UsernameToken including the username and password: admin/(encrypted password). A Nonce and Created date has been added as well.

Run the Provider Application
Let's run our web service provider and examine the actual SOAP reply message sent by the provider:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" SOAP-ENV:mustUnderstand="1">
<wsse:UsernameToken xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="UsernameToken-3" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:Username>mojo</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">mojopass</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">wVExJqRYGv9tYq8YUGkFyw==</wsse:Nonce>
<wsu:Created>2011-01-13T14:24:17.026Z</wsu:Created>
</wsse:UsernameToken>
<wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Timestamp-2">
<wsu:Created>2011-01-13T14:24:17.018Z</wsu:Created>
<wsu:Expires>2011-01-13T14:29:17.018Z</wsu:Expires>
</wsu:Timestamp><wsse11:SignatureConfirmation xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="SigConf-1"/>
</wsse:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<subscriptionResponse xmlns="http://krams915.blogspot.com/ws/schema/oss">
<code>SUCCESS</code>
<description>User has been subscribed</description>
</subscriptionResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>"

Notice the SOAP Header has been augmented with a Timestamp and UsernameToken including the username and password: mojo/mojopass. A Nonce and Created date has been added as well. These properties are exactly the same in both the provider and the client.

However, do not be mistaken. Our client application can also access XWSS-based web service providers! Just make sure you've set the correct URI. If you like to test this, feel free to run the provider application from Spring-WS 2: WS-Security Using XWSS tutorial.

That's it. We've completed our client-side WS-Security application using WSS4J. It's amazing how we enabled security on the client side. We just added a simple Wss4jSecurityInterceptor (the same bean we used in the provider application) and everything is running smoothly.

To run the client application, use the following URL:
http://localhost:8080/spring-ws-client-wss4j/krams/main/subscribe

Here's a screenshot of the client application:

The best way to learn further is to try the actual application

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-ws-2-0-0-rc2-tutorial/

You can download the project as a Maven build. Look for the spring-ws-client-wss4j.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.
Continue reading Spring WS 2: Client-side WS-Security Using WSS4J
, , , , , , , , ,

Spring-WS 2: WS-Security Using XWSS

In this tutorial we will explore how to add WS-Security using XWSS in an existing Spring-WS application. We will secure our web service using Spring's XwsSecurityInterceptor. In the client-side, we will use soapUI to verify the results.

What is WS-Security?
WS-Security (Web Services Security, short WSS) is a flexible and feature-rich extension to SOAP to apply security to web services. It is a member of the WS-* family of web service specifications and was published by OASIS.

The protocol specifies how integrity and confidentiality can be enforced on messages and allows the communication of various security token formats, such as SAML, Kerberos, and X.509. Its main focus is the use of XML Signature and XML Encryption to provide end-to-end security.

WS-Security describes three main mechanisms:
  • How to sign SOAP messages to assure integrity. Signed messages provide also non-repudiation.
  • How to encrypt SOAP messages to assure confidentiality.
  • How to attach security tokens.
Source: Wikipedia (http://en.wikipedia.org/wiki/WS-Security
)

To view the official specification please visit OASIS Web Services Security (WSS) TC

What is XWSS?
XWSS stands for XML and Web Services Security. This is a SUN's implementation of WS-Security, which is part of the Java Web Services Developer Pack

Source: Spring WS 2.0 Reference (paraphrased due to lack of official definition)
As mentioned earlier, we will be adding security to an existing unsecured web service using Spring's XwsSecurityInterceptor. This web service is available at the following tutorial Spring WS 2 and Spring 3 MVC Integration Tutorial.

What is XwsSecurityInterceptor?
The XwsSecurityInterceptor is an EndpointInterceptor (see Section 5.5.2, “Intercepting requests - the EndpointInterceptor interface”) that is based on SUN's XML and Web Services Security package (XWSS). This WS-Security implementation is part of the Java Web Services Developer Pack (Java WSDP).

Note that XWSS requires both a SUN 1.5 JDK and the SUN SAAJ reference implementation.
Source: Spring WS 2.0 Reference
We will not recreate the whole web service. We'll just focus on what needs to be added to enable an XWSS-based security.

Open the spring-ws.xml file and replace it with the following configuration:

spring-ws.xml

Actually we don't need to replace everything. What we did is add a XwsSecurityInterceptor inside the sws-interceptors element:

Then we declared a bean SimplePasswordValidationCallbackHandler referenced as callbackHandler:

Inside the XwsSecurityInterceptor we referenced a securityPolicy.xml, which is located an the WEB-INF/ folder:

The securityPolicy.xml contains a list of actions to be performed when an incoming message has arrived. This is marked by the RequireXXXXXX elements. The RequireTimestamp and RequireUsernameToken means that the web service expects an Timestamp and UsernameToken from the incoming message. If these don't exist, an exception is thrown.

When the web service replies back, it will add a timestamp and username tokens as well. This is indicated by the elements xwss:Timestamp and xwss:UsernameToken.

Now let's test our web service using soapUI.

What is soapUI?
soapUI is the world's leading Web Service Testware. With over 2 million downloads, it's the de facto tool for SOA testing.

Source: http://www.eviware.com/soapUI/soapui-products-overview.html

It's also mentioned as one of the tools for testing Spring-WS applications:
These tools can help you test your Web service applications.

- soapui is a desktop application for inspecting, invoking and testing (functional and load) of web services over HTTP.
- the WS-I testing tools, which make sure your Web service is interoperable.
- Axis Tcpmon is a monitoring tool which allows you to see the XML as it is sent and received across the wire.

Source: http://static.springsource.org/spring-ws/sites/2.0/resources.html

Follow the steps below to perform a test:
1. Open soapUI.

2. Create a new soapUI project:

3. Open the project and create a new request:

4. On the right side window, you should see a request template. To add a WSS UsernameToken or Timestamp, right-click on the request and select Add WSS UsernameToken or Add WSS Timestamp.

5. To send the message, hit the Submit button (the green arrow).

Using soapUI we send the following SOAP message:

Our web service responds back with the following SOAP message:

If we remove the Timestamp element from the client, the web responds back with an exception:

If we remove the UsernameToken instead, the web service replies:

If the username or password is incorrect, we get the following exception instead:


Our web service has been secured but this doesn't mean it's fool-proof. Security is a serious and complicated matter. There are many numerous variables that needs to be considered. By adding security in our web service we have lessened the risk of being exposed. But remember no matter how small is the risk, it's still a risk.

To access the web service, use the following endpoint in soapUI:
http://localhost:8080/{project name}/krams/ws
where {project name} is either spring-ws (if you're using the sample application from the other tutorial) or spring-ws-xwss (fi you're using the sample application at the end of this tutorial).

The best way to learn further is to try the actual application.

Download the project
You can access the project site at Google's Project Hosting at http://code.google.com/p/spring-ws-2-0-0-rc2-tutorial/

You can download the project as a Maven build. Look for the spring-ws-xwss.zip in the Download sections.

You can run the project directly using an embedded server via Maven.
For Tomcat: mvn tomcat:run
For Jetty: mvn jetty:run

If you want to learn more about Spring MVC and integration with other technologies, feel free to read my other tutorials in the Tutorials section.

For an in-depth look of the XWSS Security Configuration file (including all possible elements) , please visit the following link What is the XWS-Security Framework?

Related OASIS Specification and References:
- WS-Security Core Specification 1.1
- Username Token Profile 1.1
- To see the complete list, visit http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=wss
Continue reading Spring-WS 2: WS-Security Using XWSS