diff --git a/homeassistant/util/ssl.py b/homeassistant/util/ssl.py index a22fd0c8fb4..4e26a126f39 100644 --- a/homeassistant/util/ssl.py +++ b/homeassistant/util/ssl.py @@ -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: diff --git a/tests/util/test_ssl.py b/tests/util/test_ssl.py index c0cd2fdba10..0c30ad9b9b3 100644 --- a/tests/util/test_ssl.py +++ b/tests/util/test_ssl.py @@ -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