[Home] You are not logged in. Login here

Just my stuff

Consume SSL protected Web Services with soap4r

After hours of google this deserves a blog post. I did not find a clear example about this, so I am writing one.
I had the need to call a .NET Web Service over https with mutual authentication and basic authentication.
First of all I installed the soap4r gem, then the httpclient gem (because that one supports basic authentication).
Then I made a folder called “certs” with all the certificates and key files I had:
- ca.cer – the certificate of the certification authority that signed the server certificate
- server.cer – the certificate of the server (signed by the guys who own ca.cer)
- client.cer – the client certificate I need to send along the request to get the content
- client.key – the key file for the client certificate
That’s all the certs and key files I needed.
Now it was time to try to get the wsdl:
require 'http-access2'

url = 'https://secure.example.com/web_service/wsdl'

client = HTTPAccess2::Client.new()
client.ssl_config.set_client_cert_file('certs/client.cer', 'certs/client.key')
client.ssl_config.set_trust_ca('certs/ca.cer')
client.set_basic_auth(url, 'username', 'password')
puts client.get(url).content

This worked.
Time to try soap4r:
require 'rubygems'  #if you installed httpclient with rubygems you need this
require 'soap/wsdlDriver'

#this validates the server certificate
#so you can be sure that the server you are
#sending data to is the server you have the
#certificate of in certs/server.cer
def validate_certificate(is_ok, ctx)
  cert = ctx.current_cert
  unless (cert.subject.to_s == cert.issuer.to_s) #check the server certificate only
    is_ok &&= File.open('certs/server.cer').read == ctx.current_cert.to_pem
  end
  is_ok
end 

wsdl = 'https://secure.example.com/web_service/wsdl'
driver = SOAP::WSDLDriverFactory.new(wsdl).create_rpc_driver
#driver.wiredump_dev = STDOUT

driver.options['protocol.http.ssl_config.verify_callback'] = method(:validate_certificate)

results = driver.web_service_method(arg1, arg2)
p results

To tell soap4r that you want basic authentication and where the certificate files are, you need to create a soap/property file with the following content:
client.protocol.http.basic_auth.1.url = https://secure.example.com/web_service/wsdl
client.protocol.http.basic_auth.1.userid = username
client.protocol.http.basic_auth.1.password = password

client.protocol.http.ssl_config.client_cert = certs/client.cer
client.protocol.http.ssl_config.client_key = certs/client.key
client.protocol.http.ssl_config.ca_file = certs/ca.cer
client.protocol.http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER
client.protocol.http.ssl_config.ciphers = ALL
client.protocol.http.ssl_config.verify_depth = 1

This file is loaded at startup (you can find other options in soap/lib/soap/httpconfigloader.rb), and configures the ssl and basic auth stuff for soap4r.
Anonymous Sam said...

Wow…this post is exactly what was looking for! However, I’m just writing an example of calling a simple .NET webservice from Ruby using Basic Authentication.

Do I NEED to do this mutual verification as it appears you specify in the soap/property file with the line:

client.protocol.http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER

Basically, what is the most stripped down approach I could use that would simply encrypt the transmission of credentials using HTTP Basic Authentication? Thanks again for this work….any help you can provide would be great.

Regards,
Sam

Thu Jun 05 08:53:18 +0200 2008
Avatar S2 said...

Hi Sam. Basic Authentication does not encrypt the traffic: it’s only for authentication (and it’s very insecure as well if you don’t use it together with ssl – credentials are send in plaintext). Maybe that was what you sad, I’m not sure I understood you correctly.
You don’t need mutual authentication to encrypt the traffic. Server authentication would be enough. In that case you can leave out the part where you specify the client credentials in soap/property. This two lines

client.protocol.http.ssl_config.client_cert = certs/client.cer
client.protocol.http.ssl_config.client_key = certs/client.key

become obsolete.

Thu Jun 05 10:14:30 +0200 2008
Anonymous Sam said...

I doing poor job of explaining myself. I did know when doing HTTP basic authentication, since credentials are passed in clear text, if you don’t encrypt the traffic, you’ve got yourself a very big security hole in your app.

I’m still fuzzy on the soap/property file. Where is that located?

Thu Jun 05 19:54:37 +0200 2008
Avatar S2 said...

Just throw it in the same dir you have the script in and you should be fine.

Fri Jun 06 14:46:54 +0200 2008
Anonymous soap/property said...

i am trying to create soap/property file. where do i need to create this file..is it in this path ruby\gems\1.9.1\gems\soap4r-1.5.8\lib\soap? there is already a property.rb file in that directory. please help.

Thu Aug 11 19:54:33 +0200 2011
Anonymous Chris said...

Very interesting but how is sent the certificate?

Do you speak about web service security where the SOAP Headers are set with the Parameters of the certificate (Digestvalue, Signature, BinarySecurityToken), or is the certificate sent through the “normal” way in a parallel request?

Fri Feb 17 14:38:15 +0100 2012
 
Comments for this post have been disabled