Category Archives: web services

CXF WS-Security using JSR 181 + Interceptor Annotations (XFire Migration)

I had blogged about how to setup XFire with WS-Security a while ago and since then the XFire 1.x series as we know it is dead, instead Apache’s CXF can be considered XFire 2.0. CXF improves over XFire in many areas including better architecture and more importantly easier message handling and manipulation. In this entry, we’ll setup a CXF application that secures its services using CXF’s WS-Security features.

Before I get to the example I want to mention some of the major changes that I noticed in CXF:

  • Interceptors instead of handlers: Handlers are out and are replaced with a much more common concept of interceptors (if you’re from the Struts2/Webwork world you know what they are). Interceptors are created by extending the AbstractPhaseInterceptor class which forces you to implement handleMessage(Message). Note that you must specify the phase where you want each interceptor executed.
  • Access to MessageContext: In XFire, the MessageContext was always available in your handlers. In CXF you don’t have access to it in the interceptor but you can get contextual properties using the message.getContextualProperty(String) methods. Access to the MessageContext is also available using the @Resource annotation as described here but this only works in service implementations.
  • JAXWS Endpoints: Spring service classes must be exposed using the <jaxws:endpoint> tag. You can also do this programmatically but why would you.
  • Message and Exchange: The Message and Exchange objects have changed dramatically from XFire. CXF’s Message and Exchange objects are devoid of all those helpful methods that were present in XFire but they make up for it by having get(Class) and get(String) methods which can be used to retrieve valuable information. It’s probably a good idea to look through Exchange.keySet() and Message.keySet() and see whats available to you in your interceptors. For example when a Fault occurs, the message.get(Exception.class) returns the exception that was thrown to cause the fault. Also note that the information present in these maps varies depending on what Phase you’re in.

Now to the WS-Security example. CXF just added support for configuring interceptors using annotations which means configuring WS-Security for our web services just got easier.

Here’s the service interface and implementation.

@WebService
public interface SportsService {
    public String getTeam();
        return "Arsenal";
    }
}

@WebService(
    serviceName="SportsService",
    endpointInterface="ca.utoronto.sis.cxfapp.SportsService")
@InInterceptors(interceptors={
        "com.arsenalist.cxfapp.WSSecurityInterceptor"
})
public class SportsServiceImpl implements SportsService {

    public String getTeam() {
        return "Arsenal";
    }
}

I’ve added a single in interceptor called WSSecurityInterceptor which is a class that we’ll write. In XFire we also needed a DomInHandler and a DomOutHandler for each service implementation, none of that is required here. WSSecurityInterceptor will just wrap the WSS4JInInterceptor class, the reason we can’t just specify WSS4JInInterceptor as an annotation is because we need to set custom properties on it such as using UsernameToken authentication.

The other thing WSSecurityInterceptor does is add a ValidateUserTokenInterceptor which is similar to ValidateUserTokenHandler in the XFire examples. Since WSS4J validates a UsernameToken only if it finds a security header we need to cover the case where no security header is specified. ValidateUserTokenInterceptor just makes sure the username, password, nonce and timestamp are specified before even considering it a valid request. Here’s the WSSecurityInterceptor and the PasswordHandler class:

public class WSSecurityInterceptor extends AbstractPhaseInterceptor {

    public WSSecurityInterceptor() {
        super(Phase.PRE_PROTOCOL);
    }
    public WSSecurityInterceptor(String s) {
        super(Phase.PRE_PROTOCOL);
    }

    public void handleMessage(SoapMessage message) throws Fault {

        Map props = new HashMap();
        props.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        props.put(WSHandlerConstants.PW_CALLBACK_REF, new PasswordHandler());

        WSS4JInInterceptor wss4jInHandler = new WSS4JInInterceptor(props);
        ValidateUserTokenInterceptor userTokenInterceptor = new ValidateUserTokenInterceptor(Phase.POST_PROTOCOL);

        message.getInterceptorChain().add(wss4jInHandler);
        message.getInterceptorChain().add(new SAAJInInterceptor());
        message.getInterceptorChain().add(userTokenInterceptor);
    }
}

