Applying WSS4J based
Web Service Security based on User
Name Token to the existing Axis1.4 web service:
Assumption : Webservice Allready deployed on tomcat server with wsdl accessible and client is also generated using wsdl
and there is an entry for axis servlet in web.xml already exist just like below
<servlet>
<display-name>Apache-Axis Servlet</display-name>
<servlet-name>AxisServlet</servlet-name>
<servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/servlet/AxisServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>*.jws</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<display-name>Apache-Axis Servlet</display-name>
<servlet-name>AxisServlet</servlet-name>
<servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/servlet/AxisServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>*.jws</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
WSS4j provides 4 kinds of ws security standerd
Now start applying security using user name token
A) Server
Side:
Make changes in the
server-config.wsdd inside WEB-INF(server-config.wsdd is generated when creating
wsdl from Java class using WSDL2Java toll or eclipse
Add <requestFlow>
element in side <servive> element
For example
<ns1:service
name="UserSoap" provider="java:RPC"
style="wrapped" use="literal">
<ns3:operation
name="changePassword" qname="ns1:changePassword"
returnQName="ns1:changePasswordReturn"
returnType="ns2:UserBean" soapAction="" xmlns:ns1="http://user.services.soap.lcc.mycompany.com"
xmlns:ns2="http://beans.user.services.soap.lcc.mycompany.com"
xmlns:ns3="http://xml.apache.org/axis/wsdd/">
<ns3:parameter
qname="ns1:newPassword" type="xsd:string"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
<ns3:parameter qname="ns1:userId"
type="xsd:string"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
<ns3:parameter
qname="ns1:oldPassword" type="xsd:string"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
<ns3:parameter
qname="ns1:retypePassword" type="xsd:string"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
<ns3:parameter
qname="ns1:profile_chgpwd" type="xsd:string"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
<ns3:parameter
qname="ns1:last_pwdchg" type="xsd:string"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
<ns3:parameter
qname="ns1:submission" type="xsd:string"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"/>
</ns3:operation>
<ns1:requestFlow>
<ns1:handler
type="java:org.apache.ws.axis.security.WSDoAllReceiver">
<parameter name="action"
value="UsernameToken"/>
<ns1:parameter name="passwordCallbackClass"
value="com.mycompany.lcc.soap.services.user.ChangePasswordCallBackHandler"/>
</ns1:handler>
</ns1:requestFlow>
<ns1:parameter
name="allowedMethods" value="changePassword"/>
<ns1:parameter
name="typeMappingVersion" value="1.2"/>
<ns1:parameter
name="wsdlPortType" value="UserSoap"/>
<ns1:parameter name="className"
value="com.mycompany.lcc.soap.services.user.UserSoap"/>
<ns1:parameter name="wsdlServicePort"
value="UserSoap"/>
<ns1:parameter
name="schemaQualified"
value="http://beans.user.services.soap.lcc.mycompany.com,http://user.services.soap.lcc.mycompany.com"/>
<ns1:parameter
name="wsdlTargetNamespace" value="http://user.services.soap.lcc.mycompany.com"/>
<ns1:parameter
name="wsdlServiceElement" value="UserSoapService"/>
<ns1:typeMapping
deserializer="org.apache.axis.encoding.ser.BeanDeserializerFactory"
encodingStyle="" qname="ns3:UserBean"
serializer="org.apache.axis.encoding.ser.BeanSerializerFactory"
type="java:com.mycompany.lcc.soap.services.user.beans.UserBean"
xmlns:ns3="http://beans.user.services.soap.lcc.mycompany.com"/>
</ns1:service>
Step2: Write a callBackHandler
package com.mycompany.lcc.soap.services.user;
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;
public class
ChangePasswordCallBackHandler implements CallbackHandler{
@Override
public void
handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException
{
for (int i = 0; i <
callbacks.length; i++) {
WSPasswordCallback pwcb =
(WSPasswordCallback)callbacks[i];
// set the password given a username
if ("wss4j".equals(pwcb.getIdentifier()))
{
pwcb.setPassword("security");
}
}
}
}
Redeploy the service.
Your service should now be expecting a WSS Username Token in in the incoming
requests, and clients should send the username "wss4j" and password
"security" to get through.
Note:We can externalize
the password in any config file
We can provide user
Client jar which will contain user name and password
b) Client Side
Client
Side:
Required
Jars at client side: set in class path for writing calling class and Handler
Class
1.
wss4j-1.5.12.jar
2.
xmlsec-1.4.5.jar
Step1:Create a file client_deploy.wsdd in side your
classes folder or put in class path[for
stand-alone and web client both]
Below is the sample client_deploy.wsdd
<deployment xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<transport name="http"
pivot="java:org.apache.axis.transport.http.HTTPSender"
/>
<globalConfiguration>
<requestFlow>
<handler type="java:org.apache.ws.axis.security.WSDoAllSender">
<parameter name="user"
value="wss4j"/>
<parameter name="action"
value="UsernameToken" />
<parameter name="passwordType"
value="PasswordDigest
<parameter name="passwordCallbackClass"
value="com.ChangePwdClientCallBackHandler" />
</handler>
</requestFlow>
</globalConfiguration>
</deployment>
Step2: Create a CallBack
Handler Class to set the password
For example
package com;
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;
public class ChangePwdClientCallBackHandler
implements CallbackHandler {
@Override
public
void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException
{
for (int i = 0; i <
callbacks.length; i++) {
if (callbacks[i] instanceof WSPasswordCallback)
{
WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];
// set the password given a
username
if ("wss4j".equals(pc.getIdentifier()))
{
pc.setPassword("security");
}
} else {
throw new
UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
}
}
}
}
Step3:
Calling the webservice
package com;
import
java.io.FileNotFoundException;
import java.net.MalformedURLException;
import
java.rmi.RemoteException;
import
javax.xml.rpc.ServiceException;
import
org.apache.axis.EngineConfiguration;
import
org.apache.axis.configuration.FileProvider;
import com.mycompany.lcc.soap.services.user.UserSoap;
import com.mycompany.lcc.soap.services.user.UserSoapServiceLocator;
import com.mycompany.lcc.soap.services.user.beans.UserBean;
public class CpClient {
public static void
main(String[] args) throws ServiceException ,RemoteException,
MalformedURLException, FileNotFoundException{
EngineConfiguration config = new
FileProvider("./client_deploy.wsdd");
UserSoapServiceLocator sl= new
UserSoapServiceLocator(config);
UserSoap us = sl.getUserSoap(new
java.net.URL("http://localhost:8080/services/UserSoap"));
//this is actaul webservice method call
UserBean u = us.changePassword("Test1234",
"12345", "Test123", "Test1234", null,
null,null);
System.out.println("isSuccess:"+u.getServiceSuccess());
System.out.println("Error mesg:
"+u.getErrorMsg());
System.out.println("Success msg:
"+u.getSuccessMsg());
}
}
Explanation:
Here I am calling the
web service from an standalone client,we can also call from any POJO inside the
web application
Please note that
client_deploy.wsdd (client deployment descriptor file) is just one folder up
from the calling class so
EngineConfiguration
config = new FileProvider("./client_deploy.wsdd");
Above Line searches the
descriptor file one level above ,if you have put descriptor in other location
in class path,please specify relative path to wsdd file
ServiceLocator loads configuaration
which calls the BackBackHandler Class defind in the wsdd file and Handler reads
configuration and checks if user is ws4j then set the password as security and
this information will now be passed to the webservice as part of SOAP header
and Server will verify the password and then allow to service request if
credentials matches.
No comments:
Post a Comment