Skip to content

Commit dd14d35

Browse files
committed
Fix up SSL tests.
Tests shouldn't fail if python doesn't have an ssl module. Other changes include: - Document how to test all this (i.e. how to start the server for these tests to run) - Don't do requirements testing in setUp since it's run before every method. - Move the "no ssl module" test into it's own test class
1 parent 8536acb commit dd14d35

File tree

1 file changed

+107
-96
lines changed

1 file changed

+107
-96
lines changed

test/test_ssl.py

Lines changed: 107 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -25,51 +25,96 @@
2525
from pymongo import MongoClient, MongoReplicaSetClient
2626
from pymongo.common import HAS_SSL
2727
from pymongo.errors import ConfigurationError, ConnectionFailure
28+
from test import host, port, pair
2829

29-
if HAS_SSL:
30-
import ssl
3130

3231
CERT_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)),
3332
'certificates')
3433
CLIENT_PEM = os.path.join(CERT_PATH, 'client.pem')
3534
CA_PEM = os.path.join(CERT_PATH, 'ca.pem')
35+
SIMPLE_SSL = False
36+
CERT_SSL = False
37+
SERVER_IS_RESOLVABLE = False
38+
39+
# To fully test this start a mongod instance (built with SSL support) like so:
40+
# mongod --dbpath /path/to/data/directory --sslOnNormalPorts \
41+
# --sslPEMKeyFile /path/to/mongo/jstests/libs/server.pem \
42+
# --sslCAFile /path/to/mongo/jstests/libs/ca.pem \
43+
# --sslWeakCertificateValidation
44+
# Also, make sure you have 'server' as an alias for localhost in /etc/hosts
45+
#
46+
# Note: For all tests to pass with MongoReplicaSetConnection the replica
47+
# set configuration must use 'server' for the hostname of all hosts.
3648

37-
38-
def has_server_host_entry():
49+
def is_server_resolvable():
3950
"""Returns True if 'server' is resolvable."""
4051
socket_timeout = socket.getdefaulttimeout()
4152
socket.setdefaulttimeout(1)
4253
try:
43-
socket.gethostbyname('server')
44-
has_server_host_entry = True
45-
except:
46-
has_server_host_entry = False
47-
socket.setdefaulttimeout(socket_timeout)
48-
return has_server_host_entry
54+
try:
55+
socket.gethostbyname('server')
56+
return True
57+
except socket.error:
58+
return False
59+
finally:
60+
socket.setdefaulttimeout(socket_timeout)
61+
62+
63+
if HAS_SSL:
64+
import ssl
65+
66+
# Check this all once instead of before every test method below.
67+
68+
# Is MongoDB configured for SSL?
69+
try:
70+
MongoClient(host, port, connectTimeoutMS=100, ssl=True)
71+
SIMPLE_SSL = True
72+
except ConnectionFailure:
73+
pass
74+
75+
if SIMPLE_SSL:
76+
# Is MongoDB configured with server.pem and ca.pem from
77+
# mongodb jstests/lib?
78+
try:
79+
MongoClient(host, port, connectTimeoutMS=100, ssl=True,
80+
ssl_certfile=CLIENT_PEM)
81+
CERT_SSL = True
82+
except ConnectionFailure:
83+
pass
84+
85+
if CERT_SSL:
86+
SERVER_IS_RESOLVABLE = is_server_resolvable()
87+
88+
89+
class TestNoSSLModule(unittest.TestCase):
90+
91+
def test_no_ssl_module(self):
92+
# Test that ConfigurationError is raised if the ssl
93+
# module isn't available.
94+
if HAS_SSL:
95+
raise SkipTest(
96+
"The ssl module is available, can't test what happens "
97+
"without it."
98+
)
99+
100+
self.assertRaises(ConfigurationError,
101+
MongoClient, ssl=True)
102+
self.assertRaises(ConfigurationError,
103+
MongoReplicaSetClient, ssl=True)
49104

50105

51106
class TestSSL(unittest.TestCase):
52107

53108
def setUp(self):
109+
if not HAS_SSL:
110+
raise SkipTest("The ssl module is not available.")
111+
54112
if sys.version.startswith('3.0'):
55113
raise SkipTest("Python 3.0.x has problems "
56114
"with SSL and socket timeouts.")
57115

58-
# MongoDB not configured for SSL?
59-
try:
60-
MongoClient(connectTimeoutMS=100, ssl=True)
61-
self.simple_ssl = True
62-
except ConnectionFailure:
63-
self.simple_ssl = False
64-
65-
# MongoDB configured with server.pem, ca.pem and crl.pem from
66-
# mongodb jstests/lib
67-
try:
68-
MongoClient(connectTimeoutMS=100, ssl=True,
69-
ssl_certfile=CLIENT_PEM)
70-
self.cert_ssl = True
71-
except ConnectionFailure:
72-
self.cert_ssl = False
116+
if not SIMPLE_SSL:
117+
raise SkipTest("No simple mongod available over SSL")
73118

