Add non-shared ssl client_context (#142653)

This commit is contained in:
Mathijs van de Nes 2025-04-11 22:55:05 +02:00 committed by GitHub
parent 4f0ece1bb4
commit b20f46e8b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 44 additions and 2 deletions

View File

@ -82,10 +82,10 @@ def _client_context_no_verify(ssl_cipher_list: SSLCipherList) -> ssl.SSLContext:
return sslcontext
@cache
def _client_context(
def _create_client_context(
ssl_cipher_list: SSLCipherList = SSLCipherList.PYTHON_DEFAULT,
) -> ssl.SSLContext:
"""Return an independent SSL context for making requests."""
# 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.
@ -100,6 +100,14 @@ def _client_context(
return sslcontext
@cache
def _client_context(
ssl_cipher_list: SSLCipherList = SSLCipherList.PYTHON_DEFAULT,
) -> ssl.SSLContext:
# Cached version of _create_client_context
return _create_client_context(ssl_cipher_list)
# Create this only once and reuse it
_DEFAULT_SSL_CONTEXT = _client_context(SSLCipherList.PYTHON_DEFAULT)
_DEFAULT_NO_VERIFY_SSL_CONTEXT = _client_context_no_verify(SSLCipherList.PYTHON_DEFAULT)
@ -139,6 +147,14 @@ def client_context(
return _SSL_CONTEXTS.get(ssl_cipher_list, _DEFAULT_SSL_CONTEXT)
def create_client_context(
ssl_cipher_list: SSLCipherList = SSLCipherList.PYTHON_DEFAULT,
) -> ssl.SSLContext:
"""Return an independent SSL context for making requests."""
# This explicitly uses the non-cached version to create a client context
return _create_client_context(ssl_cipher_list)
def create_no_verify_ssl_context(
ssl_cipher_list: SSLCipherList = SSLCipherList.PYTHON_DEFAULT,
) -> ssl.SSLContext:

View File

@ -7,6 +7,7 @@ import pytest
from homeassistant.util.ssl import (
SSLCipherList,
client_context,
create_client_context,
create_no_verify_ssl_context,
)
@ -56,3 +57,28 @@ def test_ssl_context_caching() -> None:
assert create_no_verify_ssl_context() is create_no_verify_ssl_context(
SSLCipherList.PYTHON_DEFAULT
)
def test_cteate_client_context(mock_sslcontext) -> None:
"""Test create client context."""
with patch("homeassistant.util.ssl.ssl.SSLContext", return_value=mock_sslcontext):
client_context()
mock_sslcontext.set_ciphers.assert_not_called()
client_context(SSLCipherList.MODERN)
mock_sslcontext.set_ciphers.assert_not_called()
client_context(SSLCipherList.INTERMEDIATE)
mock_sslcontext.set_ciphers.assert_not_called()
client_context(SSLCipherList.INSECURE)
mock_sslcontext.set_ciphers.assert_not_called()
def test_create_client_context_independent() -> None:
"""Test create_client_context independence."""
shared_context = client_context()
independent_context_1 = create_client_context()
independent_context_2 = create_client_context()
assert shared_context is not independent_context_1
assert independent_context_1 is not independent_context_2