7

I'm using SUDS for consuming web service. I tried like bellow:

client = Client(wsdl_url)
list_of_methods = [method for method in client.wsdl.services[0].ports[0].methods]
print(list_of_methods)

I got this error:

urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:645)>

I saw link but it is just solution for python 2.7. How can I bypass SSL with SUDS? Or is there any none python solution (For example add fake certificate in windows OS)? I'm using python 3(So I have to use urllib instead of urllib2).

Community
  • 1
  • 1
Artin Falahi
  • 1,101
  • 2
  • 16
  • 34

6 Answers6

11

A suds client uses a subclass of suds.transport.Transport to process requests.

The default transport used is an instance of suds.transport.https.HttpAuthenticated, but you can override this when you instantiate the client by passing a transport keyword argument.

The http and https transports are implemented using urllib.request (or urllib2 for python2) by creating an urlopener. The list of handlers used to create this urlopener is retrieved by calling the u2handlers() method on the transport class. This means that you can create your own transport by subclassing the default and overriding that method to use a HTTPSHander with a specific ssl context, e.g:

from suds.client import Client
from suds.transport.https import HttpAuthenticated
from urllib.request import HTTPSHandler
import ssl

class CustomTransport(HttpAuthenticated):

    def u2handlers(self):

        # use handlers from superclass
        handlers = HttpAuthenticated.u2handlers(self)

        # create custom ssl context, e.g.:
        ctx = ssl.create_default_context(cafile="/path/to/ca-bundle.pem")
        # configure context as needed...
        ctx.check_hostname = False

        # add a https handler using the custom context
        handlers.append(HTTPSHandler(context=ctx))
        return handlers

# instantiate client using this transport
c = Client("https://example.org/service?wsdl", transport=CustomTransport())
mata
  • 67,110
  • 10
  • 163
  • 162
  • What is value of cafile? How can I set it? – Artin Falahi May 19 '16 at 19:46
  • 1
    That's just an example of how you may create a context. In this case `cafile` would be the path to the server's ssl certificate (pem-encoded). You can of course also use `ctx = ssl._create_unverified_context()` instead like in the answer you linked to skip verification. Or you can [save the certificate](http://superuser.com/questions/97201/how-to-save-a-remote-server-ssl-certificate-locally-as-a-file) as pem file so you don't have to disable verification entirely. – mata May 19 '16 at 20:17
  • I get an error: Exception: (415, u"Cannot process the message because the content type 'text/xml; charset=utf-8' was not the expected ty pe 'application/soap+xml; charset=utf-8'.") even tho I have headers set to soap – Tadej Vengust Mar 16 '17 at 15:21
  • @TadejVengust - That seems unrelated to this question, you should probably ask a new question. Make sure to include the complete error message and how/where you set the headers. – mata Mar 16 '17 at 15:57
  • It is related since it adds headers without this customTransport Class but when trasport is set they are not.. Meaning that headers should probably be added somewhere inside the class aswell? – Tadej Vengust Mar 17 '17 at 08:09
  • 1
    @TadejVengust So how are you setting the headers? If you use a custom transport, you should use something like `c = Client("https://example.org/service?wsdl", transport=CustomTransport(headers={'Content-Type': 'application/soap+xml; charset=utf-8'}))`, that is pass the headers to the _Transport_ constructor, not the _Client_ constructor. – mata Mar 17 '17 at 11:32
  • Thanks I didn't know I had to put it in custom transport, I was putting it directly into client. Now I am getting bed requests but at least I am somehow getting to the server. – Tadej Vengust Mar 17 '17 at 11:48
9

This code worked for me:

from suds.client import Client
import ssl

if hasattr(ssl, '_create_unverified_context'):
    ssl._create_default_https_context = ssl._create_unverified_context
cli = Client('https://your_lik_to?wsdl')

print(cli)
Nir Vana
  • 387
  • 3
  • 9
  • 2
    This solution does answer the question, but I think there should be a warning that using this solution leaves you vulnerable to not knowing if you're connecting to a trusted server or to a server that is mimicking the trusted server. I recommend implementing the custom transport described in the accepted answer -- it's quite a bit more effort, but should give more protection than completely disabling SSL verification – Seth Difley May 29 '20 at 06:04
3

You can add the code below before instantiate your suds client:

import ssl


try:
    _create_unverified_https_context = ssl._create_unverified_context
except AttributeError:
    pass
else:
    ssl._create_default_https_context = _create_unverified_https_context

See my own website for details: https://lucasmarques.me/bypass-ssl

2

This is what I came up with that seems to work well:

class MyTransport(HttpAuthenticated):

    def u2handlers(self):
        """
        Get a collection of urllib handlers.

        @return: A list of handlers to be installed in the opener.
        @rtype: [Handler,...]

        """
        handlers = []
        context = ssl._create_unverified_context()
        handlers.append(urllib2.HTTPSHandler(context=context))
        return handlers

Cheers!

radtek
  • 34,210
  • 11
  • 144
  • 111
1

You can use https://pypi.python.org/pypi/suds_requests to leverage the requests library for the transport. This gives you the ability to disable the ssl verification.

Or try my new soap library, it supports it out of the box: http://docs.python-zeep.org/en/latest/#transport-options

mvantellingen
  • 1,229
  • 10
  • 6
-1

I use this:

with mock.patch('ssl._create_default_https_context', ssl._create_unverified_context):
    client = Client(url)

See: https://bitbucket.org/jurko/suds/issues/78/allow-bypassing-ssl-certificate#comment-39029255

guettli
  • 25,042
  • 81
  • 346
  • 663
  • unittest.mock is a library for testing in Python. The question does not specify this being a test use-case. – Gregor Eesmaa Sep 03 '19 at 14:36
  • @GregorEesmaa yes, you are right. But sometimes you need to work around tthings and do ugly hacks. Please tell me better solutions. I am curious. – guettli Sep 03 '19 at 14:44
  • A combination of the top two answers did the trick for me: using a custom Transport instance with ssl._create_unverified_context. While that may be considered a hack, it's definitely not as "ugly", as overriding the transport is supported by the library. – Gregor Eesmaa Sep 04 '19 at 09:07