Secure Metro JAX-WS UsernameToken Web Service with Signature, Encryption and TLS (SSL)
Java Web Services Security: How to Secure JAX-WS UsernameToken Web Service with Signature, Encryption and TLS (SSL)
Securing the data exchanged between web service producers and consumers is essential to ensure confidentiality, authenticity and integrity of critical business data. There are many approaches to implement Web Service Security (WSS) popularly called as WS-Security. WS-Security is an extension to SOAP to apply security to web services.
Table of Contents
- Web Service Security.
- Symmetric Binding Security Assertion.
- The UsernameToken Profile and WSS Security
- Development Tools Required
- Setup the TLS (SSL) Configurations on Web Server
- Securing Web Applications in Web.xml
- Secure Web Service Implementation.
- Web Service SEI and Implementation and Password validator
- sun-jaxws.xml
- Service WSIT Policy Configuration For Secure UsernameToken Profile
- WSDL of Secure Signed and Encrypted UsernameToken MyService Service
- Secure Web Service “MyService” Client with Signed and Encrypted UsernameToken
- The Service Consumer class
- The Callbackhandler class
- The WSIT Client Configuration files for Signed and Encrypted UsernameToken Profile
- Utility Servlet Web Component
- Web.xml
- The Request and Response samples
- References
Web Service Security
In a point-to-point situation, web service security aspects such as confidentiality and data integrity can be enforced on Web services, through the use of Transport Layer Security (TLS). Here the messages are sent over HTTPS.
In our previous example, we discussed message authentication using UsernameToken as a WS-Security mechanism. There neither we configured SSL to use transport level Security nor we encrypted or signed the authentication tokens. Sending cleartext username and password is not advisable on production environment.
The Message Authentication over SSL mechanism attaches a cryptographically secured identity or authentication token with the message and use SSL for confidentiality protection.
Symmetric Binding Security Assertion
In this article, we will see how we implement UsernameToken message authentication over SSL. We use the Symmetric binding security assertion to secure message exchanges. We also use transport binding assertion, since we use HTTPS as the message exchange transport medium.
When a symmetric binding is used, only one party needs to generate the security tokens. A symmetric key is established and using that security token further signing and encrypting is done. The symmetric binding can be used when only the server possesses a X509Token. Here, the client or consumer or initiator first creates an ephemeral key and then creates an encrypted key encrypting that ephemeral key using the recipient’s public key. In Other words the symmetric key is generated by initiator and is encrypted for recipient using recipient’s public key. Then this symmetric key is used by both initiator and recipient to sign and encrypt the messages back and forth. See the reference section to read more about WS Security Policy Language and Security Policy Assertions.
The UsernameToken Profile and Web Service Security
It is a good idea to understand the basics of UsernameToken and how it is used as a method to achieve Web service Security. I strongly recommend reading the following article before starting this excercise.
Remember, unless password text or digested password is sent on a secured channel or the token is encrypted, neither password digest nor cleartext password offers no real additional security. The Web Services Security UsernameToken Profile 1.1 recommends that web service producers reject any UsernameToken not using both nonce and creation timestamps or with stale timestamps(to secure from replays) or with invalid tokens.
In our example we will sign and encrypt the tokens and will send the message over secure HTTPS connection. We use Tomcat web container to deploy and test the application.
Development tools required:
- Eclipse IDE
- Metro distribution
- JDK7
- Tomcat 6 or above
If you have Netbeans IDE, generation of WSIT policy files are pretty easy. The IDE will generate them for you. I have chosen Eclipse IDE because manual creation of WSIT configuration files will help you to understand and apply the web security policies better.
Setup the TLS (SSL) configurations on Web Server.
Since we are using Tomcat web server as our jee container, we need to setup the SSL configurations in Tomcat server.xml file. A sample configuration is given below. To know more about how to configure SSL on Tomcat please read the below articles.
Sample Tomcat server.xml TLS/SSL configuration.
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" maxThreads="150" scheme="https" secure="true" clientAuth="false" sslProtocol="TLS" keystoreFile= "PATH_TO_YOUR_KEYSTORE_FILE” keystorePass="YOUR_KEYSTORE_PASSWORD"/>
You need to configure your web.xml file to make sure that the traffic redirected to HTTPS port.
Securing web applications in Web.xml
The web.xml used in our sample application is below. Have a look at <security-constraint> configuration.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>MyWebService</display-name> <description>my Web Service</description> <security-constraint> <web-resource-collection> <web-resource-name>MyService</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <listener> <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class> </listener> <servlet> <servlet-name>MyWebServicePort</servlet-name> <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MyWebServicePort</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <session-config> <session-timeout>60</session-timeout> </session-config> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> </web-app>
Secure Web Service Implementation
We use the same source files of JAX-WS and Secure Java Web Services using UsernameToken : WS-Security with Metro and WSIT example. But there are major policy changes in both server and client side WSIT Policy configuration files. The Java class changes are minor.
Please ensure that the image download/upload methods are not ideal use cases for this example. You need to include MTOM to optimize (Read: Enable MTOM for JAX-WS Web Services) such methods.
The web service level message/token encryption and decryption also requires keystores and digital certificates for server and client. The client should know the public key of Server. For this you need to export server’s digital certificate to client’s keystore. The server doesn’t require public key of client. These configurations are added as part of client and server WSIT policy configurations. The keystore location in these WSIT files can be absolute location or if no absolute location is provided the metro/wsit runtime will look for the keystore META-INF child directory of a directory in the classpath.
For this example, we use the same keystore and digital certificates (self signed) which we used for JAX-WS Secure Web Services with Signatures and Encryption: WS-Security with Metro and WSIT example.
Web Service SEI and Implementation and Password validator
Let us create our SEI and implementation classes as well as our password validator class.
The SEI and Implementation classes:
/* * @(#)MyWebServiceIntf.java * @author Binu George * Globinch.com * copyright http://www.globinch.com. All rights reserved. */ package com.globinch.service; import java.awt.Image; import javax.jws.WebMethod; import javax.jws.WebParam; import javax.jws.WebService; /** * The SEI * @author Binu George * @since 2013 * @version 1.0 */ @WebService(name="MyWebService") public interface MyWebServiceIntf { /** * Web service operation */ @WebMethod(operationName = "greetCustomer") public String greetCustomer(@WebParam(name = "parameter") String parameter); @WebMethod(operationName = "retrieveImage") public Image retrieveImage(@WebParam(name = "name") String name); @WebMethod(operationName = "uploadImage") public String uploadImage(@WebParam(name = "file") Image file, @WebParam(name = "name") String name); }
/* * @(#)MyWebService.java * @author Binu George * Globinch.com * copyright http://www.globinch.com. All rights reserved. */ package com.globinch.service; import java.awt.Image; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.jws.WebService; import javax.xml.ws.WebServiceException; /** * The web service implementation class. * @author Binu George * @since 2013 * @version 1.0 */ @WebService() public class MyWebService implements MyWebServiceIntf { final static String PATH = "D:\\mtomtest\\upload\\"; /* (non-Javadoc) * @see com.globinch.service.MyWebServiceIntf#greetCustomer(java.lang.String) */ @Override public String greetCustomer(String parameter) { return "Hello..." + parameter; } /* (non-Javadoc) * @see com.globinch.service.MyWebServiceIntf#retrieveImage(java.lang.String) */ @Override public Image retrieveImage(String name) { try { // Create a file object with file name and read the image File image = new File(PATH + name); return ImageIO.read(image); } catch (IOException e) { e.printStackTrace(); throw new WebServiceException("Download Failed"); } } /* (non-Javadoc) * @see com.globinch.service.MyWebServiceIntf#uploadImage(java.awt.Image, java.lang.String) */ @Override public String uploadImage(Image file, String name) { if (file != null) { try { File image = new File(PATH + name); ImageIO.write((BufferedImage) file, "jpg", image); } catch (IOException e) { e.printStackTrace(); throw new WebServiceException("Upload Failed"); } return "Upload Successful"; } throw new WebServiceException("No data to upload."); } }
The Password validator class:
/* * @(#) MyServicePasswordValidator.java * @author Binu George * Globinch.com * copyright http://www.globinch.com. All rights reserved. */ package com.globinch.service; import com.sun.xml.wss.impl.callback.PasswordValidationCallback; import com.sun.xml.wss.impl.callback.PasswordValidationCallback.PasswordValidationException; /** * The plain text password validation class. * @author Binu George * @since 2013 * @version 1.0 */ public class MyServicePasswordValidator implements PasswordValidationCallback.PasswordValidator { public boolean validate(PasswordValidationCallback.Request pwdrequest) throws PasswordValidationCallback.PasswordValidationException { if(pwdrequest instanceof PasswordValidationCallback.DigestPasswordRequest){ PasswordValidationCallback.DigestPasswordRequest request = (PasswordValidationCallback.DigestPasswordRequest) pwdrequest; if ("username".equals(request.getUsername()) && "userpass".equals(request.getPassword())) { return true; }else{ throw new PasswordValidationCallback.PasswordValidationException("Error not valid"); } } if(pwdrequest instanceof PasswordValidationCallback.PlainTextPasswordRequest){ try { return new PlainTextPasswordValidators().validate(pwdrequest); } catch (PasswordValidationException e) { e.printStackTrace(); } } return false; } /** * Plain text validator */ private class PlainTextPasswordValidators implements PasswordValidationCallback.PasswordValidator { /** * Validate password * @param request * @return * @throws PasswordValidationCallback.PasswordValidationException */ public boolean validate(PasswordValidationCallback.Request request) throws PasswordValidationCallback.PasswordValidationException { PasswordValidationCallback.PlainTextPasswordRequest plainTextRequest = (PasswordValidationCallback.PlainTextPasswordRequest) request; if ("username ".equals(plainTextRequest.getUsername()) && "userpass".equals(plainTextRequest.getPassword())) { return true; } else{ throw new PasswordValidationCallback.PasswordValidationException("credentials not valid"); } } } }
sun-jaxws.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- The jax-ws xml configuration file for tomcat servlet container. www.Globinch.com --> <endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0"> <endpoint name="MyWebService" implementation="com.globinch.service.MyWebService" url-pattern="/" wsdl-location="WEB-INF/wsdl/MyWebServiceService.wsdl" enable-mtom="true"> </endpoint> </endpoints>
Service WSIT Policy Configuration For Secure UsernameToken Profile
The major changes are in the WSIT server configuration file. We added all the policies required to sign and encrypt the username tokens. In this example the soap body and message will not be signed and encrypted.
<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" name="MyWebServiceService" targetNamespace="http://com.globinch.service/" xmlns:tns="http://com.globinch.service/" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsp1="http://www.w3.org/ns/ws-policy" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsaws="http://www.w3.org/2005/08/addressing" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702"> <message name="uploadImage"> <part name="parameters" element="tns:uploadImage" /> </message> <message name="uploadImageResponse"> <part name="parameters" element="tns:uploadImageResponse" /> </message> <message name="greetCustomer"> <part name="parameters" element="tns:greetCustomer" /> </message> <message name="greetCustomerResponse"> <part name="parameters" element="tns:greetCustomerResponse" /> </message> <message name="retrieveImage"> <part name="parameters" element="tns:retrieveImage" /> </message> <message name="retrieveImageResponse"> <part name="parameters" element="tns:retrieveImageResponse" /> </message> <portType name="MyWebService"> <operation name="uploadImage"> <input wsam:Action="http://service.globinch.com/MyWebService/uploadImageRequest" message="tns:uploadImage" /> <output wsam:Action="http://service.globinch.com/MyWebService/uploadImageResponse" message="tns:uploadImageResponse" /> </operation> <operation name="greetCustomer"> <input wsam:Action="http://service.globinch.com/MyWebService/greetCustomerRequest" message="tns:greetCustomer" /> <output wsam:Action="http://service.globinch.com/MyWebService/greetCustomerResponse" message="tns:greetCustomerResponse" /> </operation> <operation name="retrieveImage"> <input wsam:Action="http://service.globinch.com/MyWebService/retrieveImageRequest" message="tns:retrieveImage" /> <output wsam:Action="http://service.globinch.com/MyWebService/retrieveImageResponse" message="tns:retrieveImageResponse" /> </operation> </portType> <binding name="MyWebServicePortBinding" type="tns:MyWebService"> <wsp:PolicyReference URI="#MyWebServicePortBindingPolicy" /> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <operation name="uploadImage"> <soap:operation soapAction="" /> <input> <wsp:PolicyReference URI="#MyWebServicePortBinding_Input_Policy"/> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> <operation name="greetCustomer"> <soap:operation soapAction="" /> <input> <wsp:PolicyReference URI="#MyWebServicePortBinding_Input_Policy"/> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> <operation name="retrieveImage"> <soap:operation soapAction="" /> <input> <wsp:PolicyReference URI="#MyWebServicePortBinding_Input_Policy"/> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> </binding> <service name="MyWebServiceService"> <port name="MyWebServicePort" binding="tns:MyWebServicePortBinding" /> </service> <wsp:Policy wsu:Id="MyWebServicePortBindingPolicy"> <wsp:ExactlyOne> <wsp:All> <wsam:Addressing wsp1:Optional="false"/> <sp:SymmetricBinding> <wsp:Policy> <sp:ProtectionToken> <wsp:Policy> <sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never"> <wsp:Policy> <sp:WssX509V3Token10/> <sp:RequireIssuerSerialReference/> </wsp:Policy> </sp:X509Token> </wsp:Policy> </sp:ProtectionToken> <sp:Layout> <wsp:Policy> <sp:Strict/> </wsp:Policy> </sp:Layout> <sp:IncludeTimestamp/> <sp:OnlySignEntireHeadersAndBody/> <sp:AlgorithmSuite> <wsp:Policy> <sp:Basic128/> </wsp:Policy> </sp:AlgorithmSuite> </wsp:Policy> </sp:SymmetricBinding> <sp:Wss11> <wsp:Policy> <sp:MustSupportRefIssuerSerial/> <sp:MustSupportRefThumbprint/> <sp:MustSupportRefEncryptedKey/> </wsp:Policy> </sp:Wss11> <sp:SignedEncryptedSupportingTokens> <wsp:Policy> <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"> <wsp:Policy> <sp:WssUsernameToken10/> </wsp:Policy> </sp:UsernameToken> </wsp:Policy> </sp:SignedEncryptedSupportingTokens <wsss:ValidatorConfiguration wspp:visibility="private" xmlns:wsss="http://schemas.sun.com/2006/03/wss/server" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy"> <wsss:Validator name="usernameValidator" classname="com.globinch.service. MyServicePasswordValidator” /> </wsss:ValidatorConfiguration> <wsss:KeyStore alias="SERVER_KEY_ALIAS" keypass="KEY_PASSWORD" location="SERVER_KEYSTORE_PATH" storepass="KEYSTORE_PASSWORD" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" wspp:visibility="private" xmlns:wsss="http://schemas.sun.com/2006/03/wss/server"/> </wsp:All> </wsp:ExactlyOne> </wsp:Policy> <wsp:Policy wsu:Id="MyWebServicePortBinding_Input_Policy"> <wsp:ExactlyOne> <wsp:All> <sp:EncryptedSupportingTokens> <wsp:Policy> <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"> <wsp:Policy> <sp:WssUsernameToken10/> </wsp:Policy> </sp:UsernameToken> </wsp:Policy> </sp:EncryptedSupportingTokens> </wsp:All> </wsp:ExactlyOne> </wsp:Policy> </definitions>
Please note that we need to provide the keystore configuration in the WSIT server file. This is because the client certificate is imported into the server keystore. The server need client public key to decrypt the encrypted tokens.
WSDL of Secure Signed and Encrypted UsernameToken MyService Service
Once all the above are ready build your application and create war file named “MyService.war” Deploy it on tomcat. If it gets deployed successfully, you will see smilar to the ollowing message in the console.
INFO: Deploying web application archive MyService.war May 19, 2013 12:25:37 PM com.sun.xml.ws.transport.http.servlet.WSServletContextListener contextInitialized INFO: WSSERVLET12: JAX-WS context listener initializing May 19, 2013 12:25:38 PM [com.sun.xml.ws.policy.parser.PolicyConfigParser] parse INFO: WSP5018: Loaded WSIT configuration from file: jndi:/localhost/MyService/WEB-INF/wsit-com.globinch.service.MyWebService.xml. May 19, 2013 12:25:40 PM com.sun.xml.ws.server.MonitorBase createRoot INFO: Metro monitoring rootname successfully set to: com.sun.metro:pp=/,type=WSEndpoint,name=/MyService-MyWebServiceService-MyWebServicePort May 19, 2013 12:25:41 PM com.sun.xml.ws.transport.http.servlet.WSServletDelegate <init> INFO: WSSERVLET14: JAX-WS servlet initializing May 19, 2013 12:25:41 PM org.apache.coyote.http11.Http11Protocol start INFO: Starting Coyote HTTP/1.1 on http-8080 May 19, 2013 12:25:41 PM org.apache.coyote.http11.Http11Protocol start INFO: Starting Coyote HTTP/1.1 on http-8443 May 19, 2013 12:25:41 PM org.apache.jk.common.ChannelSocket init INFO: JK: ajp13 listening on /0.0.0.0:8009 May 19, 2013 12:25:41 PM org.apache.jk.server.JkMain start INFO: Jk running ID=0 time=0/15 config=null May 19, 2013 12:25:41 PM org.apache.catalina.startup.Catalina start INFO: Server startup in 4284 ms
Check the WSDL file by accessing https://YOUR_HOST_NAME:8443/MyService/?wsdl. See here the transport protocol is HTTPS not HTTP.
The WSDL file
<definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp=http://www.w3.org/ns/ws-policy xmlns:wsp1_2="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap=http://schemas.xmlsoap.org/wsdl/soap/ xmlns:tns="http://service.globinch.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://service.globinch.com/" name="MyWebServiceService"> <wsp:Policy xmlns:wsapw3c="http://www.w3.org/2006/05/addressing/wsdl" xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" xmlns:ssp="http://schemas.sun.com/2006/03/wss/server" xmlns:sunwsp=http://java.sun.com/xml/ns/wsit/policy wsu:Id="MyWebServicePortBindingPolicy"> <sp:SignedEncryptedSupportingTokens> <wsp:Policy> <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"> <wsp:Policy> <sp:WssUsernameToken10 /> </wsp:Policy> </sp:UsernameToken> </wsp:Policy> </sp:SignedEncryptedSupportingTokens> <sp:TransportBinding> <wsp:Policy> <sp:AlgorithmSuite> <wsp:Policy> <sp:Basic128 /> </wsp:Policy> </sp:AlgorithmSuite> <sp:IncludeTimestamp /> <sp:Layout> <wsp:Policy> <sp:Lax /> </wsp:Policy> </sp:Layout> <sp:TransportToken> <wsp:Policy> <sp:HttpsToken RequireClientCertificate="false" /> </wsp:Policy> </sp:TransportToken> </wsp:Policy> </sp:TransportBinding> <wsapw3c:UsingAddressing /> </wsp:Policy> <wsp:Policy xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" wsu:Id="MyWebServicePortBinding_Input_Policy"> <sp:SignedEncryptedSupportingTokens> <wsp:Policy> <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"> <wsp:Policy> <sp:WssUsernameToken10 /> </wsp:Policy> </sp:UsernameToken> </wsp:Policy> </sp:SignedEncryptedSupportingTokens> </wsp:Policy> <types> <xsd:schema> <xsd:import namespace="http://service.globinch.com/" schemaLocation="https://localhost:8443/MyService/?xsd=1" /> </xsd:schema> </types> <message name="uploadImage"> <part name="parameters" element="tns:uploadImage" /> </message> <message name="uploadImageResponse"> <part name="parameters" element="tns:uploadImageResponse" /> </message> <message name="greetCustomer"> <part name="parameters" element="tns:greetCustomer" /> </message> <message name="greetCustomerResponse"> <part name="parameters" element="tns:greetCustomerResponse" /> </message> <message name="retrieveImage"> <part name="parameters" element="tns:retrieveImage" /> </message> <message name="retrieveImageResponse"> <part name="parameters" element="tns:retrieveImageResponse" /> </message> <portType name="MyWebService"> <operation name="uploadImage"> <input wsam:Action="http://service.globinch.com/MyWebService/uploadImageRequest" message="tns:uploadImage" /> <output wsam:Action="http://service.globinch.com/MyWebService/uploadImageResponse" message="tns:uploadImageResponse" /> </operation> <operation name="greetCustomer"> <input wsam:Action="http://service.globinch.com/MyWebService/greetCustomerRequest" message="tns:greetCustomer" /> <output wsam:Action="http://service.globinch.com/MyWebService/greetCustomerResponse" message="tns:greetCustomerResponse" /> </operation> <operation name="retrieveImage"> <input wsam:Action="http://service.globinch.com/MyWebService/retrieveImageRequest" message="tns:retrieveImage" /> <output wsam:Action="http://service.globinch.com/MyWebService/retrieveImageResponse" message="tns:retrieveImageResponse" /> </operation> </portType> <binding name="MyWebServicePortBinding" type="tns:MyWebService"> <wsp:PolicyReference URI="#MyWebServicePortBinding_MTOM_Policy-MyWebServicePortBinding_MTOM_Policy" /> <wsp:PolicyReference URI="#MyWebServicePortBindingPolicy" /> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <operation name="uploadImage"> <soap:operation soapAction="" /> <input> <wsp:PolicyReference URI="#MyWebServicePortBinding_Input_Policy" /> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> <operation name="greetCustomer"> <soap:operation soapAction="" /> <input> <wsp:PolicyReference URI="#MyWebServicePortBinding_Input_Policy" /> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> <operation name="retrieveImage"> <soap:operation soapAction="" /> <input> <wsp:PolicyReference URI="#MyWebServicePortBinding_Input_Policy" /> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> </binding> <service name="MyWebServiceService"> <port name="MyWebServicePort" binding="tns:MyWebServicePortBinding"> <soap:address location="https://localhost:8443/MyService/" /> </port> </service> </definitions>
Secure Web Service “MyService” Client with Signed and Encrypted UsernameToken
Secure Web Service Client application that signs and encrypts UsernameToken and use Transport Layer Security (TLS/SSL) and HTTPS to communicate with service producer.
When you create JAX-WS client application using metro you need to have the following files.
- The service proxy classes
- {wsdl file name}.xml
- wsit-client.xml
- Service client classes.
- CallbackHandler class.
- The client keystore/digital certificates
Now we need to setup our client application. Here also we will use the same example we used for JAX-WS and Secure Java Web Services using UsernameToken : WS-Security with Metro and WSIT
Here also the major change is in the client WSIT configuration file. We need to add the relevant changes to the file to support signing and encryption if usernametoken.
The Service Consumer class
The first step in creating the web service client is to generate the proxy artifacts using wsimport utility.
wsimport -keep -XadditionalHeaders http://localhost:8080/MyService/?wsdl
Using the proxy stub classes you can create Service Consumer Client class for our secure, signed and encrtpted UsernameToken Web Service.
The Service Consumer class
The service client class file.
/* * @(#)Client.java * @author Binu George * Globinch.com * copyright http://www.globinch.com. All rights reserved. */ package com.globinch.client; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; import javax.imageio.ImageIO; import javax.xml.namespace.QName; import javax.xml.ws.BindingProvider; import javax.xml.ws.Service; import com.globinch.service.MyWebService; /** * The web service client service invoker class. * @author Binu George * @since 2013 * @version 1.0 */ public class Client { private static URL url = null; private static Service service = null; private static final String PATH = "D:\\mtomtest\\download\\"; public Client() { try { url = new URL("https://localhost:8443/MyService/?wsdl"); QName qname = new QName("http://service.globinch.com/", "MyWebServiceService"); service = Service.create(url, qname); } catch (Exception e) { e.printStackTrace(); } } /** * Upload image * @return String */ public String uploadImage() { try { MyWebService myService = service.getPort(MyWebService.class); File file = new File(PATH + "11841.jpg"); BufferedImage imageToUpload = null; try { imageToUpload = ImageIO.read(file); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } double d = Math.random(); byte[] imageInByte = null; try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(imageToUpload, "jpg", baos); baos.flush(); imageInByte = baos.toByteArray(); baos.close(); } catch (IOException e) { System.out.println(e.getMessage()); } // now upload the image myService.uploadImage(imageInByte, "ImageFromClient" + d + ".jpg"); String imageToDownload = d + ""; return imageToDownload; } catch (Exception e) { e.printStackTrace(); } return null; } /** * Download the uploaded image * @param imageName * @return String */ public String downloadImage(String imageName) { try { MyWebService myService = service.getPort(MyWebService.class); // lets now download the uploaded image byte[] downloadedImage = myService .retrieveImage("ImageFromClient" + imageName + ".jpg"); File imageFromServer = new File(PATH + "ImageFromServer" + imageName + ".jpg"); try { FileOutputStream fileOuputStream = new FileOutputStream( imageFromServer); fileOuputStream.write(downloadedImage); fileOuputStream.close(); } catch (IOException e) { e.printStackTrace(); } return "success"; } catch (Exception e) { e.printStackTrace(); } return null; } /** * Greet the customer * @param name * @return String */ public String greet(String name) { try { MyWebService myService = service.getPort(MyWebService.class); String message = myService.greetCustomer(name); System.out.println(message); return message; } catch (Exception exception) { exception.printStackTrace(); } return "empty string"; } public static void main(String[] args) { try { new Client().greet("Some user"); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
The Callbackhandler class
/* * @(#)MyCallbackHandler.java * @author Binu George * Globinch.com * copyright http://www.globinch.com. All rights reserved. */ package com.globinch.client; import java.io.IOException; import javax.security.auth.callback.Callback; import javax.security.auth.callback.CallbackHandler; import javax.security.auth.callback.NameCallback; import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import com.sun.xml.wss.impl.callback.PasswordValidationCallback; /** * The callback handler class to manage username and password. * @author Binu George * @since 2013 * @version 1.0 */ public class MyCallbackHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (Callback callback : callbacks) { if (callback instanceof NameCallback) { NameCallback nc = (NameCallback) callback; nc.setName("username"); } else if (callback instanceof PasswordCallback) { PasswordCallback pc = (PasswordCallback) callback; pc.setPassword("userpass".toCharArray()); } else { throw new UnsupportedCallbackException(callback, "Unrecognized Callback"); } } } }
The WSIT Client Configuration files for Signed and Encrypted UsernameToken Profile
<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" name="mainclientconfig"> <import location="MyWebServiceService.xml" namespace="http://service.globinch.com/"/> </definitions>
The client policy configuration file. (MyWebServiceService.xml).
<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://www.w3.org/ns/ws-policy" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://service.globinch.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.xmlsoap.org/wsdl/" targetNamespace="http://service.globinch.com/" xmlns:sc="http://schemas.sun.com/2006/03/wss/client" xmlns:wspp="http://java.sun.com/xml/ns/wsit/policy" xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702" xmlns:wsp1="http://www.w3.org/ns/ws-policy" name="MyWebServiceService"> <wsp:Policy wsu:Id="MyWebServicePortBindingPolicy"> <wsp:ExactlyOne> <wsp:All> <wsam:Addressing wsp1:Optional="false"/> <sp:SymmetricBinding> <wsp:Policy> <sp:ProtectionToken> <wsp:Policy> <sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never"> <wsp:Policy> <sp:WssX509V3Token10/> <sp:RequireIssuerSerialReference/> </wsp:Policy> </sp:X509Token> </wsp:Policy> </sp:ProtectionToken> <sp:Layout> <wsp:Policy> <sp:Strict/> </wsp:Policy> </sp:Layout> <sp:IncludeTimestamp/> <sp:OnlySignEntireHeadersAndBody/> <sp:AlgorithmSuite> <wsp:Policy> <sp:Basic128/> </wsp:Policy> </sp:AlgorithmSuite> </wsp:Policy> </sp:SymmetricBinding> <sp:Wss11> <wsp:Policy> <sp:MustSupportRefIssuerSerial/> <sp:MustSupportRefThumbprint/> <sp:MustSupportRefEncryptedKey/> </wsp:Policy> </sp:Wss11> <sp:SignedEncryptedSupportingTokens> <wsp:Policy> <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"> <wsp:Policy> <sp:WssUsernameToken10/> </wsp:Policy> </sp:UsernameToken> </wsp:Policy> </sp:SignedEncryptedSupportingTokens <sc:CallbackHandlerConfiguration wspp:visibility="private"> <sc:CallbackHandler classname="com.globinch.client.MyCallbackHandler" name="usernameHandler"/> <sc:CallbackHandler classname="com.globinch.client.MyCallbackHandler" name="passwordHandler"/> </sc:CallbackHandlerConfiguration> <sc:KeyStore wspp:visibility="private" location="PATH_TO_YOUR_KEYSTORE_FILE" storepass="KEYSTORE_PASSWORD" alias="CLIENT_KEY_ALIAS_NAME" keypass="KEY_PASSWORD"/> <sc:TrustStore wspp:visibility="private" location="PATH_TO_YOUR_CLIENT_KEYSTORE_FILE" storepass="KEYSTORE_PASSWORD" peeralias="SERVER_KEY_ALIAS"/> </wsp:All> </wsp:ExactlyOne> </wsp:Policy> <wsp:Policy wsu:Id="MyWebServicePortBinding_Input_Policy"> <wsp:ExactlyOne> <wsp:All> <sp:EncryptedSupportingTokens> <wsp:Policy> <sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient"> <wsp:Policy> <sp:WssUsernameToken10/> </wsp:Policy> </sp:UsernameToken> </wsp:Policy> </sp:EncryptedSupportingTokens> </wsp:All> </wsp:ExactlyOne> </wsp:Policy> <types> <xsd:schema> <xsd:import namespace="http://service.globinch.com/" schemaLocation="http://localhost:8080/MyService/?xsd=1" /> </xsd:schema> </types> <message name="uploadImage"> <part name="parameters" element="tns:uploadImage" /> </message> <message name="uploadImageResponse"> <part name="parameters" element="tns:uploadImageResponse" /> </message> <message name="greetCustomer"> <part name="parameters" element="tns:greetCustomer" /> </message> <message name="greetCustomerResponse"> <part name="parameters" element="tns:greetCustomerResponse" /> </message> <message name="retrieveImage"> <part name="parameters" element="tns:retrieveImage" /> </message> <message name="retrieveImageResponse"> <part name="parameters" element="tns:retrieveImageResponse" /> </message> <portType name="MyWebService"> <operation name="uploadImage"> <input wsam:Action="http://service.globinch.com/MyWebService/uploadImageRequest" message="tns:uploadImage" /> <output wsam:Action="http://service.globinch.com/MyWebService/uploadImageResponse" message="tns:uploadImageResponse" /> </operation> <operation name="greetCustomer"> <input wsam:Action="http://service.globinch.com/MyWebService/greetCustomerRequest" message="tns:greetCustomer" /> <output wsam:Action="http://service.globinch.com/MyWebService/greetCustomerResponse" message="tns:greetCustomerResponse" /> </operation> <operation name="retrieveImage"> <input wsam:Action="http://service.globinch.com/MyWebService/retrieveImageRequest" message="tns:retrieveImage" /> <output wsam:Action="http://service.globinch.com/MyWebService/retrieveImageResponse" message="tns:retrieveImageResponse" /> </operation> </portType> <binding name="MyWebServicePortBinding" type="tns:MyWebService"> <wsp:PolicyReference URI="#MyWebServicePortBindingPolicy" /> <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" /> <operation name="uploadImage"> <soap:operation soapAction="" /> <input> <wsp:PolicyReference URI="#MyWebServicePortBinding_Input_Policy"/> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> <operation name="greetCustomer"> <soap:operation soapAction="" /> <input> <wsp:PolicyReference URI="#MyWebServicePortBinding_Input_Policy"/> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> <operation name="retrieveImage"> <soap:operation soapAction="" /> <input> <wsp:PolicyReference URI="#MyWebServicePortBinding_Input_Policy"/> <soap:body use="literal" /> </input> <output> <soap:body use="literal" /> </output> </operation> </binding> <service name="MyWebServiceService"> <port name="MyWebServicePort" binding="tns:MyWebServicePortBinding"> <soap:address location="http://localhost:8080/MyService/" /> </port> </service> </definitions>
Utility Servlet Web Component
We use a utility servlet class, which invokes the service client methods. You can create appropriate JSP/JSF or UI file to invoke the servlet method.
MyServiceServlet class.
/*
* @(#)MyServiceServlet.java
* @author Binu George
* Globinch.com
* copyright http://www.globinch.com. All rights reserved.
*/
package com.globinch.client;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* Servlet implementation class MyServiceServlet
*
* @author Binu George
* @since 2013
* @version 1.0
*/
public class MyServiceServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public MyServiceServlet() {
super();
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
Client service = new Client();
if (request.getParameter("UploadImage") != null) {
String imageName = service.uploadImage();
HttpSession httpSession = request.getSession();
httpSession.setAttribute("IMAGE", imageName);
PrintWriter out = response.getWriter();
out.println("<br/>");
out.println("<br/>");
out.println("<br/>");
out
.println("The image is uploaded. The image name =ImageFromClient"
+ imageName + ".jpg");
out.println("<br/>");
out.println("<br/>");
out
.println("Please choose another action from <a href=\"index.jsp\">Home Page</a>");
} else if (request.getParameter("DownloadImage") != null) {
HttpSession httpSession = request.getSession();
String imageName = (String) httpSession.getAttribute("IMAGE");
PrintWriter out = response.getWriter();
if (imageName == null || imageName.isEmpty()) {
out.println("<br/>");
out
.println("Please upload an image first to download it. Try from <a href=\"index.jsp\">Home Page</a>");
} else {
String message = service.downloadImage(imageName);
out.println("<br/>");
out.println("<br/>");
out.println("<br/>");
out.println("The download of image ImageFromClient" + imageName
+ ".jpg is " + message);
out.println("<br/>");
out.println("<br/>");
out
.println("Please choose another action from <a href=\"index.jsp\">Home Page</a>");
}
} else if (request.getParameter("GreetMe") != null) {
String message = service.greet("Friend");
PrintWriter out = response.getWriter();
out.println("<br/>");
out.println("<br/>");
out.println("<br/>");
out.println(message);
out.println("<br/>");
out.println("<br/>");
out
.println("Please choose another action from <a href=\"index.jsp\">Home Page</a>");
} else {
PrintWriter out = response.getWriter();
out.println("<br/>");
out.println("<br/>");
out
.println("Wrong Action. Please choose an action from <a href=\"index.jsp\">Home Page</a>");
out.println("<br/>");
out.println("<br/>");
}
}
}
Web.xml
MyServiceServlet class.
/* * @(#)MyServiceServlet.java * @author Binu George * Globinch.com * copyright http://www.globinch.com. All rights reserved. */ package com.globinch.client; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * Servlet implementation class MyServiceServlet * * @author Binu George * @since 2013 * @version 1.0 */ public class MyServiceServlet extends HttpServlet { private static final long serialVersionUID = 1L; /** * @see HttpServlet#HttpServlet() */ public MyServiceServlet() { super(); } /** * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse * response) */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { } /** * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse * response) */ protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Client service = new Client(); if (request.getParameter("UploadImage") != null) { String imageName = service.uploadImage(); HttpSession httpSession = request.getSession(); httpSession.setAttribute("IMAGE", imageName); PrintWriter out = response.getWriter(); out.println("<br/>"); out.println("<br/>"); out.println("<br/>"); out .println("The image is uploaded. The image name =ImageFromClient" + imageName + ".jpg"); out.println("<br/>"); out.println("<br/>"); out .println("Please choose another action from <a href=\"index.jsp\">Home Page</a>"); } else if (request.getParameter("DownloadImage") != null) { HttpSession httpSession = request.getSession(); String imageName = (String) httpSession.getAttribute("IMAGE"); PrintWriter out = response.getWriter(); if (imageName == null || imageName.isEmpty()) { out.println("<br/>"); out .println("Please upload an image first to download it. Try from <a href=\"index.jsp\">Home Page</a>"); } else { String message = service.downloadImage(imageName); out.println("<br/>"); out.println("<br/>"); out.println("<br/>"); out.println("The download of image ImageFromClient" + imageName + ".jpg is " + message); out.println("<br/>"); out.println("<br/>"); out .println("Please choose another action from <a href=\"index.jsp\">Home Page</a>"); } } else if (request.getParameter("GreetMe") != null) { String message = service.greet("Friend"); PrintWriter out = response.getWriter(); out.println("<br/>"); out.println("<br/>"); out.println("<br/>"); out.println(message); out.println("<br/>"); out.println("<br/>"); out .println("Please choose another action from <a href=\"index.jsp\">Home Page</a>"); } else { PrintWriter out = response.getWriter(); out.println("<br/>"); out.println("<br/>"); out .println("Wrong Action. Please choose an action from <a href=\"index.jsp\">Home Page</a>"); out.println("<br/>"); out.println("<br/>"); } } }
Web.xml
Since we deploy this clinet application as a web archive on tomcat, we need to configure the web.xml to support HTTPS.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name> MyServiceClient</display-name> <security-constraint> <web-resource-collection> <web-resource-name>MyServiceClient</web-resource-name> <url-pattern>/*</url-pattern> </web-resource-collection> <user-data-constraint> <transport-guarantee>CONFIDENTIAL</transport-guarantee> </user-data-constraint> </security-constraint> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <description></description> <display-name>MyServiceServlet</display-name> <servlet-name>MyServiceServlet</servlet-name> <servlet-class>com.globinch.client.MyServiceServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServiceServlet</servlet-name> <url-pattern>/MyServiceServlet</url-pattern> </servlet-mapping> </web-app>
The Request and Response samples
You can run the clinet application and check the request and responses. A sample request response pair is given below for greetCustomer service operation.
Sample Request
---[HTTP request - https://localhost:8443/MyService/]--- Accept: text/xml, multipart/related Content-Type: multipart/related;start=" <rootpart * b8717-54f4-4981-8eb9-aa683b07ef52 @ example.jaxws.sun.com> ";type="application/xop+xml";boundary="uuid:560b8717-54f4-4981-8eb9-aa683b07ef52";start-info="text/xml" SOAPAction: "http://service.globinch.com/MyWebService/greetCustomerRequest" User-Agent: Metro/2.2.1-1 (tags/2.2.1-1-7267; 2012-08-30T14:04:51+0000) JAXWS-RI/2.2.7 JAXWS/2.2 svn-revision#unknown --uuid:560b8717-54f4-4981-8eb9-aa683b07ef52 Content-Id: <rootpart * b8717-54f4-4981-8eb9-aa683b07ef52 @ example.jaxws.sun.com> Content-Type: application/xop+xml;charset=utf-8;type="text/xml" Content-Transfer-Encoding: binary <?xml version='1.0' encoding='UTF-8'?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:exc14n="http://www.w3.org/2001/10/xml-exc-c14n#"> <S:Header> <To xmlns="http://www.w3.org/2005/08/addressing">https://localhost:8443/MyService/</To> <Action xmlns="http://www.w3.org/2005/08/addressing" xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" S:mustUnderstand="1">http://service.globinch.com/MyWebService/greetCustomerRequest</Action> <ReplyTo xmlns="http://www.w3.org/2005/08/addressing"> <Address>http://www.w3.org/2005/08/addressing/anonymous</Address> </ReplyTo> <FaultTo xmlns="http://www.w3.org/2005/08/addressing"> <Address>http://www.w3.org/2005/08/addressing/anonymous</Address> </FaultTo> <MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:578e1be1-7139-4ee5-a897-f429a668482d</MessageID> <wsse:Security S:mustUnderstand="1"> <wsu:Timestamp xmlns:ns18="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns17="http://www.w3.org/2003/05/soap-envelope" wsu:Id="_3"> <wsu:Created>2013-05-19T08:55:20Z</wsu:Created> <wsu:Expires>2013-05-19T09:00:20Z</wsu:Expires> </wsu:Timestamp> <xenc:EncryptedKey xmlns:ns18="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns17="http://www.w3.org/2003/05/soap-envelope" Id="_5002"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" /> <ds:KeyInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="KeyInfoType"> <wsse:SecurityTokenReference> <ds:X509Data> <ds:X509IssuerSerial> <ds:X509IssuerName>CN=localhost, OU=home, O=home, L=city, ST=state, C=in</ds:X509IssuerName> <ds:X509SerialNumber>173056135</ds:X509SerialNumber> </ds:X509IssuerSerial> </ds:X509Data> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue xmlns:xop="http://www.w3.org/2004/08/xop/include"> <xop:Include href="cid:81ce4f87-fb39-404e-990e-d1eb8aa89e79@example.jaxws.sun.com" /> </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedKey> <xenc:ReferenceList xmlns:ns18="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns17="http://www.w3.org/2003/05/soap-envelope"> <xenc:DataReference URI="#_5003" /> <xenc:DataReference URI="#_5004" /> </xenc:ReferenceList> <xenc:EncryptedData xmlns:ns18="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns17="http://www.w3.org/2003/05/soap-envelope" Id="_5004" Type="http://www.w3.org/2001/04/xmlenc#Element"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" /> <ds:KeyInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="KeyInfoType"> <wsse:SecurityTokenRe ference wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey"> <wsse:Reference URI="#_5002" ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey" /> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue xmlns:xop="http://www.w3.org/2004/08/xop/include"> <xop:Include href="cid:04fdd703-789b-4138-b8b6-064740838730@example.jaxws.sun.com" /> </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> <xenc:EncryptedData xmlns:ns18="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns17="http://www.w3.org/2003/05/soap-envelope" Id="_5003" Type="http://www.w3.org/2001/04/xmlenc#Element"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" /> <ds:KeyInfo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="KeyInfoType"> <wsse:SecurityTokenReference wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey"> <wsse:Reference URI="#_5002" ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey" /> </wsse:SecurityTokenReference> </ds:KeyInfo> <xenc:CipherData> <xenc:CipherValue xmlns:xop="http://www.w3.org/2004/08/xop/include"> <xop:Include href="cid:ef07d044-d96b-4539-98ef-573fed8e4528@example.jaxws.sun.com" /> </xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> <ds:Signature xmlns:ns18="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns17="http://www.w3.org/2003/05/soap-envelope" Id="_1"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> <exc14n:InclusiveNamespaces PrefixList="wsse S" /> </ds:CanonicalizationMethod> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1" /> <ds:Reference URI="#_3"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> <exc14n:InclusiveNamespaces PrefixList="wsu wsse S" /> </ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>ar+A98WXKJVoIWOLSGUzr3X/W0Y=</ds:DigestValue> </ds:Reference> <ds:Reference URI="#uuid_e940023f-324e-4753-ae91-9b2471d35700"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> <exc14n:InclusiveNamespaces PrefixList="wsu wsse S" /> </ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>tn1vzElwtkLW03qv9KFS+sdfEag=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>2B7xG6PH/T4ZMHWZuQV7ZUHnQqc=</ds:SignatureValue> <ds:KeyInfo> <wsse:SecurityTokenReference wsu:Id="uuid_25f07f55-e40f-4d0f-b8ad-ab782119aa85" wsse11:TokenType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey"> <wsse:Reference URI="#_5002" ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKey" /> </wsse:SecurityTokenReference> </ds:KeyInfo> </ds:Signature> </wsse:Security> </S:Header> <S:Body> <ns2:greetCustomer xmlns:ns2="http://service.globinch.com/"> <arg0>Friend</arg0> </ns2:greetCustomer> </S:Body> </S:Envelope> --uuid:560b8717-54f4-4981-8eb9-aa683b07ef52 Content-Id: <81ce4f87-fb39-404e-990e-d1eb8aa89e79@example.jaxws.sun.com> Content-Type: application/ciphervalue Content-Transfer-Encoding: binary ktΣ♫╠╔ê-a3f?ñ═O═å┤9╣¡↕≡lô?‼α≈CTD║)⌠→ ∙û%╕q]TêÄö∩Æ╩↓ƒT£6Mxï ?_+♦Aj}O(φ?╓ÿ√`7ML☻f╦½√∟ªº÷ú↑T↓Ä▲ñv▬≤S\≥σz‼⌂╧♣#∞ßB&└²╫sÿ╪■╚*µ Γ↕▼☼í╖∩╫╚≈K]╧ö+╙k♫┤m --uuid:560b8717-54f4-4981-8eb9-aa683b07ef52 Content-Id: <04fdd703-789b-4138-b8b6-064740838730@example.jaxws.sun.com> Content-Type: application/ciphervalue Content-Transfer-Encoding: binary A♀/┼C§♫▲GO½|¼&╦ê█╪O¢X↔£┼«8â]½╠d╘░rbï=■┤║⌂♥jUêTàµ≈τB-┌╖û╜5_♥╡÷└íTπ≡α║≥√┐Äeú┘∟]úY∙πºQ╖↑J╙¿≡¢0φ!±SF╧ç•Σm↑☼7r∩«ⁿu6?─▄U¿░?eæD☻ç ╡‼ÑÖ╪%P►öY§3░╣l▒múc☺j╪♥┘τ║⌠♀&░ê╙╣σæ%⌡╘╧}l3?k╠O4>♣?k¼ûΦ╙~5↨ö•┐5@£K♫vP¿↨÷n│@²ºf¬ç╞√Ü♂▌?4C╣c♀H@⌂┤}δ^εr:☻|?-f ª╤░°₧9}Ñ┬%|≥4░─├♠▲ù┴}☻Ü╛P@Hí9ÜWEB&╗≤┴ê╝é┘├ ú0▌└|%╣aéε°♀╬ⁿ⌂╕╡╡b)ƒk6häcΓ▒è£☼s▓(,╙╬ ╝☺!▐┴σ║%p♥º⌐m│≥|ího `█♫└ ↔íSÇ█╪♂┐┴▲▀Γ)(6╗"s╛=│╦6¿¬âτ▒╗dOxù╩≈⌠∞F‼P┘Ö^Vÿô≥╤┌"▀?╠µXQ╚▄╚Ü╚¼b↨£≈sΓ┴K~Ç$30s▐kò}5≥4»±╝ö4å?bD@rÑ╗╡ò]δ¬1Jur╗µ?íl■í!w¶├ë⌐l*σz Ω±?₧å½öwñG.←5╕<♠òτ¬₧ --uuid:560b8717-54f4-4981-8eb9-aa683b07ef52 Content-Id: <ef07d044-d96b-4539-98ef-573fed8e4528 @ example.jaxws.sun.com> Content-Type: application/ciphervalue Content-Transfer-Encoding: binary ê∟╙H↔'┐█oZ1┐_¼☺\V!╕Q─,0öi_í1c/ <pë ⌡ ó è ┘ ä ° T ≤ ûα ▼ U ↕ â3Γ ? G º Rï ╞ α ╩ φZP6 ↓ í ‼ α │ Ω » g ╧ ô ] δ ] Θ ╩ QaD ┴ a ╤ p ╕ τó ╕ ÿW ≈ Ä ) E → X ╫ úè ┴ T \ gVGs → û ║ æà A- ─ d8pu ╡ ú6 ╓ eä ♀ φ & çtW µ> w▲ ╠←╤φΓëê3Σe╣╝?φçâH$♠«á≈3,¡⌠ùO§¢òû=╓☼☺☼╨⌐¶╤ (-]¼τ╙╣←$└]╛{AèÖ¿ ë╠a├R←ï│↨+←ëC‼ò┬♥░▄«ë½Γ*↓&╚Φ╢▓◄²J4TσH7â╕2?•│êJ╠>Ü,τí╒Æh↕;HÖù:pHΦ0╪α╜¶Nx♫└gGº7±:k█:∙▀Vî-x?#à⌠uÑ♫☺à╣±FΦΣ╓è╠2Öû═Γα┌←_pq9▒╚ïd& ♀]W♂!ⁿ╧♠º18♀ï«ò╚▌▼↨Ωiπ²▒|e↑♥WU╪↓♀[?↨☻♦!☺(ⁿ╖Ω‼╞└|╘H╗÷t^ⁿX░s▀Ö╩^♫╚4m@∙▀▀ΓZµj]ª╣£╘-⌡φ ┐b|∟VU --uuid:560b8717-54f4-4981-8eb9-aa683b07ef52----------------------
Sample Response:
---[HTTP response - https://localhost:8443/MyService/ - 200]--- null: HTTP/1.1 200 OK Content-Type: multipart/related;start=" <rootpart * bd210aea-ae7f-4bc2-8da8-800c509204ba @ example.jaxws.sun.com> ";type="application/xop+xml";boundary="uuid:bd210aea-ae7f-4bc2-8da8-800c509204ba";start-info="text/xml" Date: Sun, 19 May 2013 08:55:21 GMT Server: Apache-Coyote/1.1 Transfer-Encoding: chunked --uuid:bd210aea-ae7f-4bc2-8da8-800c509204ba Content-Id: <rootpart * bd210aea-ae7f-4bc2-8da8-800c509204ba @ example.jaxws.sun.com> Content-Type: application/xop+xml;charset=utf-8;type="text/xml" Content-Transfer-Encoding: binary <?xml version='1.0' encoding='UTF-8'?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse11="http://docs.oasis-open.org/wss/oasis-wss-wssecurity-secext-1.1.xsd" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:exc14n="http://www.w3.org/2001/10/xml-exc-c14n#"> <S:Header> <Action xmlns="http://www.w3.org/2005/08/addressing" xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" S:mustUnderstand="1">http://service.globinch.com/MyWebService/greetCustomerResponse</Action> <MessageID xmlns="http://www.w3.org/2005/08/addressing">uuid:19e5dd46-7c00-49d0-b8d9-48577af3de24</MessageID> <RelatesTo xmlns="http://www.w3.org/2005/08/addressing">uuid:578e1be1-7139-4ee5-a897-f429a668482d</RelatesTo> <To xmlns="http://www.w3.org/2005/08/addressing">http://www.w3.org/2005/08/addressing/anonymo us</To> <wsse:Security S:mustUnderstand="1"> <wsu:Timestamp xmlns:ns18="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns17="http://www.w3.org/2003/05/soap-envelope" wsu:Id="_3"> <wsu:Created>2013-05-19T08:55:21Z</wsu:Created> <wsu:Expires>2013-05-19T09 :00:21Z</wsu:Expires> </wsu:Timestamp> <ds:Signature xmlns:ns18="http://docs.oasis-open.org/ws-sx/ws-secureconversation/200512" xmlns:ns17="http://www.w3.org/2003/05/soap-envelope" Id="_1"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> <exc14n:InclusiveNamespaces PrefixList="wsse S" /> </ds:CanonicalizationMethod> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1" /> <ds:Reference URI="#_3"> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"> <e xc14n:InclusiveNamespaces PrefixList="wsu wsse S" /> </ds:Transform> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>qLyQw9dHKg57HBNbhP5StzRzrvg=</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>IxAq16stwyEDmwBfMSPyr6bK6iM=</ds:SignatureValue> <ds:KeyInfo> <wsse:SecurityTokenReference> <wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-soap-message-security-1.1#EncryptedKeySHA1" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">1qs60T2OmXwSq32UjIGrMmasdm4=</wsse:KeyIdentifier> </wsse:SecurityTokenReference> </ds:KeyInfo> </ds:Signature> </wsse:Security> </S:Header> <S:Body> <ns2:greetCustomerResponse xmlns:ns2="http://service.globinch.com/"> <return> Hello...Friend </return> </ns2:greetCustomerResponse> </S:Body> </S:Envelope> --uuid:bd210aea-ae7f-4bc2-8da8-800c509204ba----------------------
References:
- OASIS Web Services SecurityUsernameToken Profile 1.1
- Apache Tomcat 6 SSL Configuration HOW-TO
- Apache Tomcat 7 SSL Configuration HOW-TO
- WS-Security Policy specification
Hello,
Very very useful guide!!!
I have a problem.
In this article, it’s explained how to encrypt the username token but I would like to encrypt soap body also. Username token and soap body both encrypted & signed. Can you help me?
can you tell me how this can be configured to execute as a stand alone client?