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.
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