5

I am trying to use Zeep to implement a SOAP client, as it seems the only maintained library at the moment:

  • ZSI looked very good but its latest version on pypi dates 2006
  • suds seemed to be a popular alternative, but the master is unmaintained since 2011 and there are a lot of forks out there but none seems "official" and "recent" enough to be used in a large project.

So, trying to use Zeep, I am stuck with the authentication required by the server to access the WSDL.

Such operation was quite easy with ZSI:

from ZSI.client import Binding
from ZSI.auth import AUTH

b = Binding(url='http://mysite.dom/services/MyWebServices?WSDL')
b.SetAuth(AUTH.httpbasic, 'userid', 'password')

and I can find something similar in __main__.py of Zeep:

from six.moves.urllib.parse import urlparse
from zeep.cache import InMemoryCache, SqliteCache
from zeep.client import Client
from zeep.transports import Transport

cache = SqliteCache() if args.cache else InMemoryCache()
transport_kwargs = {'cache': cache}
result = urlparse(args.wsdl_file)
if result.username or result.password:
    transport_kwargs['http_auth'] = (result.username, result.password)
transport = Transport(**transport_kwargs)
client = Client(args.wsdl_file, transport=transport)

but that does not work in my case, I get an error:

Exception: HTTPConnectionPool(host='schemas.xmlsoap.org', port=80): Max retries exceeded with url: /soap/encoding/ (Caused by NewConnectionError('<requests.packages.urllib3.connection.HTTPConnection object at 0x7f3dab9d30b8>: Failed to establish a new connection: [Errno 110] Connection timed out',))
Pintun
  • 716
  • 1
  • 7
  • 23

3 Answers3

31

Probably with the newer Version of zeep the older solution does not work anymore. Here is the new way:

from requests.auth import HTTPBasicAuth  # or HTTPDigestAuth, or OAuth1, etc.
from requests import Session
from zeep import Client
from zeep.transports import Transport

session = Session()
session.auth = HTTPBasicAuth(user, password)
client = Client('http://my-endpoint.com/production.svc?wsdl',
            transport=Transport(session=session))
jan-seins
  • 1,253
  • 1
  • 18
  • 31
  • Yes, definitely this solutions works fine. The one above does not work for current version of zeep. `Transport` class does not accept the `http_auth` parameter. – tombishop83 Oct 02 '18 at 15:26
10

For Basic Access Authentication you can use the HTTPBasicAuth class from the requests module, as explained on Zeep documentation http://docs.python-zeep.org/en/master/transport.html:

from requests.auth import HTTPBasicAuth  # or HTTPDigestAuth, or OAuth1, etc.
from zeep import Client
from zeep.transports import Transport

client = Client('http://my-endpoint.com/production.svc?wsdl',
    transport=Transport(http_auth=HTTPBasicAuth(user, password)))
Moisés Hiraldo
  • 378
  • 1
  • 4
  • 13
  • Brilliant, thank you very much. I am now struggling with the fact that the WSDL, that is hosted inside an intranet, tries to import a namespace from the internet (''), that is not available from the client machine. Do you know if there is a way to prevent zeep client to do that? – Pintun Oct 21 '16 at 13:42
  • 1
    I don't think there's an easy workaround for that. Either you modify the WSDL to make all the namespaces local (you could have for example a copy of the WSDL on the client machine, Zeep can work with that) or somehow you serve a local copy of the schema on the intranet with the corresponding URL. – Moisés Hiraldo Oct 21 '16 at 14:15
  • I have found a solution, by overriding the transport class with a local copy. Cf [this question](http://stackoverflow.com/questions/40220134/python-soap-client-with-zeep-import-namespace). – Pintun Nov 04 '16 at 12:46
  • 5
    Hi ya, I realise you wrote this in October last year, but I believe this has now changed: see http://docs.python-zeep.org/en/master/transport.html#http-authentication (basically you need to do session=Session() and put the transport onto the session). But many thanks as without your answer I wouldn't have found this. (I think this is a change to Requests rather then a change to Zeep). – Jmons Sep 22 '17 at 11:45
5

In my case the API I was working with required WS-Security (WSSE) rather than HTTP.

from zeep import Client
from zeep.wsse.username import UsernameToken

client = Client(<wsdl_url>, wsse=UsernameToken(<username>, <password>)
stratagem
  • 525
  • 6
  • 7