Skip to content

Commit 6d1ebf4

Browse files
authored
PYTHON-2798 Workaround windows cert issue with SSL_CERT_FILE (#670)
1 parent 948ebb2 commit 6d1ebf4

File tree

4 files changed

+79
-60
lines changed

4 files changed

+79
-60
lines changed

.evergreen/run-tests.sh

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,13 +146,15 @@ if [ -n "$TEST_ENCRYPTION" ]; then
146146
. $DRIVERS_TOOLS/.evergreen/csfle/set-temp-creds.sh
147147

148148
# Start the mock KMS servers.
149-
if [ "$OS" != "Windows_NT" ]; then
150-
pushd ${DRIVERS_TOOLS}/.evergreen/csfle
151-
python -u lib/kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 &
152-
python -u lib/kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 &
153-
trap 'kill $(jobs -p)' EXIT HUP
154-
popd
149+
if [ "$OS" = "Windows_NT" ]; then
150+
# Remove after BUILD-13574.
151+
python -m pip install certifi
155152
fi
153+
pushd ${DRIVERS_TOOLS}/.evergreen/csfle
154+
python -u lib/kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/expired.pem --port 8000 &
155+
python -u lib/kms_http_server.py --ca_file ../x509gen/ca.pem --cert_file ../x509gen/wrong-host.pem --port 8001 &
156+
trap 'kill $(jobs -p)' EXIT HUP
157+
popd
156158
fi
157159

158160
if [ -z "$DATA_LAKE" ]; then

test/__init__.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
from pymongo import common, message
5050
from pymongo.common import partition_node
5151
from pymongo.server_api import ServerApi
52-
from pymongo.ssl_support import HAVE_SSL, validate_cert_reqs
52+
from pymongo.ssl_support import HAVE_SSL, _ssl
5353
from pymongo.uri_parser import parse_uri
5454
from test.version import Version
5555

@@ -898,6 +898,10 @@ def setUpClass(cls):
898898
else:
899899
cls.credentials = {}
900900

901+
def patch_system_certs(self, ca_certs):
902+
patcher = SystemCertsPatcher(ca_certs)
903+
self.addCleanup(patcher.disable)
904+
901905

902906
# Use assertRaisesRegex if available, otherwise use Python 2.7's
903907
# deprecated assertRaisesRegexp, with a 'p'.
@@ -1043,3 +1047,21 @@ def clear_warning_registry():
10431047
for name, module in list(sys.modules.items()):
10441048
if hasattr(module, "__warningregistry__"):
10451049
setattr(module, "__warningregistry__", {})
1050+
1051+
1052+
class SystemCertsPatcher(object):
1053+
def __init__(self, ca_certs):
1054+
if (ssl.OPENSSL_VERSION.lower().startswith('libressl') and
1055+
sys.platform == 'darwin' and not _ssl.IS_PYOPENSSL):
1056+
raise SkipTest(
1057+
"LibreSSL on OSX doesn't support setting CA certificates "
1058+
"using SSL_CERT_FILE environment variable.")
1059+
self.original_certs = os.environ.get('SSL_CERT_FILE')
1060+
# Tell OpenSSL where CA certificates live.
1061+
os.environ['SSL_CERT_FILE'] = ca_certs
1062+
1063+
def disable(self):
1064+
if self.original_certs is None:
1065+
os.environ.pop('SSL_CERT_FILE')
1066+
else:
1067+
os.environ['SSL_CERT_FILE'] = self.original_certs

test/test_encryption.py

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import os
2020
import traceback
2121
import socket
22-
import ssl
2322
import sys
2423
import textwrap
2524
import uuid
@@ -50,10 +49,14 @@
5049
WriteError)
5150
from pymongo.mongo_client import MongoClient
5251
from pymongo.operations import InsertOne
53-
from pymongo.ssl_support import _ssl
5452
from pymongo.write_concern import WriteConcern
53+
from test.test_ssl import CA_PEM
5554

56-
from test import unittest, IntegrationTest, PyMongoTestCase, client_context
55+
from test import (unittest,
56+
client_context,
57+
IntegrationTest,
58+
PyMongoTestCase,
59+
SystemCertsPatcher)
5760
from test.utils import (TestCreator,
5861
camel_to_snake_args,
5962
OvertCommandListener,
@@ -62,7 +65,26 @@
6265
rs_or_single_client,
6366
wait_until)
6467
from test.utils_spec_runner import SpecRunner
65-
from test.test_ssl import CA_PEM
68+
69+
try:
70+
import certifi
71+
HAVE_CERTIFI = True
72+
except ImportError:
73+
HAVE_CERTIFI = False
74+
75+
patcher = None
76+
77+
78+
def setUpModule():
79+
if sys.platform == 'win32' and HAVE_CERTIFI:
80+
# Remove after BUILD-13574.
81+
global patcher
82+
patcher = SystemCertsPatcher(certifi.where())
83+
84+
85+
def tearDownModule():
86+
if patcher:
87+
patcher.disable()
6688