public class PasswordHandler implements CallbackHandler {
    public void handle(Callback[] callbacks) throws IOException,
            UnsupportedCallbackException {
        WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
        if (pc.getIdentifer().equals("arsenal")) {
            pc.setPassword("gunners");
        }
    }
}

Note that the ValidateUserTokenInterceptor is invoked in a later phase than WSS4JInterceptor. Here’s the ValidateUsertokenInterceptor class:

public class ValidateUserTokenInterceptor extends AbstractPhaseInterceptor {

    public ValidateUserTokenInterceptor(String s) {
        super(s);
    }

    public void handleMessage(SoapMessage message) throws Fault {
        boolean userTokenValidated = false;
        Vector result = (Vector) message.getContextualProperty(WSHandlerConstants.RECV_RESULTS);
        for (int i = 0; i &lt; result.size(); i++) {
            WSHandlerResult res = (WSHandlerResult) result.get(i);
            for (int j = 0; j &lt; res.getResults().size(); j++) {
                   WSSecurityEngineResult secRes = (WSSecurityEngineResult) res.getResults().get(j);
                    WSUsernameTokenPrincipal principal = (WSUsernameTokenPrincipal) secRes
                            .getPrincipal();

                    if (!principal.isPasswordDigest() ||
                            principal.getNonce() == null ||
                            principal.getPassword() == null ||
                            principal.getCreatedTime() == null) {
                        throw new RuntimeException("Invalid Security Header");
                    } else {
                        userTokenValidated = true;
                    }
                }
            }
        }
        if (!userTokenValidated) {
            throw new RuntimeException("Security processing failed");
        }
    }
}

Now we have a service implementation annotated in a way where it is WS-Security enabled and is also registered as a web service. The final step remaining is to expose it as a consumable endpoint. That can be achieved by either of the following ways:

Using the fully qualified class name:

<jaxws:endpoint
   id="helloWorld"
   implementor="com.arsenalist.cfxapp.SportsServiceImpl"
   address="/SportsService" />

Or by referring to a Spring bean corresponding to the @WebService annotated class. This would be more prudent if you’re using Dependency Injection in your service implementations.

<bean id="sportsServiceImpl" class="com.arsenalist.cfxapp.SportsServiceImpl"/>

<jaxws:endpoint
   id="sportsService"
   implementor="#sportsServiceImpl"
   address="/SportsService" />

Finally you could also just use good ‘ol fashioned Spring beans. This comes in handy if you wan to specify a different binding like Aegis:

<bean id="aegisBean" class="org.apache.cxf.aegis.databinding.AegisDatabinding"/>
<bean class="org.apache.cxf.frontend.ServerFactoryBean" init-method="create">
	<property name="serviceBean" ref="registrationSoapService"/>
	<property name="address" value="/services/1_0_0/Registration"/>
	<property name="dataBinding" ref="aegisBean"/>
</bean>

The CXF documentation which shows how to configure the web.xml is pretty straightforward.

If you’re using Maven, the dependencies section of the pom.xml might look something like this. Remember that support for configuring interceptors via annotations was just added so you have to access the SNAPSHOT repositories instead of the main one.

<repositories>
    <repository>
        <id>apache-snapshots</id>
        <name>Apache SNAPSHOT Repository</name>
        <url>http://people.apache.org/repo/m2-snapshot-repository/</url>
        <snapshots>
        <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>apache-incubating</id>
        <name>Apache Incubating Repository</name>
        <url>http://people.apache.org/repo/m2-incubating-repository/</url>
    </repository>
</repositories>
<dependencies>
    ...
    <!-- spring beans, core, context, web 2.0.6 -->
    ...
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-transports-http</artifactId>
        <version>2.1-incubator-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-core</artifactId>
        <version>2.1-incubator-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-frontend-jaxws</artifactId>
        <version>2.1-incubator-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-ws-security</artifactId>
        <version>2.1-incubator-SNAPSHOT</version>
    </dependency>
    ...
