Skip to content

Commit 7667c10

Browse files
author
A. Jesse Jiryu Davis
committed
MongoClient respects _connect=False even with auth PYTHON-516
1 parent 81b6e1f commit 7667c10

File tree

2 files changed

+86
-34
lines changed

2 files changed

+86
-34
lines changed

pymongo/mongo_client.py

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ def __init__(self, host=None, port=None, max_pool_size=10,
350350
credentials = (source, unicode(username),
351351
unicode(password), mechanism)
352352
try:
353-
self._cache_credentials(source, credentials)
353+
self._cache_credentials(source, credentials, _connect)
354354
except OperationFailure, exc:
355355
raise ConfigurationError(str(exc))
356356

@@ -407,9 +407,10 @@ def _purge_index(self, database_name,
407407
if index_name in self.__index_cache[database_name][collection_name]:
408408
del self.__index_cache[database_name][collection_name][index_name]
409409

410-
def _cache_credentials(self, source, credentials):
410+
def _cache_credentials(self, source, credentials, connect=True):
411411
"""Add credentials to the database authentication cache
412-
for automatic login when a socket is created.
412+
for automatic login when a socket is created. If `connect` is True,
413+
verify the credentials on the server first.
413414
"""
414415
if source in self.__auth_credentials:
415416
# Nothing to do if we already have these credentials.
@@ -418,14 +419,15 @@ def _cache_credentials(self, source, credentials):
418419
raise OperationFailure('Another user is already authenticated '
419420
'to this database. You must logout first.')
420421

421-
sock_info = self.__socket()
422-
try:
423-
# Since __check_auth was called in __socket
424-
# there is no need to call it here.
425-
auth.authenticate(credentials, sock_info, self.__simple_command)
426-
sock_info.authset.add(credentials)
427-
finally:
428-
self.__pool.maybe_return_socket(sock_info)
422+
if connect:
423+
sock_info = self.__socket()
424+
try:
425+
# Since __check_auth was called in __socket
426+
# there is no need to call it here.
427+
auth.authenticate(credentials, sock_info, self.__simple_command)
428+
sock_info.authset.add(credentials)
429+
finally:
430+
self.__pool.maybe_return_socket(sock_info)
429431

430432
self.__auth_credentials[source] = credentials
431433

test/test_client.py

Lines changed: 73 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
from pymongo.errors import (ConfigurationError,
3838
ConnectionFailure,
3939
InvalidName,
40-
OperationFailure)
40+
OperationFailure,
41+
PyMongoError)
4142
from test import version, host, port
4243
from test.utils import (assertRaisesExactly,
4344
delay,
@@ -76,6 +77,35 @@ def test_constants(self):
7677
MongoClient.PORT = port
7778
self.assertTrue(MongoClient())
7879

80+
def test_init_disconnected(self):
81+
c = MongoClient(host, port, _connect=False)
82+
83+
# No errors
84+
c.is_primary
85+
c.is_mongos
86+
c.max_pool_size
87+
c.use_greenlets
88+
c.nodes
89+
c.auto_start_request
90+
c.get_document_class()
91+
c.tz_aware
92+
c.max_bson_size
93+
self.assertEqual(None, c.host)
94+
self.assertEqual(None, c.port)
95+
96+
c.pymongo_test.test.find_one() # Auto-connect.
97+
self.assertEqual(host, c.host)
98+
self.assertEqual(port, c.port)
99+
100+
bad_host = "somedomainthatdoesntexist.org"
101+
c = MongoClient(bad_host, port, connectTimeoutMS=1,_connect=False)
102+
self.assertRaises(ConnectionFailure, c.pymongo_test.test.find_one)
103+
104+
def test_init_disconnected_with_auth(self):
105+
uri = "mongodb://user:pass@somedomainthatdoesntexist"
106+
c = MongoClient(uri, connectTimeoutMS=1, _connect=False)
107+
self.assertRaises(ConnectionFailure, c.pymongo_test.test.find_one)
108+
79109
def test_connect(self):
80110
# Check that the exception is a ConnectionFailure, not a subclass like
81111
# AutoReconnect
@@ -272,29 +302,49 @@ def test_auth_from_uri(self):
272302

273303
c.admin.system.users.remove({})
274304
c.pymongo_test.system.users.remove({})
275-
c.admin.add_user("admin", "pass")
276-
c.admin.authenticate("admin", "pass")
277-
c.pymongo_test.add_user("user", "pass")
278-
279-
self.assertRaises(ConfigurationError, MongoClient,
280-
"mongodb://foo:bar@%s:%d" % (host, port))
281-
self.assertRaises(ConfigurationError, MongoClient,
282-
"mongodb://admin:bar@%s:%d" % (host, port))
283-
self.assertRaises(ConfigurationError, MongoClient,
284-
"mongodb://user:pass@%s:%d" % (host, port))
285-
MongoClient("mongodb://admin:pass@%s:%d" % (host, port))
286-
287-
self.assertRaises(ConfigurationError, MongoClient,
288-
"mongodb://admin:pass@%s:%d/pymongo_test" %
289-
(host, port))
290-
self.assertRaises(ConfigurationError, MongoClient,
291-
"mongodb://user:foo@%s:%d/pymongo_test" %
292-
(host, port))
293-
MongoClient("mongodb://user:pass@%s:%d/pymongo_test" %
294-
(host, port))
295305

296-
c.admin.system.users.remove({})
297-
c.pymongo_test.system.users.remove({})
306+
try:
307+
c.admin.add_user("admin", "pass")
308+
c.admin.authenticate("admin", "pass")
309+
c.pymongo_test.add_user("user", "pass")
310+
311+
self.assertRaises(ConfigurationError, MongoClient,
312+
"mongodb://foo:bar@%s:%d" % (host, port))
313+
self.assertRaises(ConfigurationError, MongoClient,
314+
"mongodb://admin:bar@%s:%d" % (host, port))
315+
self.assertRaises(ConfigurationError, MongoClient,
316+
"mongodb://user:pass@%s:%d" % (host, port))
317+
MongoClient("mongodb://admin:pass@%s:%d" % (host, port))
318+
319+
self.assertRaises(ConfigurationError, MongoClient,
320+
"mongodb://admin:pass@%s:%d/pymongo_test" %
321+
(host, port))
322+
self.assertRaises(ConfigurationError, MongoClient,
323+
"mongodb://user:foo@%s:%d/pymongo_test" %
324+
(host, port))
325+
MongoClient("mongodb://user:pass@%s:%d/pymongo_test" %
326+
(host, port))
327+
328+
# Auth with lazy connection.
329+
MongoClient(
330+
"mongodb://user:pass@%s:%d/pymongo_test" % (host, port),
331+
_connect=False).pymongo_test.test.find_one()
332+
333+
# Wrong password.
334+
bad_client = MongoClient(
335+
"mongodb://user:wrong@%s:%d/pymongo_test" % (host, port),
336+
_connect=False)
337+
338+
# If auth fails with lazy connection, MongoClient raises
339+
# AutoReconnect instead of the more appropriate OperationFailure,
340+
# PYTHON-517.
341+
self.assertRaises(
342+
PyMongoError, bad_client.pymongo_test.test.find_one)
343+
344+
finally:
345+
# Clean up.
346+
c.admin.system.users.remove({})
347+
c.pymongo_test.system.users.remove({})
298348

299349
def test_unix_socket(self):
300350
if not hasattr(socket, "AF_UNIX"):

0 commit comments

Comments
 (0)