Skip to content

Commit 6a5a8b9

Browse files
committed
Support MongoDB 2.4 options in add_user.
1 parent bc6368d commit 6a5a8b9

File tree

3 files changed

+70
-7
lines changed

3 files changed

+70
-7
lines changed

pymongo/database.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ def __iter__(self):
606606
def next(self):
607607
raise TypeError("'Database' object is not iterable")
608608

609-
def add_user(self, name, password, read_only=False):
609+
def add_user(self, name, password=None, read_only=None, **kwargs):
610610
"""Create user `name` with password `password`.
611611
612612
Add a new user with permissions for this :class:`Database`.
@@ -615,8 +615,17 @@ def add_user(self, name, password, read_only=False):
615615
616616
:Parameters:
617617
- `name`: the name of the user to create
618-
- `password`: the password of the user to create
619-
- `read_only` (optional): if ``True`` it will make user read only
618+
- `password` (optional): the password of the user to create. Can not
619+
be used with the ``userSource`` argument.
620+
- `read_only` (optional): if ``True`` the user will be read only
621+
- `**kwargs` (optional): optional parameters for the user document
622+
(e.g. ``userSource``, ``otherDBRoles``, or ``roles``)
623+
624+
.. note:: The use of optional keyword arguments like ``userSource``,
625+
``otherDBRoles``, or ``roles`` requires MongoDB >= 2.4.0
626+
627+
.. versionchanged:: 2.5
628+
Added kwargs support for optional fields introduced in MongoDB 2.4
620629
621630
.. versionchanged:: 2.2
622631
Added support for read only users
@@ -625,8 +634,11 @@ def add_user(self, name, password, read_only=False):
625634
"""
626635

627636
user = self.system.users.find_one({"user": name}) or {"user": name}
628-
user["pwd"] = auth._password_digest(name, password)
629-
user["readOnly"] = common.validate_boolean('read_only', read_only)
637+
if password is not None:
638+
user["pwd"] = auth._password_digest(name, password)
639+
if read_only is not None:
640+
user["readOnly"] = common.validate_boolean('read_only', read_only)
641+
user.update(kwargs)
630642

631643
try:
632644
self.system.users.save(user, **self._get_wc_override())

test/test_auth.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,5 +193,57 @@ def test_uri_options(self):
193193
self.assertTrue(client.pymongo_test.command('dbstats'))
194194

195195

196+
class TestDelegatedAuth(unittest.TestCase):
197+
198+
def setUp(self):
199+
self.client = MongoClient(host, port)
200+
if not version.at_least(self.client, (2, 4, 0)):
201+
raise SkipTest('Delegated authentication requires MongoDB >= 2.4.0')
202+
if not server_started_with_auth(self.client):
203+
raise SkipTest('Authentication is not enabled on server')
204+
# Give admin all priviledges.
205+
self.client.admin.add_user('admin', 'pass',
206+
roles=['readAnyDatabase',
207+
'readWriteAnyDatabase',
208+
'userAdminAnyDatabase',
209+
'dbAdminAnyDatabase',
210+
'clusterAdmin'])
211+
212+
def tearDown(self):
213+
self.client.admin.authenticate('admin', 'pass')
214+
self.client.pymongo_test.system.users.remove()
215+
self.client.pymongo_test2.system.users.remove()
216+
self.client.pymongo_test2.foo.remove()
217+
self.client.admin.system.users.remove()
218+
self.client.admin.logout()
219+
220+
def test_delegated_auth(self):
221+
self.client.admin.authenticate('admin', 'pass')
222+
self.client.pymongo_test2.foo.remove()
223+
self.client.pymongo_test2.foo.insert({})
224+
# User definition with no roles in pymongo_test.
225+
self.client.pymongo_test.add_user('user', 'pass', roles=[])
226+
# Delegate auth to pymongo_test.
227+
self.client.pymongo_test2.add_user('user',
228+
userSource='pymongo_test',
229+
roles=['read'])
230+
self.client.admin.logout()
231+
self.assertRaises(OperationFailure, self.client.pymongo_test2.foo.find_one)
232+
# Auth must occur on the db where the user is defined.
233+
self.assertFalse(self.client.pymongo_test2.authenticate('user', 'pass'))
234+
# Auth directly
235+
self.assertTrue(self.client.pymongo_test.authenticate('user', 'pass'))
236+
self.assertTrue(self.client.pymongo_test2.foo.find_one())
237+
self.client.pymongo_test.logout()
238+
self.assertRaises(OperationFailure, self.client.pymongo_test2.foo.find_one)
239+
# Auth using source
240+
self.assertTrue(self.client.pymongo_test2.authenticate(
241+
'user', 'pass', source='pymongo_test'))
242+
self.assertTrue(self.client.pymongo_test2.foo.find_one())
243+
# Must logout from the db authenticate was called on.
244+
self.client.pymongo_test2.logout()
245+
self.assertRaises(OperationFailure, self.client.pymongo_test2.foo.find_one)
246+
247+
196248
if __name__ == "__main__":
197249
unittest.main()

test/test_database.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,9 +309,8 @@ def test_authenticate_add_remove_user(self):
309309
db.system.users.remove({})
310310
db.remove_user("mike")
311311

312-
self.assertRaises(TypeError, db.add_user, "user", None)
313312
self.assertRaises(TypeError, db.add_user, "user", '')
314-
self.assertRaises(TypeError, db.add_user, "user", 'password', None)
313+
self.assertRaises(TypeError, db.add_user, "user", 'password', 15)
315314
self.assertRaises(ConfigurationError, db.add_user,
316315
"user", 'password', 'True')
317316

0 commit comments

Comments
 (0)