Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Added ability to choose SSL version #109

Closed
wants to merge 4 commits into from

5 participants

David Andrzejewski Ian Cordasco Andrey Petrov Ken Schwencke Kevin Burke
David Andrzejewski

This is the same as a change that I did for the requests project - which
required this urllib3 change - so I thought it might be appropriate to
contribute the change to the upstream library as well.

David Andrzejewski dandrzejewski Added ability to choose SSL protocol version
This is the same as a change that I did for the requests project - which
required this urllib3 change - so I thought it might be appropriate to
contribute the change to the upstream library as well.
5557476
Ian Cordasco

If you're submitting this here, you need to add unit tests so @shazow can sleep comfortably with 100% test coverage.

David Andrzejewski

I will try to, although I'm not sure how I can verify that it's actually using the chosen SSL protocol version.

David Andrzejewski

It looks like there's no easy way to check on that, and there's also no easy way to make Tornado start up and only support certain SSL versions. However, if I force SSLv2, it throws an exception, so I'll submit two new tests: One that forces it to TLSv1 (checks for a 200 response), and one that forces it to SSLv2 (checks for an SSLError exception)

Ian Cordasco

Hm, @shazow might have some insight on writing tests for this.

Andrey Petrov shazow commented on the diff
test/with_dummyserver/test_https.py
@@ -21,9 +22,21 @@ def setUp(self):
def test_simple(self):
r = self._pool.request('GET', '/specific_method',
- fields={'method': 'GET'})
+ fields={'method': 'GET'})
Andrey Petrov Owner
shazow added a note

Please keep indents (and other things) PEP8 style. :)

Whoops didn't catch that. I'll get it corrected!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
urllib3/connectionpool.py
@@ -76,6 +76,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
"""
cert_reqs = None
ca_certs = None
+ ssl_version = ssl.PROTOCOL_SSLv23
Andrey Petrov Owner
shazow added a note

This line will explode if ssl is None (see try/except header up top, not all platforms have Python compiled with SSL).

Andrey Petrov Owner
shazow added a note

Can we pass it in the same way we pass in cert_reqs and ca_certs?

I'm fine with assuming it's SSLv23 if ssl_version is None.

OK. I'll set ssl_version = None up top.

For the constructor, I'm assuming you'd rather I default ssl_version=None and then, in _new_conn(), check if self.ssl_version is None and set it there accordingly? That way, it'll be done after ssl has been checked for and SSLError raised.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Andrey Petrov shazow commented on the diff
urllib3/connectionpool.py
@@ -76,6 +76,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
"""
cert_reqs = None
ca_certs = None
+ ssl_version = None
Andrey Petrov Owner
shazow added a note

Why are we tracking ssl_version separately both in HTTPSConnectionPool and VerifiedHTTPSConnection? Shouldn't it be one or the other?

Doesn't HTTPSConnectionPool, pass it into VerifiedHTTPSConnection?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Andrey Petrov
Owner

Thanks for the fixes! A mention of the new ssl_version param in the docstring for HTTPSConnectionPool, or wherever we end up keeping, it would be great. :)

This was referenced
Andrey Petrov
Owner

Hrm. I'm getting this on OSX using Py27:

........................F..........................................................
======================================================================
FAIL: test_set_ssl_version_to_sslv2 (test.with_dummyserver.test_https.TestHTTPS)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/shazow/projects/urllib3/test/with_dummyserver/test_https.py", line 38, in test_set_ssl_version_to_sslv2
    fields={'method': 'GET'})
AssertionError: SSLError not raised
-------------------- >> begin captured logging << --------------------
urllib3.connectionpool: INFO: Starting new HTTPS connection (1): localhost
urllib3.connectionpool: DEBUG: "GET /specific_method?method=GET HTTP/1.1" 200 0
root: INFO: 200 GET /specific_method?method=GET (127.0.0.1) 0.78ms
--------------------- >> end captured logging << ---------------------
Andrey Petrov shazow commented on the diff
test/with_dummyserver/test_https.py
((6 lines not shown))
self.assertEqual(r.status, 200, r.data)
+ def test_set_ssl_version_to_tlsv1(self):
+ self._pool.ssl_version = ssl.PROTOCOL_TLSv1
+ r = self._pool.request('GET', '/specific_method',
+ fields={'method': 'GET'})
+ self.assertEqual(r.status, 200, r.data)
+
+ def test_set_ssl_version_to_sslv2(self):
+ self._pool.ssl_version = ssl.PROTOCOL_SSLv2
+ with self.assertRaises(SSLError):
Andrey Petrov Owner
shazow added a note

Why should this raise?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Ken Schwencke

@shazow So is this issue taken care of yet? :)

Andrey Petrov
Owner

@Schwanksta It has been merged into master. There might be minor changes before it's published, but it should be usable already.

Ken Schwencke

Awesome, I thought so, but I wasn't sure because the ticket was still open. Thanks @shazow !

