Exemplo n.º 1
0
    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 pytest.raises(MaxRetryError) as cm:
                pool.request("GET", "/", retries=0)
            assert isinstance(cm.value.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)
Exemplo n.º 2
0
    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)
Exemplo n.º 3
0
    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)
Exemplo n.º 4
0
    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()
Exemplo n.º 5
0
    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()
Exemplo n.º 6
0
    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", "/")
Exemplo n.º 7
0
    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))
Exemplo n.º 8
0
    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', '/')
Exemplo n.º 9
0
    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', '/')
Exemplo n.º 10
0
    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)
Exemplo n.º 11
0
class TestHTTPS(HTTPSDummyServerTestCase):
    tls_protocol_name = None

    def setUp(self):
        self._pool = HTTPSConnectionPool(self.host,
                                         self.port,
                                         ca_certs=DEFAULT_CA)
        self.addCleanup(self._pool.close)

    def test_simple(self):
        r = self._pool.request('GET', '/')
        self.assertEqual(r.status, 200, r.data)

    @fails_on_travis_gce
    def test_dotted_fqdn(self):
        pool = HTTPSConnectionPool(self.host + '.',
                                   self.port,
                                   ca_certs=DEFAULT_CA)
        r = pool.request('GET', '/')
        self.assertEqual(r.status, 200, r.data)

    def test_client_intermediate(self):
        client_cert, client_key = (
            DEFAULT_CLIENT_CERTS['certfile'],
            DEFAULT_CLIENT_CERTS['keyfile'],
        )
        https_pool = HTTPSConnectionPool(self.host,
                                         self.port,
                                         key_file=client_key,
                                         cert_file=client_cert,
                                         ca_certs=DEFAULT_CA)
        r = https_pool.request('GET', '/certificate')
        subject = json.loads(r.data.decode('utf-8'))
        assert subject['organizationalUnitName'].startswith(
            'Testing server cert')

    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,
                                         ca_certs=DEFAULT_CA)
        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) or
                    # https://github.com/urllib3/urllib3/issues/1422
                    'connection closed via error' in str(e)
                    or 'WSAECONNRESET' in str(e)):
                raise
        except ProtocolError as e:
            # https://github.com/urllib3/urllib3/issues/1422
            if not ('An existing connection was forcibly closed by the remote host'
                    in str(e)):
                raise

    @requires_ssl_context_keyfile_password
    def test_client_key_password(self):
        client_cert, client_key = (
            DEFAULT_CLIENT_CERTS['certfile'],
            PASSWORD_CLIENT_KEYFILE,
        )
        https_pool = HTTPSConnectionPool(self.host,
                                         self.port,
                                         ca_certs=DEFAULT_CA,
                                         key_file=client_key,
                                         cert_file=client_cert,
                                         key_password="******")
        r = https_pool.request('GET', '/certificate')
        subject = json.loads(r.data.decode('utf-8'))
        assert subject['organizationalUnitName'].startswith(
            'Testing server cert')

    @requires_ssl_context_keyfile_password
    def test_client_encrypted_key_requires_password(self):
        client_cert, client_key = (
            DEFAULT_CLIENT_CERTS['certfile'],
            PASSWORD_CLIENT_KEYFILE,
        )
        https_pool = HTTPSConnectionPool(self.host,
                                         self.port,
                                         key_file=client_key,
                                         cert_file=client_cert,
                                         key_password=None)

        with pytest.raises(MaxRetryError) as e:
            https_pool.request('GET', '/certificate')

        assert 'password is required' in str(e.value)
        assert isinstance(e.value.reason, SSLError)

    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  # SecureTransport does not support cert directories
    @notOpenSSL098  # OpenSSL 0.9.8 does not support cert directories
    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.assertIn(
                'certificate verify failed', 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,
                                   cert_reqs=ssl.CERT_NONE)
        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)
        conn.set_tunnel(self.host, self.port)
        conn._tunnel = mock.Mock()
        https_pool._make_request(conn, 'GET', '/')
        conn._tunnel.assert_called_once_with()

    @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'

        https_pool = HTTPSConnectionPool(self.host,
                                         self.port,
                                         cert_reqs='CERT_REQUIRED',
                                         ca_certs=DEFAULT_CA,
                                         assert_fingerprint=fingerprint)
        self.addCleanup(https_pool.close)

        r = https_pool.request('GET', '/')
        assert r.status == 200

    @onlyPy279OrNewer
    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)

    @onlyPy279OrNewer
    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.assertIn(str(RECENT_DATE), 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)]

    def test_set_ssl_version_to_tls_version(self):
        if self.tls_protocol_name is None:
            pytest.skip("Skipping base test class")

        self._pool.ssl_version = self.certs['ssl_version']
        r = self._pool.request('GET', '/')
        self.assertEqual(r.status, 200, r.data)

    def test_set_cert_default_cert_required(self):
        conn = VerifiedHTTPSConnection(self.host, self.port)
        conn.set_cert()
        self.assertEqual(conn.cert_reqs, ssl.CERT_REQUIRED)

    def test_tls_protocol_name_of_socket(self):
        if self.tls_protocol_name is None:
            pytest.skip("Skipping base test class")

        conn = self._pool._get_conn()
        conn.connect()

        if not hasattr(conn.sock, 'version'):
            pytest.skip('SSLSocket.version() not available')

        self.assertEqual(conn.sock.version(), self.tls_protocol_name)
