diff --git a/kazoo/client.py b/kazoo/client.py index 3f302d3f..6e788d7b 100644 --- a/kazoo/client.py +++ b/kazoo/client.py @@ -183,6 +183,8 @@ def __init__( :param use_ssl: argument to control whether SSL is used or not :param verify_certs: when using SSL, argument to bypass certs verification + :param check_hostname: when using SSL, check the hostname + against the hostname in the cert Basic Example: diff --git a/kazoo/handlers/utils.py b/kazoo/handlers/utils.py index 47c82290..3989451a 100644 --- a/kazoo/handlers/utils.py +++ b/kazoo/handlers/utils.py @@ -239,10 +239,10 @@ def create_tcp_connection( # Load default CA certs context.load_default_certs(ssl.Purpose.SERVER_AUTH) + if check_hostname and not verify_certs: + raise ValueError("Error, if check_hostname is specified, verify_certs must be False") # We must set check_hostname to False prior to setting # verify_mode to CERT_NONE. - # TODO: Make hostname verification configurable as some users may - # elect to use it. context.check_hostname = check_hostname context.verify_mode = ( ssl.CERT_REQUIRED if verify_certs else ssl.CERT_NONE diff --git a/kazoo/tests/test_utils.py b/kazoo/tests/test_utils.py index 5ff6bb03..43644bee 100644 --- a/kazoo/tests/test_utils.py +++ b/kazoo/tests/test_utils.py @@ -32,7 +32,7 @@ def test_timeout_arg(self): def test_ssl_server_hostname(self): from kazoo.handlers import utils - from kazoo.handlers.utils import create_tcp_connection, ssl + from kazoo.handlers.utils import create_tcp_connection, socket, ssl with patch.object(utils, "_set_default_tcpsock_options"): with patch.object(ssl.SSLContext, "wrap_socket") as wrap_socket: @@ -48,6 +48,40 @@ def test_ssl_server_hostname(self): server_hostname = call_args[1]["server_hostname"] assert server_hostname == "fakehostname" + def test_ssl_server_check_hostname(self): + from kazoo.handlers import utils + from kazoo.handlers.utils import create_tcp_connection, socket, ssl + + with patch.object(utils, "_set_default_tcpsock_options"): + with patch.object(ssl.SSLContext, "wrap_socket", autospec=True) as wrap_socket: + create_tcp_connection( + socket, + ("127.0.0.1", 2181), + timeout=1.5, + hostname="fakehostname", + use_ssl=True, + check_hostname=True + ) + + for call_args in wrap_socket.call_args_list: + ssl_context = call_args[0][0] + assert ssl_context.check_hostname == True + + def test_ssl_server_check_hostname_config_validation(self): + from kazoo.handlers import utils + from kazoo.handlers.utils import create_tcp_connection, socket, ssl + + with pytest.raises(ValueError): + create_tcp_connection( + socket, + ("127.0.0.1", 2181), + timeout=1.5, + hostname="fakehostname", + use_ssl=True, + verify_certs=False, + check_hostname=True + ) + def test_timeout_arg_eventlet(self): if not EVENTLET_HANDLER_AVAILABLE: pytest.skip("eventlet handler not available.")