def test_make_request_con_tmout(self): # Test pool._make_request() directly & indirectly - ensure ConnectTimeoutError is raised. block_event = Event() self.set_block_response(block_event) timeout = Timeout(connect=SHORT_TIMEOUT) pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, retries=False) exc = ReadTimeoutError # Until we fix it to be ConnectTimeoutError pos = 0 # Will be 1 once we fix ConnectTimeoutError # Test pool._make_request directly conn = pool._get_conn() self.assertIsNone( conn.sock) # Ensure we didn't get an existing connection with self.assertRaises(exc) as cmgr: pool._make_request(conn, 'GET', '/') self.assertEqual(cmgr.exception.args[pos].split()[-1], 'timeout=%s)' % timeout.connect_timeout) block_event.set() # Test pool._make_request indirectly (through pool.request) with self.assertRaises(exc) as cmgr: pool.request('GET', '/') self.assertEqual(cmgr.exception.args[pos].split()[-1], 'timeout=%s)' % timeout.connect_timeout) block_event.set()
def test_make_request_read_tmout(self): # Test pool._make_request() directly & indirectly - ensure ReadTimeoutError is raised. block_event = Event() self.set_block_response(block_event) timeout = Timeout(read=SHORT_TIMEOUT, connect=2) # Ensure connect with a very long timeout pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, retries=False) # Test pool._make_request directly conn = pool._get_conn() self.assertIsNone( conn.sock) # Ensure we didn't get an existing connection with self.assertRaises(ReadTimeoutError) as cmgr: pool._make_request(conn, 'GET', '/') self.assertEqual(cmgr.exception.args[0].split()[-1], 'timeout=%s)' % timeout.read_timeout) block_event.set() # Test pool._make_request indirectly (through pool.request) with self.assertRaises(ReadTimeoutError) as cmgr: pool.request('GET', '/', timeout=timeout) self.assertEqual(cmgr.exception.args[0].split()[-1], 'timeout=%s)' % timeout.read_timeout) block_event.set()
def test_enhanced_ssl_connection(self): conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool( self.host, self.port, timeout=Timeout(total=None, connect=5), cert_reqs="CERT_REQUIRED" ) https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = "CC:45:6A:90:82:F7FF:C0:8218:8e:" "7A:F2:8A:D7:1E:07:33:67:DE" https_pool._make_request(conn, "GET", "/")
def test_enhanced_ssl_connection(self): conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=Timeout(total=None, connect=5), cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool._make_request(conn, 'GET', '/')
def test_enhanced_ssl_connection(self): fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:BF:93:CF:F9:71:CC:07:7D:0A' conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA, assert_fingerprint=fingerprint) https_pool._make_request(conn, 'GET', '/')
def test_enhanced_ssl_connection(self): fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:7A:F2:8A:D7:1E:07:33:67:DE' conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA, assert_fingerprint=fingerprint) https_pool._make_request(conn, 'GET', '/')
def test_reuse_conn(self): # Test pool.request() connection reusal: # 1. Create a new connection. # 2. Perform a request which will succeed. # 3. Reuse the connection - delay the response with original pool settings. # 4. Reuse same connection for a successful read request with delay in response. # 5. Reuse same connection for a timeout read request. # Create the connection pool with default timeouts long enough to connect and read. self.set_block_response(None) timeout = Timeout(connect=1., read=4) headers = make_headers(keep_alive=True) pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, headers=headers, retries=False) # First request - direct with pool._make_request() with delay=conn_timeout+read_timeout-0.5 delay = timeout.connect_timeout + timeout.read_timeout - 0.5 self.set_block_response(delay) conn = pool._get_conn() self.assertIsNone(conn.sock) pool._make_request(conn, 'GET', '/') self.set_block_response(None) # Make a request - it must succeed pool.request('GET', '/') # Reuse the connection - successful read request with delayed response. # * Ensure that new connection is not created by using a short connect timeout with # pool._make_request. # * Use a read timeout which will be larger than the pool's connect timeout but shorter # than the pool's read timeout timeout = Timeout(connect=SHORT_TIMEOUT, read=2.5) delay = 1.1 # Check that the timeouts are as intended self.assertLess(timeout.connect_timeout, pool.timeout.connect_timeout) self.assertLess(pool.timeout.connect_timeout, delay) self.assertLess(delay, timeout.read_timeout) self.assertLess(timeout.read_timeout, pool.timeout.read_timeout) # Make the request self.set_block_response(delay) pool.request('GET', '/', timeout=timeout) # Reuse the connection - timeout read request delay = timeout.read_timeout + 1 self.set_block_response(delay) now = time.time() with self.assertRaises(ReadTimeoutError) as cmgr: pool.request('GET', '/', timeout=timeout) delta = time.time() - now self.assertEqual(cmgr.exception.args[0].split()[-1], 'timeout=%s)' % timeout.read_timeout) self.assertAlmostEqual(delta, timeout.read_timeout, places=1) print('delta={}'.format(delta))
def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') self.addCleanup(https_pool.close) conn = https_pool._new_conn() self.addCleanup(conn.close) conn.set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with()
def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs="CERT_NONE") conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, "GET", "/") conn._tunnel.assert_called_once_with()
def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with()
def test_enhanced_timeout(self): import urllib3.connectionpool OriginalHTTPSConnection = urllib3.connectionpool.HTTPSConnection OriginalSSL = urllib3.connectionpool.ssl urllib3.connectionpool.ssl = None timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') conn = https_pool._new_conn() self.assertEqual(conn.__class__, HTTPSConnection) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') timeout = Timeout(connect=5) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() try: https_pool._make_request(conn, 'GET', '/') except AttributeError: # wrap_socket unavailable when you mock out ssl pass conn._tunnel.assert_called_once_with() # Undo urllib3.HTTPSConnection = OriginalHTTPSConnection urllib3.connectionpool.ssl = OriginalSSL
def test_https_connect_timeout(self): url = '/' host, port = self.host, self.port timeout = Timeout(connect=SHORT_TIMEOUT) # Pool-global timeout pool = HTTPSConnectionPool(host, port, timeout=timeout) conn = pool._get_conn() exc = ReadTimeoutError # Until we fix it to be ConnectTimeoutError pos = 0 # Will be 1 once we fix ConnectTimeoutError with self.assertRaises(exc) as cmgr: pool._make_request(conn, 'GET', url) self.assertEqual(cmgr.exception.args[pos].split()[-1], 'timeout=%s)' % timeout.connect_timeout) # Retries retries = Retry(connect=0) self.assertRaises(MaxRetryError, pool.request, 'GET', url, retries=retries, timeout=timeout) # Request-specific connection timeouts timeout2 = Timeout(read=LONG_TIMEOUT, connect=SHORT_TIMEOUT / 100) pool = HTTPSConnectionPool(host, port, timeout=timeout2, retries=False) conn = pool._get_conn() with self.assertRaises(exc) as cmgr: pool._make_request(conn, 'GET', url, timeout=timeout2) self.assertEqual(cmgr.exception.args[pos].split()[-1], 'timeout=%s)' % timeout2.connect_timeout) pool._put_conn(conn) timeout = Timeout(connect=SHORT_TIMEOUT) with self.assertRaises(exc) as cmgr: pool.request('GET', url, timeout=timeout) self.assertEqual(cmgr.exception.args[pos].split()[-1], 'timeout=%s)' % timeout.connect_timeout)
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) def test_simple(self): r = self._pool.request('GET', '/') 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', '/') self.assertEqual(r.status, 200, r.data) def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool.ca_certs = DEFAULT_CA_BAD try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with wrong CA") except SSLError as e: self.assertTrue('certificate verify failed' in str(e), "Expected 'certificate verify failed'," "instead got: %r" % e) https_pool.ca_certs = DEFAULT_CA https_pool.request('GET', '/') # Should succeed without exceptions. https_fail_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_fail_pool.ca_certs = DEFAULT_CA try: https_fail_pool.request('GET', '/') self.fail("Didn't raise SSL invalid common name") except SSLError as e: self.assertTrue("doesn't match" in str(e)) def test_no_ssl(self): OriginalConnectionCls = self._pool.ConnectionCls try: self._pool.ConnectionCls = None self.assertRaises(SSLError, self._pool._new_conn) self.assertRaises(SSLError, self._pool.request, 'GET', '/') finally: self._pool.ConnectionCls = OriginalConnectionCls def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ try: OriginalConnectionCls = self._pool.ConnectionCls self._pool.ConnectionCls = UnverifiedHTTPSConnection self._pool.request('GET', '/') finally: self._pool.ConnectionCls = OriginalConnectionCls def test_cert_reqs_as_constant(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs=ssl.CERT_REQUIRED) https_pool.ca_certs = DEFAULT_CA_BAD # if we pass in an invalid value it defaults to CERT_NONE self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_cert_reqs_as_short_string(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='REQUIRED') https_pool.ca_certs = DEFAULT_CA_BAD # if we pass in an invalid value it defaults to CERT_NONE self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_ssl_unverified_with_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE') https_pool.ca_certs = DEFAULT_CA_BAD https_pool.request('GET', '/') @requires_network def test_ssl_verified_with_platform_ca_certs(self): """ This test check that whe rely on platform CA file to validate authenticity of SSL certificate. Since this file is used by many components of the OS, such as curl, apt-get, etc., we decided to not touch it, in order to not compromise the security of the OS running the test suite (typically urllib3 developer's OS). This test assume that httpbin.org use a certificate signed by a well known Certificate Authority. """ try: import urllib3.contrib.pyopenssl except ImportError: raise SkipTest('This test needs pyopenssl support') if (urllib3.connection.ssl_wrap_socket is urllib3.contrib.pyopenssl.orig_connection_ssl_wrap_socket): # Not patched raise SkipTest('This test needs pyopenssl support') https_pool = HTTPSConnectionPool('httpbin.org', 443, cert_reqs=ssl.CERT_REQUIRED) https_pool.request('HEAD', '/') def test_verified_without_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_invalid_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') # Empty string won't throw on py2 https_pool.ca_certs = '/no_valid_path_to_ca_certs' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_hostname = False https_pool.request('GET', '/') def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_hostname = 'localhost' https_pool.request('GET', '/') def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CA:84:E1:AD0E5a:ef:2f:C3:09' \ ':E7:30:F8:CD:C8:5B' https_pool.request('GET', '/') def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool.request('GET', '/') def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') # invalid length https_pool.assert_fingerprint = 'AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') # uneven length https_pool.assert_fingerprint = 'AA:A' self.assertRaises(SSLError, https_pool.request, 'GET', '/') @requires_network def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' url = '/sleep?seconds=0.005' self.assertRaises(ReadTimeoutError, https_pool.request, 'GET', url) timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') https_pool.request('GET', '/') def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with() def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, 'GET', '/') @requires_network def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs='CERT_REQUIRED'): https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs=cert_reqs) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) def test_enhanced_ssl_connection(self): conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=Timeout(total=None, connect=5), cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool._make_request(conn, 'GET', '/')
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) self.addCleanup(self._pool.close) def test_simple(self): r = self._pool.request('GET', '/') 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', '/') self.assertEqual(r.status, 200, r.data) def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) # Modern versions of Python, or systems using PyOpenSSL, don't # emit warnings. if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL: self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) if util.HAS_SNI: call = warn.call_args_list[0] else: call = warn.call_args_list[1] error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) def test_verified_with_context(self): ctx = util.ssl_.create_urllib3_context(cert_reqs=ssl.CERT_REQUIRED) ctx.load_verify_locations(cafile=DEFAULT_CA) https_pool = HTTPSConnectionPool(self.host, self.port, ssl_context=ctx) self.addCleanup(https_pool.close) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) # Modern versions of Python, or systems using PyOpenSSL, don't # emit warnings. if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL: self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) if util.HAS_SNI: call = warn.call_args_list[0] else: call = warn.call_args_list[1] error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) def test_context_combines_with_ca_certs(self): ctx = util.ssl_.create_urllib3_context(cert_reqs=ssl.CERT_REQUIRED) https_pool = HTTPSConnectionPool(self.host, self.port, ca_certs=DEFAULT_CA, ssl_context=ctx) self.addCleanup(https_pool.close) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) # Modern versions of Python, or systems using PyOpenSSL, don't # emit warnings. if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL: self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) if util.HAS_SNI: call = warn.call_args_list[0] else: call = warn.call_args_list[1] error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) @onlyPy279OrNewer def test_ca_dir_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_cert_dir=DEFAULT_CA_DIR) self.addCleanup(https_pool.close) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) if sys.version_info >= (2, 7, 9): self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) call, = warn.call_args_list error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) def test_invalid_common_name(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL invalid common name") except SSLError as e: self.assertTrue("doesn't match" in str(e)) def test_verified_with_bad_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA_BAD) self.addCleanup(https_pool.close) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with bad CA certs") except SSLError as e: self.assertTrue('certificate verify failed' in str(e), "Expected 'certificate verify failed'," "instead got: %r" % e) def test_verified_without_ca_certs(self): # default is cert_reqs=None which is ssl.CERT_NONE https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') self.addCleanup(https_pool.close) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with no CA certs when" "CERT_REQUIRED is set") except SSLError as e: # there is a different error message depending on whether or # not pyopenssl is injected self.assertTrue('No root certificates specified' in str(e) or 'certificate verify failed' in str(e), "Expected 'No root certificates specified' or " "'certificate verify failed', " "instead got: %r" % e) def test_no_ssl(self): pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = None self.addCleanup(pool.close) self.assertRaises(SSLError, pool._new_conn) self.assertRaises(SSLError, pool.request, 'GET', '/') def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = UnverifiedHTTPSConnection self.addCleanup(pool.close) with mock.patch('warnings.warn') as warn: r = pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertTrue(warn.called) # Modern versions of Python, or systems using PyOpenSSL, only emit # the unverified warning. Older systems may also emit other # warnings, which we want to ignore here. calls = warn.call_args_list if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL: category = calls[0][0][1] elif util.HAS_SNI: category = calls[1][0][1] else: category = calls[2][0][1] self.assertEqual(category, InsecureRequestWarning) def test_ssl_unverified_with_ca_certs(self): pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) self.addCleanup(pool.close) with mock.patch('warnings.warn') as warn: r = pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertTrue(warn.called) # Modern versions of Python, or systems using PyOpenSSL, only emit # the unverified warning. Older systems may also emit other # warnings, which we want to ignore here. calls = warn.call_args_list if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL: category = calls[0][0][1] elif util.HAS_SNI: category = calls[1][0][1] else: category = calls[2][0][1] self.assertEqual(category, InsecureRequestWarning) def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_hostname = False https_pool.request('GET', '/') def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_hostname = 'localhost' https_pool.request('GET', '/') def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = 'F2:06:5A:42:10:3F:45:1C:17:FE:E6:' \ '07:1E:8A:86:E5' https_pool.request('GET', '/') def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' https_pool.request('GET', '/') def test_assert_fingerprint_sha256(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = ('C5:4D:0B:83:84:89:2E:AE:B4:58:BB:12:' 'F7:A6:C4:76:05:03:88:D8:57:65:51:F3:' '1E:60:B0:8B:70:18:64:E6') https_pool.request('GET', '/') def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool._get_conn() # Uneven length https_pool.assert_fingerprint = 'AA:A' self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool._get_conn() # Invalid length https_pool.assert_fingerprint = 'AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_verify_none_and_bad_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_verify_none_and_good_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' https_pool.request('GET', '/') def test_good_fingerprint_and_hostname_mismatch(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' https_pool.request('GET', '/') @requires_network def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') self.addCleanup(https_pool.close) timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') self.addCleanup(https_pool.close) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') self.addCleanup(https_pool.close) https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') self.addCleanup(https_pool.close) https_pool.request('GET', '/') def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') self.addCleanup(https_pool.close) conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with() @onlyPy26OrOlder def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, 'GET', '/') @requires_network def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs='CERT_REQUIRED'): https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs=cert_reqs) self.addCleanup(https_pool.close) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) def test_enhanced_ssl_connection(self): fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:BF:93:CF:F9:71:CC:07:7D:0A' conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA, assert_fingerprint=fingerprint) self.addCleanup(https_pool.close) https_pool._make_request(conn, 'GET', '/') def test_ssl_correct_system_time(self): self._pool.cert_reqs = 'CERT_REQUIRED' self._pool.ca_certs = DEFAULT_CA w = self._request_without_resource_warnings('GET', '/') self.assertEqual([], w) def test_ssl_wrong_system_time(self): self._pool.cert_reqs = 'CERT_REQUIRED' self._pool.ca_certs = DEFAULT_CA with mock.patch('urllib3.connection.datetime') as mock_date: mock_date.date.today.return_value = datetime.date(1970, 1, 1) w = self._request_without_resource_warnings('GET', '/') self.assertEqual(len(w), 1) warning = w[0] self.assertEqual(SystemTimeWarning, warning.category) self.assertTrue(str(RECENT_DATE) in warning.message.args[0]) def _request_without_resource_warnings(self, method, url): with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') self._pool.request(method, url) return [x for x in w if not isinstance(x.message, ResourceWarning)]
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) def test_simple(self): r = self._pool.request('GET', '/') 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', '/') self.assertEqual(r.status, 200, r.data) def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertFalse(warn.called, warn.call_args_list) def test_invalid_common_name(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL invalid common name") except SSLError as e: self.assertTrue("doesn't match" in str(e)) def test_verified_with_bad_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA_BAD) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with bad CA certs") except SSLError as e: self.assertTrue('certificate verify failed' in str(e), "Expected 'certificate verify failed'," "instead got: %r" % e) def test_verified_without_ca_certs(self): # default is cert_reqs=None which is ssl.CERT_NONE https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with no CA certs when" "CERT_REQUIRED is set") except SSLError as e: # there is a different error message depending on whether or # not pyopenssl is injected self.assertTrue('No root certificates specified' in str(e) or 'certificate verify failed' in str(e), "Expected 'No root certificates specified' or " "'certificate verify failed', " "instead got: %r" % e) def test_no_ssl(self): pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = None self.assertRaises(SSLError, pool._new_conn) self.assertRaises(SSLError, pool.request, 'GET', '/') def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = UnverifiedHTTPSConnection with mock.patch('warnings.warn') as warn: r = pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertTrue(warn.called) call, = warn.call_args_list category = call[0][1] self.assertEqual(category, InsecureRequestWarning) def test_ssl_unverified_with_ca_certs(self): pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) with mock.patch('warnings.warn') as warn: r = pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertTrue(warn.called) call, = warn.call_args_list category = call[0][1] self.assertEqual(category, InsecureRequestWarning) @requires_network def test_ssl_verified_with_platform_ca_certs(self): """ We should rely on the platform CA file to validate authenticity of SSL certificates. Since this file is used by many components of the OS, such as curl, apt-get, etc., we decided to not touch it, in order to not compromise the security of the OS running the test suite (typically urllib3 developer's OS). This test assumes that httpbin.org uses a certificate signed by a well known Certificate Authority. """ try: import urllib3.contrib.pyopenssl except ImportError: raise SkipTest('Test requires PyOpenSSL') if (urllib3.connection.ssl_wrap_socket is urllib3.contrib.pyopenssl.orig_connection_ssl_wrap_socket): # Not patched raise SkipTest('Test should only be run after PyOpenSSL ' 'monkey patching') https_pool = HTTPSConnectionPool('httpbin.org', 443, cert_reqs=ssl.CERT_REQUIRED) https_pool.request('HEAD', '/') def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_hostname = False https_pool.request('GET', '/') def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_hostname = 'localhost' https_pool.request('GET', '/') def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = 'CA:84:E1:AD0E5a:ef:2f:C3:09' \ ':E7:30:F8:CD:C8:5B' https_pool.request('GET', '/') def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool.request('GET', '/') def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool._get_conn() # Uneven length https_pool.assert_fingerprint = 'AA:A' self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool._get_conn() # Invalid length https_pool.assert_fingerprint = 'AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_verify_none_and_bad_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_verify_none_and_good_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool.request('GET', '/') @requires_network def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' url = '/sleep?seconds=0.005' self.assertRaises(ReadTimeoutError, https_pool.request, 'GET', url) timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') https_pool.request('GET', '/') def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with() @onlyPy26OrOlder def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, 'GET', '/') @requires_network def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs='CERT_REQUIRED'): https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs=cert_reqs) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) def test_enhanced_ssl_connection(self): fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:7A:F2:8A:D7:1E:07:33:67:DE' conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA, assert_fingerprint=fingerprint) https_pool._make_request(conn, 'GET', '/') def test_ssl_correct_system_time(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') self._pool.request('GET', '/') self.assertEqual([], w) def test_ssl_wrong_system_time(self): with mock.patch('urllib3.connection.datetime') as mock_date: mock_date.date.today.return_value = datetime.date(1970, 1, 1) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') self._pool.request('GET', '/') self.assertEqual(len(w), 1) warning = w[0] self.assertEqual(SystemTimeWarning, warning.category) self.assertTrue(str(RECENT_DATE) in warning.message.args[0])
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) def test_simple(self): r = self._pool.request('GET', '/') 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', '/') self.assertEqual(r.status, 200, r.data) def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool.ca_certs = DEFAULT_CA_BAD try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with wrong CA") except SSLError as e: self.assertTrue( 'certificate verify failed' in str(e), "Expected 'certificate verify failed'," "instead got: %r" % e) https_pool.ca_certs = DEFAULT_CA https_pool.request('GET', '/') # Should succeed without exceptions. https_fail_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_fail_pool.ca_certs = DEFAULT_CA try: https_fail_pool.request('GET', '/') self.fail("Didn't raise SSL invalid common name") except SSLError as e: self.assertTrue("doesn't match" in str(e)) def test_no_ssl(self): OriginalConnectionCls = self._pool.ConnectionCls try: self._pool.ConnectionCls = None self.assertRaises(SSLError, self._pool._new_conn) self.assertRaises(SSLError, self._pool.request, 'GET', '/') finally: self._pool.ConnectionCls = OriginalConnectionCls def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ try: OriginalConnectionCls = self._pool.ConnectionCls self._pool.ConnectionCls = UnverifiedHTTPSConnection self._pool.request('GET', '/') finally: self._pool.ConnectionCls = OriginalConnectionCls def test_cert_reqs_as_constant(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs=ssl.CERT_REQUIRED) https_pool.ca_certs = DEFAULT_CA_BAD # if we pass in an invalid value it defaults to CERT_NONE self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_cert_reqs_as_short_string(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='REQUIRED') https_pool.ca_certs = DEFAULT_CA_BAD # if we pass in an invalid value it defaults to CERT_NONE self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_ssl_unverified_with_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE') https_pool.ca_certs = DEFAULT_CA_BAD https_pool.request('GET', '/') @requires_network def test_ssl_verified_with_platform_ca_certs(self): """ We should rely on the platform CA file to validate authenticity of SSL certificates. Since this file is used by many components of the OS, such as curl, apt-get, etc., we decided to not touch it, in order to not compromise the security of the OS running the test suite (typically urllib3 developer's OS). This test assumes that httpbin.org uses a certificate signed by a well known Certificate Authority. """ try: import urllib3.contrib.pyopenssl except ImportError: raise SkipTest('This test needs pyopenssl support') if (urllib3.connection.ssl_wrap_socket is urllib3.contrib.pyopenssl.orig_connection_ssl_wrap_socket): # Not patched raise SkipTest('This test should only be run after pyopenssl ' 'monkey patching') https_pool = HTTPSConnectionPool('httpbin.org', 443, cert_reqs=ssl.CERT_REQUIRED) https_pool.request('HEAD', '/') def test_verified_without_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_invalid_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') # Empty string won't throw on py2 https_pool.ca_certs = '/no_valid_path_to_ca_certs' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_hostname = False https_pool.request('GET', '/') def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_hostname = 'localhost' https_pool.request('GET', '/') def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CA:84:E1:AD0E5a:ef:2f:C3:09' \ ':E7:30:F8:CD:C8:5B' https_pool.request('GET', '/') def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool.request('GET', '/') def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') # invalid length https_pool.assert_fingerprint = 'AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') # uneven length https_pool.assert_fingerprint = 'AA:A' self.assertRaises(SSLError, https_pool.request, 'GET', '/') @requires_network def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' url = '/sleep?seconds=0.005' self.assertRaises(ReadTimeoutError, https_pool.request, 'GET', url) timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') https_pool.request('GET', '/') def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with() def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, 'GET', '/') @requires_network def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs='CERT_REQUIRED'): https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs=cert_reqs) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) def test_enhanced_ssl_connection(self): conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=Timeout(total=None, connect=5), cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool._make_request(conn, 'GET', '/') @onlyPy26OrOlder def test_source_address_ignored(self): # source_address is ignored in Python 2.6 and earlier. for addr in INVALID_SOURCE_ADDRESSES: https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', source_address=addr) https_pool.ca_certs = DEFAULT_CA r = https_pool.request('GET', '/source_address') assert r.status == 200 @onlyPy27OrNewer def test_source_address(self): for addr in VALID_SOURCE_ADDRESSES: https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', source_address=addr) https_pool.ca_certs = DEFAULT_CA r = https_pool.request('GET', '/source_address') assert r.data == b(addr[0]) @onlyPy27OrNewer def test_source_address_error(self): for addr in INVALID_SOURCE_ADDRESSES: https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', source_address=addr) https_pool.ca_certs = DEFAULT_CA self.assertRaises(MaxRetryError, https_pool.request, 'GET', '/source_address')
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) def test_simple(self): r = self._pool.request('GET', '/') 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', '/') self.assertEqual(r.status, 200, r.data) def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool.ca_certs = DEFAULT_CA_BAD try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with wrong CA") except SSLError as e: self.assertTrue('certificate verify failed' in str(e), "Expected 'certificate verify failed'," "instead got: %r" % e) https_pool.ca_certs = DEFAULT_CA https_pool.request('GET', '/') # Should succeed without exceptions. https_fail_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_fail_pool.ca_certs = DEFAULT_CA try: https_fail_pool.request('GET', '/') self.fail("Didn't raise SSL invalid common name") except SSLError as e: self.assertTrue("doesn't match" in str(e)) def test_no_ssl(self): OriginalConnectionCls = self._pool.ConnectionCls try: self._pool.ConnectionCls = None self.assertRaises(SSLError, self._pool._new_conn) self.assertRaises(SSLError, self._pool.request, 'GET', '/') finally: self._pool.ConnectionCls = OriginalConnectionCls def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ try: OriginalConnectionCls = self._pool.ConnectionCls self._pool.ConnectionCls = UnverifiedHTTPSConnection self._pool.request('GET', '/') finally: self._pool.ConnectionCls = OriginalConnectionCls def test_cert_reqs_as_constant(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs=ssl.CERT_REQUIRED) https_pool.ca_certs = DEFAULT_CA_BAD # if we pass in an invalid value it defaults to CERT_NONE self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_cert_reqs_as_short_string(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='REQUIRED') https_pool.ca_certs = DEFAULT_CA_BAD # if we pass in an invalid value it defaults to CERT_NONE self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_ssl_unverified_with_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE') https_pool.ca_certs = DEFAULT_CA_BAD https_pool.request('GET', '/') def test_verified_without_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_invalid_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') # Empty string won't throw on py2 https_pool.ca_certs = '/no_valid_path_to_ca_certs' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_hostname = False https_pool.request('GET', '/') def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_hostname = 'localhost' https_pool.request('GET', '/') def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CA:84:E1:AD0E5a:ef:2f:C3:09' \ ':E7:30:F8:CD:C8:5B' https_pool.request('GET', '/') def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool.request('GET', '/') def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') # invalid length https_pool.assert_fingerprint = 'AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') # uneven length https_pool.assert_fingerprint = 'AA:A' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' url = '/sleep?seconds=0.005' self.assertRaises(ReadTimeoutError, https_pool.request, 'GET', url) timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') https_pool.request('GET', '/') def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with() def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, 'GET', '/') def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs='CERT_REQUIRED'): https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs=cert_reqs) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) def test_enhanced_ssl_connection(self): conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=Timeout(total=None, connect=5), cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool._make_request(conn, 'GET', '/')
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) def test_simple(self): r = self._pool.request('GET', '/') 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', '/') self.assertEqual(r.status, 200, r.data) def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) # Modern versions of Python, or systems using PyOpenSSL, don't # emit warnings. if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL: self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) if util.HAS_SNI: call = warn.call_args_list[0] else: call = warn.call_args_list[1] error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) def test_verified_with_context(self): ctx = util.ssl_.create_urllib3_context(cert_reqs=ssl.CERT_REQUIRED) ctx.load_verify_locations(cafile=DEFAULT_CA) https_pool = HTTPSConnectionPool(self.host, self.port, ssl_context=ctx) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) # Modern versions of Python, or systems using PyOpenSSL, don't # emit warnings. if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL: self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) if util.HAS_SNI: call = warn.call_args_list[0] else: call = warn.call_args_list[1] error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) def test_context_combines_with_ca_certs(self): ctx = util.ssl_.create_urllib3_context(cert_reqs=ssl.CERT_REQUIRED) https_pool = HTTPSConnectionPool(self.host, self.port, ca_certs=DEFAULT_CA, ssl_context=ctx) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) # Modern versions of Python, or systems using PyOpenSSL, don't # emit warnings. if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL: self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) if util.HAS_SNI: call = warn.call_args_list[0] else: call = warn.call_args_list[1] error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) @onlyPy279OrNewer def test_ca_dir_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_cert_dir=DEFAULT_CA_DIR) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) if sys.version_info >= (2, 7, 9): self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) call, = warn.call_args_list error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) def test_invalid_common_name(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL invalid common name") except SSLError as e: self.assertTrue("doesn't match" in str(e)) def test_verified_with_bad_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA_BAD) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with bad CA certs") except SSLError as e: self.assertTrue('certificate verify failed' in str(e), "Expected 'certificate verify failed'," "instead got: %r" % e) def test_verified_without_ca_certs(self): # default is cert_reqs=None which is ssl.CERT_NONE https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with no CA certs when" "CERT_REQUIRED is set") except SSLError as e: # there is a different error message depending on whether or # not pyopenssl is injected self.assertTrue('No root certificates specified' in str(e) or 'certificate verify failed' in str(e), "Expected 'No root certificates specified' or " "'certificate verify failed', " "instead got: %r" % e) def test_no_ssl(self): pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = None self.assertRaises(SSLError, pool._new_conn) self.assertRaises(SSLError, pool.request, 'GET', '/') def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = UnverifiedHTTPSConnection with mock.patch('warnings.warn') as warn: r = pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertTrue(warn.called) # Modern versions of Python, or systems using PyOpenSSL, only emit # the unverified warning. Older systems may also emit other # warnings, which we want to ignore here. calls = warn.call_args_list if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL: category = calls[0][0][1] elif util.HAS_SNI: category = calls[1][0][1] else: category = calls[2][0][1] self.assertEqual(category, InsecureRequestWarning) def test_ssl_unverified_with_ca_certs(self): pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) with mock.patch('warnings.warn') as warn: r = pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertTrue(warn.called) # Modern versions of Python, or systems using PyOpenSSL, only emit # the unverified warning. Older systems may also emit other # warnings, which we want to ignore here. calls = warn.call_args_list if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL: category = calls[0][0][1] elif util.HAS_SNI: category = calls[1][0][1] else: category = calls[2][0][1] self.assertEqual(category, InsecureRequestWarning) def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_hostname = False https_pool.request('GET', '/') def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_hostname = 'localhost' https_pool.request('GET', '/') def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = 'F2:06:5A:42:10:3F:45:1C:17:FE:E6:' \ '07:1E:8A:86:E5' https_pool.request('GET', '/') def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' https_pool.request('GET', '/') def test_assert_fingerprint_sha256(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = ('C5:4D:0B:83:84:89:2E:AE:B4:58:BB:12:' 'F7:A6:C4:76:05:03:88:D8:57:65:51:F3:' '1E:60:B0:8B:70:18:64:E6') https_pool.request('GET', '/') def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool._get_conn() # Uneven length https_pool.assert_fingerprint = 'AA:A' self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool._get_conn() # Invalid length https_pool.assert_fingerprint = 'AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_verify_none_and_bad_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_verify_none_and_good_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' https_pool.request('GET', '/') def test_good_fingerprint_and_hostname_mismatch(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' https_pool.request('GET', '/') @requires_network def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') https_pool.request('GET', '/') def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with() @onlyPy26OrOlder def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, 'GET', '/') @requires_network def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs='CERT_REQUIRED'): https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs=cert_reqs) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) def test_enhanced_ssl_connection(self): fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:BF:93:CF:F9:71:CC:07:7D:0A' conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA, assert_fingerprint=fingerprint) https_pool._make_request(conn, 'GET', '/') def test_ssl_correct_system_time(self): self._pool.cert_reqs = 'CERT_REQUIRED' self._pool.ca_certs = DEFAULT_CA w = self._request_without_resource_warnings('GET', '/') self.assertEqual([], w) def test_ssl_wrong_system_time(self): self._pool.cert_reqs = 'CERT_REQUIRED' self._pool.ca_certs = DEFAULT_CA with mock.patch('urllib3.connection.datetime') as mock_date: mock_date.date.today.return_value = datetime.date(1970, 1, 1) w = self._request_without_resource_warnings('GET', '/') self.assertEqual(len(w), 1) warning = w[0] self.assertEqual(SystemTimeWarning, warning.category) self.assertTrue(str(RECENT_DATE) in warning.message.args[0]) def _request_without_resource_warnings(self, method, url): with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') self._pool.request(method, url) return [x for x in w if not isinstance(x.message, ResourceWarning)]
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) def test_simple(self): r = self._pool.request('GET', '/') 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', '/') self.assertEqual(r.status, 200, r.data) def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool.ca_certs = DEFAULT_CA_BAD try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with wrong CA") except SSLError as e: self.assertTrue('certificate verify failed' in str(e), "Expected 'certificate verify failed'," "instead got: %r" % e) https_pool.ca_certs = DEFAULT_CA https_pool.request('GET', '/') # Should succeed without exceptions. https_fail_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_fail_pool.ca_certs = DEFAULT_CA try: https_fail_pool.request('GET', '/') self.fail("Didn't raise SSL invalid common name") except SSLError as e: self.assertTrue("doesn't match" in str(e)) def test_no_ssl(self): OriginalConnectionCls = self._pool.ConnectionCls self._pool.ConnectionCls = None self.assertRaises(SSLError, self._pool._new_conn) self.assertRaises(SSLError, self._pool.request, 'GET', '/') # Undo self._pool.ConnectionCls = OriginalConnectionCls def test_cert_reqs_as_constant(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs=ssl.CERT_REQUIRED) https_pool.ca_certs = DEFAULT_CA_BAD # if we pass in an invalid value it defaults to CERT_NONE self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_cert_reqs_as_short_string(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='REQUIRED') https_pool.ca_certs = DEFAULT_CA_BAD # if we pass in an invalid value it defaults to CERT_NONE self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_ssl_unverified_with_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE') https_pool.ca_certs = DEFAULT_CA_BAD https_pool.request('GET', '/') def test_verified_without_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_invalid_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') # Empty string won't throw on py2 https_pool.ca_certs = '/no_valid_path_to_ca_certs' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_hostname = False https_pool.request('GET', '/') def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_hostname = 'localhost' https_pool.request('GET', '/') def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CA:84:E1:AD0E5a:ef:2f:C3:09' \ ':E7:30:F8:CD:C8:5B' https_pool.request('GET', '/') def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool.request('GET', '/') def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') # invalid length https_pool.assert_fingerprint = 'AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') # uneven length https_pool.assert_fingerprint = 'AA:A' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' url = '/sleep?seconds=0.005' self.assertRaises(ReadTimeoutError, https_pool.request, 'GET', url) timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') https_pool.request('GET', '/') def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with() def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, 'GET', '/') def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs='CERT_REQUIRED'): https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs=cert_reqs) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) def test_enhanced_ssl_connection(self): conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=Timeout(total=None, connect=5), cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool._make_request(conn, 'GET', '/')
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) def test_simple(self): r = self._pool.request('GET', '/') 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', '/') self.assertEqual(r.status, 200, r.data) def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertFalse(warn.called, warn.call_args_list) def test_invalid_common_name(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL invalid common name") except SSLError as e: self.assertTrue("doesn't match" in str(e)) def test_verified_with_bad_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA_BAD) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with bad CA certs") except SSLError as e: self.assertTrue( 'certificate verify failed' in str(e), "Expected 'certificate verify failed'," "instead got: %r" % e) def test_verified_without_ca_certs(self): # default is cert_reqs=None which is ssl.CERT_NONE https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with no CA certs when" "CERT_REQUIRED is set") except SSLError as e: # there is a different error message depending on whether or # not pyopenssl is injected self.assertTrue( 'No root certificates specified' in str(e) or 'certificate verify failed' in str(e), "Expected 'No root certificates specified' or " "'certificate verify failed', " "instead got: %r" % e) def test_no_ssl(self): pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = None self.assertRaises(SSLError, pool._new_conn) self.assertRaises(SSLError, pool.request, 'GET', '/') def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = UnverifiedHTTPSConnection with mock.patch('warnings.warn') as warn: r = pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertTrue(warn.called) call, = warn.call_args_list category = call[0][1] self.assertEqual(category, InsecureRequestWarning) def test_ssl_unverified_with_ca_certs(self): pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) with mock.patch('warnings.warn') as warn: r = pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertTrue(warn.called) call, = warn.call_args_list category = call[0][1] self.assertEqual(category, InsecureRequestWarning) @requires_network def test_ssl_verified_with_platform_ca_certs(self): """ We should rely on the platform CA file to validate authenticity of SSL certificates. Since this file is used by many components of the OS, such as curl, apt-get, etc., we decided to not touch it, in order to not compromise the security of the OS running the test suite (typically urllib3 developer's OS). This test assumes that httpbin.org uses a certificate signed by a well known Certificate Authority. """ try: import urllib3.contrib.pyopenssl except ImportError: raise SkipTest('Test requires PyOpenSSL') if (urllib3.connection.ssl_wrap_socket is urllib3.contrib.pyopenssl.orig_connection_ssl_wrap_socket): # Not patched raise SkipTest('Test should only be run after PyOpenSSL ' 'monkey patching') https_pool = HTTPSConnectionPool('httpbin.org', 443, cert_reqs=ssl.CERT_REQUIRED) https_pool.request('HEAD', '/') def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_hostname = False https_pool.request('GET', '/') def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_hostname = 'localhost' https_pool.request('GET', '/') def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = 'CA:84:E1:AD0E5a:ef:2f:C3:09' \ ':E7:30:F8:CD:C8:5B' https_pool.request('GET', '/') def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool.request('GET', '/') def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool._get_conn() # Uneven length https_pool.assert_fingerprint = 'AA:A' self.assertRaises(SSLError, https_pool.request, 'GET', '/') https_pool._get_conn() # Invalid length https_pool.assert_fingerprint = 'AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_verify_none_and_bad_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') def test_verify_none_and_good_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool.request('GET', '/') @requires_network def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' url = '/sleep?seconds=0.005' self.assertRaises(ReadTimeoutError, https_pool.request, 'GET', url) timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') https_pool.request('GET', '/') def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with() @onlyPy26OrOlder def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, 'GET', '/') @requires_network def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs='CERT_REQUIRED'): https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs=cert_reqs) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) def test_enhanced_ssl_connection(self): fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:7A:F2:8A:D7:1E:07:33:67:DE' conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA, assert_fingerprint=fingerprint) https_pool._make_request(conn, 'GET', '/') def test_ssl_correct_system_time(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') self._pool.request('GET', '/') self.assertEqual([], w) def test_ssl_wrong_system_time(self): with mock.patch('urllib3.connection.datetime') as mock_date: mock_date.date.today.return_value = datetime.date(1970, 1, 1) with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') self._pool.request('GET', '/') self.assertEqual(len(w), 1) warning = w[0] self.assertEqual(SystemTimeWarning, warning.category) self.assertTrue(str(RECENT_DATE) in warning.message.args[0])
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) def test_simple(self): r = self._pool.request('GET', '/') 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', '/') self.assertEqual(r.status, 200, r.data) def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) https_pool.request('GET', '/') # Should succeed without exceptions. def test_invalid_common_name(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL invalid common name") except SSLError as e: self.assertTrue("doesn't match" in str(e)) def test_verified_with_bad_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA_BAD) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with bad CA certs") except SSLError as e: self.assertTrue('certificate verify failed' in str(e), "Expected 'certificate verify failed'," "instead got: %r" % e) def test_verified_without_ca_certs(self): # default is cert_reqs=None which is ssl.CERT_NONE https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with no CA certs when" "CERT_REQUIRED is set") except SSLError as e: # there is a different error message depending on whether or # not pyopenssl is injected self.assertTrue('No root certificates specified' in str(e) or 'certificate verify failed' in str(e), "Expected 'No root certificates specified' or " "'certificate verify failed', " "instead got: %r" % e) def test_no_ssl(self): OriginalConnectionCls = self._pool.ConnectionCls try: self._pool.ConnectionCls = None self.assertRaises(SSLError, self._pool._new_conn) self.assertRaises(SSLError, self._pool.request, 'GET', '/') finally: self._pool.ConnectionCls = OriginalConnectionCls def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ try: OriginalConnectionCls = self._pool.ConnectionCls self._pool.ConnectionCls = UnverifiedHTTPSConnection self._pool.request('GET', '/') finally: self._pool.ConnectionCls = OriginalConnectionCls def test_ssl_unverified_with_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE') https_pool.ca_certs = DEFAULT_CA_BAD https_pool.request('GET', '/') @requires_network def test_ssl_verified_with_platform_ca_certs(self): """ We should rely on the platform CA file to validate authenticity of SSL certificates. Since this file is used by many components of the OS, such as curl, apt-get, etc., we decided to not touch it, in order to not compromise the security of the OS running the test suite (typically urllib3 developer's OS). This test assumes that httpbin.org uses a certificate signed by a well known Certificate Authority. """ try: import urllib3.contrib.pyopenssl except ImportError: raise SkipTest('This test needs pyopenssl support') if (urllib3.connection.ssl_wrap_socket is urllib3.contrib.pyopenssl.orig_connection_ssl_wrap_socket): # Not patched raise SkipTest('This test should only be run after pyopenssl ' 'monkey patching') https_pool = HTTPSConnectionPool('httpbin.org', 443, cert_reqs=ssl.CERT_REQUIRED) https_pool.request('HEAD', '/') def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_hostname = False https_pool.request('GET', '/') def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_hostname = 'localhost' https_pool.request('GET', '/') def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CA:84:E1:AD0E5a:ef:2f:C3:09' \ ':E7:30:F8:CD:C8:5B' https_pool.request('GET', '/') def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool.request('GET', '/') def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') # invalid length https_pool.assert_fingerprint = 'AA' self.assertRaises(SSLError, https_pool.request, 'GET', '/') # uneven length https_pool.assert_fingerprint = 'AA:A' self.assertRaises(SSLError, https_pool.request, 'GET', '/') @requires_network def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' url = '/sleep?seconds=0.005' self.assertRaises(ReadTimeoutError, https_pool.request, 'GET', url) timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') https_pool.request('GET', '/') def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with() def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, 'GET', '/') @requires_network def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs='CERT_REQUIRED'): https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, cert_reqs=cert_reqs) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) def test_enhanced_ssl_connection(self): conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=Timeout(total=None, connect=5), cert_reqs='CERT_REQUIRED') https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = 'CC:45:6A:90:82:F7FF:C0:8218:8e:' \ '7A:F2:8A:D7:1E:07:33:67:DE' https_pool._make_request(conn, 'GET', '/') @onlyPy26OrOlder def test_source_address_ignored(self): # source_address is ignored in Python 2.6 and earlier. for addr in INVALID_SOURCE_ADDRESSES: https_pool = HTTPSConnectionPool( self.host, self.port, cert_reqs='CERT_REQUIRED', source_address=addr) https_pool.ca_certs = DEFAULT_CA r = https_pool.request('GET', '/source_address') assert r.status == 200 @onlyPy27OrNewer def test_source_address(self): for addr in VALID_SOURCE_ADDRESSES: https_pool = HTTPSConnectionPool( self.host, self.port, cert_reqs='CERT_REQUIRED', source_address=addr) https_pool.ca_certs = DEFAULT_CA r = https_pool.request('GET', '/source_address') assert r.data == b(addr[0]) @onlyPy27OrNewer def test_source_address_error(self): for addr in INVALID_SOURCE_ADDRESSES: https_pool = HTTPSConnectionPool( self.host, self.port, cert_reqs='CERT_REQUIRED', source_address=addr) https_pool.ca_certs = DEFAULT_CA self.assertRaises( MaxRetryError, https_pool.request, 'GET', '/source_address')
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) self.addCleanup(self._pool.close) def test_simple(self): r = self._pool.request('GET', '/') self.assertEqual(r.status, 200, r.data) def test_dotted_fqdn(self): pool = HTTPSConnectionPool(self.host + '.', self.port) r = pool.request('GET', '/') 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', '/') self.assertEqual(r.status, 200, r.data) def test_client_intermediate(self): client_cert, client_key, client_subject = ( DEFAULT_CLIENT_CERTS['certfile'], DEFAULT_CLIENT_CERTS['keyfile'], DEFAULT_CLIENT_CERTS['subject']) https_pool = HTTPSConnectionPool(self.host, self.port, key_file=client_key, cert_file=client_cert) r = https_pool.request('GET', '/certificate') self.assertDictEqual(json.loads(r.data.decode('utf-8')), client_subject, r.data) def test_client_no_intermediate(self): client_cert, client_key = ( DEFAULT_CLIENT_NO_INTERMEDIATE_CERTS['certfile'], DEFAULT_CLIENT_NO_INTERMEDIATE_CERTS['keyfile']) https_pool = HTTPSConnectionPool(self.host, self.port, cert_file=client_cert, key_file=client_key) try: https_pool.request('GET', '/certificate', retries=False) except SSLError as e: if not ('alert unknown ca' in str(e) or 'invalid certificate chain' in str(e) or 'unknown Cert Authority' in str(e)): raise def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) # Modern versions of Python, or systems using PyOpenSSL, don't # emit warnings. if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL \ or util.IS_SECURETRANSPORT: self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) if util.HAS_SNI: call = warn.call_args_list[0] else: call = warn.call_args_list[1] error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) def test_verified_with_context(self): ctx = util.ssl_.create_urllib3_context(cert_reqs=ssl.CERT_REQUIRED) ctx.load_verify_locations(cafile=DEFAULT_CA) https_pool = HTTPSConnectionPool(self.host, self.port, ssl_context=ctx) self.addCleanup(https_pool.close) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) # Modern versions of Python, or systems using PyOpenSSL, don't # emit warnings. if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL \ or util.IS_SECURETRANSPORT: self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) if util.HAS_SNI: call = warn.call_args_list[0] else: call = warn.call_args_list[1] error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) def test_context_combines_with_ca_certs(self): ctx = util.ssl_.create_urllib3_context(cert_reqs=ssl.CERT_REQUIRED) https_pool = HTTPSConnectionPool(self.host, self.port, ca_certs=DEFAULT_CA, ssl_context=ctx) self.addCleanup(https_pool.close) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) # Modern versions of Python, or systems using PyOpenSSL, don't # emit warnings. if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL \ or util.IS_SECURETRANSPORT: self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) if util.HAS_SNI: call = warn.call_args_list[0] else: call = warn.call_args_list[1] error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) @onlyPy279OrNewer @notSecureTransport def test_ca_dir_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_cert_dir=DEFAULT_CA_DIR) self.addCleanup(https_pool.close) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch('warnings.warn') as warn: r = https_pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertFalse(warn.called, warn.call_args_list) def test_invalid_common_name(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL invalid common name") except MaxRetryError as e: self.assertIsInstance(e.reason, SSLError) self.assertTrue("doesn't match" in str(e.reason) or "certificate verify failed" in str(e.reason)) def test_verified_with_bad_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA_BAD) self.addCleanup(https_pool.close) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with bad CA certs") except MaxRetryError as e: self.assertIsInstance(e.reason, SSLError) self.assertTrue( 'certificate verify failed' in str(e.reason), "Expected 'certificate verify failed'," "instead got: %r" % e.reason) def test_verified_without_ca_certs(self): # default is cert_reqs=None which is ssl.CERT_NONE https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED') self.addCleanup(https_pool.close) try: https_pool.request('GET', '/') self.fail("Didn't raise SSL error with no CA certs when" "CERT_REQUIRED is set") except MaxRetryError as e: self.assertIsInstance(e.reason, SSLError) # there is a different error message depending on whether or # not pyopenssl is injected self.assertTrue( 'No root certificates specified' in str(e.reason) or 'certificate verify failed' in str(e.reason) or 'invalid certificate chain' in str(e.reason), "Expected 'No root certificates specified', " "'certificate verify failed', or " "'invalid certificate chain', " "instead got: %r" % e.reason) def test_no_ssl(self): pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = None self.addCleanup(pool.close) self.assertRaises(SSLError, pool._new_conn) with self.assertRaises(MaxRetryError) as cm: pool.request('GET', '/', retries=0) self.assertIsInstance(cm.exception.reason, SSLError) def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = UnverifiedHTTPSConnection self.addCleanup(pool.close) with mock.patch('warnings.warn') as warn: r = pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertTrue(warn.called) # Modern versions of Python, or systems using PyOpenSSL, only emit # the unverified warning. Older systems may also emit other # warnings, which we want to ignore here. calls = warn.call_args_list self.assertIn(InsecureRequestWarning, [x[0][1] for x in calls]) def test_ssl_unverified_with_ca_certs(self): pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) self.addCleanup(pool.close) with mock.patch('warnings.warn') as warn: r = pool.request('GET', '/') self.assertEqual(r.status, 200) self.assertTrue(warn.called) # Modern versions of Python, or systems using PyOpenSSL, only emit # the unverified warning. Older systems may also emit other # warnings, which we want to ignore here. calls = warn.call_args_list if sys.version_info >= (2, 7, 9) or util.IS_PYOPENSSL \ or util.IS_SECURETRANSPORT: category = calls[0][0][1] elif util.HAS_SNI: category = calls[1][0][1] else: category = calls[2][0][1] self.assertEqual(category, InsecureRequestWarning) def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_hostname = False https_pool.request('GET', '/') def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_hostname = 'localhost' https_pool.request('GET', '/') def test_server_hostname(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA, server_hostname='localhost') self.addCleanup(https_pool.close) conn = https_pool._new_conn() conn.request('GET', '/') # Assert the wrapping socket is using the passed-through SNI name. # pyopenssl doesn't let you pull the server_hostname back off the # socket, so only add this assertion if the attribute is there (i.e. # the python ssl module). if hasattr(conn.sock, 'server_hostname'): self.assertEqual(conn.sock.server_hostname, "localhost") def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = 'F2:06:5A:42:10:3F:45:1C:17:FE:E6:' \ '07:1E:8A:86:E5' https_pool.request('GET', '/') def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' https_pool.request('GET', '/') def test_assert_fingerprint_sha256(self): https_pool = HTTPSConnectionPool('localhost', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = ('C5:4D:0B:83:84:89:2E:AE:B4:58:BB:12:' 'F7:A6:C4:76:05:03:88:D8:57:65:51:F3:' '1E:60:B0:8B:70:18:64:E6') https_pool.request('GET', '/') def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' def _test_request(pool): with self.assertRaises(MaxRetryError) as cm: pool.request('GET', '/', retries=0) self.assertIsInstance(cm.exception.reason, SSLError) _test_request(https_pool) https_pool._get_conn() # Uneven length https_pool.assert_fingerprint = 'AA:A' _test_request(https_pool) https_pool._get_conn() # Invalid length https_pool.assert_fingerprint = 'AA' _test_request(https_pool) def test_verify_none_and_bad_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = 'AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:' \ 'AA:AA:AA:AA:AA:AA:AA:AA:AA' with self.assertRaises(MaxRetryError) as cm: https_pool.request('GET', '/', retries=0) self.assertIsInstance(cm.exception.reason, SSLError) def test_verify_none_and_good_fingerprint(self): https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_NONE', ca_certs=DEFAULT_CA_BAD) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' https_pool.request('GET', '/') @notSecureTransport def test_good_fingerprint_and_hostname_mismatch(self): # This test doesn't run with SecureTransport because we don't turn off # hostname validation without turning off all validation, which this # test doesn't do (deliberately). We should revisit this if we make # new decisions. https_pool = HTTPSConnectionPool('127.0.0.1', self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA) self.addCleanup(https_pool.close) https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' https_pool.request('GET', '/') @requires_network def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') self.addCleanup(https_pool.close) timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') self.addCleanup(https_pool.close) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, retries=False, cert_reqs='CERT_REQUIRED') self.addCleanup(https_pool.close) https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:' \ 'BF:93:CF:F9:71:CC:07:7D:0A' timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') self.addCleanup(https_pool.close) https_pool.request('GET', '/') def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs='CERT_NONE') self.addCleanup(https_pool.close) conn = https_pool._new_conn() self.addCleanup(conn.close) try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, 'GET', '/') conn._tunnel.assert_called_once_with() @onlyPy26OrOlder def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, 'GET', '/') @requires_network def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs='CERT_REQUIRED'): https_pool = HTTPSConnectionPool(TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs=cert_reqs) self.addCleanup(https_pool.close) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/') self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, 'GET', '/') https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, 'GET', '/', timeout=Timeout(total=None, connect=0.001)) def test_enhanced_ssl_connection(self): fingerprint = '92:81:FE:85:F7:0C:26:60:EC:D6:B3:BF:93:CF:F9:71:CC:07:7D:0A' conn = VerifiedHTTPSConnection(self.host, self.port) self.addCleanup(conn.close) https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs='CERT_REQUIRED', ca_certs=DEFAULT_CA, assert_fingerprint=fingerprint) self.addCleanup(https_pool.close) https_pool._make_request(conn, 'GET', '/') def test_ssl_correct_system_time(self): self._pool.cert_reqs = 'CERT_REQUIRED' self._pool.ca_certs = DEFAULT_CA w = self._request_without_resource_warnings('GET', '/') self.assertEqual([], w) def test_ssl_wrong_system_time(self): self._pool.cert_reqs = 'CERT_REQUIRED' self._pool.ca_certs = DEFAULT_CA with mock.patch('urllib3.connection.datetime') as mock_date: mock_date.date.today.return_value = datetime.date(1970, 1, 1) w = self._request_without_resource_warnings('GET', '/') self.assertEqual(len(w), 1) warning = w[0] self.assertEqual(SystemTimeWarning, warning.category) self.assertTrue(str(RECENT_DATE) in warning.message.args[0]) def _request_without_resource_warnings(self, method, url): with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') self._pool.request(method, url) return [x for x in w if not isinstance(x.message, ResourceWarning)]
class TestHTTPS(HTTPSDummyServerTestCase): def setUp(self): self._pool = HTTPSConnectionPool(self.host, self.port) def test_simple(self): r = self._pool.request("GET", "/") 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", "/") self.assertEqual(r.status, 200, r.data) def test_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch("warnings.warn") as warn: r = https_pool.request("GET", "/") self.assertEqual(r.status, 200) if sys.version_info >= (2, 7, 9): self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) if HAS_SNI: call = warn.call_args_list[0] else: call = warn.call_args_list[1] error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) @onlyPy279OrNewer def test_ca_dir_verified(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs="CERT_REQUIRED", ca_cert_dir=DEFAULT_CA_DIR) conn = https_pool._new_conn() self.assertEqual(conn.__class__, VerifiedHTTPSConnection) with mock.patch("warnings.warn") as warn: r = https_pool.request("GET", "/") self.assertEqual(r.status, 200) if sys.version_info >= (2, 7, 9): self.assertFalse(warn.called, warn.call_args_list) else: self.assertTrue(warn.called) call, = warn.call_args_list error = call[0][1] self.assertEqual(error, InsecurePlatformWarning) def test_invalid_common_name(self): https_pool = HTTPSConnectionPool("127.0.0.1", self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA) try: https_pool.request("GET", "/") self.fail("Didn't raise SSL invalid common name") except SSLError as e: self.assertTrue("doesn't match" in str(e)) def test_verified_with_bad_ca_certs(self): https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA_BAD) try: https_pool.request("GET", "/") self.fail("Didn't raise SSL error with bad CA certs") except SSLError as e: self.assertTrue( "certificate verify failed" in str(e), "Expected 'certificate verify failed'," "instead got: %r" % e ) def test_verified_without_ca_certs(self): # default is cert_reqs=None which is ssl.CERT_NONE https_pool = HTTPSConnectionPool(self.host, self.port, cert_reqs="CERT_REQUIRED") try: https_pool.request("GET", "/") self.fail("Didn't raise SSL error with no CA certs when" "CERT_REQUIRED is set") except SSLError as e: # there is a different error message depending on whether or # not pyopenssl is injected self.assertTrue( "No root certificates specified" in str(e) or "certificate verify failed" in str(e), "Expected 'No root certificates specified' or " "'certificate verify failed', " "instead got: %r" % e, ) def test_no_ssl(self): pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = None self.assertRaises(SSLError, pool._new_conn) self.assertRaises(SSLError, pool.request, "GET", "/") def test_unverified_ssl(self): """ Test that bare HTTPSConnection can connect, make requests """ pool = HTTPSConnectionPool(self.host, self.port) pool.ConnectionCls = UnverifiedHTTPSConnection with mock.patch("warnings.warn") as warn: r = pool.request("GET", "/") self.assertEqual(r.status, 200) self.assertTrue(warn.called) call, = warn.call_args_list category = call[0][1] self.assertEqual(category, InsecureRequestWarning) def test_ssl_unverified_with_ca_certs(self): pool = HTTPSConnectionPool(self.host, self.port, cert_reqs="CERT_NONE", ca_certs=DEFAULT_CA_BAD) with mock.patch("warnings.warn") as warn: r = pool.request("GET", "/") self.assertEqual(r.status, 200) self.assertTrue(warn.called) calls = warn.call_args_list if sys.version_info >= (2, 7, 9): category = calls[0][0][1] elif HAS_SNI: category = calls[1][0][1] else: category = calls[2][0][1] self.assertEqual(category, InsecureRequestWarning) @requires_network def test_ssl_verified_with_platform_ca_certs(self): """ We should rely on the platform CA file to validate authenticity of SSL certificates. Since this file is used by many components of the OS, such as curl, apt-get, etc., we decided to not touch it, in order to not compromise the security of the OS running the test suite (typically urllib3 developer's OS). This test assumes that httpbin.org uses a certificate signed by a well known Certificate Authority. """ try: import urllib3.contrib.pyopenssl except ImportError: raise SkipTest("Test requires PyOpenSSL") if urllib3.connection.ssl_wrap_socket is urllib3.contrib.pyopenssl.orig_connection_ssl_wrap_socket: # Not patched raise SkipTest("Test should only be run after PyOpenSSL " "monkey patching") https_pool = HTTPSConnectionPool("httpbin.org", 443, cert_reqs=ssl.CERT_REQUIRED) https_pool.request("HEAD", "/") def test_assert_hostname_false(self): https_pool = HTTPSConnectionPool("localhost", self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA) https_pool.assert_hostname = False https_pool.request("GET", "/") def test_assert_specific_hostname(self): https_pool = HTTPSConnectionPool("localhost", self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA) https_pool.assert_hostname = "localhost" https_pool.request("GET", "/") def test_assert_fingerprint_md5(self): https_pool = HTTPSConnectionPool("localhost", self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = "CA:84:E1:AD0E5a:ef:2f:C3:09" ":E7:30:F8:CD:C8:5B" https_pool.request("GET", "/") def test_assert_fingerprint_sha1(self): https_pool = HTTPSConnectionPool("localhost", self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = "CC:45:6A:90:82:F7FF:C0:8218:8e:" "7A:F2:8A:D7:1E:07:33:67:DE" https_pool.request("GET", "/") def test_assert_fingerprint_sha256(self): https_pool = HTTPSConnectionPool("localhost", self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = ( "9A:29:9D:4F:47:85:1C:51:23:F5:9A:A3:" "0F:5A:EF:96:F9:2E:3C:22:2E:FC:E8:BC:" "0E:73:90:37:ED:3B:AA:AB" ) https_pool.request("GET", "/") def test_assert_invalid_fingerprint(self): https_pool = HTTPSConnectionPool("127.0.0.1", self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = "AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:" "AA:AA:AA:AA:AA:AA:AA:AA:AA" self.assertRaises(SSLError, https_pool.request, "GET", "/") https_pool._get_conn() # Uneven length https_pool.assert_fingerprint = "AA:A" self.assertRaises(SSLError, https_pool.request, "GET", "/") https_pool._get_conn() # Invalid length https_pool.assert_fingerprint = "AA" self.assertRaises(SSLError, https_pool.request, "GET", "/") def test_verify_none_and_bad_fingerprint(self): https_pool = HTTPSConnectionPool("127.0.0.1", self.port, cert_reqs="CERT_NONE", ca_certs=DEFAULT_CA_BAD) https_pool.assert_fingerprint = "AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:" "AA:AA:AA:AA:AA:AA:AA:AA:AA" self.assertRaises(SSLError, https_pool.request, "GET", "/") def test_verify_none_and_good_fingerprint(self): https_pool = HTTPSConnectionPool("127.0.0.1", self.port, cert_reqs="CERT_NONE", ca_certs=DEFAULT_CA_BAD) https_pool.assert_fingerprint = "CC:45:6A:90:82:F7FF:C0:8218:8e:" "7A:F2:8A:D7:1E:07:33:67:DE" https_pool.request("GET", "/") def test_good_fingerprint_and_hostname_mismatch(self): https_pool = HTTPSConnectionPool("127.0.0.1", self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA) https_pool.assert_fingerprint = "CC:45:6A:90:82:F7FF:C0:8218:8e:" "7A:F2:8A:D7:1E:07:33:67:DE" https_pool.request("GET", "/") @requires_network def test_https_timeout(self): timeout = Timeout(connect=0.001) https_pool = HTTPSConnectionPool( TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs="CERT_REQUIRED" ) timeout = Timeout(total=None, connect=0.001) https_pool = HTTPSConnectionPool( TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs="CERT_REQUIRED" ) self.assertRaises(ConnectTimeoutError, https_pool.request, "GET", "/") timeout = Timeout(read=0.001) https_pool = HTTPSConnectionPool( self.host, self.port, timeout=timeout, retries=False, cert_reqs="CERT_REQUIRED" ) https_pool.ca_certs = DEFAULT_CA https_pool.assert_fingerprint = "CC:45:6A:90:82:F7FF:C0:8218:8e:" "7A:F2:8A:D7:1E:07:33:67:DE" timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs="CERT_NONE") https_pool.request("GET", "/") def test_tunnel(self): """ test the _tunnel behavior """ timeout = Timeout(total=None) https_pool = HTTPSConnectionPool(self.host, self.port, timeout=timeout, cert_reqs="CERT_NONE") conn = https_pool._new_conn() try: conn.set_tunnel(self.host, self.port) except AttributeError: # python 2.6 conn._set_tunnel(self.host, self.port) conn._tunnel = mock.Mock() https_pool._make_request(conn, "GET", "/") conn._tunnel.assert_called_once_with() @onlyPy26OrOlder def test_tunnel_old_python(self): """HTTPSConnection can still make connections if _tunnel_host isn't set The _tunnel_host attribute was added in 2.6.3 - because our test runners generally use the latest Python 2.6, we simulate the old version by deleting the attribute from the HTTPSConnection. """ conn = self._pool._new_conn() del conn._tunnel_host self._pool._make_request(conn, "GET", "/") @requires_network def test_enhanced_timeout(self): def new_pool(timeout, cert_reqs="CERT_REQUIRED"): https_pool = HTTPSConnectionPool( TARPIT_HOST, self.port, timeout=timeout, retries=False, cert_reqs=cert_reqs ) return https_pool https_pool = new_pool(Timeout(connect=0.001)) conn = https_pool._new_conn() self.assertRaises(ConnectTimeoutError, https_pool.request, "GET", "/") self.assertRaises(ConnectTimeoutError, https_pool._make_request, conn, "GET", "/") https_pool = new_pool(Timeout(connect=5)) self.assertRaises(ConnectTimeoutError, https_pool.request, "GET", "/", timeout=Timeout(connect=0.001)) t = Timeout(total=None) https_pool = new_pool(t) conn = https_pool._new_conn() self.assertRaises( ConnectTimeoutError, https_pool.request, "GET", "/", timeout=Timeout(total=None, connect=0.001) ) def test_enhanced_ssl_connection(self): fingerprint = "CC:45:6A:90:82:F7FF:C0:8218:8e:7A:F2:8A:D7:1E:07:33:67:DE" conn = VerifiedHTTPSConnection(self.host, self.port) https_pool = HTTPSConnectionPool( self.host, self.port, cert_reqs="CERT_REQUIRED", ca_certs=DEFAULT_CA, assert_fingerprint=fingerprint ) https_pool._make_request(conn, "GET", "/") def test_ssl_correct_system_time(self): self._pool.cert_reqs = "CERT_REQUIRED" self._pool.ca_certs = DEFAULT_CA w = self._request_without_resource_warnings("GET", "/") self.assertEqual([], w) def test_ssl_wrong_system_time(self): self._pool.cert_reqs = "CERT_REQUIRED" self._pool.ca_certs = DEFAULT_CA with mock.patch("urllib3.connection.datetime") as mock_date: mock_date.date.today.return_value = datetime.date(1970, 1, 1) w = self._request_without_resource_warnings("GET", "/") self.assertEqual(len(w), 1) warning = w[0] self.assertEqual(SystemTimeWarning, warning.category) self.assertTrue(str(RECENT_DATE) in warning.message.args[0]) def _request_without_resource_warnings(self, method, url): with warnings.catch_warnings(record=True) as w: warnings.simplefilter("always") self._pool.request(method, url) return [x for x in w if not isinstance(x.message, ResourceWarning)]