Soap4r ntlm Authentication Issue

124 views
Skip to first unread message
Message has been deleted

jrclark

unread,
Feb 18, 2009, 10:18:06 AM2/18/09
to soap4r
I am using wsdl2ruby and soap4r to create a driver for a Microsoft
Exchange Server 2007. I current have to use ntlm authentication. Im
new to soap4r and unsure how to add ntlm auth to the creater driver. I
used wsdl2ruby and create the following files:

default.rb
defaultDriver.rb
defaultMappingRegistry.rb

This is the code that i have so far

require 'rubygems'
gem 'soap4r'
require 'soap/rpc/driver'
require 'httpclient'
require 'defaultDriver'
require 'soap/wsdlDriver'

ISSUER_CA_PEM = "/entrust_ssl_ca.cer"
SERVER_PEM = "/server.pem"
def validate_certificate(is_ok, ctx)
cert = ctx.current_cert
# Only check the server certificate, not the issuer.
unless (cert.subject.to_s == cert.issuer.to_s)
is_ok &&= File.open(SERVER_PEM).read == ctx.current_cert.to_pem
end
is_ok
end
endpoint = 'https://myservicename/ews'
namespace = 'http://schemas.microsoft.com/exchange/services/2006/
messages'
user = 'DOMAIN\user'
pass = 'password'
driver = SOAP::WSDLDriverFactory.new(endpoint)
#driver.options['protocol.http.ssl_config.ca_file'] = ISSUER_CA_PEM
#driver.options['protocol.http.ssl_config.verify_callback'] = method
(:validate_certificate)
driver.options["protocol.http.ssl_config.verify_mode"] = nil
driver.set_auth[:ntlm => [user,pass]]
driver.get_content('https://myservice/ews/?wsdl

Currently I do not need to use SSL until I can get pass the 401 error
that I am receiving. The authentication should be ntlm with WWW-Auth.

Thanks in advance!
jrclark

zenChild

unread,
Feb 18, 2009, 4:17:06 PM2/18/09
to soap4r
I thought it interesting that you should ask this because I've been
struggling with this exact same problem for the last couple days.
Here is the solution that I have gotten to work. See the comments in
the code to see the explanations behind some of what is going on.

http://pastie.org/393286

If you can get the methods working please let me know how you are
calling them because I haven't been successful there as of yet.

Cheers,

Dan
Message has been deleted

jrclark

unread,
Feb 19, 2009, 10:41:37 AM2/19/09
to soap4r
I still have not found a solution, but yet another error which is the
"SOAP::PostUnavailableError: 405: Method Not Allowed". Here is the
code in
which I am trying now:

require 'rubygems'
gem 'soap4r'
require 'defaultDriver'
endpoint = 'https://my.exchange.com/ews/'
user = 'user'
pass = 'pass'
driver = ExchangeServicePortType.new(endpoint)
driver.wiredump_dev = STDERR
driver.options['protocol.http.auth.ntlm'] = [endpoint,user,pass]
#driver.options['protocol.http.ssl_config.ca_file'] = ISSUER_CA_PEM
#driver.options['protocol.http.ssl_config.verify_callback'] =
method(:validate_certificate)
driver.options["protocol.http.ssl_config.verify_mode"] = nil

result = driver.getUserOofSettings('myemailaddress',nil)
puts result.inspect

The Wiredump is very long but after being connected to the server the
response is:

= Response

HTTP/1.1 405 Method Not Allowed
Allow: OPTIONS, TRACE, GET, HEAD
Content-Length: 1564
Content-Type: text/html
Server: Microsoft-IIS/6.0
X-Powered-By: ASP.NET
Date: Thu, 19 Feb 2009 15:31:52 GMT

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "
http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>The page cannot be displayed</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html;
charset=Windows-1252">
<STYLE type="text/css">
BODY { font: 8pt/12pt verdana }
H1 { font: 13pt/15pt verdana }
H2 { font: 8pt/12pt verdana }
A:link { color: red }
A:visited { color: maroon }
</STYLE>
</HEAD><BODY><TABLE width=500 border=0 cellspacing=10><TR><TD>

<h1>The page cannot be displayed</h1>
The page you are looking for cannot be displayed because an invalid
method
(HTTP verb) was used to attempt access.
<hr>
<p>Please try the following:</p>
<ul>
<li>Contact the Web site administrator if you believe that this
request
should be allowed.</li>
<li>Make sure that the Web site address displayed in the address bar
of your
browser is spelled and formatted correctly. </li>
</ul>
<h2>HTTP Error 405 - The HTTP verb used to access this page is not
allowed.<br>Internet Information Services (IIS)</h2>
<hr>
<p>Technical Information (for support personnel)</p>
<ul>
<li>Go to <a href="http://go.microsoft.com/fwlink/?
linkid=8180">Microsoft
Product Support Services</a> and perform a title search for the words
<b>HTTP</b> and <b>405</b>.</li>
<li>Open <b>IIS Help</b>, which is accessible in IIS Manager
(inetmgr),
and search for topics titled <b>Setting Application Mappings</b>,
<b>Securing Your Site with Web Site Permissions</b>, and <b>About
Custom
Error Messages</b>.</li>
</ul>

</TD></TR></TABLE></BODY></HTML>

If you have any ideas or solutions to this problem then please help!

Thanks,
Justin

zenChild

unread,
Feb 19, 2009, 12:49:38 PM2/19/09
to soap4r
I'm still working out some of the technicalities of the wsdl2ruby
generated classes, but I have gotten some things to work by removing
the following lines from defaultDriver.rb.

["in", "Impersonation", ["::SOAP::SOAPElement", "http://
schemas.microsoft.com/exchange/services/2006/types",
"ExchangeImpersonation"]],
["in", "S2SAuth", ["::SOAP::SOAPElement", "http://
schemas.microsoft.com/exchange/services/2006/types",
"SerializedSecurityContext"]],
["in", "MailboxCulture", ["::SOAP::SOAPElement", "http://
schemas.microsoft.com/exchange/services/2006/types",
"MailboxCulture"]],
["in", "RequestVersion", ["::SOAP::SOAPElement", "http://
schemas.microsoft.com/exchange/services/2006/types",
"RequestServerVersion"]],

I believe these should be Header elements, but they are being placed
in the body. I tried setting SOAP::SOAPElement to
SOAP::SOAPHeaderItem instead, but that seemingly had no effect. In
any case, they are optional so if you remove them this should kind-of
work. I also had to make the additional changes:

# added the exchange.asmx. It won't work otherwise
obj = ExchangeServicePortType.new(endpoint + "exchange.asmx")

# Sample resolveNames query ( Yes I know this is ugly, but that's
what it is for now )
rnt = ResolveNamesType.new(nil,"testuser")
rnt.xmlattr_ReturnFullContactData=true
resp = obj.resolveNames
(rnt).responseMessages.resolveNamesResponseMessage
resol = resp[0].resolutionSet.resolution[0]
puts resol.inspect

