Skip to content

Commit b7c49ba

Browse files
Snow 2355881 Add CERT_REVOCATION_CHECK_MODE to CLIENT_ENVIRONMENT (#2562)
1 parent d6113ba commit b7c49ba

File tree

14 files changed

+77
-18
lines changed

14 files changed

+77
-18
lines changed

DESCRIPTION.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
88

99
# Release Notes
1010
- v4.1.0(TBD)
11+
- Added `CERT_REVOCATION_CHECK_MODE` to `CLIENT_ENVIRONMENT`
1112

1213
- v4.0.0(October 01,2025)
1314
- Added support for checking certificates revocation using revocation lists (CRLs)

src/snowflake/connector/auth/_auth.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ def base_auth_data(
101101
internal_application_name,
102102
internal_application_version,
103103
ocsp_mode,
104+
cert_revocation_check_mode,
104105
login_timeout: int | None = None,
105106
network_timeout: int | None = None,
106107
socket_timeout: int | None = None,
@@ -123,6 +124,7 @@ def base_auth_data(
123124
"PYTHON_RUNTIME": IMPLEMENTATION,
124125
"PYTHON_COMPILER": COMPILER,
125126
"OCSP_MODE": ocsp_mode.name,
127+
"CERT_REVOCATION_CHECK_MODE": cert_revocation_check_mode,
126128
"TRACING": logger.getEffectiveLevel(),
127129
"LOGIN_TIMEOUT": login_timeout,
128130
"NETWORK_TIMEOUT": network_timeout,
@@ -183,6 +185,7 @@ def authenticate(
183185
self._rest._connection._internal_application_name,
184186
self._rest._connection._internal_application_version,
185187
self._rest._connection._ocsp_mode(),
188+
self._rest._connection.cert_revocation_check_mode,
186189
self._rest._connection.login_timeout,
187190
self._rest._connection._network_timeout,
188191
self._rest._connection._socket_timeout,

src/snowflake/connector/auth/okta.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ def _step1(
166166
conn._internal_application_name,
167167
conn._internal_application_version,
168168
conn._ocsp_mode(),
169+
conn.cert_revocation_check_mode,
169170
conn.login_timeout,
170171
conn.network_timeout,
171172
conn.socket_timeout,

src/snowflake/connector/auth/webbrowser.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,7 @@ def _get_sso_url(
460460
conn._internal_application_name,
461461
conn._internal_application_version,
462462
conn._ocsp_mode(),
463+
conn.cert_revocation_check_mode,
463464
conn.login_timeout,
464465
conn.network_timeout,
465466
conn.socket_timeout,

src/snowflake/connector/connection.py

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
QueryStatus,
8888
)
8989
from .converter import SnowflakeConverter
90+
from .crl import CRLConfig
9091
from .cursor import LOG_MAX_QUERY_LENGTH, SnowflakeCursor, SnowflakeCursorBase
9192
from .description import (
9293
CLIENT_NAME,
@@ -438,7 +439,7 @@ def _get_private_bytes_from_file(
438439
), # Read timeout for CRL downloads in milliseconds
439440
"crl_cache_validity_hours": (
440441
None,
441-
(type(None), int),
442+
(type(None), float),
442443
), # CRL cache validity time in hours
443444
"enable_crl_cache": (None, (type(None), bool)), # Enable CRL caching
444445
"enable_crl_file_cache": (None, (type(None), bool)), # Enable file-based CRL cache
@@ -592,6 +593,7 @@ def __init__(
592593

593594
# Placeholder attributes; will be initialized in connect()
594595
self._http_config: HttpConfig | None = None
596+
self._crl_config: CRLConfig | None = None
595597
self._session_manager: SessionManager | None = None
596598
self._rest: SnowflakeRestful | None = None
597599

@@ -688,57 +690,81 @@ def _ocsp_mode(self) -> OCSPMode:
688690
@property
689691
def cert_revocation_check_mode(self) -> str | None:
690692
"""Certificate revocation check mode: DISABLED, ENABLED, or ADVISORY."""
691-
return self._cert_revocation_check_mode
693+
if not self._crl_config:
694+
return self._cert_revocation_check_mode
695+
return self._crl_config.cert_revocation_check_mode.value
692696

693697
@property
694698
def allow_certificates_without_crl_url(self) -> bool | None:
695699
"""Whether to allow certificates without CRL distribution points."""
696-
return self._allow_certificates_without_crl_url
700+
if not self._crl_config:
701+
return self._allow_certificates_without_crl_url
702+
return self._crl_config.allow_certificates_without_crl_url
697703

698704
@property
699705
def crl_connection_timeout_ms(self) -> int | None:
700706
"""Connection timeout for CRL downloads in milliseconds."""
701-
return self._crl_connection_timeout_ms
707+
if not self._crl_config:
708+
return self._crl_connection_timeout_ms
709+
return self._crl_config.connection_timeout_ms
702710

703711
@property
704712
def crl_read_timeout_ms(self) -> int | None:
705713
"""Read timeout for CRL downloads in milliseconds."""
706-
return self._crl_read_timeout_ms
714+
if not self._crl_config:
715+
return self._crl_read_timeout_ms
716+
return self._crl_config.read_timeout_ms
707717

708718
@property
709-
def crl_cache_validity_hours(self) -> int | None:
719+
def crl_cache_validity_hours(self) -> float | None:
710720
"""CRL cache validity time in hours."""
711-
return self._crl_cache_validity_hours
721+
if not self._crl_config:
722+
return self._crl_cache_validity_hours
723+
return self._crl_config.cache_validity_time.total_seconds() / 3600
712724

713725
@property
714726
def enable_crl_cache(self) -> bool | None:
715727
"""Whether CRL caching is enabled."""
716-
return self._enable_crl_cache
728+
if not self._crl_config:
729+
return self._enable_crl_cache
730+
return self._crl_config.enable_crl_cache
717731

718732
@property
719733
def enable_crl_file_cache(self) -> bool | None:
720734
"""Whether file-based CRL cache is enabled."""
721-
return self._enable_crl_file_cache
735+
if not self._crl_config:
736+
return self._enable_crl_file_cache
737+
return self._crl_config.enable_crl_file_cache
722738

723739
@property
724740
def crl_cache_dir(self) -> str | None:
725741
"""Directory for CRL file cache."""
726-
return self._crl_cache_dir
742+
if not self._crl_config:
743+
return self._crl_cache_dir
744+
if not self._crl_config.crl_cache_dir:
745+
return None
746+
return str(self._crl_config.crl_cache_dir)
727747

728748
@property
729749
def crl_cache_removal_delay_days(self) -> int | None:
730750
"""Days to keep expired CRL files before removal."""
731-
return self._crl_cache_removal_delay_days
751+
if not self._crl_config:
752+
return self._crl_cache_removal_delay_days
753+
return self._crl_config.crl_cache_removal_delay_days
732754

733755
@property
734756
def crl_cache_cleanup_interval_hours(self) -> int | None:
735757
"""CRL cache cleanup interval in hours."""
736-
return self._crl_cache_cleanup_interval_hours
758+
if not self._crl_config:
759+
return self._crl_cache_cleanup_interval_hours
760+
return self._crl_config.crl_cache_cleanup_interval_hours
737761

738762
@property
739763
def crl_cache_start_cleanup(self) -> bool | None:
740764
"""Whether to start CRL cache cleanup immediately."""
741-
return self._crl_cache_start_cleanup
765+
if not self._crl_config:
766+
return self._crl_cache_start_cleanup
767+
return self._crl_config.crl_cache_start_cleanup
742768

743769
@property
744770
def session_id(self) -> int:
@@ -1041,6 +1067,8 @@ def connect(self, **kwargs) -> None:
10411067
if len(kwargs) > 0:
10421068
self.__config(**kwargs)
10431069

1070+
self._crl_config: CRLConfig = CRLConfig.from_connection(self)
1071+
10441072
self._http_config = HttpConfig(
10451073
adapter_factory=ProxySupportAdapterFactory(),
10461074
use_pooling=(not self.disable_request_pooling),

src/snowflake/connector/crl.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,11 @@ def from_connection(cls, sf_connection) -> CRLConfig:
105105
)
106106
cert_revocation_check_mode = cls.cert_revocation_check_mode
107107

108-
if cert_revocation_check_mode == CertRevocationCheckMode.DISABLED:
109-
# The rest of the parameters don't matter if CRL checking is disabled
110-
return cls(cert_revocation_check_mode=cert_revocation_check_mode)
111-
112108
# Apply default value logic for all other parameters when connection attribute is None
113109
cache_validity_time = (
114110
cls.cache_validity_time
115111
if sf_connection.crl_cache_validity_hours is None
116-
else timedelta(hours=int(sf_connection.crl_cache_validity_hours))
112+
else timedelta(hours=float(sf_connection.crl_cache_validity_hours))
117113
)
118114
crl_cache_dir = (
119115
cls.crl_cache_dir

test/helpers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ def create_mock_auth_body():
277277
"internal_application_name",
278278
"internal_application_version",
279279
ocsp_mode,
280+
"CRL_MODE",
280281
login_timeout=60 * 60,
281282
network_timeout=60 * 60,
282283
socket_timeout=60 * 60,

test/integ/test_crl.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ def test_crl_validation_advisory_mode(conn_cnx):
6363
assert cnx.cert_revocation_check_mode == "ADVISORY"
6464
assert cnx.allow_certificates_without_crl_url is False
6565
assert cnx.enable_crl_cache is True
66+
assert cnx.crl_connection_timeout_ms == 3000
67+
assert cnx.crl_read_timeout_ms == 3000
68+
assert cnx.crl_cache_validity_hours == 1
69+
assert cnx.crl_cache_dir is None
6670

6771

6872
@pytest.mark.skipolddriver

test/unit/test_auth.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def _init_rest(application, post_requset):
4242
connection = mock_connection()
4343
connection.errorhandler = Mock(return_value=None)
4444
connection._ocsp_mode = Mock(return_value=OCSPMode.FAIL_OPEN)
45+
connection.cert_revocation_check_mode = "TEST_CRL_MODE"
4546
type(connection).application = PropertyMock(return_value=application)
4647
type(connection)._internal_application_name = PropertyMock(return_value=CLIENT_NAME)
4748
type(connection)._internal_application_version = PropertyMock(

test/unit/test_auth_keypair.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ def _init_rest(application, post_requset):
155155
connection = mock_connection()
156156
connection.errorhandler = Mock(return_value=None)
157157
connection._ocsp_mode = Mock(return_value=OCSPMode.FAIL_OPEN)
158+
connection.cert_revocation_check_mode = "TEST_CRL_MODE"
158159
type(connection).application = PropertyMock(return_value=application)
159160
type(connection)._internal_application_name = PropertyMock(return_value=CLIENT_NAME)
160161
type(connection)._internal_application_version = PropertyMock(

0 commit comments

Comments
 (0)