My Secret Life as a Spaghetti Coder
home | about | contact | privacy statement
SOAP can be a huge PITA in Ruby if you're not dealing with a web service that falls under the defaults. In particular, if your web service falls under HTTPS where you need to change the default certificate acceptance, or if you need to authenticate before seeing the WSDL, you're SOL as far as I can tell as of writing this post. (If you know of a way that doesn't resort to this complexity, please speak up!)

I was using Ruby 1.8.7 and soap4r 1.5.8, but this may apply to other versions. Anyway, here are a couple of monkey patches to help get you there if you're having trouble.

If you need to change the SSL verify mode, for example, to accept a certificate unconditionally, you can use this monkeypatch:

def monkeypatch_httpclient_sslsocketwrap(ssl_verify_mode)
    return unless ssl_verify_mode 
    @sslsocket_monkeypatched = true

    require 'soap/nethttpclient'
    block = <<END 
      alias :original_initialize :initialize
      def initialize(socket, context, debug_dev = nil)

        unless SOAP::NetHttpClient::SSLEnabled
          raise ConfigurationError.new('Ruby/OpenSSL module is required')
        end

        @context = context
        @context.verify_mode = #{ssl_verify_mode}
        @socket = socket
        @ssl_socket = create_openssl_socket(@socket)

        @debug_dev = debug_dev
      end
END
      HTTPClient::SSLSocketWrap.class_eval block
end

If you need to authenticate before seeing the WSDL, you'll need this patch:

def monkeypatch_authentication(username, password)
    return unless username && password
    @auth_monkeypatched = true

    require 'wsdl/xmlSchema/importer'
    block = <<END
      alias :original_fetch :fetch
      def fetch(location)

        warn("importing: " + location) if $DEBUG
        content = nil

        normalizedlocation = location
        if location.scheme == 'file' or

          (location.relative? and FileTest.exist?(location.path))

        content = File.open(location.path).read
          normalizedlocation = URI.parse('file://' + File.expand_path(location.path))

        elsif location.scheme and location.scheme.size == 1 and

          FileTest.exist?(location.to_s)
          content = File.open(location.to_s).read
        else

          client = web_client.new(nil, "WSDL4R")
          client.proxy = ::SOAP::Env::HTTP_PROXY
          client.no_proxy = ::SOAP::Env::NO_PROXY
          client.set_auth(location, "#{username}", "#{password}") #added for auth

          if opt = ::SOAP::Property.loadproperty(::SOAP::PropertyName)
            http_opt = opt["client.protocol.http"]

            ::SOAP::HTTPConfigLoader.set_options(client, http_opt) if http_opt
          end
          content = client.get_content(location)

        end
        return content, normalizedlocation
      end
END
      WSDL::XMLSchema::Importer.class_eval block
end


Hope that helps someone else avoid days' long foray into piecing together blogs posts, message boards, and searching through source code.

And because you might get here via a search for related terms, normal access that only requires basic authentication could be done like this, without opening existing classes:

class SendBasicAuthFilter < SOAP::Filter::StreamHandler
  def initialize(loginname, password)

    @authorization = 'Basic ' + [ loginname + ':' + password ].pack('m').delete("\r\n")

  end

  def on_http_outbound(req)
    req.header.delete('Authorization')

    req.header['Authorization'] = @authorization
  end

  def on_http_inbound(req, res)

  end
end

list_service_url = 'https://somesite/path/?WSDL'
list_service_driver = SOAP::WSDLDriverFactory.new(list_service_url).create_rpc_driver

user = 'username'

pass = 'password'
list_service_driver.streamhandler.filterchain << SendBasicAuthFilter.new(user,pass)


I'm very welcoming of suggestions regarding how these things might be better accomplished. Resorting to this messy level of monkeypatching just sucks. Let me know in the comments.

Hey! Why don't you make your life easier and subscribe to the full post or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!


Comments
Leave a comment

There are no comments for this entry yet.

Leave a comment

Leave this field empty
Your Name
Email (not displayed, more info?)
Website

Comment:

Subcribe to this comment thread
Remember my details
Google
Web CodeOdor.com

Me
Picture of me

Topics
.NET (19)
AI/Machine Learning (14)
Answers To 100 Interview Questions (10)
Bioinformatics (2)
Business (1)
C and Cplusplus (6)
cfrails (22)
ColdFusion (78)
Customer Relations (15)
Databases (3)
DRY (18)
DSLs (11)
Future Tech (5)
Games (5)
Groovy/Grails (8)
Hardware (1)
IDEs (9)
Java (38)
JavaScript (4)
Linux (2)
Lisp (1)
Mac OS (4)
Management (15)
MediaServerX (1)
Miscellany (76)
OOAD (37)
Productivity (11)
Programming (168)
Programming Quotables (9)
Rails (31)
Ruby (67)
Save Your Job (58)
scriptaGulous (4)
Software Development Process (23)
TDD (41)
TDDing xorblog (6)
Tools (5)
Web Development (8)
Windows (1)
With (1)
YAGNI (10)

Resources
Agile Manifesto & Principles
Principles Of OOD
ColdFusion
CFUnit
Ruby
Ruby on Rails
JUnit



RSS 2.0: Full Post | Short Blurb
Subscribe by email:

Delivered by FeedBurner