Exemplo n.º 12
0
class TestHTTPS(HTTPSDummyServerTestCase):
    tls_protocol_name = None

    def setUp(self):
        self._pool = HTTPSConnectionPool(self.host, self.port, ca_certs=DEFAULT_CA)
        self.addCleanup(self._pool.close)

    def test_simple(self):
        r = self._pool.request('GET', '/')
        self.assertEqual(r.status, 200, r.data)

    @fails_on_travis_gce
    def test_dotted_fqdn(self):
        pool = HTTPSConnectionPool(self.host + '.', self.port, ca_certs=DEFAULT_CA)
        r = pool.request('GET', '/')
        self.assertEqual(r.status, 200, r.data)

    def test_client_intermediate(self):
        client_cert, client_key = (
            DEFAULT_CLIENT_CERTS['certfile'],
            DEFAULT_CLIENT_CERTS['keyfile'],
        )
        https_pool = HTTPSConnectionPool(self.host, self.port,
                                         key_file=client_key,
                                         cert_file=client_cert,
                                         ca_certs=DEFAULT_CA)
        r = https_pool.request('GET', '/certificate')
        subject = json.loads(r.data.decode('utf-8'))
        assert subject['organizationalUnitName'].startswith(
            'Testing server cert')

    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,
                                         ca_certs=DEFAULT_CA)
        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) or
                    # https://github.com/urllib3/urllib3/issues/1422
                    'connection closed via error' in str(e) or
                    'WSAECONNRESET' in str(e)):
                raise
        except ProtocolError as e:
            # https://github.com/urllib3/urllib3/issues/1422
            if not ('An existing connection was forcibly closed by the remote host' in str(e)):
                raise

    @requires_ssl_context_keyfile_password
    def test_client_key_password(self):
        client_cert, client_key = (
            DEFAULT_CLIENT_CERTS['certfile'],
            PASSWORD_CLIENT_KEYFILE,
        )
        https_pool = HTTPSConnectionPool(self.host, self.port,
                                         ca_certs=DEFAULT_CA,
                                         key_file=client_key,
                                         cert_file=client_cert,
                                         key_password="******")
        r = https_pool.request('GET', '/certificate')
        subject = json.loads(r.data.decode('utf-8'))
        assert subject['organizationalUnitName'].startswith(
            'Testing server cert')

    @requires_ssl_context_keyfile_password
    def test_client_encrypted_key_requires_password(self):
        client_cert, client_key = (
            DEFAULT_CLIENT_CERTS['certfile'],
            PASSWORD_CLIENT_KEYFILE,
        )
        https_pool = HTTPSConnectionPool(self.host, self.port,
                                         key_file=client_key,
                                         cert_file=client_cert,
                                         key_password=None)

        with pytest.raises(MaxRetryError) as e:
            https_pool.request('GET', '/certificate')

        assert 'password is required' in str(e.value)
        assert isinstance(e.value.reason, SSLError)

    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  # SecureTransport does not support cert directories
    @notOpenSSL098  # OpenSSL 0.9.8 does not support cert directories
    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.assertIn('certificate verify failed', 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, cert_reqs=ssl.CERT_NONE)
        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)
        conn.set_tunnel(self.host, self.port)
        conn._tunnel = mock.Mock()
        https_pool._make_request(conn, 'GET', '/')
        conn._tunnel.assert_called_once_with()

    @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'

        https_pool = HTTPSConnectionPool(self.host, self.port,
                                         cert_reqs='CERT_REQUIRED',
                                         ca_certs=DEFAULT_CA,
                                         assert_fingerprint=fingerprint)
        self.addCleanup(https_pool.close)

        r = https_pool.request('GET', '/')
        assert r.status == 200

    @onlyPy279OrNewer
    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)

    @onlyPy279OrNewer
    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.assertIn(str(RECENT_DATE), 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)]

    def test_set_ssl_version_to_tls_version(self):
        if self.tls_protocol_name is None:
            pytest.skip("Skipping base test class")

        self._pool.ssl_version = self.certs['ssl_version']
        r = self._pool.request('GET', '/')
        self.assertEqual(r.status, 200, r.data)

    def test_set_cert_default_cert_required(self):
        conn = VerifiedHTTPSConnection(self.host, self.port)
        conn.set_cert()
        self.assertEqual(conn.cert_reqs, ssl.CERT_REQUIRED)

    def test_tls_protocol_name_of_socket(self):
        if self.tls_protocol_name is None:
            pytest.skip("Skipping base test class")

        conn = self._pool._get_conn()
        conn.connect()

        if not hasattr(conn.sock, 'version'):
            pytest.skip('SSLSocket.version() not available')

        self.assertEqual(conn.sock.version(), self.tls_protocol_name)
