soap client with windows NTLM authorization

1,395 views
Skip to first unread message

Pengfei Yu

unread,
Jun 8, 2015, 10:28:39 AM6/8/15
to web...@googlegroups.com
Hi,

I am trying to access a web service which requires windows NTLM authorization. I am able to successfully implement it using suds python library with following code:

from suds.transport.http import *
from suds.transport.https import WindowsHttpAuthenticated
from suds.client import *

import time


sampleID
= "AAAAAA"
user
= 'XXXXXXX'
password
= "***********"
url
= "https://XXX.XXX.XXX.XXX/YYYY?wsdl"


transport
= WindowsHttpAuthenticated(username=user, password=password)
client
= Client(url, transport=transport)


print "List of methods for this web service:"
print [method for method in client.wsdl.services[0].ports[0].methods]


print "\nsample info:"
print client.service.GetSampleInfoById(sampleID)

The NTLM transport is supported by python-ntlm package as mentioned in https://fedorahosted.org/suds/wiki/Documentation#WindowsNTLM.

But I prefer to use pysimplesoap as SOAP client in my web2py application. I wonder if there is also an feasible approach to implement it with pysimplesoap + python-ntlm? If someone could provide a code example, that will be perfect.

Thanks!
 

Derek

unread,
Jun 8, 2015, 12:18:38 PM6/8/15
to web...@googlegroups.com
looks like pycurl is supported by pysimplesoap. That supports NTLM. See line 67.



On Monday, June 8, 2015 at 7:28:39 AM UTC-7, Pengfei Yu wrote:
Hi,

I am trying to access a web service which requires windows NTLM authorization. I am able to successfully implement it using suds python library with following code:

from suds.transport.http import *
from suds.transport.https import WindowsHttpAuthenticated
from suds.client import *

import time


sampleID
= "AAAAAA"
user
= 'XXXXXXX'
password
= "***********"



transport
= WindowsHttpAuthenticated(username=user, password=password)
client
= Client(url, transport=transport)


print "List of methods for this web service:"
print [method for method in client.wsdl.services[0].ports[0].methods]


print "\nsample info:"
print client.service.GetSampleInfoById(sampleID)

Pengfei Yu

unread,
Jun 8, 2015, 2:45:44 PM6/8/15
to web...@googlegroups.com
Hi Derek,

Thanks for your reply! I saw similar source code as well. But there is no document how to set it up using pysimplesoap. Could you provide an example?

I tried to use following, but it cannot work.
import sys,time
sys
.path.append("/home/www-data/web2py")
import pprint


from gluon.contrib.pysimplesoap.client import *
from gluon.contrib.pysimplesoap.transport import *



user
= 'XXXXXXX'
password
= "***********"


proxy
={'proxy_user':user,'proxy_pass':password}
Http = set_http_wrapper(library='pycurl')
client
=SoapClient(wsdl="https://XXX.XXX.XXX.XXX/YYYY?wsdl",proxy=proxy)



Thanks!

Derek

unread,
Jun 8, 2015, 5:28:08 PM6/8/15
to web...@googlegroups.com
a simple monkey patch will do you. I would suggest you don't import into the base namespace though.
import gluon.contrib.pysimplesoap.client as ssClient

then do the monkey...
ssClient.Http = set_http_wrapper(library='pycurl')

and use it like normal.

I don't get why you are trying to use a proxy?

import pycurl

name='bob'
pwd='pwd1'
url="https://mywebservice"

curl = pycurl.Curl()
curl.setopt(pycurl.URL, url)
curl.setopt(pycurl.SSL_VERIFYPEER, 0)

curl.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_NTLM)
curl.setopt(pycurl.USERPWD, "{}:{}".format(name, pwd))

curl.perform()
curl.close()

On Monday, June 8, 2015 at 11:45:44 AM UTC-7, Pengfei Yu wrote:
Hi Derek,

Thanks for your reply! I saw similar source code as well. But there is no document how to set it up using pysimplesoap. Could you provide an example?

I tried to use following, but it cannot work.
import sys,time
sys
.path.append("/home/www-data/web2py")
import pprint


from gluon.contrib.pysimplesoap.client import *
from gluon.contrib.pysimplesoap.transport import *


user
= 'XXXXXXX'
password
= "***********"

proxy
={'proxy_user':user,'proxy_pass':password}
Http = set_http_wrapper(library='pycurl')

client
=SoapClient(wsdl="https://54.153.5.133:53441/ForAGISService?wsdl",proxy=proxy)

Pengfei Yu

unread,
Jun 9, 2015, 10:27:55 AM6/9/15
to web...@googlegroups.com
Thanks for your reply! I used the proxy because I checked from the source code that proxy is the only place I can pass my username and password to pycurl from SoapClient class.

I can connect to this SOAP service directly with pycurl using the code you provided. But I want to create a SoapClient object based on this SOAP service. I still cannot figure it out yet.

Derek

