erhesto
erhesto

Reputation: 1186

SOAPpy WSDL client authentication

I'm trying to do simple SOAP call with WSDL and authentication, but don't know really how to pass credentials to the call. Is this possible with WSDL, or should I do this some other way?

from SOAPpy import WSDL

WSDLFILE = 'link/to/wsdl/file'
server = WSDL.Proxy(WSDLFILE)

result = server.methodCall()

Right now, I'm getting this error:

File "/usr/lib/pymodules/python2.7/SOAPpy/Client.py", line 263, in call
raise HTTPError(code, msg)
SOAPpy.Errors.HTTPError: <HTTPError 401 Unauthorized>

Upvotes: 0

Views: 1871

Answers (1)

Greg0ry
Greg0ry

Reputation: 1069

Quite an old question but since it shows up first when googling "SOAPpy authentication" - I will leave my findings so maybe you won't have to bang your head for 10 hours. Giving back to community.

Googling does not provide much help but this sample here (http://code.activestate.com/recipes/444758-how-to-add-cookiesheaders-to-soappy-calls/) made me to write my own helper (version 0.0 beta)

from SOAPpy import (
    WSDL,
    HTTPTransport,
    Config,
    SOAPAddress,
)
import urllib2
import base64

class AuthenticatedTransport(HTTPTransport):
    _username = None
    _password = None

    def call(self, addr, data, namespace, soapaction = None, encoding = None, http_proxy = None, config = Config, timeout = 10):
        if not isinstance(addr, SOAPAddress):
            addr = SOAPAddress(addr, config)

        content_type = 'text/xml'
        if encoding != None:
            content_type += '; charset="%s"' % encoding

        encoded_auth = None
        if ( isinstance(AuthenticatedTransport._username, str) != False ):
            if ( isinstance(AuthenticatedTransport._password, str) == False ):
                AuthenticatedTransport._password = ""
            encoded_auth = base64.b64encode('%s:%s' % (self._username, self._password))

        this_request = None
        if ( encoded_auth is not None ):
            this_request = urllib2.Request(
                url=addr.proto + "://" + addr.host + addr.path,
                data=data,
                headers={
                    "Content-Type":content_type,
                    "SOAPAction":"%s" % soapaction,
                    "Authorization":"Basic %s" % encoded_auth
                }
            )
        else:
            this_request = urllib2.Request(
                url=addr.proto + "://" + addr.host + addr.path,
                data=data,
                headers={
                    "Content-Type":content_type,
                    "SOAPAction":"%s" % soapaction,
                }
            )

        response = urllib2.urlopen(this_request)
        data = response.read()

        # get the new namespace
        if namespace is None:
            new_ns = None
        else:
            new_ns = self.getNS(namespace, data)

        # return response payload
        return data, new_ns

WSDL.Config.strictNamespaces = 0

username = "your_username"
password = "your_password"

WSDLFile = "https://%s:%s@some_host/your_wsdl.php?wsdl" % (username, password)
namespace = "http://futureware.biz/mantisconnect"
proxy = WSDL.Proxy(WSDLFile, namespace=namespace, transport = AuthenticatedTransport(username,password))

print(proxy.mc_get_version()) # This is my WSDL call, your will be different

For whatever reason it is not enough to use AuthenticatedTransport class, the WSDL url itself also has to contain user name and password. Maybe it's because SOAP wrapper called by WSDL here is creating separate HTTP session (remember reading about it on SOAPpy mailing list).

Hope this helps somebody.

Upvotes: 1

Related Questions