Accessing a Java AXIS web service with Ruby and SOAP

I’ve been working with soap4r in Ruby to access some Java web services which use AXIS 1.1. The particular api I’m accessing requires an initial authentication call which returns a token that must be passed in all subsequent SOAP headers. This is a pretty common scenario, but it took me awhile to get it working correctly.

There were basically two “tricks”. The first which I found on a few other blogs entails creating a HeaderHandler (some suggested SimpleHeaderHandler, but that didn’t work for me because of trick #2). Here’s what I ended up with:

class ClientAuthHeaderHandler < SOAP::Header::Handler
  HEADER = 
    XSD::QName.new('http://www.foo.com/SecurityPass', 
                             'SecurityPass')
 
  def initialize(token)
    super(HEADER)
    @token = token
  end
 
  def on_outbound
    el = SOAP::SOAPElement.new(HEADER, @token)
    el.extraattr['xsi:type'] = "xsd:string"
    SOAP::SOAPHeaderItem.new(el, false)
  end
end

The second “trick” was in the on_outbound method. What I found was that AXIS was requiring the xsi:type to be included in the header that I added or it wouldn’t be recognized. Using extraattr was the only way I could figure out how to coerce it to be included. I suspect at some point this will be unnecessary, but for now it did the trick.

Here’s a simple example:

class FooService
  # pass STDOUT to wiredump to see messages
  def initialize(uri, wiredump=nil)
    @uri = uri
    @wiredump = wiredump
  end
 
  def svc(ref)
    ws = SOAP::WSDLDriverFactory.new("#{@uri}#{ref}?wsdl").create_rpc_driver
    ws.wiredump_dev = @wiredump
    ws.generate_explicit_type = true
    if !@sec_token.nil?
      ws.headerhandler << ClientAuthHeaderHandler.new(@sec_token)
    end
    ws
  end
 
  def authenticate(username, password)
    ws = svc("/services/AuthenticationService")
    @sec_token = ws.authenticate(username, password)
  end
 
  def lookup(stuff)
    ws = svc("/services/LookupService")
    ws.lookup(stuff)
  end
end

Leave a Reply