blob: e56a36aa770c1c848937639956c66558e0fcdaca [file] [log] [blame]
<?xml version="1.0" encoding="ISO-8859-1"?>
<document><properties><title>Axis Deployment Tutorial</title></properties><body><section name="Apache WSS4J"></section><section name="Axis Deployment Tutorial"></section><section name=""><subsection name="Contents"><ul>
<li>Introduction</li>
<li>Prerequisties</li>
<li>Steps</li>
<ul>
<li>Username Token<br></br>
</li>
</ul>
</ul></subsection></section><section name=""><subsection name="Introduction"><div style="margin-left: 40px;">WSS4J can be used for securing web
services deployed in virtually any application server, but it includes
special support for Axis. WSS4J 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.<br></br>
</div><br></br></subsection><subsection name="Prerequisties"><div style="margin-left: 40px;"><a href="http://ws.apache.org/axis/">Axis
1.2</a> installed and configured on a <a href="http://jakarta.apache.org/tomcat/">Tomcat Server</a>.  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.<br></br>
</div></subsection><subsection name="Steps"></subsection><subsection name="    Installing WSS4J"><div style="margin-left: 40px;">
<ol>
<li>Download the WSS4J binaries or build it from sources<br></br>
</li>
<li>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.</li>
<li>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.</li>
</ol>
<h4>Creating the Service</h4>
</div><ol>
<ol>
<li>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:</li>
</ol>
</ol><div style="margin-left: 40px;">
<ol start="2">
<br></br>
<span style="color: rgb(0, 0, 153);">&lt;deployment
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"> &lt;service
name="stock-wss-01" provider="java:RPC" style="document"
use="literal"&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">  &lt;parameter
name="className" value="samples.stock.StockQuoteService"/&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">  &lt;parameter
name="allowedMethods" value="getQuote"/&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">  &lt;parameter
name="scope" value="application"/&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"> &lt;/service&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">&lt;/deployment&gt;<br></br>
<br></br>
</span><li>deploy the service (using AxisAdmin):</li>
</ol>
</div><div style="margin-left: 40px;">
<ol>
<span style="color: rgb(0, 0, 153);">java
org.apache.axis.client.AdminClient
-lhttp://localhost:8080/axis/services/AdminService deploy.wsdd<br></br>
</span>
</ol>
<h4>Creating the Client</h4>
<ol>
<li>Use WSDL2Java to generate the client service bindings:<br></br>
<span style="color: rgb(0, 0, 153);">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</span><br></br>
<br></br>
A bunch of java classes will be created under samples/stock/client,
including the StockQuoteServiceServiceLocator.<br></br>
<br></br>
</li>
<li>Write a simple java client that uses the generated service
locator. For example:<br></br>
<br></br>
<span style="color: rgb(0, 0, 153);">package samples.stock.client;</span><br style="color: rgb(0, 0, 153);"></br>
<br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
java.rmi.RemoteException;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
javax.xml.rpc.ServiceException;</span><br style="color: rgb(0, 0, 153);"></br>
<br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">public class
StockServiceClient {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">    public
StockServiceClient() {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">    }</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">    public
static void main(String[] args) throws ServiceException,
RemoteException {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">       
if (args.length == 0) {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">           
System.out.println("Usage:\njava StockServiceClient [symbol]");</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">           
return;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">       
}</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">       
StockQuoteServiceService locator = new
StockQuoteServiceServiceLocator();</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">       
StockQuoteService service = locator.getStockWss01();</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">       
float quote = service.getQuote(args[0]);</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">       
System.out.println("stock quote service returned " + args[0] + ": " +
quote);</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">    }</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">}</span><br></br>
<br></br>
</li>
<li>run the client:<br></br>
<span style="color: rgb(0, 0, 153);">java
samples.stock.client.StockServiceClient IBM</span><br></br>
<br></br>
If all went well, you should get the result:<br></br>
<br></br>
<span style="color: rgb(0, 0, 153);"></span> <span style="color: rgb(0, 0, 153);">stock quote service returned IBM: 95.68</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"><br></br>
</span></li>
</ol>
</div><div style="margin-left: 40px;">
<h3>Username Token</h3>
<h4>Configuring the Service<br></br>
</h4>
<ol>
<li>Modify the deployment descriptor you created above to look like
this:<br></br>
<span style="color: rgb(0, 0, 153);">&lt;deployment
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"> &lt;service
name="stock-wss-01" provider="java:RPC" style="document"
use="literal"&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153); font-weight: bold;"> 
&lt;requestFlow&gt;</span><br style="color: rgb(0, 0, 153); font-weight: bold;"></br>
<span style="color: rgb(0, 0, 153); font-weight: bold;">  
&lt;handler type="java:org.apache.ws.axis.security.WSDoAllReceiver"&gt;</span><br style="color: rgb(0, 0, 153); font-weight: bold;"></br>
<span style="color: rgb(0, 0, 153); font-weight: bold;">   
&lt;parameter name="passwordCallbackClass" value="PWCallback"/&gt;</span><br style="color: rgb(0, 0, 153); font-weight: bold;"></br>
<span style="color: rgb(0, 0, 153); font-weight: bold;">   
&lt;parameter name="action" value="UsernameToken"/&gt;</span><br style="color: rgb(0, 0, 153); font-weight: bold;"></br>
<span style="color: rgb(0, 0, 153); font-weight: bold;"></span><span style="color: rgb(0, 0, 153); font-weight: bold;">  
&lt;/handler&gt;</span><br style="color: rgb(0, 0, 153); font-weight: bold;"></br>
<span style="color: rgb(0, 0, 153); font-weight: bold;"> 
&lt;/requestFlow&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">  &lt;parameter
name="className" value="samples.stock.StockQuoteService"/&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">  &lt;parameter
name="allowedMethods" value="getQuote"/&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">  &lt;parameter
name="scope" value="application"/&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"> &lt;/service&gt;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">&lt;/deployment&gt;<br></br>
<br></br>
</span>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.<br></br>
<br></br>
</li>
<li>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).<br></br>
<br></br>
The following code snippet shows a simple password callback class:<br></br>
<br></br>
<span style="color: rgb(0, 0, 153);">import java.io.IOException;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
javax.security.auth.callback.Callback;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
javax.security.auth.callback.CallbackHandler;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
javax.security.auth.callback.UnsupportedCallbackException;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
org.apache.ws.security.WSPasswordCallback;</span><br style="color: rgb(0, 0, 153);"></br>
<br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">public class PWCallback
implements CallbackHandler {</span><span style="color: rgb(0, 0, 153);"></span><span style="color: rgb(0, 0, 153);"></span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">    public void
handle(Callback[] callbacks)</span><span style="color: rgb(0, 0, 153);">
throws IOException, UnsupportedCallbackException {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">       
for (int i = 0; i &lt; callbacks.length; i++) {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">           
if (callbacks[i] instanceof WSPasswordCallback) {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">               
WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];<br></br>
               
// set the password given a username<br></br>
</span>               
<span style="color: rgb(0, 0, 153);">if
("wss4j".equals(pc.getIdentifier())) {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">                   
pc.setPassword("security");</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">               
}</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"></span><span style="color: rgb(0, 0, 153);">           
} else {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">               
throw new UnsupportedCallbackException(</span><span style="color: rgb(0, 0, 153);">callbacks[i], "Unrecognized Callback");</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">           
}</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">       
}</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">    }</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">}</span><br></br>
<span style="font-weight: bold;"></span><br></br>
<br></br>
<br></br>
</li>
<li>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.<br></br>
</li>
</ol>
<h4>Configuring the Client</h4>
<ol>
<li>run the client we created again:<br></br>
<span style="color: rgb(0, 0, 153);">java
samples.stock.client.StockServiceClient IBM</span><br></br>
<br></br>
You should now get an error:<br></br>
<br></br>
<span style="color: rgb(0, 0, 153);">Exception in thread "main"
AxisFault</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"> faultCode:
{http://schemas.xmlsoap.org/soap/envelope/}Server.generalException</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"> faultSubcode:</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"> faultString:
WSDoAllReceiver: Request does not contain required Security header</span><br></br>
<br></br>
This is because your client is not configured to send a Username Token
yet, so the service is rejecting the request.<br></br>
<br></br>
</li>
<li>Create a deployment descriptor file (client_deploy.wsdd) for the
client:<br></br>
<br></br>
<span style="color: rgb(0, 0, 153);">&lt;deployment
xmlns="http://xml.apache.org/axis/wsdd/"
xmlns:java="http://xml.apache.org/axis/wsdd/providers/java"&gt;<br></br>
 &lt;transport name="http"
pivot="java:org.apache.axis.transport.http.HTTPSender"/&gt;<br></br>
  &lt;globalConfiguration &gt;<br></br>
   &lt;requestFlow &gt;<br></br>
    &lt;handler
type="java:org.apache.ws.axis.security.WSDoAllSender" &gt;<br></br>
     &lt;parameter name="action"
value="UsernameToken"/&gt;<br></br>
     &lt;parameter name="user" value="wss4j"/&gt;<br></br>
     &lt;parameter name="passwordCallbackClass"
value="samples.stock.client.PWCallback"/&gt;<br></br>
     &lt;parameter name="passwordType"
value="PasswordDigest"/&gt;<br></br>
    &lt;/handler&gt;<br></br>
   &lt;/requestFlow &gt;<br></br>
  &lt;/globalConfiguration &gt;<br></br>
&lt;/deployment&gt;</span><span style="color: rgb(0, 0, 153);"></span><br></br>
<br></br>
</li>
<li>Create the <span style="color: rgb(0, 0, 153);">samples.stock.client.PWCallback</span>
class:<br></br>
<br></br>
<span style="color: rgb(0, 0, 153);">package samples.stock.client;</span><br style="color: rgb(0, 0, 153);"></br>
<br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import java.io.IOException;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
javax.security.auth.callback.Callback;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
javax.security.auth.callback.CallbackHandler;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
javax.security.auth.callback.UnsupportedCallbackException;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
org.apache.ws.security.WSPasswordCallback;</span><br style="color: rgb(0, 0, 153);"></br>
<br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">/**</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"> * PWCallback for the
Client</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);"> */</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">public class PWCallback
implements CallbackHandler {</span><br style="color: rgb(0, 0, 153);"></br>
<br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">    /**</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">     *
@see
javax.security.auth.callback.CallbackHandler#handle(javax.security.auth.callback.Callback[])</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">     */</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">    public void
handle(Callback[] callbacks) throws IOException,</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">                   
UnsupportedCallbackException {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">       
for (int i = 0; i &lt; callbacks.length; i++) {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">           
if (callbacks[i] instanceof WSPasswordCallback) {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">               
WSPasswordCallback pc = (WSPasswordCallback)callbacks[i];</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">               
// set the password given a username</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">               
if ("wss4j".equals(pc.getIdentifier())) {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">                   
pc.setPassword("security");</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">               
}</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">           
} else {</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">               
throw new UnsupportedCallbackException(callbacks[i], "Unrecognized
Callback");</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">           
}</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">       
}</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">    }</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">}</span><br></br>
<br></br>
</li>
<li>Define the system property axis.ClientConfigFile for your client:<br></br>
<br></br>
<span style="color: rgb(0, 0, 153);">java
-Daxis.ClientConfigFile=client_deploy.wsdd -classpath $AXISCLASSPATH
samples.stock.client.StockServiceClient</span><br></br>
<br></br>
Make sure that your classpath includes the jar files under WEB-INF/lib.<br></br>
<br></br>
Another way to do this is to specify the wsdd file in your
StockServiceClient to the service locator programmatically:<br></br>
<br></br>
<span style="color: rgb(0, 0, 153);">...</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
org.apache.axis.EngineConfiguration;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
org.apache.axis.configuration.FileProvider;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">...</span><br style="color: rgb(0, 0, 153);"></br>
<br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">EngineConfiguration config =
new FileProvider("client_deploy.wsdd");</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">StockQuoteServiceService
locator = new StockQuoteServiceServiceLocator(config);</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">...</span><br></br>
<br></br>
</li>
<li>Run the client, you should get no errors:<br></br>
<br></br>
<span style="color: rgb(0, 0, 153);">stock quote service returned
IBM: 95.7</span><br></br>
<br></br>
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).<br></br>
<br></br>
Another way to do this is to have the client application set the
username and CallbackHandler implementation programmatically instead of
client_deploy.wsdd:<br></br>
<br></br>
<span style="color: rgb(0, 0, 153);">...</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">import
org.apache.axis.client.Stub;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">...</span><br style="color: rgb(0, 0, 153);"></br>
<br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">Remote remote =
locator.getPort(StockQuoteService.class);</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">Stub axisPort = (Stub)remote;</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">axisPort._setProperty(UsernameToken.PASSWORD_TYPE,
WSConstants.PASSWORD_DIGEST);</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">axisPort._setProperty(WSHandlerConstants.USER,
"wss4j");</span><br style="color: rgb(0, 0, 153);"></br>
<span style="color: rgb(0, 0, 153);">axisPort._setProperty(WSHandlerConstants.PW_CALLBACK_REF,
pwCallback);</span><br></br>
<br></br>
where "pwCallback" is a reference to a PWCallback implementation. See
the Axis handler for WSS4J documentation for more details on this.<br></br>
<br></br>
</li>
<li>Try modifying your client's PWCallback to return the wrong
password, or send the wrong username. The service should reject your
requests.</li>
</ol>
<br></br>
</div><br></br><br></br><div style="margin-left: 40px;"></div></subsection></section></body></document>