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>
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
Another workaround is to use requests library as transport which has better support for ssl. This is what I'm using now to access SOAP services through https using suds:-
import requests from suds.transport.http import HttpAuthenticated from suds.transport import Reply, TransportError class RequestsTransport(HttpAuthenticated): def __init__(self, **kwargs): self.cert = kwargs.pop('cert', None) # super won't work because not using new style class HttpAuthenticated.__init__(self, **kwargs) def send(self, request): self.addcredentials(request) resp = requests.post(request.url, data=request.message, headers=request.headers, cert=self.cert) result = Reply(resp.status_code, resp.headers, resp.content) return result
And then you can instantiate suds client as:-
headers = {"Content-TYpe" : "text/xml;charset=UTF-8", "SOAPAction" : ""} t = RequestsTransport(cert='/path/to/cert', **credentials) client = Client(wsdl_uri, location=send_url, headers=headers, transport=t))
Update
We're now using Zeep, which use requests
underneath.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With