A web service is a method of communication between multiple devices over the World Wide Web. Using Web Services we can publish application's functions to everyone.In my previous blog I have explained with example how to create simple jaxws webservice application using apache cxf Jaxws Web Services example using CXF .
This Blog instruction will help us to create a sample secure jaxws webservice using apahe cxf and webservice policies
(http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd).
Please note I choose wsdl and spring xml configuration to secure jaxws webservice application so it will be easy for user to switch on/off and configure security features without modifying service interface and implementation classes. Pre-requsite
Instructions assume that jdk,jboss,cxf is installed without any error.
Implemenation instructions
Please note I choose wsdl and spring xml configuration to secure jaxws webservice application so it will be easy for user to switch on/off and configure security features without modifying service interface and implementation classes.
- Required Software
- Developemnt
- Testing
- java webservice client classes
- please open existing project that successfully created by using previous blog instructions previous blog instructions . Now we will modify existing project and secure the web application.
- Open Sample.wsdl under WEB-INF\wsdl\Sample.wsdl and add following 3 options is wsdl.
- Username token with plain text
- Username token with password hash
- SignEncryption
- Create a new package "com.kaustuv.poc.ws.security"
- create a new CallbackHandler class ServerPasswordCallback under package "com.kaustuv.poc.ws.security". Add following code snippet.
- Create SignatureInfoBean class under package "com.kaustuv.poc.ws.security". Add following code snippet
- Open cxf-beans.xml under WEB-INF/conf and modify as following.
- Create security-beans.xml under WEB-INF/conf and add following snippet.
- create folder name keys under WEB-INF/
- create following private and public key and certificates under WEB-INF/keys
- create serviceKeystore.properties under WEB-INF/keys and add following snippet
- open web.xml and modify as following This step is optional. We are doing it for just to be in safely sync with the examples.
- Export and package this as war(jaws-security-example.war).Destination path %JBOSS_HOME%\server\default\deploy Note:If we do not modify the web.xml then we do not need to change the war name.
- Open command prompt and go to directory %JBOSS_HOME\bin .
- Execute run.bat -c default -b 0.0.0.0
- click following link for our secure jaxws webservice project. http://localhost:8080/jaxws-security-example/Greetings?wsdl
<!-- Option 1 -->
<!-- UsernameTokenWithPlainTextPassword ## Simple username token policy plain text -->
<!-- -->
<wsp:Policy wsu:Id="UsernameTokenWithPlainTextPassword"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient" />
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
<!-- Option 2 -->
<!-- UsernameTokenWithTimestampNoncePasswordHash ## UsernameToken With Hash -->
<wsp:Policy wsu:Id="UsernameTokenWithTimestampNoncePasswordHash"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:HashPassword/>
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
<!-- Option 3 -->
<!-- SignEncryption ## Policy for first signing and then encrypting all messages, with the certificate
included in the message from client to server but only a thumb print on messages from
the server to the client. -->
<wsp:Policy wsu:Id="SignEncryption"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:AsymmetricBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:InitiatorToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:RequireThumbprintReference/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:InitiatorToken>
<sp:RecipientToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
<wsp:Policy>
<sp:RequireThumbprintReference/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:RecipientToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:TripleDesRsa15/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Strict/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
<sp:OnlySignEntireHeadersAndBody/>
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:SignedParts xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:SignedParts>
<sp:EncryptedParts xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:EncryptedParts>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
After adding above three security policy in wsdl we will use them one by one by referring the policy in wsdl:binding section.
eg .
<wsp:PolicyReference xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" URI="#UsernameTokenWithPlainTextPassword" />After adding three security policy wsdl will look like following.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<wsdl:definitions name="BSGLifecycleServices"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://poc.kaustuv.com/ws/service/greetings"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://poc.kaustuv.com/ws/service/greetings">
<!-- Option 1 -->
<!-- UsernameTokenWithPlainTextPassword ## Simple username token policy plain text -->
<!-- -->
<wsp:Policy wsu:Id="UsernameTokenWithPlainTextPassword"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient" />
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
<!-- Option 2 -->
<!-- UsernameTokenWithTimestampNoncePasswordHash ## UsernameToken With Hash -->
<!--
<wsp:Policy wsu:Id="UsernameTokenWithTimestampNoncePasswordHash"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:ExactlyOne>
<wsp:All>
<sp:SupportingTokens xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:UsernameToken sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:HashPassword/>
</wsp:Policy>
</sp:UsernameToken>
</wsp:Policy>
</sp:SupportingTokens>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
-->
<!-- Option 3 -->
<!-- SignEncryption ## Policy for first signing and then encrypting all messages, with the certificate
included in the message from client to server but only a thumb print on messages from
the server to the client. -->
<!--
<wsp:Policy wsu:Id="SignEncryption"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsp:ExactlyOne>
<wsp:All>
<sp:AsymmetricBinding xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<wsp:Policy>
<sp:InitiatorToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
<wsp:Policy>
<sp:RequireThumbprintReference/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:InitiatorToken>
<sp:RecipientToken>
<wsp:Policy>
<sp:X509Token sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Never">
<wsp:Policy>
<sp:RequireThumbprintReference/>
</wsp:Policy>
</sp:X509Token>
</wsp:Policy>
</sp:RecipientToken>
<sp:AlgorithmSuite>
<wsp:Policy>
<sp:TripleDesRsa15/>
</wsp:Policy>
</sp:AlgorithmSuite>
<sp:Layout>
<wsp:Policy>
<sp:Strict/>
</wsp:Policy>
</sp:Layout>
<sp:IncludeTimestamp/>
<sp:OnlySignEntireHeadersAndBody/>
</wsp:Policy>
</sp:AsymmetricBinding>
<sp:SignedParts xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:SignedParts>
<sp:EncryptedParts xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702">
<sp:Body/>
</sp:EncryptedParts>
</wsp:All>
</wsp:ExactlyOne>
</wsp:Policy>
-->
<wsdl:types>
<xsd:schema targetNamespace="http://poc.kaustuv.com/ws/service/greetings">
<xsd:element name="GreetingsRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="name" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="GreetingsResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="message" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</wsdl:types>
<wsdl:message name="GreetingsReq">
<wsdl:part element="tns:GreetingsRequest" name="parameterIn" />
</wsdl:message>
<wsdl:message name="GreetingsRes">
<wsdl:part element="tns:GreetingsResponse" name="parameterOut" />
</wsdl:message>
<wsdl:portType name="Greetings">
<wsdl:operation name="Greetings">
<wsdl:input message="tns:GreetingsReq" />
<wsdl:output message="tns:GreetingsRes" />
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="GreetingsSOAPBinding" type="tns:Greetings">
<wsp:PolicyReference xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" URI="#UsernameTokenWithPlainTextPassword" />
<!-- wsp:PolicyReference xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" URI="#UsernameTokenWithTimestampNoncePasswordHash" /-->
<!-- wsp:PolicyReference xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" URI="#SignEncryption" /-->
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<wsdl:operation name="Greetings">
<soap:operation soapAction="Greetings" />
<wsdl:input>
<soap:body use="literal" />
</wsdl:input>
<wsdl:output>
<soap:body use="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="GreetingsService">
<wsdl:port name="GreetingsPort" binding="tns:GreetingsSOAPBinding">
<soap:address location="http://www.kaustuv.com/ws/service/" />
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
It is strongly recommended to use above three options individually.
Eg. suppose we are planning to use security option 1 then comment out other two security options and refer option 1 in wsd:binding section.
/**
*
* Copyright (c) Kaustuv Maji , 2014
* Repos - https://github.com/kaustuvmaji
* Blog - http://kaustuvmaji.blogspot.in
*
*/
package com.kaustuv.poc.ws.security;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
/**
* This class is responsible to implement web service security features.
*
* @author KMaji
*
*/
public class ServerPasswordCallback implements CallbackHandler {
private SignatureInfoBean signatureInfo;
/**
* Getter for the property signatureInfo.
*
* @return Returns the value of signatureInfo.
*/
public SignatureInfoBean getSignatureInfo() {
return signatureInfo;
}
/**
* Setter for the property signatureInfo.
*
* @param signatureInfo
* The new value of signatureInfo.
*/
public void setSignatureInfo(SignatureInfoBean signatureInfo) {
this.signatureInfo = signatureInfo;
}
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback wsPasswordCallback = null;
String password = null;
for (int count = 0; count < callbacks.length; count++) {
wsPasswordCallback = (WSPasswordCallback) callbacks[count];
// String identifier = wsPasswordCallback.getIdentifier();
switch (wsPasswordCallback.getUsage()) {
case WSPasswordCallback.USERNAME_TOKEN :
try {
password = "password";
} catch (Exception exp) {
exp.printStackTrace();
}
wsPasswordCallback.setPassword(password);
break;
case WSPasswordCallback.DECRYPT :
wsPasswordCallback.setPassword(signatureInfo.getSignatureServiceKeyPassword());
break;
case WSPasswordCallback.SIGNATURE :
wsPasswordCallback.setPassword(signatureInfo.getSignatureServiceKeyPassword());
break;
}
}
}
}
/**
*
* Copyright (c) Kaustuv Maji , 2014
* Repos - https://github.com/kaustuvmaji
* Blog - http://kaustuvmaji.blogspot.in
*
*/
package com.kaustuv.poc.ws.security;
import java.io.Serializable;
public class SignatureInfoBean implements Serializable {
private static final long serialVersionUID = -5749465533676763004L;
public SignatureInfoBean() {
}
private String signatureServiceKey = null;
private String signatureServiceKeyPassword = null;
/**
* Getter for the property signatureServiceKey.
*
* @return Returns the value of signatureServiceKey.
*/
public String getSignatureServiceKey() {
return signatureServiceKey;
}
/**
* Setter for the property signatureServiceKey.
*
* @param signatureServiceKey
* The new value of signatureServiceKey.
*/
public void setSignatureServiceKey(String signatureServiceKey) {
this.signatureServiceKey = signatureServiceKey;
}
/**
* Getter for the property signatureServiceKeyPassword.
*
* @return Returns the value of signatureServiceKeyPassword.
*/
public String getSignatureServiceKeyPassword() {
return signatureServiceKeyPassword;
}
/**
* Setter for the property signatureServiceKeyPassword.
*
* @param signatureServiceKeyPassword
* The new value of signatureServiceKeyPassword.
*/
public void setSignatureServiceKeyPassword(String signatureServiceKeyPassword) {
this.signatureServiceKeyPassword = signatureServiceKeyPassword;
}
}
<?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:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="greeting" class="com.kaustuv.poc.ws.service.greetings.GreetingsImpl" />
<jaxws:endpoint xmlns:tns="http://poc.kaustuv.com/ws/service/greetings" id="greetings"
implementor="#greeting" wsdlLocation="WEB-INF/wsdl/Sample.wsdl" endpointName="tns:GreetingsPort"
serviceName="tns:GreetingsService" address="/Greetings">
<jaxws:features>
<bean class="org.apache.cxf.feature.LoggingFeature" />
</jaxws:features>
<!-- usernameToken option 1 and 2 -->
<!-- -->
<jaxws:properties>
<entry key="schema-validation-enabled" value="true" />
<entry key="ws-security.callback-handler">
<ref bean="serverPasswordCallback" />
</entry>
</jaxws:properties>
<!-- Sign Encryption option 3 only-->
<!--
<jaxws:properties>
<entry key="ws-security.signature.properties" value="file:D:/workspace/jaxws-security-example/WebContent/WEB-INF/keys/serviceKeystore.properties"/>
<entry key="ws-security.signature.username" value="myservicekey"/>
<entry key="ws-security.encryption.username" value="useReqSigCert"/>
<entry key="ws-security.callback-handler">
<ref bean="serverPasswordCallback" />
</entry>
</jaxws:properties>
-->
</jaxws:endpoint>
</beans>
In above xml there are two jaxws:properties configuration added for three security option that we already mentioned security options in wsdl.
For option 1 and 2 written in wsdl we must enable following by following snippet in cxf-beans.xml.
<jaxws:properties> <entry key="schema-validation-enabled" value="true" /> <entry key="ws-security.callback-handler"> <ref bean="serverPasswordCallback" /> </entry> </jaxws:properties>For option 3 written in wsdl we must enable corresponding jaxws:properties by following snippet in cxf-beans.xml .
<jaxws:properties> <entry key="ws-security.signature.properties" value="file:D:/workspace/jaxws-security-example/WebContent/WEB-INF/keys/serviceKeystore.properties"/> <entry key="ws-security.signature.username" value="myservicekey"/> <entry key="ws-security.encryption.username" value="useReqSigCert"/> <entry key="ws-security.callback-handler"> <ref bean="serverPasswordCallback" /> </entry> </jaxws:properties>Please notice we can not keep both jaxws:properties in cxf-beans.xml .
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="serverPasswordCallback" class="com.kaustuv.poc.ws.security.ServerPasswordCallback">
<property name="signatureInfo" ref="signatureInfo" />
</bean>
<bean id="signatureInfo" class="com.kaustuv.poc.ws.security.SignatureInfoBean">
<property name="signatureServiceKey" value="myservicekey" />
<property name="signatureServiceKeyPassword" value="skpass" />
</bean>
</beans>
In abve xml we created two bean one is serverPasswordCallback and another one is signatureInfo both are used for security implementation.
keytool -genkey -keyalg RSA -sigalg SHA1withRSA -validity 730 -alias myservicekey -keypass skpass -storepass sspass -keystore serviceKeystore.jks -dname "cn=localhost" keytool -genkey -keyalg RSA -sigalg SHA1withRSA -validity 730 -alias myclientkey -keypass ckpass -storepass cspass -keystore clientKeystore.jks -dname "cn=clientuser" keytool -export -rfc -keystore clientKeystore.jks -storepass cspass -alias myclientkey -file MyClient.cer keytool -import -trustcacerts -keystore serviceKeystore.jks -storepass sspass -alias myclientkey -file MyClient.cer -noprompt keytool -export -rfc -keystore serviceKeystore.jks -storepass sspass -alias myservicekey -file MyService.cer keytool -import -trustcacerts -keystore clientKeystore.jks -storepass cspass -alias myservicekey -file MyService.cer -noprompt
org.apache.ws.security.crypto.provider=org.apache.ws.security.components.crypto.Merlin org.apache.ws.security.crypto.merlin.keystore.file=D:/workspace/jaxws-security-example/WebContent/WEB-INF/keys/serviceKeystore.jks org.apache.ws.security.crypto.merlin.keystore.password=sspass org.apache.ws.security.crypto.merlin.keystore.type=jks org.apache.ws.security.crypto.merlin.keystore.alias=myservicekeyNow for security option 3 server side is secured with private key and to access secured webservice then user need to provide public key. Once user is authorized by public key then user will be able to access webservice.
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>jaxws-security-example</display-name>
<servlet>
<description>Apache CXF Endpoint</description>
<display-name>cxf</display-name>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/conf/*beans.xml</param-value>
</context-param>
</web-app>
Using webservice policy is very transparent for webservice client to understand what kind of security is associated to service by readin published webservice wsdl link. Check highlighted part in following image.
- Option 1 security test. Following class will be used to test the username token policy.
- Option 2 security test. For testing option 2 we will use the same class which we used to test username token plain text.
- Option 3 security test. Create clientcallback class for client application for encrypting message.
Post Development testing
/**
*
* Copyright (c) Kaustuv Maji , 2014
* Repos - https://github.com/kaustuvmaji
* Blog - http://kaustuvmaji.blogspot.in
*
*/
package client;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import com.kaustuv.poc.ws.service.greetings.Greetings;
import com.kaustuv.poc.ws.service.greetings.GreetingsRequest;
import com.kaustuv.poc.ws.service.greetings.GreetingsResponse;
/**
* @author KMaji
*
*/
public class TestUserNameToken {
private static final Logger LOG = Logger.getLogger(TestUserNameToken.class.getName());
/**
* @param args
* @throws MalformedURLException
*/
public static void main(String[] args) throws MalformedURLException {
Service service = Service.create(new URL("http://localhost:8080/jaxws-security-example/Greetings?wsdl"),
new QName("http://poc.kaustuv.com/ws/service/greetings",
"GreetingsService"));
Greetings greetings = service.getPort(Greetings.class);
Client client = ClientProxy.getClient(greetings);
Endpoint endPoint = client.getEndpoint();
endPoint.getOutInterceptors().add(new LoggingOutInterceptor());
endPoint.getInInterceptors().add(new LoggingInInterceptor());
Map<String, Object> ctx = ((BindingProvider) greetings).getRequestContext();
ctx.put("ws-security.username", "demo");
ctx.put("ws-security.password", "password");
GreetingsRequest gReq = new GreetingsRequest();
gReq.setName("kaustuv");
GreetingsResponse gRes = null;
try {
gRes = greetings.greetings(gReq);
} catch (Throwable e) {
LOG.error(e.getMessage(), e.getCause());
}
LOG.info("Response # " + gRes.getMessage());
}
}
ID: 2
Address: http://localhost:8080/jaxws-security-example/Greetings
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[*/*], cache-control=[no-cache], connection=[keep-alive], Content-Length=[745], content-type=[text/xml; charset=UTF-8], host=[localhost:8080], pragma=[no-cache], SOAPAction=["Greetings"], user-agent=[Apache CXF 2.5.2]}
Payload: demo password kaustuv
--------------------------------------
18:58:33,784 INFO [STDOUT] com.kaustuv.poc.ws.service.greetings.GreetingsRequest@74d345b8
INFO: Outbound Message
---------------------------
ID: 2
Encoding: UTF-8
Content-Type: text/xml
Headers: {}
Payload: kaustuv
--------------------------------------
In above console log we saw the username and password (plain text) is wrapped in soap:header section.
ID: 3
Address: http://localhost:8080/jaxws-security-example/Greetings
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[*/*], cache-control=[no-cache], connection=[keep-alive], Content-Length=[977], content-type=[text/xml; charset=UTF-8], host=[localhost:8080], pragma=[no-cache], SOAPAction=["Greetings"], user-agent=[Apache CXF 2.5.2]}
Payload: demo ZQl7x4is11VIDiZXxZex7jAPe4g= /okFkV98Off1m8VYQs0BXg== 2014-09-27T13:36:29.140Z kaustuv
--------------------------------------
19:06:29,471 INFO [STDOUT] com.kaustuv.poc.ws.service.greetings.GreetingsRequest@46d4db6
INFO: Outbound Message
---------------------------
ID: 3
Encoding: UTF-8
Content-Type: text/xml
Headers: {}
Payload: kaustuv
--------------------------------------
In above console log we saw the username and password (encrypted) is wrapped in soap:header section.
/**
*
* Copyright (c) Kaustuv Maji , 2014
* Repos - https://github.com/kaustuvmaji
* Blog - http://kaustuvmaji.blogspot.in
*
*/
package client;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.ws.security.WSPasswordCallback;
/**
* @author KMaji
*
*/
public class SignEncrClientCallback implements CallbackHandler {
private Map<String, String> passwords = new HashMap<String, String>();
public SignEncrClientCallback() {
passwords.put("myclientkey", "ckpass");
}
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
String pass = passwords.get(pc.getIdentifier());
if (pass != null) {
pc.setPassword(pass);
return;
}
}
}
}
Following class is main test class for security option 3.
/**
*
* Copyright (c) Kaustuv Maji , 2014
* Repos - https://github.com/kaustuvmaji
* Blog - http://kaustuvmaji.blogspot.in
*
*/
package client;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Service;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import com.kaustuv.poc.ws.service.greetings.Greetings;
import com.kaustuv.poc.ws.service.greetings.GreetingsRequest;
import com.kaustuv.poc.ws.service.greetings.GreetingsResponse;
/**
* @author KMaji
*
*/
public class SignEncryptionClient {
/**
* @param args
* @throws MalformedURLException
*/
public static void main(String[] args) throws MalformedURLException {
Service service = Service.create(new URL("http://localhost:8080/jaxws-security-example/Greetings?wsdl"),
new QName("http://poc.kaustuv.com/ws/service/greetings",
"GreetingsService"));
Logger LOG = Logger.getLogger(SignEncryptionClient.class.getName());
Greetings greetings = service.getPort(Greetings.class);
Client client = ClientProxy.getClient(greetings);
Endpoint endPoint = client.getEndpoint();
endPoint.getOutInterceptors().add(new LoggingOutInterceptor());
endPoint.getInInterceptors().add(new LoggingInInterceptor());
Map<String, Object> ctx = ((BindingProvider) greetings).getRequestContext();
ctx.put("ws-security.signature.properties", "clientKeystore.properties");
ctx.put("ws-security.signature.username", "myclientkey");
ctx.put("ws-security.encryption.properties", "clientKeystore.properties");
ctx.put("ws-security.encryption.username", "myservicekey");
ctx.put("ws-security.callback-handler", "client.SignEncrClientCallback");
GreetingsRequest gReq = new GreetingsRequest();
gReq.setName("kaustuv");
GreetingsResponse gRes = null;
try {
gRes = greetings.greetings(gReq);
LOG.info("Response #" + gRes.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
}
}
ID: 4
Address: http://localhost:8080/jaxws-security-example/Greetings
Encoding: UTF-8
Http-Method: POST
Content-Type: text/xml; charset=UTF-8
Headers: {Accept=[*/*], cache-control=[no-cache], connection=[keep-alive], content-type=[text/xml; charset=UTF-8], host=[localhost:8080], pragma=[no-cache], SOAPAction=["Greetings"], transfer-encoding=[chunked], user-agent=[Apache CXF 2.5.2]}
Payload: MIIBoTCCAQqgAwIBAgIEUVm7NzANBgkqhkiG9w0BAQUFADAVMRMwEQYDVQQDEwpjbGllbnR1c2VyMB4XDTEzMDQwMTE2NTIwN1oXDTE1MDQwMTE2NTIwN1owFTETMBEGA1UEAxMKY2xpZW50dXNlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmvRe7Fw4zS4z+whmwFfzuma9R2GbG1kkZTzUkogDdR2zes6qnk84LxIwbyoLDL4HOBrm4ENdGMknYletrLppejRqXdyu4mkbJ1FH0zLAuGJzxN5vZluu0uQJvc1YmKVAbsAwDsKnkvURLn471YtBAtCJsEdUyYOESTOc2lQrrSMCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBbJfRlYAyhGMkEUqKkb1epaxa6TfR5aAE4UPV5fbw5H7EYPJkC7i5Rg1uUqSC7ZI4+fNnMGU2Pbg9at4FLCyB9++KhQu0hWsE/AfwIIff+57aXBU3n3oJK+5RUaYaTmQWQnTc3nwui2eRgIG9yGiR1wkNntvYNVXmKsXP+h1e9Kg== 2014-09-27T13:56:49.689Z 2014-09-27T14:01:49.689Z o4dTpJf/6Meble547wkYIbB6M60= Oi7ejMXN+dPXHSmYUdAH+kxmB3XTscAbqp3TfMgSxegIBMdgb/Ce/HukLqZqgpClDZFX+iMKHSR8hCNdOM7X3v/gdL+zJbvSAgrRDt7+aPv+wdtSSjSzdhEVlWM5zIEsQ0QIAoz8P55hZjbRl4/4kJEf5Fu/ez909jslcApgp6M= WBhxAWuZAfryjQe7v04w87EMtvI= yvK+/PtNMYLa+S2qnMe3ZMkm0zE= aXQTtQLlupIbjWV3lhhrxcABAheoCT1EWDQPx6qIb1xwV6PgFedQIuX5+3a/I9cyrPEBcgTTooBu
+Aot8R8nYdcOhwv8jgfuhmlsAZPSQFd0KE7S2u/SmAB2tC5RUSNAFKb2/bf2VXEzTQyk6b/Muom+
z509bUL8/jLA1lUJpu8= cJ4gcuZwuuqskkjU9Hi9dUe2jjtVT+xKMypmnQf4CxkI/VXchAo7xgNoSrJLIPUlbdfBJ/TZ4c2dGkyV5L6DSBGSQz7B1BcvWulWQfrlvrLy1r0YtvGUtzmeON4TPLV0LfTeS+vz6p1bd3EP0mg5dJaVrnhedSpp/x3FWvTDbS/5OWfnJjR9plwW0ggbdYs+gfVh2NhBHcv7cXty+ABA2d2Cz7WChsYXgDKHm4S9PXwFiayH1uebAxEwSfUz0U8eC+eMCyZEFDorG9ZJgRhbtIBvvPxzyvOVg9BJISXNgNFFq25J0n79I0nhEOKht1wePJXAux+HR7PPeTZEygrqcGzbJO36vBBGhrDSIK/DBg8YIzGHmq8RGQ==
--------------------------------------
19:26:52,164 INFO [STDOUT] com.kaustuv.poc.ws.service.greetings.GreetingsRequest@3a4c421b
INFO: Outbound Message
---------------------------
ID: 4
Encoding: UTF-8
Content-Type: text/xml
Headers: {}
Payload: MIIBoTCCAQqgAwIBAgIEUVm7NzANBgkqhkiG9w0BAQUFADAVMRMwEQYDVQQDEwpjbGllbnR1c2VyMB4XDTEzMDQwMTE2NTIwN1oXDTE1MDQwMTE2NTIwN1owFTETMBEGA1UEAxMKY2xpZW50dXNlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmvRe7Fw4zS4z+whmwFfzuma9R2GbG1kkZTzUkogDdR2zes6qnk84LxIwbyoLDL4HOBrm4ENdGMknYletrLppejRqXdyu4mkbJ1FH0zLAuGJzxN5vZluu0uQJvc1YmKVAbsAwDsKnkvURLn471YtBAtCJsEdUyYOESTOc2lQrrSMCAwEAATANBgkqhkiG9w0BAQUFAAOBgQBbJfRlYAyhGMkEUqKkb1epaxa6TfR5aAE4UPV5fbw5H7EYPJkC7i5Rg1uUqSC7ZI4+fNnMGU2Pbg9at4FLCyB9++KhQu0hWsE/AfwIIff+57aXBU3n3oJK+5RUaYaTmQWQnTc3nwui2eRgIG9yGiR1wkNntvYNVXmKsXP+h1e9Kg== 2014-09-27T13:56:52.253Z 2014-09-27T14:01:52.253Z dXw6imyjRGr3un72RDm6T4MuYiaq2jHT3rtAWgQFWoeeCQXl05WMRi3sWVHyZFCmCZIqyjEh4yVbkNuS06KGRupQpP3PyC6f2YVFqxa5m2u0z+CZZRbeIxWuihwbL3mXDcJylOdgpfM8C1nJSXv6mbSKMk49NrSnL546FbUBRSc= SrBUKiCsZWWkUJ+g88BRlFbbv1Q= dI2z5gM35CEySeXSGZqTzb637dA= js1iy79LBQLszVLDR6q3keKlnXxTAb9DAe9OtXYC3Crm9tjd+jdox2F+JMacRa/frvgk+45ZmI2b1WTpn70ZdngTUlSSH393bmSFZKZnGiTDrzyPHNRYl/NPIESUsyW0kjQS6hK5RYt25SRHOGcBLrMz93VH6+DDSoqWGODKIO0= o4dTpJf/6Meble547wkYIbB6M60= HaP1FpvQM09q+e72nhytV2n/j/Nlz5wVk/wZdWWc234HPibx08f2/DGrvCuP9FdheC41XqgKHVa6/zLWw5I2jXoUIpxnVkyRyCxUHi3x7Cu7uQtRqvdGdhho0hrNI99d2fZ1QLDyXy3hRkiL3BD7d3Gmh1RTqLghDJOUkY6VqCvWT1xpVBV50Uu0fycub94br8fmKDZTOh8av78pF7DCfj9D+y3r4bvZwJXvVWbDbUVsKWFYcXQJJXwj1RahgxegvMnUfd5QRIPT0wympH41RnjccBMojBZ/NYLAwqMV0O32/IZZ2I7slkjYyoeQOp9OxgafQJnK3mM45ASaN+2VnSeY5W4d1AHgdi/PCfsTlJ6W7ry/gEXY2DXYh3ajyx9R
--------------------------------------
In above example console log we can see that entire message is encrypted now.
Source Code
- References:
European Union laws require you to give European Union visitors information about cookies used on your blog. In many cases, these laws also require you to obtain consent.
As a courtesy, we have added a notice on your blog to explain Google's use of certain Blogger and Google cookies, including use of Google Analytics and AdSense cookies.



No comments:
Post a Comment