MongoClient respects _connect=False even with auth PYTHON-516

This commit is contained in:
A. Jesse Jiryu Davis 2013-05-10 14:32:17 -04:00
parent 81b6e1fa3a
commit 7667c10ded
2 changed files with 84 additions and 32 deletions

View File

@ -350,7 +350,7 @@ class MongoClient(common.BaseObject):
credentials = (source, unicode(username),
unicode(password), mechanism)
try:
self._cache_credentials(source, credentials)
self._cache_credentials(source, credentials, _connect)
except OperationFailure, exc:
raise ConfigurationError(str(exc))
@ -407,9 +407,10 @@ class MongoClient(common.BaseObject):
if index_name in self.__index_cache[database_name][collection_name]:
del self.__index_cache[database_name][collection_name][index_name]
def _cache_credentials(self, source, credentials):
def _cache_credentials(self, source, credentials, connect=True):
"""Add credentials to the database authentication cache
for automatic login when a socket is created.
for automatic login when a socket is created. If `connect` is True,
verify the credentials on the server first.
"""
if source in self.__auth_credentials:
# Nothing to do if we already have these credentials.
@ -418,14 +419,15 @@ class MongoClient(common.BaseObject):
raise OperationFailure('Another user is already authenticated '
'to this database. You must logout first.')
sock_info = self.__socket()
try:
# Since __check_auth was called in __socket
# there is no need to call it here.
auth.authenticate(credentials, sock_info, self.__simple_command)
sock_info.authset.add(credentials)
finally:
self.__pool.maybe_return_socket(sock_info)
if connect:
sock_info = self.__socket()
try:
# Since __check_auth was called in __socket
# there is no need to call it here.
auth.authenticate(credentials, sock_info, self.__simple_command)
sock_info.authset.add(credentials)
finally:
self.__pool.maybe_return_socket(sock_info)
self.__auth_credentials[source] = credentials

View File

@ -37,7 +37,8 @@ from pymongo import thread_util
from pymongo.errors import (ConfigurationError,
ConnectionFailure,
InvalidName,
OperationFailure)
OperationFailure,
PyMongoError)
from test import version, host, port
from test.utils import (assertRaisesExactly,
delay,
@ -76,6 +77,35 @@ class TestClient(unittest.TestCase, TestRequestMixin):
MongoClient.PORT = port
self.assertTrue(MongoClient())
def test_init_disconnected(self):
c = MongoClient(host, port, _connect=False)
# No errors
c.is_primary
c.is_mongos
c.max_pool_size
c.use_greenlets
c.nodes
c.auto_start_request
c.get_document_class()
c.tz_aware
c.max_bson_size
self.assertEqual(None, c.host)
self.assertEqual(None, c.port)
c.pymongo_test.test.find_one() # Auto-connect.
self.assertEqual(host, c.host)
self.assertEqual(port, c.port)
bad_host = "somedomainthatdoesntexist.org"
c = MongoClient(bad_host, port, connectTimeoutMS=1,_connect=False)
self.assertRaises(ConnectionFailure, c.pymongo_test.test.find_one)
def test_init_disconnected_with_auth(self):
uri = "mongodb://user:pass@somedomainthatdoesntexist"
c = MongoClient(uri, connectTimeoutMS=1, _connect=False)
self.assertRaises(ConnectionFailure, c.pymongo_test.test.find_one)
def test_connect(self):
# Check that the exception is a ConnectionFailure, not a subclass like
# AutoReconnect
@ -272,29 +302,49 @@ class TestClient(unittest.TestCase, TestRequestMixin):
c.admin.system.users.remove({})
c.pymongo_test.system.users.remove({})
c.admin.add_user("admin", "pass")
c.admin.authenticate("admin", "pass")
c.pymongo_test.add_user("user", "pass")
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://foo:bar@%s:%d" % (host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://admin:bar@%s:%d" % (host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://user:pass@%s:%d" % (host, port))
MongoClient("mongodb://admin:pass@%s:%d" % (host, port))
try:
c.admin.add_user("admin", "pass")
c.admin.authenticate("admin", "pass")
c.pymongo_test.add_user("user", "pass")
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://admin:pass@%s:%d/pymongo_test" %
(host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://user:foo@%s:%d/pymongo_test" %
(host, port))
MongoClient("mongodb://user:pass@%s:%d/pymongo_test" %
(host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://foo:bar@%s:%d" % (host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://admin:bar@%s:%d" % (host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://user:pass@%s:%d" % (host, port))
MongoClient("mongodb://admin:pass@%s:%d" % (host, port))
c.admin.system.users.remove({})
c.pymongo_test.system.users.remove({})
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://admin:pass@%s:%d/pymongo_test" %
(host, port))
self.assertRaises(ConfigurationError, MongoClient,
"mongodb://user:foo@%s:%d/pymongo_test" %
(host, port))
MongoClient("mongodb://user:pass@%s:%d/pymongo_test" %
(host, port))
# Auth with lazy connection.
MongoClient(
"mongodb://user:pass@%s:%d/pymongo_test" % (host, port),
_connect=False).pymongo_test.test.find_one()
# Wrong password.
bad_client = MongoClient(
"mongodb://user:wrong@%s:%d/pymongo_test" % (host, port),
_connect=False)
# If auth fails with lazy connection, MongoClient raises
# AutoReconnect instead of the more appropriate OperationFailure,
# PYTHON-517.
self.assertRaises(
PyMongoError, bad_client.pymongo_test.test.find_one)
finally:
# Clean up.
c.admin.system.users.remove({})
c.pymongo_test.system.users.remove({})
def test_unix_socket(self):
if not hasattr(socket, "AF_UNIX"):