74119
def test_config_ssl(self):
75120
"""Tests various ssl configurations"""
@@ -135,42 +180,22 @@ def test_config_ssl(self):
135180
ssl_keyfile=CLIENT_PEM,
136181
ssl_certfile=CLIENT_PEM)
137182

138-
def test_no_ssl(self):
139-
# Tests what happens when ssl is off on the server but you try to
140-
# connect to mongodb with ssl=True
141-
142-
if HAS_SSL:
143-
raise SkipTest(
144-
"The ssl module is available, can't test what happens "
145-
"without it."
146-
)
147-
148-
self.assertRaises(ConfigurationError,
149-
MongoClient, ssl=True)
150-
self.assertRaises(ConfigurationError,
151-
MongoReplicaSetClient, ssl=True)
152-
153183
def test_simple_ssl(self):
154184
# Expects the server to be running with ssl and with
155185
# no --sslPEMKeyFile or with --sslWeakCertificateValidation
156-
157-
if not HAS_SSL:
158-
raise SkipTest("The ssl module is not available.")
159-
160-
if not self.simple_ssl:
161-
raise SkipTest("No simple mongod available over SSL")
162-
163-
client = MongoClient(ssl=True)
186+
client = MongoClient(host, port, ssl=True)
164187
response = client.admin.command('ismaster')
165188
if 'setName' in response:
166-
client = MongoReplicaSetClient(replicaSet=response['setName'],
189+
client = MongoReplicaSetClient(pair,
190+
replicaSet=response['setName'],
167191
w=len(response['hosts']),
168192
ssl=True)
169193

170194
db = client.pymongo_ssl_test
171195
db.test.drop()
172196
self.assertTrue(db.test.insert({'ssl': True}))
173197
self.assertTrue(db.test.find_one()['ssl'])
198+
client.drop_database('pymongo_ssl_test')
174199

175200
def test_cert_ssl(self):
176201
# Expects the server to be running with the the server.pem, ca.pem
@@ -181,24 +206,22 @@ def test_cert_ssl(self):
181206
# --sslCRLFile=jstests/libs/crl.pem
182207
#
183208
# Also requires an /etc/hosts entry where "server" is resolvable
184-
185-
if not HAS_SSL:
186-
raise SkipTest("The ssl module is not available.")
187-
188-
if not self.cert_ssl:
209+
if not CERT_SSL:
189210
raise SkipTest("No mongod available over SSL with certs")
190211

191-
client = MongoClient(ssl=True, ssl_certfile=CLIENT_PEM)
212+
client = MongoClient(host, port, ssl=True, ssl_certfile=CLIENT_PEM)
192213
response = client.admin.command('ismaster')
193214
if 'setName' in response:
194-
client = MongoReplicaSetClient(replicaSet=response['setName'],
215+
client = MongoReplicaSetClient(pair,
216+
replicaSet=response['setName'],
195217
w=len(response['hosts']),
196218
ssl=True, ssl_certfile=CLIENT_PEM)
197219

198220
db = client.pymongo_ssl_test
199221
db.test.drop()
200222
self.assertTrue(db.test.insert({'ssl': True}))
201223
self.assertTrue(db.test.find_one()['ssl'])
224+
client.drop_database('pymongo_ssl_test')
202225

203226
def test_cert_ssl_implicitly_set(self):
204227
# Expects the server to be running with the the server.pem, ca.pem
@@ -209,24 +232,22 @@ def test_cert_ssl_implicitly_set(self):
209232
# --sslCRLFile=jstests/libs/crl.pem
210233
#
211234
# Also requires an /etc/hosts entry where "server" is resolvable
212-
213-
if not HAS_SSL:
214-
raise SkipTest("The ssl module is not available.")
215-
216-
if not self.cert_ssl:
235+
if not CERT_SSL:
217236
raise SkipTest("No mongod available over SSL with certs")
218237

219-
client = MongoClient(ssl_certfile=CLIENT_PEM)
238+
client = MongoClient(host, port, ssl_certfile=CLIENT_PEM)
220239
response = client.admin.command('ismaster')
221240
if 'setName' in response:
222-
client = MongoReplicaSetClient(replicaSet=response['setName'],
241+
client = MongoReplicaSetClient(pair,
242+
replicaSet=response['setName'],
223243
w=len(response['hosts']),
224244
ssl_certfile=CLIENT_PEM)
225245

226246
db = client.pymongo_ssl_test
227247
db.test.drop()
228248
self.assertTrue(db.test.insert({'ssl': True}))
229249
self.assertTrue(db.test.find_one()['ssl'])
250+
client.drop_database('pymongo_ssl_test')
230251

231252
def test_cert_ssl_validation(self):
232253
# Expects the server to be running with the the server.pem, ca.pem
@@ -237,15 +258,11 @@ def test_cert_ssl_validation(self):
237258
# --sslCRLFile=jstests/libs/crl.pem
238259
#
239260
# Also requires an /etc/hosts entry where "server" is resolvable
240-
241-
if not HAS_SSL:
242-
raise SkipTest("The ssl module is not available.")
243-
244-
if not self.cert_ssl:
261+
if not CERT_SSL:
245262
raise SkipTest("No mongod available over SSL with certs")
246263

247-
if not has_server_host_entry():
248-
raise SkipTest("No hosts entry for 'server' cannot validate "
264+
if not SERVER_IS_RESOLVABLE:
265+
raise SkipTest("No hosts entry for 'server'. Cannot validate "
249266
"hostname in the certificate")
250267

251268
client = MongoClient('server',
@@ -267,6 +284,7 @@ def test_cert_ssl_validation(self):
267284
db.test.drop()
268285
self.assertTrue(db.test.insert({'ssl': True}))
269286
self.assertTrue(db.test.find_one()['ssl'])
287+
client.drop_database('pymongo_ssl_test')
270288

271289
def test_cert_ssl_validation_optional(self):
272290
# Expects the server to be running with the the server.pem, ca.pem
@@ -277,15 +295,11 @@ def test_cert_ssl_validation_optional(self):
277295
# --sslCRLFile=jstests/libs/crl.pem
278296
#
279297
# Also requires an /etc/hosts entry where "server" is resolvable
280-
281-
if not HAS_SSL:
282-
raise SkipTest("The ssl module is not available.")
283-
284-
if not self.cert_ssl:
298+
if not CERT_SSL:
285299
raise SkipTest("No mongod available over SSL with certs")
286300

287-
if not has_server_host_entry():
288-
raise SkipTest("No hosts entry for 'server' cannot validate "
301+
if not SERVER_IS_RESOLVABLE:
302+
raise SkipTest("No hosts entry for 'server'. Cannot validate "
289303
"hostname in the certificate")
290304

291305
client = MongoClient('server',
@@ -307,6 +321,7 @@ def test_cert_ssl_validation_optional(self):
307321
db.test.drop()
308322
self.assertTrue(db.test.insert({'ssl': True}))
309323
self.assertTrue(db.test.find_one()['ssl'])
324+
client.drop_database('pymongo_ssl_test')
310325

311326
def test_cert_ssl_validation_hostname_fail(self):
312327
# Expects the server to be running with the the server.pem, ca.pem
@@ -315,36 +330,32 @@ def test_cert_ssl_validation_hostname_fail(self):
315330
# --sslPEMKeyFile=jstests/libs/server.pem
316331
# --sslCAFile=jstests/libs/ca.pem
317332
# --sslCRLFile=jstests/libs/crl.pem
318-
319-
if not HAS_SSL:
320-
raise SkipTest("The ssl module is not available.")
321-
322-
if not self.cert_ssl:
333+
if not CERT_SSL:
323334
raise SkipTest("No mongod available over SSL with certs")
324335

325336
client = MongoClient(ssl=True, ssl_certfile=CLIENT_PEM)
326337
response = client.admin.command('ismaster')
327-
singleServer = 'setName' not in response
338+
single_server = 'setName' not in response
328339

329-
if singleServer:
340+
if single_server:
330341
try:
331-
MongoClient('localhost',
332-
ssl=True,
333-
ssl_certfile=CLIENT_PEM,
334-
ssl_cert_reqs=ssl.CERT_REQUIRED,
335-
ssl_ca_certs=CA_PEM)
342+
MongoClient(pair,
343+
ssl=True,
344+
ssl_certfile=CLIENT_PEM,
345+
ssl_cert_reqs=ssl.CERT_REQUIRED,
346+
ssl_ca_certs=CA_PEM)
336347
self.fail("Invalid hostname should have failed")
337348
except:
338349
pass
339350
else:
340351
try:
341-
MongoReplicaSetClient('localhost',
342-
replicaSet=response['setName'],
343-
w=len(response['hosts']),
344-
ssl=True,
345-
ssl_certfile=CLIENT_PEM,
346-
ssl_cert_reqs=ssl.CERT_OPTIONAL,
347-
ssl_ca_certs=CA_PEM)
352+
MongoReplicaSetClient(pair,
353+
replicaSet=response['setName'],
354+
w=len(response['hosts']),
355+
ssl=True,
356+
ssl_certfile=CLIENT_PEM,
357+
ssl_cert_reqs=ssl.CERT_OPTIONAL,
358+
ssl_ca_certs=CA_PEM)
348359
self.fail("Invalid hostname should have failed")
349360
except:
350361
pass

0 commit comments

Comments
 (0)