Andrey Petrov shazow closed this
Kevin Burke

Might be missing something but I can't find these commits in urllib3 master...

Andrey Petrov
Owner

Bits and pieces are still there I think, but we've had several other ssl-related PRs which probably mutated much of the diff.

I think it's largely urllib3.util.resolve_ssl_version and such now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Oct 19, 2012
  1. David Andrzejewski

    Added ability to choose SSL protocol version

    dandrzejewski authored
    This is the same as a change that I did for the requests project - which
    required this urllib3 change - so I thought it might be appropriate to
    contribute the change to the upstream library as well.
  2. David Andrzejewski
Commits on Oct 20, 2012
  1. David Andrzejewski
Commits on Oct 22, 2012
  1. David Andrzejewski
This page is out of date. Refresh to see the latest.
Showing with 27 additions and 5 deletions.
  1. +14 −1 test/with_dummyserver/test_https.py
  2. +13 −4 urllib3/connectionpool.py
15 test/with_dummyserver/test_https.py
View
@@ -1,4 +1,5 @@
import logging
+import ssl
import sys
import unittest
@@ -21,9 +22,21 @@ def setUp(self):
def test_simple(self):
r = self._pool.request('GET', '/specific_method',
- fields={'method': 'GET'})
+ fields={'method': 'GET'})
Andrey Petrov Owner
shazow added a note

Please keep indents (and other things) PEP8 style. :)

Whoops didn't catch that. I'll get it corrected!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
self.assertEqual(r.status, 200, r.data)
+ def test_set_ssl_version_to_tlsv1(self):
+ self._pool.ssl_version = ssl.PROTOCOL_TLSv1
+ r = self._pool.request('GET', '/specific_method',
+ fields={'method': 'GET'})
+ self.assertEqual(r.status, 200, r.data)
+
+ def test_set_ssl_version_to_sslv2(self):
+ self._pool.ssl_version = ssl.PROTOCOL_SSLv2
+ with self.assertRaises(SSLError):
Andrey Petrov Owner
shazow added a note

Why should this raise?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ r = self._pool.request('GET', '/specific_method',
+ fields={'method': 'GET'})
+
def test_verified(self):
https_pool = HTTPSConnectionPool(self.host, self.port,
cert_reqs='CERT_REQUIRED')
17 urllib3/connectionpool.py
View
@@ -76,6 +76,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
"""
cert_reqs = None
ca_certs = None
+ ssl_version = None
Andrey Petrov Owner
shazow added a note

Why are we tracking ssl_version separately both in HTTPSConnectionPool and VerifiedHTTPSConnection? Shouldn't it be one or the other?

Doesn't HTTPSConnectionPool, pass it into VerifiedHTTPSConnection?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
def set_cert(self, key_file=None, cert_file=None,
cert_reqs='CERT_NONE', ca_certs=None):
@@ -98,7 +99,8 @@ def connect(self):
# trusted_root_certs
self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file,
cert_reqs=self.cert_reqs,
- ca_certs=self.ca_certs)
+ ca_certs=self.ca_certs,
+ ssl_version=self.ssl_version)
if self.ca_certs:
match_hostname(self.sock.getpeercert(), self.host)
@@ -493,8 +495,8 @@ class HTTPSConnectionPool(HTTPConnectionPool):
:class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates,
instead of :class:httplib.HTTPSConnection`.
- The ``key_file``, ``cert_file``, ``cert_reqs``, and ``ca_certs`` parameters
- are only used if :mod:`ssl` is available and are fed into
+ The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``, and ``ssl_version``
+ parameters are only used if :mod:`ssl` is available and are fed into
:meth:`ssl.wrap_socket` to upgrade the connection socket into an SSL socket.
"""
@@ -504,7 +506,7 @@ def __init__(self, host, port=None,
strict=False, timeout=None, maxsize=1,
block=False, headers=None,
key_file=None, cert_file=None,
- cert_reqs='CERT_NONE', ca_certs=None):
+ cert_reqs='CERT_NONE', ca_certs=None, ssl_version=None):
HTTPConnectionPool.__init__(self, host, port,
strict, timeout, maxsize,
@@ -513,6 +515,7 @@ def __init__(self, host, port=None,
self.cert_file = cert_file
self.cert_reqs = cert_reqs
self.ca_certs = ca_certs
+ self.ssl_version = ssl_version
def _new_conn(self):
"""
@@ -532,6 +535,12 @@ def _new_conn(self):
connection = VerifiedHTTPSConnection(host=self.host, port=self.port)
connection.set_cert(key_file=self.key_file, cert_file=self.cert_file,
cert_reqs=self.cert_reqs, ca_certs=self.ca_certs)
+
+ if self.ssl_version is None:
+ connection.ssl_version = ssl.PROTOCOL_SSLv23
+ else:
+ connection.ssl_version = self.ssl_version
+
return connection
Something went wrong with that request. Please try again.