<dependencies>

Thanks for reading.

Advertisement

Web Service Versioning with Endpoints using XFire

I wanted to document an example of using web service versioning using endpoints. I posted on the XFire mailing list asking what other people do but got little in return. I read the XFire Versioning Wiki entry and that mentioned using namespaces and/or custom headers. Although the namespaces/custom header approach works fine, it has the significant drawback of your web service clients to actually modify the outgoing SOAP message, which is always nice to avoid.

Using endpoints also allows us to have nicer WSDL URLs based on version number, e.g.:

http://arsenalist.com/services/1_0_0/SportsService
http://arsenalist.com/services/1_0_1/SportsService

In this example, I want to host multiple versions of the service while maintaining a logical URL like shown above. There’s a simple little trick involved in doing this using XFire and it needs us to override the getService(HttpServletRequest) method of the XFireServletController class. In order to plug a different controller, we must override the createController() method in XFire’s main servlet. I’m using Spring so I would need to override XFireSpringServlet but if your’e not using Spring you would override XFireServlet instead.

public class CustomXFireServlet extends
                         XFireSpringServlet {
  public XFireServletController createController()
                      throws ServletException {
    return new CustomXFireServletController(getXFire(),
                                 getServletContext());
  }
}

So I’ve specified a new controller, CustomXFireServletController which is the primary entry point for all service requests. I’ll override the getService(HttpServletRequest) method which will parse the service name out of the URL as per your convention.

public class CustomXFireServletController extends
        XFireServletController {

  public CustomXFireServletController(XFire xFire) {
    super(xFire);
  }

  public CustomXFireServletController(XFire xFire,
                     ServletContext servletContext) {
    super(xFire, servletContext);
  }

  /**
   * Override getService to look for a URL of the form:
   * http://.../services/1_0_0/SportsService
   * which would map to a service registered as
   * SportsService1_0_0
   *
   * @param request HttpServletRequest
   * @return Service name corresponding to URL
   */
  protected String getService(HttpServletRequest
                                          request) {
    String pathInfo = request.getPathInfo();
    if (pathInfo != null && pathInfo.startsWith("/") &&
        StringUtils.countMatches(pathInfo, "/") == 2) {
      int lastSlash = pathInfo.lastIndexOf("/");
      String version = pathInfo.substring(1, lastSlash);
      String name = pathInfo.substring(lastSlash+1);
      return name + version;
    } else {
      return super.getService(request);
    }
  }
}

So I’m counting on a service with the name of SportsService1_0_0 to be registered with XFire. This service would be accessible at http://arsenalist.com/services/1_0_0/SportsService

The last step is to modify your web.xml so that it uses the CustomXFireServlet:

<servlet>
 <servlet-name>XFireServlet</servlet-name>
 <servlet-class>
  com.arsenalist.xfire.CustomXFireServlet
 </servlet-class>
