Prevent duplicate default SSLContext instances (#105348)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
vexofp 2023-12-09 16:30:12 -05:00 committed by GitHub
parent a090bcb8a5
commit 885410bcfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 12 deletions

View File

@ -61,16 +61,11 @@ SSL_CIPHER_LISTS = {
@cache
def create_no_verify_ssl_context(
ssl_cipher_list: SSLCipherList = SSLCipherList.PYTHON_DEFAULT,
) -> ssl.SSLContext:
"""Return an SSL context that does not verify the server certificate.
def _create_no_verify_ssl_context(ssl_cipher_list: SSLCipherList) -> ssl.SSLContext:
# This is a copy of aiohttp's create_default_context() function, with the
# ssl verify turned off.
# https://github.com/aio-libs/aiohttp/blob/33953f110e97eecc707e1402daa8d543f38a189b/aiohttp/connector.py#L911
This is a copy of aiohttp's create_default_context() function, with the
ssl verify turned off.
https://github.com/aio-libs/aiohttp/blob/33953f110e97eecc707e1402daa8d543f38a189b/aiohttp/connector.py#L911
"""
sslcontext = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
sslcontext.check_hostname = False
sslcontext.verify_mode = ssl.CERT_NONE
@ -84,12 +79,16 @@ def create_no_verify_ssl_context(
return sslcontext
@cache
def client_context(
def create_no_verify_ssl_context(
ssl_cipher_list: SSLCipherList = SSLCipherList.PYTHON_DEFAULT,
) -> ssl.SSLContext:
"""Return an SSL context for making requests."""
"""Return an SSL context that does not verify the server certificate."""
return _create_no_verify_ssl_context(ssl_cipher_list=ssl_cipher_list)
@cache
def _client_context(ssl_cipher_list: SSLCipherList) -> ssl.SSLContext:
# Reuse environment variable definition from requests, since it's already a
# requirement. If the environment variable has no value, fall back to using
# certs from certifi package.
@ -104,6 +103,14 @@ def client_context(
return sslcontext
def client_context(
ssl_cipher_list: SSLCipherList = SSLCipherList.PYTHON_DEFAULT,
) -> ssl.SSLContext:
"""Return an SSL context for making requests."""
return _client_context(ssl_cipher_list=ssl_cipher_list)
# Create this only once and reuse it
_DEFAULT_SSL_CONTEXT = client_context()
_DEFAULT_NO_VERIFY_SSL_CONTEXT = create_no_verify_ssl_context()

View File

@ -51,3 +51,12 @@ def test_no_verify_ssl_context(mock_sslcontext) -> None:
mock_sslcontext.set_ciphers.assert_called_with(
SSL_CIPHER_LISTS[SSLCipherList.INTERMEDIATE]
)
def test_ssl_context_caching() -> None:
"""Test that SSLContext instances are cached correctly."""
assert client_context() is client_context(SSLCipherList.PYTHON_DEFAULT)
assert create_no_verify_ssl_context() is create_no_verify_ssl_context(
SSLCipherList.PYTHON_DEFAULT
)