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:

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 = "***********"
URL = "https://XXX.XXX.XXX.XXX/YYYY?wsdl 
<https://54.153.5.133:53441/ForAGISService?wsdl>"

proxy={'proxy_user':user,'proxy_pass':password}
SSclient.Http = set_http_wrapper(library='urllib2')
client=SSclient.SoapClient(wsdl=URL,proxy=proxy)



On Tuesday, June 9, 2015 at 3:32:03 PM UTC-4, Derek wrote:
>
> 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 ...
>
>
>
> On Tuesday, June 9, 2015 at 7:27:55 AM UTC-7, Pengfei Yu wrote:
>>
>> 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.
>>
>>  
>>
>> On Monday, June 8, 2015 at 5:28:08 PM UTC-4, Derek wrote:
>>>
>>> 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)
>>>>
>>>>
>>>>
>>>> Thanks!
>>>>
>>>> On Monday, June 8, 2015 at 12:18:38 PM UTC-4, Derek wrote:
>>>>>
>>>>> looks like pycurl is supported by pysimplesoap. That supports NTLM. 
>>>>> See line 67.
>>>>>
>>>>>
>>>>> https://code.google.com/p/pysimplesoap/source/browse/pysimplesoap/client.py?r=6ed06397b4f0c1894156ee5d0a1c165f80ed6a68
>>>>>
>>>>>
>>>>> 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 = "***********"
>>>>>> url = "https://54.153.5.133:53441/ForAGISService?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!
>>>>>>  
>>>>>>
>>>>>

-- 
Resources:
- http://web2py.com
- http://web2py.com/book (Documentation)
- http://github.com/web2py/web2py (Source code)
- https://code.google.com/p/web2py/issues/list (Report Issues)
--- 
You received this message because you are subscribed to the Google Groups 
"web2py-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to web2py+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to