unread,
Jun 9, 2015, 3:32:03 PM6/9/15
to web...@googlegroups.com
alright, well you are going to have to modify the client.py for pysimplesoap then in order to achieve this.
I'd suggest you add a variable to the class like 'USERPWD' and populate it. Take a look at lines 75+.
See all those 'setopt' calls? Add in your own for HTTPAUTH and USERPWD ...

Pengfei Yu

unread,
Jun 10, 2015, 12:53:08 PM6/10/15
to web...@googlegroups.com
I am able to modify the code in transport.py and enable NTLM authentication using PycURL. But the pycurl library or the inside libcurl is not friendly with SOAP request using NTLM authentication, it always send request with invalid "content-length", although it is already correctly specified in header of the client. I always get http error 411 when trying to call SOAP web service function with NTLM authentication through PycURL.

Here is the error information: 
<?xml version="1.0" ?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Header/>
<soap:Body>
   
<GetSampleInfoById xmlns="http://tempuri.org/">
   
<sampleId>de63c455-0849-4716-abb0-43d0a52073cf</sampleId></GetSampleInfoById>
</soap:Body>
</soap:Envelope>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Length Required</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Length Required</h2>
<hr><p>HTTP Error 411. The request must be chunked or have a content length.</p>
</BODY></HTML>

Since in SUDS, they use python-ntlm to allow NTLM authentication utilizing "urllib2", then I tried to modify the code in "urllib2Transport" class of pysimplesoap's transport.py, and enable NTLM authentication using urllib2 transport. It works finally. Here is the modifications (python-ntlm need to installed first):

Original code:

class urllib2Transport(TransportBase):
    _wrapper_version
= "urllib2 %s" % urllib2.__version__
    _wrapper_name
= 'urllib2'

   
def __init__(self, timeout=None, proxy=None, cacert=None, sessions=False):
       
if (timeout is not None) and not self.supports_feature('timeout'):
           
raise RuntimeError('timeout is not supported with urllib2 transport')
       
if proxy: raise RuntimeError('proxy is not supported with urllib2 transport')
       
if cacert: raise RuntimeError('cacert is not support with urllib2 transport')
       
self.request_opener = urllib2.urlopen
       
if sessions:
            opener
= urllib2.build_opener(urllib2.HTTPCookieProcessor(CookieJar()))
           
self.request_opener = opener.open
       
self._timeout = timeout
   
def request(self, url, method="GET", body=None, headers={}):
        req
= urllib2.Request(url, body, headers)
       
try:
            f
= self.request_opener(req, timeout=self._timeout)
           
return f.info(), f.read()
       
except urllib2.HTTPError as f:
           
if f.code != 500:
               
raise
           
return f.info(), f.read()

Modified code:

class urllib2Transport(TransportBase):
    _wrapper_version
= "urllib2 %s" % urllib2.__version__
    _wrapper_name
= 'urllib2'


   
def __init__(self, timeout=None, proxy=None, cacert=None, sessions=False):
       
if (timeout is not None) and not self.supports_feature('timeout'):
           
raise RuntimeError('timeout is not supported with urllib2 transport')
       
#if proxy:
       
#    raise RuntimeError('proxy is not supported with urllib2 transport')
       
self.proxy = proxy or {}
       
if cacert:
           
raise RuntimeError('cacert is not support with urllib2 transport')


       
self.request_opener = urllib2.urlopen
       
if sessions:
            opener
= urllib2.build_opener(urllib2.HTTPCookieProcessor(CookieJar()))
           
self.request_opener = opener.open


       
self._timeout = timeout


   
def request(self, url, method="GET", body=None, headers={}):
        req
= urllib2.Request(url, body, headers)
       
if 'proxy_user' in self.proxy:
           
from ntlm import HTTPNtlmAuthHandler
            passman
= urllib2.HTTPPasswordMgrWithDefaultRealm()
            passman
.add_password(None, url, self.proxy['proxy_user'], self.proxy['proxy_pass'])
           
# create the NTLM authentication handler
            auth_NTLM
= HTTPNtlmAuthHandler.HTTPNtlmAuthHandler(passman)
           
# create and install the opener
            opener
= urllib2.build_opener(auth_NTLM)
           
self.request_opener = opener.open
       
try:
            f
= self.request_opener(req, timeout=self._timeout)
           
return f.info(), f.read()
       
except urllib2.HTTPError as f:
           
if f.code != 500:
               
raise
           
return f.info(), f.read()

Now, we can create the client object for SOAP service with NTLM authentication by:

import sys
sys
.path.append("/home/www-data/web2py")

import gluon.contrib.pysimplesoap.client as SSclient



user
= 'XXXXXXX'
password
= "***********"

proxy
={'proxy_user':user,'proxy_pass':password}
SSclient.Http = set_http_wrapper(library='urllib2')
client
=SSclient.SoapClient(wsdl=URL,proxy=proxy)
Reply all
Reply to author
Forward
0 new messages