« Engaged! | Main | Camping in Big Sur »

JAX-RPC Handlers

I am using the JAX-RPC 1.1 Reference Implementation (RI) at work to expose operations in a business processing system we're building as XML Web Services. I've been building XML Web Services for several years, and have used numerous APIs to perform Object-XML (O-X) binding (notably, JAXM and JAXB). I wanted to use JAX-RPC on this project to take advantage of the automated WSDL generation and generation of serialization components from existing Java classes.

One nice feature of JAX-RPC is the support for Handlers, which follow the Intercepting Filter design pattern. The 1.1 specification support SOAP protocol handlers, while the 1.2 specification makes a further distinction between Logical and Protocol Handlers. I like the idea of being able to plug Handlers in series to perform functions like logging, auditing, and security operations.

In this case, I was trying to create my first Handler which would restrict access to the service to trusted hosts. This is pretty simple in principle: inspect the ServletRequest for the remote address and verify that it is trusted.

I had a hell of a time finding documentation on how to specify server Handlers. I finally got it straightened out. I needed to modify the config.xml file used by the wscompile process. Here's what the config.xml looked like when I was done (names changed to protect my employer):

<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://java.sun.com/xml/ns/jax-rpc/ri/config">
  <service name="MyService" targetNamespace="urn://MyService/wsdl" 
                   typeNamespace="urn://MyService/types" packageName="foo">
    <interface name="foo.MyService" servantName="foo.MyServiceImpl"/>
    <handlerChains>
      <chain runAt="server">
        <handler className="foo.handlers.TrustedHostsHandler"/>
      </chain>
    </handlerChains>
  </service>
</configuration>

Then, the TrustedHostsHandler class overrode the handleRequest method in the Handler interface in order to inspect the remote host's IP. Here are the relevent sections:

public class TrustedHostsHandler extends GenericHandler {
  private static final String SERVLET_CONTEXT_CLASS = 
    "com.sun.xml.rpc.server.http.HttpServletRequest";
  private HandlerInfo config;

  public TrustedHostsHandler() {
  }

  public void init(HandlerInfo config) {
    assert null != config : "HandlerInfo argument was unexpectedly null";
    this.config = config;
  }

  public QName[] getHeaders() {
    return config.getHeaders();
  }

  public boolean handleRequest(MessageContext msgContext) {
    assert null != msgContext : "MessageContext argument unexpectedly null";

    ServletRequest req = 
        (ServletRequest) msgContext.getProperty(SERVLET_CONTEXT_CLASS);
    assert null != req : "ServletRequest unexpectedly null";

    boolean result = false;
    String remoteAddress = req.getRemoteAddr();

    if ((null != remoteAddress) && isTrusted(remoteAddress)) {
      result = true;
    }

    return result;
  }
}