snowflakedb / snowflakedb/snowflake-connector-python
SNOW-4108603: Vendored urllib3 triggers pyOpenSSL X509.get_subject DeprecationWarning
@sfc-gh-snow-drivers-warsaw-dl is already working on this.
Since Sep 14, 2026.
- Dominant language
- Python
- Stars
- 730
- Forks
- 574
- Avg merge
- 5h 45m
- Merged PRs (30d)
- 16
Description
Python version
Python 3.14.7 (main, Aug 14 2026, 15:24:10) [Clang 22.1.3 ]
Operating system and processor architecture
macOS-26.6.2-arm64-arm-64bit-Mach-O
Installed packages
certifi==2026.5.20
cffi==2.0.0
cryptography==50.0.1
pyopenssl==26.4.0
requests==2.33.1
snowflake-connector-python==4.7.1
snowflake-sqlalchemy==1.11.0
urllib3==2.7.0
What did you do?
Any successful TLS connection to Snowflake now emits a `DeprecationWarning`.
# python -W error::DeprecationWarning repro.py
import snowflake.connector
snowflake.connector.connect(
account="<account>",
user="<user>",
private_key_file="<path>",
)
Offline reproduction that exercises the exact code path without credentials:
import datetime
from types import SimpleNamespace
from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID
from OpenSSL import crypto
from snowflake.connector.vendored.urllib3.contrib import pyopenssl
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
name = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, "example.snowflakecomputing.com")])
now = datetime.datetime.now(datetime.UTC)
cert = (
x509.CertificateBuilder()
.subject_name(name)
.issuer_name(name)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(now)
.not_valid_after(now + datetime.timedelta(days=1))
.sign(key, hashes.SHA256())
)
fake_socket = SimpleNamespace(
connection=SimpleNamespace(get_peer_certificate=lambda: crypto.X509.from_cryptography(cert)),
)
pyopenssl.WrappedSocket.getpeercert(fake_socket, binary_form=False)
$ python -W error::DeprecationWarning repro_offline.py
File ".../snowflake/connector/vendored/urllib3/contrib/pyopenssl.py", line 397, in getpeercert
"subject": ((("commonName", x509.get_subject().CN),),),
DeprecationWarning: X509.get_subject is deprecated. You should use cryptography's X.509 APIs instead.
What did you expect to see?
Connecting should not emit deprecation warnings from code the connector vendors.
What happens instead: since 4.6.0, ssl_wrap_socket.py runs _verify_hostname_after_handshake(), which calls wrapped_socket.getpeercert() on the vendored urllib3.contrib.pyopenssl.WrappedSocket. That method builds the subject entry with x509.get_subject().CN. pyOpenSSL 26.x deprecates X509.get_subject and X509Name, so every connection now warns. Under -W error the connection raises:
conftest.py:151: in setup_snowflake_test_db
with target_engine.begin() as target_conn:
...
snowflake/connector/connection.py:1219: in connect
self.__open_connection()
snowflake/connector/connection.py:1660: in __open_connection
self.authenticate_with_retry(self.auth_class)
...
snowflake/connector/network.py:1121: in _request_exec
raw_ret = session.request(
...
snowflake/connector/vendored/urllib3/connection.py:984: in _ssl_wrap_socket_and_match_hostname
ssl_sock = ssl_wrap_socket(
snowflake/connector/ssl_wrap_socket.py:315: in ssl_wrap_socket_with_cert_revocation_checks
_verify_hostname_after_handshake(ret, server_hostname, params.get("ssl_context"))
snowflake/connector/ssl_wrap_socket.py:270: in _verify_hostname_after_handshake
cert = wrapped_socket.getpeercert()
snowflake/connector/vendored/urllib3/contrib/pyopenssl.py:397: in getpeercert
"subject": ((("commonName", x509.get_subject().CN),),), # type: ignore[dict-item]
E DeprecationWarning: X509.get_subject is deprecated. You should use cryptography's X.509 APIs instead.
4.5.0 did not call getpeercert() on this path, so the deprecated API was never reached even with pyOpenSSL 26.4.0 installed.
urllib3 already fixed this on main (unreleased as of 2.7.0): getpeercert now uses a _get_common_name(x509) helper based on x509.to_cryptography().subject.get_attributes_for_oid(NameOID.COMMON_NAME). See https://github.com/urllib3/urllib3/blob/5f2a6a843d0100d1351c3f94d58581ca98d17267/src/urllib3/contrib/pyopenssl.py#L417. Suggested fix: backport that change into the vendored copy (or read the common name via to_cryptography() in _verify_hostname_after_handshake), so the connector stays clean once X509Name is removed from pyOpenSSL.
Can you set logging to DEBUG and collect the logs?
not necessary
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.