Exemplo n.º 13
0
class TestHTTPS(HTTPSDummyServerTestCase):
    tls_protocol_name = None

    def setup_method(self, method):
        self._pool = HTTPSConnectionPool(self.host,
                                         self.port,
                                         ca_certs=DEFAULT_CA)

    def teardown_method(self, method):
        self._pool.close()

    def test_simple(self):
        r = self._pool.request("GET", "/")
        assert r.status == 200, r.data

    @fails_on_travis_gce
    def test_dotted_fqdn(self):
        pool = HTTPSConnectionPool(self.host + ".",
                                   self.port,
                                   ca_certs=DEFAULT_CA)
        r = pool.request("GET", "/")
        assert r.status == 200, r.data

    def test_client_intermediate(self):
        client_cert, client_key = (
            DEFAULT_CLIENT_CERTS["certfile"],
            DEFAULT_CLIENT_CERTS["keyfile"],
        )
        https_pool = HTTPSConnectionPool(
            self.host,
            self.port,
            key_file=client_key,
            cert_file=client_cert,
            ca_certs=DEFAULT_CA,
        )
        r = https_pool.request("GET", "/certificate")
        subject = json.loads(r.data.decode("utf-8"))
        assert subject["organizationalUnitName"].startswith(
            "Testing server cert")

    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,
            ca_certs=DEFAULT_CA,
        )
        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) or
                    # https://github.com/urllib3/urllib3/issues/1422
                    "connection closed via error" in str(e)
                    or "WSAECONNRESET" in str(e)):
                raise
        except ProtocolError as e:
            if not ("An existing connection was forcibly closed by the remote host"
                    in str(e)
                    # Python 3.7.4+
                    or "WSAECONNRESET" in str(e)  # Windows
                    or "EPIPE" in str(e)  # macOS
                    ):
                raise

    @requires_ssl_context_keyfile_password
    def test_client_key_password(self):
        client_cert, client_key = (
            DEFAULT_CLIENT_CERTS["certfile"],
            PASSWORD_CLIENT_KEYFILE,
        )
        https_pool = HTTPSConnectionPool(
            self.host,
            self.port,
            ca_certs=DEFAULT_CA,
            key_file=client_key,
            cert_file=client_cert,
            key_password="******",
        )
        r = https_pool.request("GET", "/certificate")
        subject = json.loads(r.data.decode("utf-8"))
        assert subject["organizationalUnitName"].startswith(
            "Testing server cert")

    @requires_ssl_context_keyfile_password
    def test_client_encrypted_key_requires_password(self):
        client_cert, client_key = (
            DEFAULT_CLIENT_CERTS["certfile"],
            PASSWORD_CLIENT_KEYFILE,
        )
        with pytest.raises(SSLError) as e:
            HTTPSConnectionPool(
                self.host,
                self.port,
                key_file=client_key,
                cert_file=client_cert,
                key_password=None,
            )

        assert "password is required" in str(e.value)

    def test_verified(self):
        with HTTPSConnectionPool(self.host,
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_certs=DEFAULT_CA) as https_pool:
            with mock.patch("warnings.warn") as warn:
                r = https_pool.request("GET", "/")
                assert 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):
                    assert not warn.called, warn.call_args_list
                else:
                    assert warn.called
                    if util.HAS_SNI:
                        call = warn.call_args_list[0]
                    else:
                        call = warn.call_args_list[1]
                    error = call[0][1]
                    assert 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)
        with HTTPSConnectionPool(self.host, self.port,
                                 ssl_context=ctx) as https_pool:
            with mock.patch("warnings.warn") as warn:
                r = https_pool.request("GET", "/")
                assert 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):
                    assert not warn.called, warn.call_args_list
                else:
                    assert warn.called
                    if util.HAS_SNI:
                        call = warn.call_args_list[0]
                    else:
                        call = warn.call_args_list[1]
                    error = call[0][1]
                    assert error == InsecurePlatformWarning

    def test_context_combines_with_ca_certs(self):
        ctx = util.ssl_.create_urllib3_context(cert_reqs=ssl.CERT_REQUIRED)
        with HTTPSConnectionPool(self.host,
                                 self.port,
                                 ca_certs=DEFAULT_CA,
                                 ssl_context=ctx) as https_pool:
            with mock.patch("warnings.warn") as warn:
                r = https_pool.request("GET", "/")
                assert 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):
                    assert not warn.called, warn.call_args_list
                else:
                    assert warn.called
                    if util.HAS_SNI:
                        call = warn.call_args_list[0]
                    else:
                        call = warn.call_args_list[1]
                    error = call[0][1]
                    assert error == InsecurePlatformWarning

    @onlyPy279OrNewer
    @notSecureTransport  # SecureTransport does not support cert directories
    @notOpenSSL098  # OpenSSL 0.9.8 does not support cert directories
    def test_ca_dir_verified(self):
        with HTTPSConnectionPool(self.host,
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_cert_dir=DEFAULT_CA_DIR) as https_pool:
            with mock.patch("warnings.warn") as warn:
                r = https_pool.request("GET", "/")
                assert r.status == 200
                assert not warn.called, warn.call_args_list

    def test_invalid_common_name(self):
        with HTTPSConnectionPool("127.0.0.1",
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_certs=DEFAULT_CA) as https_pool:
            try:
                https_pool.request("GET", "/")
                self.fail("Didn't raise SSL invalid common name")
            except MaxRetryError as e:
                assert isinstance(e.reason, SSLError)
                assert "doesn't match" in str(
                    e.reason) or "certificate verify failed" in str(e.reason)

    def test_verified_with_bad_ca_certs(self):
        with HTTPSConnectionPool(self.host,
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_certs=DEFAULT_CA_BAD) as https_pool:
            try:
                https_pool.request("GET", "/")
                self.fail("Didn't raise SSL error with bad CA certs")
            except MaxRetryError as e:
                assert isinstance(e.reason, SSLError)
                assert "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
        with HTTPSConnectionPool(self.host,
                                 self.port,
                                 cert_reqs="CERT_REQUIRED") as https_pool:
            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:
                assert isinstance(e.reason, SSLError)
                # there is a different error message depending on whether or
                # not pyopenssl is injected
                assert ("No root certificates specified" in str(e.reason)
                        # PyPy sometimes uses all-caps here
                        or
                        "certificate verify failed" in str(e.reason).lower() 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_unverified_ssl(self):
        """ Test that bare HTTPSConnection can connect, make requests """
        with HTTPSConnectionPool(self.host, self.port,
                                 cert_reqs=ssl.CERT_NONE) as pool:
            with mock.patch("warnings.warn") as warn:
                r = pool.request("GET", "/")
                assert r.status == 200
                assert 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
                assert InsecureRequestWarning in [x[0][1] for x in calls]

    def test_ssl_unverified_with_ca_certs(self):
        with HTTPSConnectionPool(self.host,
                                 self.port,
                                 cert_reqs="CERT_NONE",
                                 ca_certs=DEFAULT_CA_BAD) as pool:
            with mock.patch("warnings.warn") as warn:
                r = pool.request("GET", "/")
                assert r.status == 200
                assert 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]
                assert category == InsecureRequestWarning

    def test_assert_hostname_false(self):
        with HTTPSConnectionPool("localhost",
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_certs=DEFAULT_CA) as https_pool:
            https_pool.assert_hostname = False
            https_pool.request("GET", "/")

    def test_assert_specific_hostname(self):
        with HTTPSConnectionPool("localhost",
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_certs=DEFAULT_CA) as https_pool:
            https_pool.assert_hostname = "localhost"
            https_pool.request("GET", "/")

    def test_server_hostname(self):
        with HTTPSConnectionPool(
                "127.0.0.1",
                self.port,
                cert_reqs="CERT_REQUIRED",
                ca_certs=DEFAULT_CA,
                server_hostname="localhost",
        ) as https_pool:
            conn = https_pool._new_conn()
            https_pool._start_conn(conn, connect_timeout=None)

            # 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).
            # XXX This is highly-specific to SyncBackend
            # See https://github.com/python-trio/urllib3/pull/54#discussion_r241683895
            # for potential solutions
            sock = conn._sock._sock
            if hasattr(sock, "server_hostname"):
                assert sock.server_hostname == "localhost"

    def test_assert_fingerprint_md5(self):
        with HTTPSConnectionPool("localhost",
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_certs=DEFAULT_CA) as https_pool:
            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):
        with HTTPSConnectionPool("localhost",
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_certs=DEFAULT_CA) as https_pool:
            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):
        with HTTPSConnectionPool("localhost",
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_certs=DEFAULT_CA) as https_pool:
            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):
        with HTTPSConnectionPool("127.0.0.1",
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_certs=DEFAULT_CA) as https_pool:
            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 pytest.raises(MaxRetryError) as cm:
                    pool.request("GET", "/", retries=0)
                assert isinstance(cm.value.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):
        with HTTPSConnectionPool("127.0.0.1",
                                 self.port,
                                 cert_reqs="CERT_NONE",
                                 ca_certs=DEFAULT_CA_BAD) as https_pool:
            https_pool.assert_fingerprint = (
                "AA:AA:AA:AA:AA:AAAA:AA:AAAA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA")
            with pytest.raises(MaxRetryError) as cm:
                https_pool.request("GET", "/", retries=0)
            assert isinstance(cm.value.reason, SSLError)

    def test_verify_none_and_good_fingerprint(self):
        with HTTPSConnectionPool("127.0.0.1",
                                 self.port,
                                 cert_reqs="CERT_NONE",
                                 ca_certs=DEFAULT_CA_BAD) as https_pool:
            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.
        with HTTPSConnectionPool("127.0.0.1",
                                 self.port,
                                 cert_reqs="CERT_REQUIRED",
                                 ca_certs=DEFAULT_CA) as https_pool:
            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(total=None, connect=0.001)
        with HTTPSConnectionPool(
                TARPIT_HOST,
                self.port,
                timeout=timeout,
                retries=False,
                cert_reqs="CERT_REQUIRED",
        ) as https_pool:
            with pytest.raises(ConnectTimeoutError):
                https_pool.request("GET", "/")

        timeout = Timeout(read=0.01)
        with HTTPSConnectionPool(
                self.host,
                self.port,
                timeout=timeout,
                retries=False,
                cert_reqs="CERT_REQUIRED",
        ) as https_pool:
            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)
        with HTTPSConnectionPool(self.host,
                                 self.port,
                                 timeout=timeout,
                                 cert_reqs="CERT_NONE") as https_pool:
            https_pool.request("GET", "/")

    @requires_network
    def test_enhanced_timeout(self):
        with HTTPSConnectionPool(
                TARPIT_HOST,
                self.port,
                timeout=Timeout(connect=0.001),
                retries=False,
                cert_reqs="CERT_REQUIRED",
        ) as https_pool:
            conn = https_pool._new_conn()
            with pytest.raises(ConnectTimeoutError):
                https_pool.request("GET", "/")
            with pytest.raises(ConnectTimeoutError):
                https_pool._make_request(conn, "GET", "/")

        with HTTPSConnectionPool(
                TARPIT_HOST,
                self.port,
                timeout=Timeout(connect=5),
                retries=False,
                cert_reqs="CERT_REQUIRED",
        ) as https_pool:
            with pytest.raises(ConnectTimeoutError):
                https_pool.request("GET", "/", timeout=Timeout(connect=0.001))

        with HTTPSConnectionPool(
                TARPIT_HOST,
                self.port,
                timeout=Timeout(total=None),
                retries=False,
                cert_reqs="CERT_REQUIRED",
        ) as https_pool:
            conn = https_pool._new_conn()
            with pytest.raises(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"

        with HTTPSConnectionPool(
                self.host,
                self.port,
                cert_reqs="CERT_REQUIRED",
                ca_certs=DEFAULT_CA,
                assert_fingerprint=fingerprint,
        ) as https_pool:
            r = https_pool.urlopen("GET", "/")
            assert r.status == 200

    @onlyPy279OrNewer
    def test_ssl_correct_system_time(self):
        w = self._request_without_resource_warnings("GET", "/")
        assert [] == w

    @onlyPy279OrNewer
    def test_ssl_wrong_system_time(self):
        with mock.patch("urllib3._sync.connection.datetime") as mock_date:
            mock_date.date.today.return_value = datetime.date(1970, 1, 1)

            w = self._request_without_resource_warnings("GET", "/")

            assert len(w) == 1
            warning = w[0]

            assert SystemTimeWarning == warning.category
            assert str(RECENT_DATE) in warning.message.args[0]

    def _request_without_resource_warnings(self, method, url):
        pool = HTTPSConnectionPool(self.host,
                                   self.port,
                                   cert_reqs="CERT_REQUIRED",
                                   ca_certs=DEFAULT_CA)
        with warnings.catch_warnings(record=True) as w:
            warnings.simplefilter("always")
            pool.request(method, url)

        return [x for x in w if not isinstance(x.message, ResourceWarning)]

    def test_set_ssl_version_to_tls_version(self):
        if self.tls_protocol_name is None:
            pytest.skip("Skipping base test class")

        self._pool.ssl_version = self.certs["ssl_version"]
        r = self._pool.request("GET", "/")
        assert r.status == 200, r.data

    def test_set_cert_default_cert_required(self):
        pool = HTTPSConnectionPool(self.host, self.port, ca_certs=DEFAULT_CA)
        assert pool.ssl_context.verify_mode == ssl.CERT_REQUIRED

    def test_tls_protocol_name_of_socket(self):
        if self.tls_protocol_name is None:
            pytest.skip("Skipping base test class")

        conn = self._pool._get_conn()
        conn.connect(self._pool.ssl_context)

        if not hasattr(conn._sock, "_version"):
            pytest.skip("_version() not available in backend")

        assert conn._sock._version() == self.tls_protocol_name