Axis1 Deployment Tutorial
Introduction
WSS4J 1.5.x can be used for securing web services deployed in virtually any application server, but it includes special support for Axis. WSS4J 1.5.x ships with handlers that can be used in Axis-based web services for an easy integration. These handlers can be added to the service deployment descriptor (wsdd file) to add a WS-Security layer to the web service. This is a step by step tutorial for deploying a simple service with Username Token.Prerequisites
Axis 1.2 installed and configured on a Tomcat Server. This tutorial was performed on a Linux machine with Tomcat 5.5.4/Java 1.5.0, however, the setup should be similar on other application servers, or other operating systems (like Windows) unless we stated otherwise.Steps
Installing WSS4J
- Download the WSS4J binaries or build it from sources
- Copy the contents of the WSS4J lib directory to your Axis WEB-INF/lib directory. Many jar files will already exist. Most of them will already exist there but you can just overwrite them all.
- You may need to restart Tomcat unless you have automatic deployment/class loading turned on. Check the Axis Happiness Page (typically at http://localhost:8080/axis), make sure that the XML Security (xmlsec.jar) is listed under the "Optional Components" section.
Creating the Service
- This tutorial will secure the StockQuoteService which ships with Axis. Unless you have one already, create a deployment descriptor (deploy.wsdd) file with the following contents:
- deploy the service (using AxisAdmin):
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="stock-wss-01" provider="java:RPC" style="document" use="literal">
<parameter name="className" value="samples.stock.StockQuoteService"/>
<parameter name="allowedMethods" value="getQuote"/>
<parameter name="scope" value="application"/>
</service>
</deployment>
-
java
org.apache.axis.client.AdminClient
-lhttp://localhost:8080/axis/services/AdminService deploy.wsdd
Creating the Client
- Use WSDL2Java to generate the client service bindings:
java org.apache.axis.wsdl.WSDL2Java -o . -Nhttp://fox:8080/axis/services/stock-wss-01 samples.stock.client http://fox:8080/axis/services/stock-wss-01?wsdl
A bunch of java classes will be created under samples/stock/client, including the StockQuoteServiceServiceLocator.
- Write a simple java client that uses the generated service
locator. For example:
package samples.stock.client;
import java.rmi.RemoteException;
import javax.xml.rpc.ServiceException;
public class StockServiceClient {
public StockServiceClient() {
}
public static void main(String[] args) throws ServiceException, RemoteException {
if (args.length == 0) {
System.out.println("Usage:\njava StockServiceClient [symbol]");
return;
}
StockQuoteServiceService locator = new StockQuoteServiceServiceLocator();
StockQuoteService service = locator.getStockWss01();
float quote = service.getQuote(args[0]);
System.out.println("stock quote service returned " + args[0] + ": " + quote);
}
}
- run the client:
java samples.stock.client.StockServiceClient IBM
If all went well, you should get the result:
stock quote service returned IBM: 95.68
Username Token
Configuring the Service
- Modify the deployment descriptor you created above to look like
this:
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
<service name="stock-wss-01" provider="java:RPC" style="document" use="literal">
<requestFlow>
<handler type="java:org.apache.ws.axis.security.WSDoAllReceiver">
<parameter name="passwordCallbackClass" value="PWCallback"/>
<parameter name="action" value="UsernameToken"/>
</handler>
</requestFlow>
<parameter name="className" value="samples.stock.StockQuoteService"/>
<parameter name="allowedMethods" value="getQuote"/>
<parameter name="scope" value="application"/>
</service>
</deployment>
WSDoAllReceiver is an Axis handler that can be located in wss4j.jar. This is the standard way to deploy an Axis handler. For more details please refer to the Axis handler for WSS4J documentation.
- Create a class named PWCallback.java and compile it into your
Axis WEB-INF/classes directory. In this example I used the default
package for simplicity, but you might need to use the fully qualified
class name (be consistent
with the deployment descriptor).
The following code snippet shows a simple password callback class:
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 PWCallback implements CallbackHandler {
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");
}
}
}
}
- 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.
Configuring the Client
- run the client we created again:
java samples.stock.client.StockServiceClient IBM
You should now get an error:
Exception in thread "main" AxisFault
faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.generalException
faultSubcode:
faultString: WSDoAllReceiver: Request does not contain required Security header
This is because your client is not configured to send a Username Token yet, so the service is rejecting the request.
- Create a deployment descriptor file (client_deploy.wsdd) for the
client:
<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="action" value="UsernameToken"/>
<parameter name="user" value="wss4j"/>
<parameter name="passwordCallbackClass" value="samples.stock.client.PWCallback"/>
<parameter name="passwordType" value="PasswordDigest"/>
</handler>
</requestFlow >
</globalConfiguration >
</deployment>
- Create the samples.stock.client.PWCallback
class:
package samples.stock.client;
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;
/**
* PWCallback for the Client
*/
public class PWCallback implements CallbackHandler {
/**
* @see javax.security.auth.callback.CallbackHandler#handle(javax.security.auth.callback.Callback[])
*/
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");
}
}
}
}
- Define the system property axis.ClientConfigFile for your client:
java -Daxis.ClientConfigFile=client_deploy.wsdd -classpath $AXISCLASSPATH samples.stock.client.StockServiceClient
Make sure that your classpath includes the jar files under WEB-INF/lib.
Another way to do this is to specify the wsdd file in your StockServiceClient to the service locator programmatically:
...
import org.apache.axis.EngineConfiguration;
import org.apache.axis.configuration.FileProvider;
...
EngineConfiguration config = new FileProvider("client_deploy.wsdd");
StockQuoteServiceService locator = new StockQuoteServiceServiceLocator(config);
...
- Run the client, you should get no errors:
stock quote service returned IBM: 95.7
Your client is now sending a Username Token in the wsse request header with the username "wss4j" (see client_deploy.wsdd) and password "security" (see the PWCallback implementation).
Another way to do this is to have the client application set the username and CallbackHandler implementation programmatically instead of client_deploy.wsdd:
...
import org.apache.axis.client.Stub;
...
Remote remote = locator.getPort(StockQuoteService.class);
Stub axisPort = (Stub)remote;
axisPort._setProperty(UsernameToken.PASSWORD_TYPE, WSConstants.PASSWORD_DIGEST);
axisPort._setProperty(WSHandlerConstants.USER, "wss4j");
axisPort._setProperty(WSHandlerConstants.PW_CALLBACK_REF, pwCallback);
where "pwCallback" is a reference to a PWCallback implementation. See the Axis handler for WSS4J documentation for more details on this.
- Try modifying your client's PWCallback to return the wrong password, or send the wrong username. The service should reject your requests.

