Merge lp:~jml/lazr.restfulclient/disable-ssl-cert-verification into lp:lazr.restfulclient

Proposed by Jonathan Lange on 2012-06-15
Status: Merged
Merged at revision: 132
Proposed branch: lp:~jml/lazr.restfulclient/disable-ssl-cert-verification
Merge into: lp:lazr.restfulclient
Diff against target: 69 lines (+28/-3)
1 file modified
src/lazr/restfulclient/_browser.py (+28/-3)
To merge this branch: bzr merge lp:~jml/lazr.restfulclient/disable-ssl-cert-verification
Reviewer Review Type Date Requested Status
Benji York (community) code 2012-06-15 Approve on 2012-06-18
Review via email: mp+110503@code.launchpad.net

Description of the Change

The SSL certificates for launchpad.dev and dogfood are invalid, but we still want to test against them. Add an environment variable to disable certificate checking.

<jml> oh right.
<jml> I can't seem to use the API against launchpad.dev
<jml> I get an error about SSL.
<wgrant> Yeah, cert verification will break that.
<jml> httplib2.SSLHandshakeError: [Errno 1] _ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
<jml> wgrant: is there a work around?
<wgrant> I either hack launchpadlib to not verify the cert, or generate a new cert for launchpad.dev and tell it to trust that.
<cjwatson> I often end up hacking httplib2.
<cjwatson> (search for disable_ssl and change False defaults to True)
<cjwatson> I wish there were an environment variable override.
<cjwatson> dogfood has the same problem.
<jml> wgrant, cjwatson: thanks.
<wgrant> jml: In lazr.restfulclient._browser.RestfulHttp.__init__, add disable_ssl_certificate_validation=True to the super call
<jml> wgrant: even better, thanks.
<cjwatson> There are three sites you need to change, IME.
<cjwatson> I always forget the full list.
<cjwatson> Which is why I've started editing httplib2 instead.
<wgrant> Yeah
<wgrant> Trial and error works for me...
<cjwatson> Because not all the call sites are in the same file.
<wgrant> Yep

To post a comment you must log in.
Jonathan Lange (jml) wrote :

New changes factor the code slightly better. I haven't added tests.

Benji York (benji) wrote :

Looks good.

It's too bad that the environment variable isn't discoverable. Maybe we could annotate SSH certificate errors with a message about how to disable validation. Or we could just whitelist the development sites with known-bad certs and the user won't see the errors to start with.

review: Approve (code)
132. By Jonathan Lange on 2012-06-19

Make the env var discoverable.

Benji York (benji) wrote :

The extra info in the exception looks great.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/lazr/restfulclient/_browser.py'
2--- src/lazr/restfulclient/_browser.py 2012-03-25 14:19:29 +0000
3+++ src/lazr/restfulclient/_browser.py 2012-06-19 11:46:20 +0000
4@@ -27,6 +27,7 @@
5 __all__ = [
6 'Browser',
7 'RestfulHttp',
8+ 'ssl_certificate_validation_disabled',
9 ]
10
11 import atexit
12@@ -40,6 +41,7 @@
13 from time import sleep
14 from httplib2 import (
15 Http,
16+ SSLHandshakeError,
17 urlnorm,
18 )
19 import simplejson
20@@ -97,6 +99,17 @@
21 return ",".join((filename, filemd5))
22
23
24+def ssl_certificate_validation_disabled():
25+ """Whether the user has disabled SSL certificate connection.
26+
27+ Some testing servers have broken certificates. Rather than raising an
28+ error, we allow an environment variable,
29+ ``LP_DISABLE_SSL_CERTIFICATE_VALIDATION`` to disable the check.
30+ """
31+ return bool(
32+ os.environ.get('LP_DISABLE_SSL_CERTIFICATE_VALIDATION', False))
33+
34+
35 class RestfulHttp(Http):
36 """An Http subclass with some custom behavior.
37
38@@ -109,7 +122,10 @@
39
40 def __init__(self, authorizer=None, cache=None, timeout=None,
41 proxy_info=None):
42- super(RestfulHttp, self).__init__(cache, timeout, proxy_info)
43+ cert_disabled = ssl_certificate_validation_disabled()
44+ super(RestfulHttp, self).__init__(
45+ cache, timeout, proxy_info,
46+ disable_ssl_certificate_validation=cert_disabled)
47 self.authorizer = authorizer
48 if self.authorizer is not None:
49 self.authorizer.authorizeSession(self)
50@@ -333,8 +349,17 @@
51 if extra_headers is not None:
52 headers.update(extra_headers)
53 # Make the request.
54- response, content = self._request_and_retry(
55- str(url), method=method, body=data, headers=headers)
56+ try:
57+ response, content = self._request_and_retry(
58+ str(url), method=method, body=data, headers=headers)
59+ except SSLHandshakeError, e:
60+ msg = str(e)
61+ if "SSL3_GET_SERVER_CERTIFICATE:certificate verify failed" in msg:
62+ raise SSLHandshakeError(
63+ "%s: perhaps set LP_DISABLE_SSL_CERTIFICATE_VALIDATION if "
64+ "certificate validation failed and you genuinely trust the "
65+ "remote server." % (e,))
66+ raise
67 if response.status == 304:
68 # The resource didn't change.
69 if content == '':

Subscribers

People subscribed via source and target branches