</servlet>
<servlet-mapping>
 <servlet-name>XFireServlet</servlet-name>
 <url-pattern>/services/*</url-pattern>
</servlet-mapping>

This is one of the cleanest solutions for having versioning capabilities for your web services. Your web service clients don’t need to specify any specific namespaces or create custom headers just to invoke a specific version of a service. There are no external dependencies (not even on Spring) The endpoint method works on top of the SOAP envelope and you have the power to customize it to any convention that you might want to use.  For example, you could actually specify the version number using the querystring if you like:

http://arsenalist.com/services/SportsService?v=1.1

All these are delectable options that you can choose from.

Update: Andrew Ochsner’s excellent comment on this post also shows how you can do versioning using Spring’s DispatcherServlet and SimpleUrlHandlerMapping.

Python client for web services using WS-Security

Hopefully this entry serves as some decent documentation on how to write a Python client that accesses a web service which uses WS-Security. When I was trying to figure it out, Otu Ekanem’s response on the mailing list was invaluable. The example is relevant for any web service framework independent of programming language. This is tested with XFire 1.2.4 but can be used with .NET or other Java web service frameworks like Axis2.

When accessing a web service which has WS-Security enabled you must send very specific headers as part of your SOAP envelope in order for the request to be processed. You can read all about the glorious specification in PDF Format if you like. I’m using the Zolera Soap Infrastructure (ZSI) Library for Python which supports client stub generation. Given the generated stubs, there are two ways of adding custom headers to outgoing SOAP messages.

Method 1 – Not desirable but worth a mention

The first method involves modifying the generated code which is highly undesirable. Using the very simple SportsService web service example, you must modify the generated SportsService_client.py and edit the following line:

self.binding.Send(None, None,
   request, soapaction="", **kw)

to read

self.binding.Send(None, None,
   request, soapaction="", soapheaders=(obj1,obj2) )

where obj1 and obj2 are instances of Python objects which are serialized as part of the SOAP header. I found this way to be tedious as you have to design your classes to match the SOAP header and write additional serialization code. It is also hard to create the exact header as namespaces and prefixes tend to be a problem.

Method 2 – Probably the way to go, way more customizable

We can use DOM-like methods to modify the SOAP header and send out exactly what we need. The example implements the UsernameToken strategy but other ones can also be implemented by modifying the headers in a similar manner. The generated Port class’ binding attribute has a sig_handler attribute which can be assigned an instance of a custom class. In this custom class, we must implement two methods, sign and verify, that can modify the header and check it’s validity, respectively. The sign method takes in as argument a SoapWriter which enables us to modify the header. So without further ado, here’s the class that adds WS-Security headers to the outgoing SOAP envelope as discussed above. The code has been formatted and modified to fit the page.

# Deprecated in 2.5, use the hashlib module instead:
#     http://docs.python.org/lib/module-hashlib.html
import sha

import binascii
import base64
import time
import random

class SignatureHandler:

  OASIS_PREFIX =
    "http://docs.oasis-open.org/wss/2004/01/" +
      "oasis-200401"

  SEC_NS = OASIS_PREFIX +
    "-wss-wssecurity-secext-1.0.xsd"
  UTIL_NS = OASIS_PREFIX +
    "-wss-wssecurity-utility-1.0.xsd"
  PASSWORD_DIGEST_TYPE = OASIS_PREFIX +
    "-wss-username-token-profile-1.0#PasswordDigest"
  PASSWORD_PLAIN_TYPE = OASIS_PREFIX +
    "-wss-username-token-profile-1.0#PasswordText"

  def __init__(self, user, password, useDigest=False):
    self._user = user
    self._created = time.strftime('%Y-%m-%dT%H:%M:%SZ',
      time.gmtime(time.time()))
    self._nonce = sha.new(str(random.random())).
      digest()
    if (useDigest):
      self._passwordType = self.PASSWORD_DIGEST_TYPE
      digest = sha.new(self._nonce + self._created +
        password).digest()

      # binascii.b2a_base64 adds a newline at the end
      self._password = binascii.b2a_base64(digest)[:-1]
    else:
      self._passwordType = self.PASSWORD_PLAIN_TYPE
      self._password = password

  def sign(self,soapWriter):

    # create  element
    securityElem = soapWriter._header.
      createAppendElement("", "wsse:Security")
    securityElem.node.
      setAttribute("xmlns:wsse", self.SEC_NS)
    securityElem.node.
      setAttribute("SOAP-ENV:mustunderstand", "1")

    # create  element
    usernameTokenElem = securityElem.
      createAppendElement("", "wsse:UsernameToken")
    usernameTokenElem.node.
      setAttribute("xmlns:wsse", self.SEC_NS)
    usernameTokenElem.node.
      setAttribute("xmlns:wsu", self.UTIL_NS)

    # create  element
    usernameElem = usernameTokenElem.
      createAppendElement("", "wsse:Username")
    usernameElem.node.
      setAttribute("xmlns:wsse", self.SEC_NS)

    # create  element
    passwordElem = usernameTokenElem.
      createAppendElement("", "wsse:Password")
    passwordElem.node.
      setAttribute("xmlns:wsse", self.SEC_NS)
    passwordElem.node.
      setAttribute("Type", self._passwordType)

    # create  element
    nonceElem = usernameTokenElem.
      createAppendElement("", "wsse:Nonce")
    nonceElem.node.
      setAttribute("xmlns:wsse", self.SEC_NS)

    # create  element
    createdElem = usernameTokenElem.
      createAppendElement("", "wsse:Created")
    createdElem.node.
      setAttribute("xmlns:wsse", self.UTIL_NS)

    # put values in elements
    usernameElem.
      createAppendTextNode(self._user)
    passwordElem.
      createAppendTextNode(self._password)
    # binascii.b2a_base64 adds a newline at the end
    nonceElem.
      createAppendTextNode(
        binascii.b2a_base64(self._nonce)[:-1])
    createdElem.createAppendTextNode(self._created)

  def verify(self,soapWriter):
    self

Example usage of this is:

from SportsService_client import *
from SportsService_types import *

locator = SportsServiceLocator()
port = locator.getSportsServiceHttpPort()
sigHandler = SignatureHandler("user", "password", True)
port.binding.sig_handler = sigHandler

request = getMascotRequest()
teamObj = ns0.Team_Def("Team")
teamObj._name = "toronto"
request._team = teamObj

response = port.getMascot(request)
print response._out._name

As you can see the SignatureHandler class is implementing an “interface” which enables it to process outgoing SOAP Requests. The verify method is empty but can contain code to check whether the SOAP header is valid.

If you would like write a PHP client that accesses a WS-Security enabled service, you should read Kim Cameron’s IdentityBlog entry which has links to the source code needed. If you simply want to use a PHP client for a non WS-Security web service, an earlier blog entry covers that.

Writing PHP clients for XFire, Axis and .NET Web Services

If you’re finding yourself hunting down incomplete documentation about writing a PHP client for your Java or .NET web services, you’re not alone. PHP SOAP toolkits like NuSOAP and Pear SOAP provide sub-par API’s into web service development and give a decent person a really hard time when it comes to writing clients. The best way to go IMHO is using PHP’s built-in SOAP libraries. The other thing to keep your eye on is Axis2 for PHP which is still in Beta. For now we’ll focus on the PHP 5 and it’s SOAP extension. To enable the extension, your php.ini file must something like the following:

Under Dynamic Extensions:

extension_dir="C:/php/ext/"
extension=php_soap.dll

Under Module Settings:

[soap]
soap.wsdl_cache_enabled=0
soap.wsdl_cache_dir="/tmp"
soap.wsdl_cache_ttl=86400

Restart the Apache Web Server for the changes to take effect, once that is done, we are free to use the PHP Soap extensions. This example is applicable to Java web services generated by XFire or Axis or any other framework and also to .NET web services. As long as there’s a WSDL, we’re good. This example has been tested with XFire 1.2.4.

In this example there is one web service called SportsService which exposes one method: public Mascot getMascot(Team team)

The method takes in as parameter a complex Java object called Team and returns a Mascot, another complex data type. Although this example can easily use primitives, I’ve chosen to use Java objects because I want to illustrate a specific point. The XFire Java client is fairly easy to write and a previous blog entry covered a similar client. Both the Team and Mascot classes are POJO’s with one String property called name, a default constructor and getter/setter methods. They are excluded here for brevity.

Before we look at the PHP client, let’s look at the relevant portion of the WSDL that is generated, mainly the types and the information about the method getMascot which we will be calling:

<wsdl:types>
    <xsd:schema
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            attributeFormDefault="qualified"
            elementFormDefault="qualified"
            targetNamespace="http://vo.arsenalist.com">
        <xsd:complexType name="Team">
            <xsd:sequence>
                <xsd:element minOccurs="0"
                             name="name"
                             nillable="true"
                             type="xsd:string"/>
            </xsd:sequence>
        </xsd:complexType>
        <xsd:complexType name="Mascot">
            <xsd:sequence>
                <xsd:element minOccurs="0"
                             name="name"
                             nillable="true"
                             type="xsd:string"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:schema>
    <xsd:schema
            xmlns:xsd="http://www.w3.org/2001/XMLSchema"
            attributeFormDefault="qualified"
            elementFormDefault="qualified"
            targetNamespace="http://ws.arsenalist.com">
        <xsd:element name="getMascot">
            <xsd:complexType>
                <xsd:sequence>
                    <xsd:element maxOccurs="1"
                                 minOccurs="1"
                                 name="team"
                                 nillable="true"
                                 type="ns1:Team"/>
                </xsd:sequence>
            </xsd:complexType>
        </xsd:element>
        <xsd:element name="getMascotResponse">
            <xsd:complexType>
                <xsd:sequence>
                    <xsd:element maxOccurs="1"
                                 minOccurs="1"
                                 name="out"
                                 nillable="true"
                                 type="ns1:Mascot"/>
                </xsd:sequence>
            </xsd:complexType>
        </xsd:element>
    </xsd:schema>
</wsdl:types>

Here’s the PHP client that creates a Team type, passes it to the web service which returns a Mascot type.

<?php

//set up the service client using WSDL
$wsdl = "http://arsenalist.com/SportsService?wsdl";
$client = new SoapClient($wsdl);

// assign the name attribute of Team to "toronto"
$wrapper->team->name =
		new SoapVar("toronto", XSD_STRING);

// call the getMascot method
$response = $client->__soapCall("getMascot",
				    array($wrapper));

// print out the Mascot
print($response->out->name);

?>

The wrapper object is created out of the blue so as to pass it to the web service as the lone parameter encapsulating the Team data type.

By looking at the WSDL, we can determine how to “instantiate” Team and Mascot data types on the client side. For example, to create a Team data type and assign it’s name property to “toronto”, we simply refer to it using associative array syntax and both the Team object and it’s property name are created “on the fly”. There’s no mucking around with namespaces etc. We’re simply wrapping the primitives inside other PHP “objects” using the same syntax as associative arrays. You can go as deep as you want in the object hierarchy in PHP without having to worry about encountering nulls because if an array element being accessed doesn’t exist, it is created for you.

It’s also always a good idea to use the $client->__getTypes() and do a print_r(..) on the results to see what you are dealing with before you start communicating with a WSDL For example, the result of a print_r($client->__getTypes()) on the above WSDL returned the following:

Array (
   [0] => struct Team { string name; }
   [1] => struct Mascot { string name; }
   [2] => struct getMascot { Team team; }
   [3] => struct getMascotResponse { Mascot out; }
)

As you can see this information can be helpful when deciding how to initialize your client side variables.

Note that you can also use $client->getMascot($wrapper) instead of $client->__soapCall(“getMascot”, array($wrapper)). The latter is used mostly when passing extra parameters such as SOAP headers etc.

This is a fairly simple example which hopefully illustrated the point that accessing web services using PHP is not a daunting task, and most of all there are no additional libraries to install as long as you’re using PHP5 and up.  If you would like write a PHP client that accesses a WS-Security enabled service, you should read Kim Cameron’s IdentityBlog entry which has links to the source code needed.

Implementing WS-Security with JSR 181 Annotations using WSS4J in XFire

The Logemann Blog really helped me out when I was trying to use JSR181 Annotations in favor of the services.xml configuration in XFire. Reading that blog entry is most likely a prerequisite for this one. Once you’ve configured your Spring beans and web.xml to use JSR181 Annotations, the next step is to implement security for your web services. The example shown implements WS-Security as specified by OASIS Web Services Security and implemented by WSS4J in XFire.

Looking at the ws-security example packaged with XFire, for a service to be security enabled, you need the following configuration in your services.xml. We are dealing with the “User Token with Hashed Password” scheme.

<service>
 <name>BookServiceUTHP</name>
 <namespace>
  http://xfire.codehaus.org/BookService
 </namespace>
 <serviceClass>
  org.codehaus.xfire.demo.BookService
 </serviceClass>
 <inHandlers>
  <handler handlerClass=
    "org.codehaus.xfire.util.dom.DOMInHandler" />
  <bean class=
   "org.codehaus.xfire.security.wss4j.WSS4JInHandler">
   <property name="properties">
    <props>
     <prop key="action">UsernameToken</prop>
     <prop key="passwordCallbackClass">
      org.codehaus.xfire.demo.PasswordHandler
     </prop>
    </props>
   </property>
  </bean>
  <handler handlerClass=
   "org.codehaus.xfire.demo.ValidateUserTokenHandler"/>
 </inHandlers>
</service>

However, we want to substitute this configuration with annotations. There are three InHandlers being applied which we must specify via annotations. The problem is that when specifying handlers using annotations you may not supply any parameters to them, as we do above in the case of WSS4JInHandler. The solution is to create a custom handler which wraps the other handlers and passes in the parameters to WSS4JInHandler programmatically. Here’s a custom handler which does just that:

public class WSSecurityHandler
                  extends AbstractHandler {
 List<Handler> inHandlers;

 public WSSecurityHandler() {
  WSS4JInHandler wss4jInHandler;
  ValidateUserTokenHandler userTokenHandler;
  Properties props = new Properties();
  props.put("action", "UsernameToken");
  props.put("passwordCallbackClass",
  PasswordHandler.class.getName());

  wss4jInHandler = new WSS4JInHandler(props);
  userTokenHandler = new ValidateUserTokenHandler();
  inHandlers = new ArrayList<Handler>();
  inHandlers.add(wss4jInHandler);
  inHandlers.add(userTokenHandler);
 }

public QName[] getUnderstoodHeaders() {
  return new QName[] {
    new QName("http://docs.oasis-open.org/wss/2004/01/" +
     	      "oasis-200401-wss-wssecurity-secext-1.0.xsd",
     	      "Security")
  };
 }
 public void invoke(MessageContext messageContext)
                                   throws Exception {
  for (Handler handler : inHandlers) {
   handler.invoke(messageContext);
  }
  // User should be set by ValidateUserTokenHandler
  // You can also choose to do all your security checks in
  // ValidateUserTokenHandler which does a lot of the work for you
  if (messageContext.getProperty(
        WSHandlerConstants.ENCRYPTION_USER) == null) {
    throw new Exception("Principal not found");
  }

 }
}

The implementation is fairly straightforward. The one thing to note is the getUnderstoodHeaders() method which returns a QName. The reason this is important is that Java clients send this as part of the SOAP header and it is mandatory for the web service to recognize this as a valid header. I encountered this problem and reported it on the mailing list with no response.

The last piece of the puzzle is that we must annotate our web service class with our custom handler. Here’s an example:

@WebService
@InHandlers(handlers={
 "my.package.WSSecurityHandler",
 "org.codehaus.xfire.util.dom.DOMInHandler"
})
public class BookService {
 // methods go here
}

The DOMInHandler must be configured via an annotation. The client code for calling a web service configured using services.xml is the same as when configured via annotations:

Service serviceModel = new ObjectServiceFactory().
				create(IBook.class,
				 "BookService",
				 SERVICE_NAMESPACE,
				 null);
IBook service = (IBook) new XFireProxyFactory().
create(serviceModel, SERVICE_URL);

Client client = ((XFireProxy)
     Proxy.getInvocationHandler(service)).getClient();
client.addOutHandler(new DOMOutHandler());
Properties p = new Properties();
// Action to perform : user token
p.setProperty(WSHandlerConstants.ACTION,
		WSHandlerConstants.USERNAME_TOKEN);
// Set password type to hashed
p.setProperty(WSHandlerConstants.PASSWORD_TYPE,
				WSConstants.PW_DIGEST);
// Username in keystore
p.setProperty(WSHandlerConstants.USER, "serveralias");
// Used do retrive password for given user name
p.setProperty(WSHandlerConstants.PW_CALLBACK_CLASS,
	          PasswordHandler.class.getName());

client.addOutHandler(new WSS4JOutHandler(p));
Book b = service.findBook("0123456789");

That’s all it takes.