Cheers,

Dan Wanek

Justin Clark

unread,
Feb 19, 2009, 3:12:59 PM2/19/09
to soa...@googlegroups.com, dan....@gmail.com
For all of those out there trying to figure out how to receive information from an exchange server 2007, here is my process to create a working web service client.

  • Make sure you have the following gems:
    • rubygems
    • soap4r
    • httpclient
  • Use wsdl2ruby in the directory you have currently the wsdl and generate the following three files:
    • default.rb
    • defaultDriver.rb
    • defaultMappingRegistry.rb


Once you have generated these files you can use them to create your web service file which if you are connecting to Exchange 2007 with ntlm authentication, it will look similar to this:


require 'rubygems'
gem 'soap4r'
require 'defaultDriver'
require 'default'
endpoint = 'https://yourservice.com/ews/Exchange.asmx'
namespace = 'http://schemas.microsoft.com/exchange/services/2006/messages'

user = 'user'
pass = 'pass'
driver = ExchangeServicePortType.new(endpoint)
driver.wiredump_dev = STDERR
driver.options['protocol.http.auth.ntlm'] = [endpoint,user,pass]
driver.options["protocol.http.ssl_config.verify_mode"] = nil

#create the time zone
dayOfWeekType = DayOfWeekType.new('Sunday')
standardTime = SerializableTimeZoneTime.new(0, '02:00:00', 5, 10, dayOfWeekType)
daylightTime = SerializableTimeZoneTime.new(-60, '02:00:00', 1, 4, dayOfWeekType)
TimeZone = SerializableTimeZone.new(300,standardTime,daylightTime)

#create mailbox data
email = EmailAddress.new('', 'your...@blah.com', 'SMPT')
attendeeType = MeetingAttendeeType.new('Organizer')
excludeConflicts = false
mailBoxData = MailboxData.new(email,attendeeType,excludeConflicts)
mailBoxDataArray = ArrayOfMailboxData.new
mailBoxDataArray = [mailBoxData]

#create freeBusyViewOptions
duration = Duration.new('2009-02-19T00:00:00','2009-02-25T23:59:59')
mergedFreeBusyInterval = SOAP::SOAPInt.new(60)
requestedView = 'FreeBusyMerged'
freeBusyViewOptionsType = FreeBusyViewOptionsType.new(duration,60,requestedView)

