diff options
| author | hodbn <hodbn@users.noreply.github.com> | 2020-08-23 17:19:37 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-08-23 19:19:37 -0500 |
| commit | 16dc22b419e3958e0457bcfbc97d8a160d95208a (patch) | |
| tree | 1d9469cdd38a764e8420db5eb10dd5766cf71a3e /test | |
| parent | 0210ddb33c28249425ddeb7704c357d5b07c46f6 (diff) | |
| download | urllib3-16dc22b419e3958e0457bcfbc97d8a160d95208a.tar.gz | |
Don't raise SNI warning on SecureTransport with server_hostname=None
Diffstat (limited to 'test')
| -rw-r--r-- | test/contrib/test_pyopenssl.py | 1 | ||||
| -rw-r--r-- | test/contrib/test_securetransport.py | 2 | ||||
| -rw-r--r-- | test/test_util.py | 210 |
3 files changed, 120 insertions, 93 deletions
diff --git a/test/contrib/test_pyopenssl.py b/test/contrib/test_pyopenssl.py index 25b8deb1..7d1af312 100644 --- a/test/contrib/test_pyopenssl.py +++ b/test/contrib/test_pyopenssl.py @@ -30,6 +30,7 @@ def teardown_module(): pass +from ..test_util import TestUtilSSL # noqa: E402, F401 from ..with_dummyserver.test_https import ( # noqa: E402, F401 TestHTTPS, TestHTTPS_TLSv1, diff --git a/test/contrib/test_securetransport.py b/test/contrib/test_securetransport.py index 5fb8fbcf..41519436 100644 --- a/test/contrib/test_securetransport.py +++ b/test/contrib/test_securetransport.py @@ -29,6 +29,8 @@ def teardown_module(): pass +from ..test_util import TestUtilSSL # noqa: E402, F401 + # SecureTransport does not support TLSv1.3 # https://github.com/urllib3/urllib3/issues/1674 from ..with_dummyserver.test_https import ( # noqa: E402, F401 diff --git a/test/test_util.py b/test/test_util.py index 838c7515..1630ece7 100644 --- a/test/test_util.py +++ b/test/test_util.py @@ -10,7 +10,7 @@ from itertools import chain from mock import patch, Mock import pytest -from urllib3 import add_stderr_logger, disable_warnings +from urllib3 import add_stderr_logger, disable_warnings, util from urllib3.util.request import make_headers, rewind_body, _FAILEDTELL from urllib3.util.response import assert_header_parsing from urllib3.util.timeout import Timeout @@ -29,7 +29,7 @@ from urllib3.exceptions import ( UnrewindableBodyError, ) from urllib3.util.connection import allowed_gai_family, _has_ipv6 -from urllib3.util import is_fp_closed, ssl_ +from urllib3.util import is_fp_closed from urllib3.packages import six from . import clear_warnings @@ -666,31 +666,6 @@ class TestUtil(object): current_time.return_value = TIMEOUT_EPOCH + 37 assert timeout.get_connect_duration() == 37 - @pytest.mark.parametrize( - "candidate, requirements", - [ - (None, ssl.CERT_REQUIRED), - (ssl.CERT_NONE, ssl.CERT_NONE), - (ssl.CERT_REQUIRED, ssl.CERT_REQUIRED), - ("REQUIRED", ssl.CERT_REQUIRED), - ("CERT_REQUIRED", ssl.CERT_REQUIRED), - ], - ) - def test_resolve_cert_reqs(self, candidate, requirements): - assert resolve_cert_reqs(candidate) == requirements - - @pytest.mark.parametrize( - "candidate, version", - [ - (ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1), - ("PROTOCOL_TLSv1", ssl.PROTOCOL_TLSv1), - ("TLSv1", ssl.PROTOCOL_TLSv1), - (ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23), - ], - ) - def test_resolve_ssl_version(self, candidate, version): - assert resolve_ssl_version(candidate) == version - def test_is_fp_closed_object_supports_closed(self): class ClosedFile(object): @property @@ -722,72 +697,6 @@ class TestUtil(object): with pytest.raises(ValueError): is_fp_closed(NotReallyAFile()) - def test_ssl_wrap_socket_loads_the_cert_chain(self): - socket = object() - mock_context = Mock() - ssl_wrap_socket( - ssl_context=mock_context, sock=socket, certfile="/path/to/certfile" - ) - - mock_context.load_cert_chain.assert_called_once_with("/path/to/certfile", None) - - @patch("urllib3.util.ssl_.create_urllib3_context") - def test_ssl_wrap_socket_creates_new_context(self, create_urllib3_context): - socket = object() - ssl_wrap_socket(sock=socket, cert_reqs="CERT_REQUIRED") - - create_urllib3_context.assert_called_once_with( - None, "CERT_REQUIRED", ciphers=None - ) - - def test_ssl_wrap_socket_loads_verify_locations(self): - socket = object() - mock_context = Mock() - ssl_wrap_socket(ssl_context=mock_context, ca_certs="/path/to/pem", sock=socket) - mock_context.load_verify_locations.assert_called_once_with( - "/path/to/pem", None, None - ) - - def test_ssl_wrap_socket_loads_certificate_directories(self): - socket = object() - mock_context = Mock() - ssl_wrap_socket( - ssl_context=mock_context, ca_cert_dir="/path/to/pems", sock=socket - ) - mock_context.load_verify_locations.assert_called_once_with( - None, "/path/to/pems", None - ) - - def test_ssl_wrap_socket_loads_certificate_data(self): - socket = object() - mock_context = Mock() - ssl_wrap_socket( - ssl_context=mock_context, ca_cert_data="TOTALLY PEM DATA", sock=socket - ) - mock_context.load_verify_locations.assert_called_once_with( - None, None, "TOTALLY PEM DATA" - ) - - def test_ssl_wrap_socket_with_no_sni_warns(self): - socket = object() - mock_context = Mock() - # Ugly preservation of original value - HAS_SNI = ssl_.HAS_SNI - ssl_.HAS_SNI = False - try: - with patch("warnings.warn") as warn: - ssl_wrap_socket( - ssl_context=mock_context, - sock=socket, - server_hostname="www.google.com", - ) - mock_context.wrap_socket.assert_called_once_with(socket) - assert warn.call_count >= 1 - warnings = [call[0][1] for call in warn.call_args_list] - assert SNIMissingWarning in warnings - finally: - ssl_.HAS_SNI = HAS_SNI - def test_const_compare_digest_fallback(self): target = hashlib.sha256(b"abcdef").digest() assert _const_compare_digest_backport(target, target) @@ -838,3 +747,118 @@ class TestUtil(object): def test_assert_header_parsing_throws_typeerror_with_non_headers(self, headers): with pytest.raises(TypeError): assert_header_parsing(headers) + + +class TestUtilSSL(object): + """Test utils that use an SSL backend.""" + + @pytest.mark.parametrize( + "candidate, requirements", + [ + (None, ssl.CERT_REQUIRED), + (ssl.CERT_NONE, ssl.CERT_NONE), + (ssl.CERT_REQUIRED, ssl.CERT_REQUIRED), + ("REQUIRED", ssl.CERT_REQUIRED), + ("CERT_REQUIRED", ssl.CERT_REQUIRED), + ], + ) + def test_resolve_cert_reqs(self, candidate, requirements): + assert resolve_cert_reqs(candidate) == requirements + + @pytest.mark.parametrize( + "candidate, version", + [ + (ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1), + ("PROTOCOL_TLSv1", ssl.PROTOCOL_TLSv1), + ("TLSv1", ssl.PROTOCOL_TLSv1), + (ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23), + ], + ) + def test_resolve_ssl_version(self, candidate, version): + assert resolve_ssl_version(candidate) == version + + def test_ssl_wrap_socket_loads_the_cert_chain(self): + socket = object() + mock_context = Mock() + ssl_wrap_socket( + ssl_context=mock_context, sock=socket, certfile="/path/to/certfile" + ) + + mock_context.load_cert_chain.assert_called_once_with("/path/to/certfile", None) + + @patch("urllib3.util.ssl_.create_urllib3_context") + def test_ssl_wrap_socket_creates_new_context(self, create_urllib3_context): + socket = object() + ssl_wrap_socket(sock=socket, cert_reqs="CERT_REQUIRED") + + create_urllib3_context.assert_called_once_with( + None, "CERT_REQUIRED", ciphers=None + ) + + def test_ssl_wrap_socket_loads_verify_locations(self): + socket = object() + mock_context = Mock() + ssl_wrap_socket(ssl_context=mock_context, ca_certs="/path/to/pem", sock=socket) + mock_context.load_verify_locations.assert_called_once_with( + "/path/to/pem", None, None + ) + + def test_ssl_wrap_socket_loads_certificate_directories(self): + socket = object() + mock_context = Mock() + ssl_wrap_socket( + ssl_context=mock_context, ca_cert_dir="/path/to/pems", sock=socket + ) + mock_context.load_verify_locations.assert_called_once_with( + None, "/path/to/pems", None + ) + + def test_ssl_wrap_socket_loads_certificate_data(self): + socket = object() + mock_context = Mock() + ssl_wrap_socket( + ssl_context=mock_context, ca_cert_data="TOTALLY PEM DATA", sock=socket + ) + mock_context.load_verify_locations.assert_called_once_with( + None, None, "TOTALLY PEM DATA" + ) + + def _wrap_socket_and_mock_warn(self, sock, server_hostname): + mock_context = Mock() + with patch("warnings.warn") as warn: + ssl_wrap_socket( + ssl_context=mock_context, sock=sock, server_hostname=server_hostname, + ) + return mock_context, warn + + def test_ssl_wrap_socket_sni_hostname_use_or_warn(self): + """Test that either an SNI hostname is used or a warning is made.""" + sock = object() + context, warn = self._wrap_socket_and_mock_warn(sock, "www.google.com") + if util.HAS_SNI: + warn.assert_not_called() + context.wrap_socket.assert_called_once_with( + sock, server_hostname="www.google.com" + ) + else: + assert warn.call_count >= 1 + warnings = [call[0][1] for call in warn.call_args_list] + assert SNIMissingWarning in warnings + context.wrap_socket.assert_called_once_with(sock) + + def test_ssl_wrap_socket_sni_ip_address_no_warn(self): + """Test that a warning is not made if server_hostname is an IP address.""" + sock = object() + context, warn = self._wrap_socket_and_mock_warn(sock, "8.8.8.8") + if util.IS_SECURETRANSPORT: + context.wrap_socket.assert_called_once_with(sock, server_hostname="8.8.8.8") + else: + context.wrap_socket.assert_called_once_with(sock) + warn.assert_not_called() + + def test_ssl_wrap_socket_sni_none_no_warn(self): + """Test that a warning is not made if server_hostname is not given.""" + sock = object() + context, warn = self._wrap_socket_and_mock_warn(sock, None) + context.wrap_socket.assert_called_once_with(sock) + warn.assert_not_called() |
