Exemplo n.º 1
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.º 2
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.º 3
0
 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", "/")
Exemplo n.º 4
0
 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', '/')
Exemplo n.º 5
0
    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', '/')
Exemplo n.º 6
0
    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', '/')
Exemplo n.º 7
0
    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', '/')
Exemplo n.º 8
0
    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', '/')
Exemplo n.º 9
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.º 10
0
 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()
Exemplo n.º 11
0
 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()
Exemplo n.º 12
0
 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()
Exemplo n.º 13
0
 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()
Exemplo n.º 14
0
    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
Exemplo n.º 15
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.º 16
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):
        """
        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', '/')
Exemplo n.º 17
0
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)]
Exemplo n.º 18
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)

        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])
Exemplo n.º 19
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')
Exemplo n.º 20
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', '/')

    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', '/')
Exemplo n.º 21
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)

        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)]
Exemplo n.º 22
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
        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', '/')
Exemplo n.º 23
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)

        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])
Exemplo n.º 24
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')
Exemplo n.º 25
0
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)]
Exemplo n.º 26
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)

        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)]