Skip to content

Commit 8d6fdc5

Browse files
committed
connection: require cert validation for hostname checks
1 parent 9d63584 commit 8d6fdc5

3 files changed

Lines changed: 15 additions & 3 deletions

File tree

cassandra/connection.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656

5757
log = logging.getLogger(__name__)
5858

59-
6059
segment_codec_no_compression = SegmentCodec()
6160
segment_codec_lz4 = None
6261

@@ -1208,14 +1207,17 @@ def _build_ssl_context_from_options(self):
12081207
# being explicit
12091208
ssl_version = opts.get('ssl_version', None) or ssl.PROTOCOL_TLS_CLIENT
12101209
cert_reqs = opts.get('cert_reqs', None)
1210+
check_hostname = bool(opts.get('check_hostname', False))
12111211
if cert_reqs is None:
12121212
cert_reqs = (ssl.CERT_REQUIRED
12131213
if self.ssl_options
12141214
else ssl.CERT_NONE)
1215+
elif check_hostname and cert_reqs == ssl.CERT_NONE:
1216+
cert_reqs = ssl.CERT_REQUIRED
12151217
rv = ssl.SSLContext(protocol=int(ssl_version))
12161218
rv.check_hostname = False
12171219
rv.verify_mode = cert_reqs
1218-
rv.check_hostname = bool(opts.get('check_hostname', False))
1220+
rv.check_hostname = check_hostname
12191221

12201222
certfile = opts.get('certfile', None)
12211223
keyfile = opts.get('keyfile', None)

tests/unit/test_cloud.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright DataStax, Inc.
1+
# Copyright 2026 ScyllaDB, Inc.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.

tests/unit/test_connection.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,16 @@ def test_ssl_options_check_hostname_requires_validation(self):
257257
assert c.ssl_context.check_hostname
258258
assert c._check_hostname
259259

260+
def test_ssl_options_check_hostname_promotes_cert_none_to_cert_required(self):
261+
c = Connection(
262+
DefaultEndPoint('1.2.3.4'),
263+
ssl_options={'cert_reqs': ssl.CERT_NONE, 'check_hostname': True})
264+
265+
assert isinstance(c.ssl_context, ssl.SSLContext)
266+
assert c.ssl_context.verify_mode == ssl.CERT_REQUIRED
267+
assert c.ssl_context.check_hostname
268+
assert c._check_hostname
269+
260270
def test_bad_protocol_version(self, *args):
261271
c = self.make_connection()
262272
c._requests = Mock()

0 commit comments

Comments
 (0)