#create the getAvailabilityRequest
getAvailabilityRequest = GetUserAvailabilityRequestType.new(TimeZone,mailBoxDataArray,freeBusyViewOptionsType)
driver.getUserAvailability(getAvailabilityRequest)

The soap request that is created from the method call getUserAvailability will return a 405 error if you do not pass the correct parameters. Each parameter is a different soap type. These types can be found in the default.rb file that you created earlier, and must match the schema from the defaultDriver file.

Here is the full version of what the following client could look like:

require 'rubygems'
gem 'soap4r'
require 'defaultDriver'
require 'default'
endpoint = 'https://yourservice.com/ews/Exchange.asmx'
namespace = 'http://schemas.microsoft.com/exchange/services/2006/messages'

user = 'user'
pass = 'pass'
driver = ExchangeServicePortType.new(endpoint)
driver.wiredump_dev = STDERR
driver.options['protocol.http.auth.ntlm'] = [endpoint,user,pass]
driver.options["protocol.http.ssl_config.verify_mode"] = nil

#create the time zone
bias = SOAP::SOAPInt.new(480)
dayOfWeekType = DayOfWeekType.new('Sunday')
standardTime = SerializableTimeZoneTime.new(SOAP::SOAPInt.new(-180), SOAP::SOAPString.new('02:00:00'), SOAP::SOAPShort.new(5), SOAP::SOAPShort.new(10), dayOfWeekType)
daylightTime = SerializableTimeZoneTime.new(SOAP::SOAPInt.new(-60), SOAP::SOAPString.new('02:00:00'), SOAP::SOAPShort.new(1), SOAP::SOAPShort.new(4), dayOfWeekType)
TimeZone = SerializableTimeZone.new(bias,standardTime,daylightTime)

#create mailbox data
email = EmailAddress.new(SOAP::SOAPString.new(), SOAP::SOAPString.new('your...@blah.com'), SOAP::SOAPString.new('SMPT'))
attendeeType = MeetingAttendeeType.new('Organizer')
excludeConflicts = SOAP::SOAPBoolean.new(false)
mailBoxData = MailboxData.new(email,attendeeType,excludeConflicts)
mailBoxDataArray = ArrayOfMailboxData.new
mailBoxDataArray = [mailBoxData]

#create freeBusyViewOptions
duration = Duration.new(SOAP::SOAPDateTime.new('2009-02-19T00:00:00'), SOAP::SOAPDateTime.new('2009-02-25T23:59:59'))
mergedFreeBusyInterval = SOAP::SOAPInt.new(60)
requestedView = 'FreeBusyMerged'
freeBusyViewOptionsType = FreeBusyViewOptionsType.new(duration,mergedFreeBusyInterval,requestedView)

#create the getAvailabilityRequest
getAvailabilityRequest = GetUserAvailabilityRequestType.new(TimeZone,mailBoxDataArray,freeBusyViewOptionsType)

driver.getUserAvailability(getAvailabilityRequest)

The defaultDriver.rb file has been modified by deleting the following blue lines to match the parameters from my getUserAvailability method call:

[ "http://schemas.microsoft.com/exchange/services/2006/messages/GetUserAvailability",
      "getUserAvailability",
      [ ["in", "GetUserAvailabilityRequest", ["::SOAP::SOAPElement", "http://schemas.microsoft.com/exchange/services/2006/messages", "GetUserAvailabilityRequest"]],
        ["in", "SerializedSecurityContext", ["::SOAP::SOAPElement", "http://schemas.microsoft.com/exchange/services/2006/types", "SerializedSecurityContext"]],
        ["in", "ProxyRequestTypeHeader", ["::SOAP::SOAPElement", "http://schemas.microsoft.com/exchange/services/2006/types", "ProxyRequestTypeHeader"]],

        ["in", "Impersonation", ["::SOAP::SOAPElement", "http://schemas.microsoft.com/exchange/services/2006/types", "ExchangeImpersonation"]],
        ["out", "GetUserAvailabilityResult", ["::SOAP::SOAPElement", "http://schemas.microsoft.com/exchange/services/2006/messages", "GetUserAvailabilityResponse"]],
        ["out", "ServerVersion", ["::SOAP::SOAPElement", "http://schemas.microsoft.com/exchange/services/2006/types", "ServerVersionInfo"]] ],
      { :request_style =>  :document, :request_use =>  :literal,
        :response_style => :document, :response_use => :literal,
        :faults => {} }

Thanks and good luck!
Justin
Reply all
Reply to author
Forward
0 new messages