Posted Thursday, April 14th at 7:51a.m. under Work, Python
If you are using Python to make requests over SSL then most likely you'll have run into the limitations of urllib2 if you are using a web service that requires client authentication. I found some recipes that "kind of" solved the problem but didn't bother to check server certificates, which kind of defeats the point if you are using two-way SSL to prevent man-in-the-middle attacks.
It was frustrating since most simple things are relatively simple to do in Python. In cURL, two-way SSL verification can be as easy as:
curl -cacert CA.crt -E client.pem https://myservice.com:443/secure/page
Obviously here we are doing verification with a Certificate Authority we created ourselves. When I vented to a colleague about the difficulty of implementing similar functionality in Python, he wondered why I hadn't bothered using pycurl. pycurl is a C-binding and the documentation is not the greatest, nor do the examples explain how to do simple SSL never mind two-way. But after digging around the source, here is one recipe that works:
import pycurl
class Response(object):
""" utility class to collect the response """
def __init__(self):
self.chunks = []
def callback(self, chunk):
self.chunks.append(chunk)
def content(self):
return ''.join(self.chunks)
res = Response()
curl = pycurl.Curl()
curl.setopt(curl.URL, "https://yourservice/path")
curl.setopt(curl.WRITEFUNCTION, res.callback)
curl.setopt(curl.CAINFO, "/path/to/CA.crt")
curl.setopt(curl.SSLCERT, "/path/to/client.pem")
curl.perform()
print res.content()
And that's it. One other option you might use when testing your SSL implementation with curl is the -k flag, which skips host verification of the server. The option to set in pycurl to do the same is:
curl.setopt(curl.SSL_VERIFYHOST, 0)
Hopefully this saved you digging around the pycurl mailing list and source code like I had to.