I recently needed to pass a WSSE authentication header with some SOAP messages sent from a Rails app to a government service. Ruby’s native SOAP library is soap4r. It’s featureful, but under-documented, so it took some fiddling to get WSSE to work.
WSSE is a pretty simple standard for sending a username and password to a service in a SOAP message’s header. The layout is:
<wsse:Security xmlns:wsse="http://schemas.xmlsoap.org/ws/2002/07/secext" soap:mustUnderstand="0">
<wsse:UsernameToken>
<wsse:Username>Username</wsse:Username>
<wsse:Password>Password</wsse:Password>
</wsse:UsernameToken>
</wsse:Security>
Constructing the WSSE headers
Adding headers in soap4r requires constructing an object that responds to a method that will return the headers to be added. A helper class provided for this is SOAP::Header::SimpleHandler. SimpleHandler allows us to respond with a hash that is converted into XML.
SimpleHandler also expects subclasses to call its initialize method with an enclosing tag. We can use xsd4r (the XML parser/constructor used by soap4r) to create the tag and define its namespace:
XSD::QName.new(NAMESPACE, 'Security')
Our call back method is a hash containing the username and password to be sent:
{"UsernameToken" => {"Username" => USERNAME, "Password" => PASSWORD}}
The entire class looks like this:
require 'soap/header/simplehandler'
class WsseAuthHeader < SOAP::Header::SimpleHandler
NAMESPACE = 'http://schemas.xmlsoap.org/ws/2002/07/secext'
USERNAME = 'username'
PASSWORD = 'password'
def initialize()
super(XSD::QName.new(NAMESPACE, 'Security'))
end
def on_simple_outbound
{"UsernameToken" => {"Username" => USERNAME, "Password" => PASSWORD}}
end
end
Adding the WSSE headers
Adding the headers to a soap4r driver is quite easy (this has only been tested with a driver that has been auto-generated from a WSDL file).
require 'soap_driver.rb' require 'wsse_authentication.rb' d = Driver.new ... d.headerhandler << WsseAuthHeader.new()