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
