diff --git a/doc/changelog.rst b/doc/changelog.rst index b61bedec7..709325862 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -9,6 +9,9 @@ Highlights: - Increase the performance of :meth:`~pymongo.mongo_client.MongoClient.database_names` by using the `nameOnly` option for listDatabases when available. +- Username and password can be passed to + :class:`~pymongo.mongo_client.MongoClient` as keyword arguments. Before, the + only way to pass them was in the URI. Changes and Deprecations: diff --git a/pymongo/common.py b/pymongo/common.py index cd4584d39..d0d1ea7dc 100644 --- a/pymongo/common.py +++ b/pymongo/common.py @@ -508,7 +508,9 @@ KW_VALIDATORS = { 'document_class': validate_document_class, 'read_preference': validate_read_preference, 'event_listeners': _validate_event_listeners, - 'tzinfo': validate_tzinfo + 'tzinfo': validate_tzinfo, + 'username': validate_string, + 'password': validate_string, } URI_VALIDATORS.update(TIMEOUT_VALIDATORS) diff --git a/pymongo/mongo_client.py b/pymongo/mongo_client.py index ef8d0d430..d364a0a28 100644 --- a/pymongo/mongo_client.py +++ b/pymongo/mongo_client.py @@ -259,6 +259,30 @@ class MongoClient(common.BaseObject): is set, it must be a positive integer greater than or equal to 90 seconds. + | **Authentication:** + + - `username`: A string. + - `password`: A string. + + Although username and password must be percent-escaped in a MongoDB + URI, they must not be percent-escaped when passed as parameters. In + this example, both the space and slash special characters are passed + as-is:: + + MongoClient(username="user name", password="pass/word") + + - `authSource`: The database to authenticate on. Defaults to the + database specified in the URI, if provided, or to "admin". + - `authMechanism`: See :data:`~pymongo.auth.MECHANISMS` for options. + By default, use SCRAM-SHA-1 with MongoDB 3.0 and later, MONGODB-CR + (MongoDB Challenge Response protocol) for older servers. + - `authMechanismProperties`: Used to specify authentication mechanism + specific options. To specify the service name for GSSAPI + authentication pass authMechanismProperties='SERVICE_NAME:' + + .. seealso:: :doc:`/examples/authentication` + | **SSL configuration:** - `ssl`: If ``True``, create the connection to the server using SSL. @@ -312,6 +336,11 @@ class MongoClient(common.BaseObject): .. mongodoc:: connections + .. versionchanged:: 3.5 + Add ``username`` and ``password`` options. Document the + ``authSource``, ``authMechanism``, and ``authMechanismProperties `` + options. + .. versionchanged:: 3.0 :class:`~pymongo.mongo_client.MongoClient` is now the one and only client class for a standalone server, mongos, or replica set. @@ -421,6 +450,9 @@ class MongoClient(common.BaseObject): keyword_opts = dict(common.validate(k, v) for k, v in keyword_opts.items()) opts.update(keyword_opts) + # Username and password passed as kwargs override user info in URI. + username = opts.get("username", username) + password = opts.get("password", password) self.__options = options = ClientOptions( username, password, dbase, opts) diff --git a/test/test_client.py b/test/test_client.py index 90aa50b68..55f653152 100644 --- a/test/test_client.py +++ b/test/test_client.py @@ -592,6 +592,16 @@ class TestClient(IntegrationTest): self.assertRaises(OperationFailure, bad_client.pymongo_test.test.find_one) + @client_context.require_auth + def test_username_and_password(self): + self.client.admin.add_user("ad min", "pa/ss", roles=["root"]) + self.addCleanup(self.client.admin.remove_user, "ad min") + + rs_or_single_client(username="ad min", password="pa/ss").server_info() + + with self.assertRaises(OperationFailure): + rs_or_single_client(username="ad min", password="foo").server_info() + @client_context.require_auth def test_multiple_logins(self): self.client.pymongo_test.add_user('user1', 'pass', roles=['readWrite'])