Search code examples
pythonsslhttpssuds

Suds over https with cert


I have soap service under Apache with ssl, suds works greate without ssl.
I have client certificate (my.crt and user.p12 files).
How I need to configure suds client ot make it work with service over https?

without certs i see

urllib2.URLError: <urlopen error [Errno 1] _ssl.c:499: error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake failure>

Solution

  • It sounds like you want to authenticate using a client certificate, not a server certificate as was stated in some of the comments. I had the same issue and was able to write a custom transport for SUDS. Here's the code that works for me.

    You'll need your certificates in PEM format for this to work; OpenSSL can easily perform this conversion, though I don't remember the exact syntax.

    import urllib2, httplib, socket
    from suds.client import Client
    from suds.transport.http import HttpTransport, Reply, TransportError
    
    class HTTPSClientAuthHandler(urllib2.HTTPSHandler):
        def __init__(self, key, cert):
            urllib2.HTTPSHandler.__init__(self)
            self.key = key
            self.cert = cert
    
        def https_open(self, req):
            #Rather than pass in a reference to a connection class, we pass in
            # a reference to a function which, for all intents and purposes,
            # will behave as a constructor
            return self.do_open(self.getConnection, req)
    
        def getConnection(self, host, timeout=300):
            return httplib.HTTPSConnection(host,
                                           key_file=self.key,
                                           cert_file=self.cert)
    
    class HTTPSClientCertTransport(HttpTransport):
        def __init__(self, key, cert, *args, **kwargs):
            HttpTransport.__init__(self, *args, **kwargs)
            self.key = key
            self.cert = cert
    
        def u2open(self, u2request):
            """
            Open a connection.
            @param u2request: A urllib2 request.
            @type u2request: urllib2.Requet.
            @return: The opened file-like urllib2 object.
            @rtype: fp
            """
            tm = self.options.timeout
            url = urllib2.build_opener(HTTPSClientAuthHandler(self.key, self.cert))
            if self.u2ver() < 2.6:
                socket.setdefaulttimeout(tm)
                return url.open(u2request)
            else:
                return url.open(u2request, timeout=tm)
    
    # These lines enable debug logging; remove them once everything works.
    import logging
    logging.basicConfig(level=logging.INFO)
    logging.getLogger('suds.client').setLevel(logging.DEBUG)
    logging.getLogger('suds.transport').setLevel(logging.DEBUG)
    
    c = Client('https://YOUR_URL_HERE',
        transport = HTTPSClientCertTransport('PRIVATE_KEY.pem',
                                             'CERTIFICATE_CHAIN.pem'))
    print c