6789

6890
def get_client_opts(client):
@@ -1629,25 +1651,11 @@ def test_bypassAutoEncryption(self):
16291651

16301652
# https://github.com/mongodb/specifications/tree/master/source/client-side-encryption/tests#kms-tls-tests
16311653
class TestKmsTLSProse(EncryptionIntegrationTest):
1632-
@unittest.skipIf(sys.platform == 'win32',
1633-
"Can't test system ca certs on Windows")
1634-
@unittest.skipIf(ssl.OPENSSL_VERSION.lower().startswith('libressl') and
1635-
sys.platform == 'darwin' and not _ssl.IS_PYOPENSSL,
1636-
"LibreSSL on OSX doesn't support setting CA certificates "
1637-
"using SSL_CERT_FILE environment variable.")
16381654
@unittest.skipUnless(any(AWS_CREDS.values()),
16391655
'AWS environment credentials are not set')
16401656
def setUp(self):
1641-
self.original_certs = os.environ.get('SSL_CERT_FILE')
1642-
def restore_certs():
1643-
if self.original_certs is None:
1644-
os.environ.pop('SSL_CERT_FILE')
1645-
else:
1646-
os.environ['SSL_CERT_FILE'] = self.original_certs
1647-
# Tell OpenSSL where CA certificates live.
1648-
os.environ['SSL_CERT_FILE'] = CA_PEM
1649-
self.addCleanup(restore_certs)
1650-
1657+
super(TestKmsTLSProse, self).setUp()
1658+
self.patch_system_certs(CA_PEM)
16511659
self.client_encrypted = ClientEncryption(
16521660
{'aws': AWS_CREDS}, 'keyvault.datakeys', self.client, OPTS)
16531661
self.addCleanup(self.client_encrypted.close)

test/test_ssl.py

Lines changed: 20 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -449,45 +449,32 @@ def test_validation_with_system_ca_certs(self):
449449
# --sslCAFile=/path/to/pymongo/test/certificates/ca.pem
450450
# --sslWeakCertificateValidation
451451
#
452-
if sys.platform == "win32":
453-
raise SkipTest("Can't test system ca certs on Windows.")
454-
455-
if (ssl.OPENSSL_VERSION.lower().startswith('libressl') and
456-
sys.platform == 'darwin' and not _ssl.IS_PYOPENSSL):
457-
raise SkipTest(
458-
"LibreSSL on OSX doesn't support setting CA certificates "
459-
"using SSL_CERT_FILE environment variable.")
460-
461-
# Tell OpenSSL where CA certificates live.
462-
os.environ['SSL_CERT_FILE'] = CA_PEM
463-
try:
464-
with self.assertRaises(ConnectionFailure):
465-
# Server cert is verified but hostname matching fails
466-
connected(MongoClient('server',
467-
ssl=True,
468-
serverSelectionTimeoutMS=100,
469-
**self.credentials))
470-
471-
# Server cert is verified. Disable hostname matching.
452+
self.patch_system_certs(CA_PEM)
453+
with self.assertRaises(ConnectionFailure):
454+
# Server cert is verified but hostname matching fails
472455
connected(MongoClient('server',
473456
ssl=True,
474-
ssl_match_hostname=False,
475457
serverSelectionTimeoutMS=100,
476458
**self.credentials))
477459

478-
# Server cert and hostname are verified.
479-
connected(MongoClient('localhost',
480-
ssl=True,
481-
serverSelectionTimeoutMS=100,
482-
**self.credentials))
460+
# Server cert is verified. Disable hostname matching.
461+
connected(MongoClient('server',
462+
ssl=True,
463+
ssl_match_hostname=False,
464+
serverSelectionTimeoutMS=100,
465+
**self.credentials))
483466

484-
# Server cert and hostname are verified.
485-
connected(
486-
MongoClient(
487-
'mongodb://localhost/?ssl=true&serverSelectionTimeoutMS=100',
488-
**self.credentials))
489-
finally:
490-
os.environ.pop('SSL_CERT_FILE')
467+
# Server cert and hostname are verified.
468+
connected(MongoClient('localhost',
469+
ssl=True,
470+
serverSelectionTimeoutMS=100,
471+
**self.credentials))
472+
473+
# Server cert and hostname are verified.
474+
connected(
475+
MongoClient(
476+
'mongodb://localhost/?ssl=true&serverSelectionTimeoutMS=100',
477+
**self.credentials))
491478

492479
def test_system_certs_config_error(self):
493480
ctx = get_ssl_context(

0 commit comments

Comments
 (0)