[Java] Setting WSS4J properties for Username Token at run-time

I managed to dynamically set the username and the other properties that normally goes into the client WSDD file. Again, many thanks to the nice people in the WSS4J mailing list.

First you have to modify the client WSDD file from the tutorial and comment out the properties. If you leave them in there, I believe those values will be used. So, the client_deploy.wsdd looks something like this:

<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" >
    <!-- parameters removed -->
    </handler>
   </requestFlow >
  </globalConfiguration >
</deployment>

Then you have to modify the StockServiceClient.java code somewhat to be able to set the handler properties

package samples.stock.client;

import java.rmi.RemoteException;
import javax.xml.rpc.ServiceException;
import org.apache.axis.EngineConfiguration;
import org.apache.axis.configuration.FileProvider;
import org.apache.axis.client.Stub;
import java.rmi.Remote;
import org.apache.ws.security.handler.WSHandlerConstants;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.message.token.UsernameToken;

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;
        }
        
        //modify the path to the client_deploy.wsdd
        EngineConfiguration config = new FileProvider("client_deploy.wsdd");
        StockQuoteServiceService locator = new StockQuoteServiceServiceLocator(config);
       
        Remote remote = locator.getPort(StockQuoteService.class);
        Stub axisPort = (Stub)remote;
        axisPort._setProperty(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        axisPort._setProperty(UsernameToken.PASSWORD_TYPE, WSConstants.PASSWORD_DIGEST);
        axisPort._setProperty(WSHandlerConstants.USER, "wss4j");
        axisPort._setProperty(WSHandlerConstants.PW_CALLBACK_CLASS, "samples.stock.client.PWCallback");

        //possible to pass a callback instance by ref instead of a class as above
        //PWCallback pwCallback = new PWCallback();
        //axisPort._setProperty(WSHandlerConstants.PW_CALLBACK_REF, pwCallback);

        //Need to cast 
        StockQuoteService service = (StockWss01SoapBindingStub)axisPort;

        System.out.println("Calling service...");
        float quote = service.getQuote(args[0]);
        System.out.println("stock quote service returned " + args[0] + ": "
                + quote);
    }
}

Note that there are several ways to read the WSDD file dynamically, you can also define "axis.ClientConfigFile" as a system property.

In this sample you're still using a client WSDD file, specifying the handler (WSDoAllSender) Axis should be calling when the SOAP request is sent. It's possible to code so that you don't need the WSDD file at all, but I'll try that at a later state.

I'm going to be quite busy travelling the next week, but I'll try to make a simple Java Axis/Wss4j client call a ASP.NET service with a UsernameToken added. It'll be fun.

No Comments