Repository: celery/celery

Issue:
Celery does not consider authSource on mongodb backend URLs
Version: Celery 4.0.2 (from looking at the changes since then it seems there is no change addressing this issue here: https://github.com/celery/celery/commits/master/celery/backends/mongodb.py )

(Edit) Confirmed with the following versions as well:
amqp==2.2.2
billiard==3.5.0.3
celery==4.1.0
kombu==4.1.0
pymongo==3.6.0

Celery Report

software -> celery:4.0.2 (latentcall) kombu:4.0.2 py:2.7.8
            billiard:3.5.0.3 py-amqp:2.2.1
platform -> system:Linux arch:64bit, ELF imp:CPython
loader   -> celery.loaders.default.Loader
settings -> transport:amqp results:disabled


## Steps to reproduce

Give Celery a Backend URL pointing to a MongoDB instance with authentication and username/password (user/pwd set on the Admin DB by default) in the format:

mongodb://user:pass@your-server/your_db?authSource=admin

(Please see http://api.mongodb.com/python/current/examples/authentication.html#default-database-and-authsource and http://api.mongodb.com/python/current/api/pymongo/mongo_client.html?highlight=authsource )

## Expected behavior

Celery authenticates the user in the admin database (this is the same as passing --authenticationDatabase to the mongo client or the same url to MongoClient)

## Actual behavior

Celery tries to authenticate the user on the your_db database (failing to authenticate)

## Workaround (not recommended)

Change the db on the URL to /admin (this db shouldn't be used to store arbitrary data normally)


Discussion:
Workaround ; 

create a user specific to the database you are using in Mongo.  
In mongo shell 
 1. use dbname
 2.  db.createUser( { user: "user",
                 pwd: "passwd",
                 roles:[ "readWrite", "dbAdmin" ] }
               )

3. set the backend url 
 mongodb://user:passwd@192.168.0.100:27017/dbname

Hello,

This limitation doesn't allow to use MongoDB Atlas as result_backend a huge limitation.

Could you please add the authSource options and update mongodb.py wrapper with the latest functionalities of pymongo?

Thank you!
PRs are welcome.
I don't use the MongoDB backend myself... 
There's an existing PR but it requires tests.
https://github.com/celery/celery/pull/4581/files

Thank you for the info

ok I'll test PR and I'll evaluate if I can help somehow!

Resolving patch:
diff --git a/celery/backends/mongodb.py b/celery/backends/mongodb.py
--- a/celery/backends/mongodb.py
+++ b/celery/backends/mongodb.py
@@ -271,7 +271,10 @@ def _get_database(self):
         conn = self._get_connection()
         db = conn[self.database_name]
         if self.user and self.password:
-            if not db.authenticate(self.user, self.password):
+            source = self.options.get('authsource', 
+                        self.database_name or 'admin'
+            )
+            if not db.authenticate(self.user, self.password, source=source):
                 raise ImproperlyConfigured(
                     'Invalid MongoDB username or password.')
         return db


Test patch:
diff --git a/t/unit/backends/test_mongodb.py b/t/unit/backends/test_mongodb.py
--- a/t/unit/backends/test_mongodb.py
+++ b/t/unit/backends/test_mongodb.py
@@ -235,7 +235,7 @@ def test_get_database_no_existing(self, mock_get_connection):
         assert database is mock_database
         assert self.backend.__dict__['database'] is mock_database
         mock_database.authenticate.assert_called_once_with(
-            MONGODB_USER, MONGODB_PASSWORD)
+            MONGODB_USER, MONGODB_PASSWORD, source=self.backend.database_name)
 
     @patch('celery.backends.mongodb.MongoBackend._get_connection')
     def test_get_database_no_existing_no_auth(self, mock_get_connection):