Merge lp:~jml/launchpadlib/ssl-creds into lp:launchpadlib

Proposed by Jonathan Lange
Status: Merged
Merged at revision: 128
Proposed branch: lp:~jml/launchpadlib/ssl-creds
Merge into: lp:launchpadlib
Diff against target: 61 lines (+31/-8)
1 file modified
src/launchpadlib/credentials.py (+31/-8)
To merge this branch: bzr merge lp:~jml/launchpadlib/ssl-creds
Reviewer Review Type Date Requested Status
Benji York (community) code Approve
Review via email: mp+110848@code.launchpad.net

Description of the change

Same thing as https://code.launchpad.net/~jml/lazr.restfulclient/disable-ssl-cert-verification/+merge/110503 but for launchpadlib.

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.
Revision history for this message
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)
Revision history for this message
Jonathan Lange (jml) wrote :

Good point re discoverability. I've annotated the exception.

Revision history for this message
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/launchpadlib/credentials.py'
2--- src/launchpadlib/credentials.py 2011-12-05 18:53:25 +0000
3+++ src/launchpadlib/credentials.py 2012-06-18 15:52:56 +0000
4@@ -61,6 +61,35 @@
5 EXPLOSIVE_ERRORS = (MemoryError, KeyboardInterrupt, SystemExit)
6
7
8+def _ssl_certificate_validation_disabled():
9+ """Whether the user has disabled SSL certificate connection.
10+
11+ Some testing servers have broken certificates. Rather than raising an
12+ error, we allow an environment variable,
13+ ``LP_DISABLE_SSL_CERTIFICATE_VALIDATION`` to disable the check.
14+ """
15+ # XXX: Copied from lazr/restfulclient/_browser.py. Once it appears in a
16+ # released version of lazr.restfulclient, depend on that new version and
17+ # delete this copy.
18+ return bool(
19+ os.environ.get('LP_DISABLE_SSL_CERTIFICATE_VALIDATION', False))
20+
21+
22+def _http_post(url, headers, params):
23+ """POST to ``url`` with ``headers`` and a body of urlencoded ``params``.
24+
25+ Wraps it up to make sure we avoid the SSL certificate validation if our
26+ environment tells us to. Also, raises an error on non-200 statuses.
27+ """
28+ cert_disabled = _ssl_certificate_validation_disabled()
29+ response, content = httplib2.Http(
30+ disable_ssl_certificate_validation=cert_disabled).request(
31+ url, method='POST', headers=headers, body=urlencode(params))
32+ if response.status != 200:
33+ raise HTTPError(response, content)
34+ return response, content
35+
36+
37 class Credentials(OAuthAuthorizer):
38 """Standard credentials storage and usage class.
39
40@@ -131,10 +160,7 @@
41 headers = {'Referer': web_root}
42 if token_format == self.DICT_TOKEN_FORMAT:
43 headers['Accept'] = 'application/json'
44- response, content = httplib2.Http().request(
45- url, method='POST', headers=headers, body=urlencode(params))
46- if response.status != 200:
47- raise HTTPError(response, content)
48+ response, content = _http_post(url, headers, params)
49 if token_format == self.DICT_TOKEN_FORMAT:
50 params = simplejson.loads(content)
51 if context is not None:
52@@ -172,10 +198,7 @@
53 oauth_signature='&%s' % self._request_token.secret)
54 url = web_root + access_token_page
55 headers = {'Referer': web_root}
56- response, content = httplib2.Http().request(
57- url, method='POST', headers=headers, body=urlencode(params))
58- if response.status != 200:
59- raise HTTPError(response, content)
60+ response, content = _http_post(url, headers, params)
61 self.access_token = AccessToken.from_string(content)
62
63

Subscribers

People subscribed via source and target branches