From c55d98663133f4dbce4ce009f123532eeac1d8e1 Mon Sep 17 00:00:00 2001 From: Stanislav Tomilov Date: Wed, 6 Jul 2016 13:57:34 +0500 Subject: [PATCH 1/9] connection: Add authentication mechanism support. #905 --- mongoengine/connection.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/mongoengine/connection.py b/mongoengine/connection.py index 4055a9b6e..9f9ddcf86 100644 --- a/mongoengine/connection.py +++ b/mongoengine/connection.py @@ -25,6 +25,7 @@ class ConnectionError(Exception): def register_connection(alias, name=None, host=None, port=None, read_preference=READ_PREFERENCE, username=None, password=None, authentication_source=None, + authentication_mechanism=None, **kwargs): """Add a connection. @@ -38,6 +39,9 @@ def register_connection(alias, name=None, host=None, port=None, :param username: username to authenticate with :param password: password to authenticate with :param authentication_source: database to authenticate against + :param authentication_mechanism: database authentication mechanisms. + By default, use SCRAM-SHA-1 with MongoDB 3.0 and later, + MONGODB-CR (MongoDB Challenge Response protocol) for older servers. :param is_mock: explicitly use mongomock for this connection (can also be done by using `mongomock://` as db host prefix) :param kwargs: allow ad-hoc parameters to be passed into the pymongo driver @@ -53,7 +57,8 @@ def register_connection(alias, name=None, host=None, port=None, 'read_preference': read_preference, 'username': username, 'password': password, - 'authentication_source': authentication_source + 'authentication_source': authentication_source, + 'authentication_mechanism': authentication_mechanism } # Handle uri style connections @@ -75,6 +80,8 @@ def register_connection(alias, name=None, host=None, port=None, conn_settings['replicaSet'] = True if 'authsource' in uri_options: conn_settings['authentication_source'] = uri_options['authsource'] + if 'authmechanism' in uri_options: + conn_settings['authentication_mechanism'] = uri_options['authmechanism'] # Deprecated parameters that should not be passed on kwargs.pop('slaves', None) @@ -113,6 +120,7 @@ def get_connection(alias=DEFAULT_CONNECTION_NAME, reconnect=False): conn_settings.pop('username', None) conn_settings.pop('password', None) conn_settings.pop('authentication_source', None) + conn_settings.pop('authentication_mechanism', None) is_mock = conn_settings.pop('is_mock', None) if is_mock: @@ -147,6 +155,7 @@ def get_connection(alias=DEFAULT_CONNECTION_NAME, reconnect=False): connection_settings.pop('username', None) connection_settings.pop('password', None) connection_settings.pop('authentication_source', None) + connection_settings.pop('authentication_mechanism', None) if conn_settings == connection_settings and _connections.get(db_alias, None): connection = _connections[db_alias] break @@ -170,7 +179,8 @@ def get_db(alias=DEFAULT_CONNECTION_NAME, reconnect=False): if conn_settings['username'] and conn_settings['password']: db.authenticate(conn_settings['username'], conn_settings['password'], - source=conn_settings['authentication_source']) + source=conn_settings['authentication_source'], + mechanism=conn_settings['authentication_mechanism']) _dbs[alias] = db return _dbs[alias] From 83bf50dea66695a55ff10f2883a1667207b84edc Mon Sep 17 00:00:00 2001 From: Stanislav Tomilov Date: Wed, 6 Jul 2016 14:26:47 +0500 Subject: [PATCH 2/9] connection: remove check password before db.authenticate. (MONGODB-X509 without password) --- mongoengine/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoengine/connection.py b/mongoengine/connection.py index 9f9ddcf86..468ea606e 100644 --- a/mongoengine/connection.py +++ b/mongoengine/connection.py @@ -176,7 +176,7 @@ def get_db(alias=DEFAULT_CONNECTION_NAME, reconnect=False): conn_settings = _connection_settings[alias] db = conn[conn_settings['name']] # Authenticate if necessary - if conn_settings['username'] and conn_settings['password']: + if conn_settings['username']: db.authenticate(conn_settings['username'], conn_settings['password'], source=conn_settings['authentication_source'], From cc090818a5e8d60f9efdaa548e2c1b9be9606198 Mon Sep 17 00:00:00 2001 From: Stanislav Tomilov Date: Tue, 19 Jul 2016 03:36:26 +0500 Subject: [PATCH 3/9] connection: add default authentication_mechanism --- mongoengine/connection.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mongoengine/connection.py b/mongoengine/connection.py index 468ea606e..c72447473 100644 --- a/mongoengine/connection.py +++ b/mongoengine/connection.py @@ -8,9 +8,11 @@ DEFAULT_CONNECTION_NAME = 'default' if IS_PYMONGO_3: READ_PREFERENCE = ReadPreference.PRIMARY + AUTHENTICATION_MECHANISM = 'SCRAM-SHA-1' else: from pymongo import MongoReplicaSetClient READ_PREFERENCE = False + AUTHENTICATION_MECHANISM = 'MONGODB-CR' class ConnectionError(Exception): @@ -25,7 +27,7 @@ class ConnectionError(Exception): def register_connection(alias, name=None, host=None, port=None, read_preference=READ_PREFERENCE, username=None, password=None, authentication_source=None, - authentication_mechanism=None, + authentication_mechanism=AUTHENTICATION_MECHANISM, **kwargs): """Add a connection. From ce55d27cfc46dceb2bfc575cf716743e32b95360 Mon Sep 17 00:00:00 2001 From: Stanislav Tomilov Date: Sun, 31 Jul 2016 01:43:12 +0500 Subject: [PATCH 4/9] check IS_PYMONGO_27 for AUTHENTICATION_MECHANISM --- mongoengine/connection.py | 10 +++++++--- mongoengine/python_support.py | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/mongoengine/connection.py b/mongoengine/connection.py index c72447473..1c15b9e77 100644 --- a/mongoengine/connection.py +++ b/mongoengine/connection.py @@ -1,17 +1,20 @@ from pymongo import MongoClient, ReadPreference, uri_parser -from mongoengine.python_support import IS_PYMONGO_3 +from mongoengine.python_support import IS_PYMONGO_3, IS_PYMONGO_27 __all__ = ['ConnectionError', 'connect', 'register_connection', 'DEFAULT_CONNECTION_NAME'] DEFAULT_CONNECTION_NAME = 'default' +AUTHENTICATION_MECHANISM = 'DEFAULT' + if IS_PYMONGO_3: READ_PREFERENCE = ReadPreference.PRIMARY - AUTHENTICATION_MECHANISM = 'SCRAM-SHA-1' else: from pymongo import MongoReplicaSetClient READ_PREFERENCE = False + +if IS_PYMONGO_27: AUTHENTICATION_MECHANISM = 'MONGODB-CR' @@ -182,7 +185,8 @@ def get_db(alias=DEFAULT_CONNECTION_NAME, reconnect=False): db.authenticate(conn_settings['username'], conn_settings['password'], source=conn_settings['authentication_source'], - mechanism=conn_settings['authentication_mechanism']) + mechanism=conn_settings['authentication_mechanism'] + ) _dbs[alias] = db return _dbs[alias] diff --git a/mongoengine/python_support.py b/mongoengine/python_support.py index 5bb9038dd..bddce612f 100644 --- a/mongoengine/python_support.py +++ b/mongoengine/python_support.py @@ -6,6 +6,10 @@ if pymongo.version_tuple[0] < 3: IS_PYMONGO_3 = False + if pymongo.version_tuple[1] < 8: + IS_PYMONGO_27 = True + else: + IS_PYMONGO_27 = False else: IS_PYMONGO_3 = True From ef37c669fb3397e01741ddb88e9cd8335e3cfb43 Mon Sep 17 00:00:00 2001 From: Stanislav Tomilov Date: Sun, 31 Jul 2016 02:17:11 +0500 Subject: [PATCH 5/9] fix import IS_PYMONGO_27 --- mongoengine/connection.py | 10 +++++++--- mongoengine/python_support.py | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/mongoengine/connection.py b/mongoengine/connection.py index c72447473..1c15b9e77 100644 --- a/mongoengine/connection.py +++ b/mongoengine/connection.py @@ -1,17 +1,20 @@ from pymongo import MongoClient, ReadPreference, uri_parser -from mongoengine.python_support import IS_PYMONGO_3 +from mongoengine.python_support import IS_PYMONGO_3, IS_PYMONGO_27 __all__ = ['ConnectionError', 'connect', 'register_connection', 'DEFAULT_CONNECTION_NAME'] DEFAULT_CONNECTION_NAME = 'default' +AUTHENTICATION_MECHANISM = 'DEFAULT' + if IS_PYMONGO_3: READ_PREFERENCE = ReadPreference.PRIMARY - AUTHENTICATION_MECHANISM = 'SCRAM-SHA-1' else: from pymongo import MongoReplicaSetClient READ_PREFERENCE = False + +if IS_PYMONGO_27: AUTHENTICATION_MECHANISM = 'MONGODB-CR' @@ -182,7 +185,8 @@ def get_db(alias=DEFAULT_CONNECTION_NAME, reconnect=False): db.authenticate(conn_settings['username'], conn_settings['password'], source=conn_settings['authentication_source'], - mechanism=conn_settings['authentication_mechanism']) + mechanism=conn_settings['authentication_mechanism'] + ) _dbs[alias] = db return _dbs[alias] diff --git a/mongoengine/python_support.py b/mongoengine/python_support.py index 5bb9038dd..19efe973a 100644 --- a/mongoengine/python_support.py +++ b/mongoengine/python_support.py @@ -4,8 +4,11 @@ import pymongo +IS_PYMONGO_27 = False if pymongo.version_tuple[0] < 3: IS_PYMONGO_3 = False + if pymongo.version_tuple[1] < 8: + IS_PYMONGO_27 = True else: IS_PYMONGO_3 = True From 2e06e1bd8c6f5faa694be4bd07e57839f4a36224 Mon Sep 17 00:00:00 2001 From: Stanislav Tomilov Date: Tue, 29 Nov 2016 13:36:40 +0500 Subject: [PATCH 6/9] Fix wrong order of imported names --- mongoengine/connection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoengine/connection.py b/mongoengine/connection.py index b10070e41..4ff47ca97 100644 --- a/mongoengine/connection.py +++ b/mongoengine/connection.py @@ -1,5 +1,5 @@ from pymongo import MongoClient, ReadPreference, uri_parser -from mongoengine.python_support import (IS_PYMONGO_3, IS_PYMONGO_27, str_types) +from mongoengine.python_support import (IS_PYMONGO_27, IS_PYMONGO_3, str_types) __all__ = ['ConnectionError', 'connect', 'register_connection', 'DEFAULT_CONNECTION_NAME'] From 130cbecc78c881d7187ebb4f274664b8017b8b4c Mon Sep 17 00:00:00 2001 From: Stanislav Tomilov Date: Wed, 30 Nov 2016 16:30:10 +0500 Subject: [PATCH 7/9] Fix IS_PYMONGO_27 definition and check both 'username' and 'password' conn_settings for connections with not 'MONGODB-X509' mechanism --- mongoengine/connection.py | 6 +++--- mongoengine/python_support.py | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mongoengine/connection.py b/mongoengine/connection.py index 4ff47ca97..a7b6f2b2c 100644 --- a/mongoengine/connection.py +++ b/mongoengine/connection.py @@ -192,12 +192,12 @@ def get_db(alias=DEFAULT_CONNECTION_NAME, reconnect=False): conn_settings = _connection_settings[alias] db = conn[conn_settings['name']] # Authenticate if necessary - if conn_settings['username']: + if (conn_settings['authentication_mechanism'] == 'MONGODB-X509' and conn_settings['username']) or\ + (conn_settings['username'] and conn_settings['password']): db.authenticate(conn_settings['username'], conn_settings['password'], source=conn_settings['authentication_source'], - mechanism=conn_settings['authentication_mechanism'] - ) + mechanism=conn_settings['authentication_mechanism']) _dbs[alias] = db return _dbs[alias] diff --git a/mongoengine/python_support.py b/mongoengine/python_support.py index 19efe973a..a1f37bddc 100644 --- a/mongoengine/python_support.py +++ b/mongoengine/python_support.py @@ -7,8 +7,7 @@ IS_PYMONGO_27 = False if pymongo.version_tuple[0] < 3: IS_PYMONGO_3 = False - if pymongo.version_tuple[1] < 8: - IS_PYMONGO_27 = True + IS_PYMONGO_27 = pymongo.version_tuple[0] == 2 and pymongo.version_tuple[1] == 7 else: IS_PYMONGO_3 = True From 6f2e9a09402765acada7133344f0b8ff338ed228 Mon Sep 17 00:00:00 2001 From: Stanislav Tomilov Date: Thu, 1 Dec 2016 21:01:37 +0500 Subject: [PATCH 8/9] No set value for authentication_mechanism by default --- mongoengine/connection.py | 29 ++++++++++++++++------------- mongoengine/python_support.py | 2 -- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/mongoengine/connection.py b/mongoengine/connection.py index a7b6f2b2c..8d136d76f 100644 --- a/mongoengine/connection.py +++ b/mongoengine/connection.py @@ -1,12 +1,11 @@ from pymongo import MongoClient, ReadPreference, uri_parser -from mongoengine.python_support import (IS_PYMONGO_27, IS_PYMONGO_3, str_types) +from mongoengine.python_support import (IS_PYMONGO_3, str_types) __all__ = ['ConnectionError', 'connect', 'register_connection', 'DEFAULT_CONNECTION_NAME'] DEFAULT_CONNECTION_NAME = 'default' -AUTHENTICATION_MECHANISM = 'DEFAULT' if IS_PYMONGO_3: READ_PREFERENCE = ReadPreference.PRIMARY @@ -14,9 +13,6 @@ from pymongo import MongoReplicaSetClient READ_PREFERENCE = False -if IS_PYMONGO_27: - AUTHENTICATION_MECHANISM = 'MONGODB-CR' - class ConnectionError(Exception): pass @@ -30,7 +26,7 @@ class ConnectionError(Exception): def register_connection(alias, name=None, host=None, port=None, read_preference=READ_PREFERENCE, username=None, password=None, authentication_source=None, - authentication_mechanism=AUTHENTICATION_MECHANISM, + authentication_mechanism=None, **kwargs): """Add a connection. @@ -63,8 +59,9 @@ def register_connection(alias, name=None, host=None, port=None, 'username': username, 'password': password, 'authentication_source': authentication_source, - 'authentication_mechanism': authentication_mechanism } + if authentication_mechanism is not None: + conn_settings.update(authentication_mechanism=authentication_mechanism) # Handle uri style connections conn_host = conn_settings['host'] @@ -192,12 +189,18 @@ def get_db(alias=DEFAULT_CONNECTION_NAME, reconnect=False): conn_settings = _connection_settings[alias] db = conn[conn_settings['name']] # Authenticate if necessary - if (conn_settings['authentication_mechanism'] == 'MONGODB-X509' and conn_settings['username']) or\ - (conn_settings['username'] and conn_settings['password']): - db.authenticate(conn_settings['username'], - conn_settings['password'], - source=conn_settings['authentication_source'], - mechanism=conn_settings['authentication_mechanism']) + if 'authentication_mechanism' in conn_settings: + if conn_settings['username'] and (conn_settings['password'] or + conn_settings['authentication_mechanism'] == 'MONGODB-X509'): + db.authenticate(conn_settings['username'], + conn_settings['password'], + source=conn_settings['authentication_source'], + mechanism=conn_settings['authentication_mechanism']) + else: + if conn_settings['username'] and conn_settings['password']: + db.authenticate(conn_settings['username'], + conn_settings['password'], + source=conn_settings['authentication_source']) _dbs[alias] = db return _dbs[alias] diff --git a/mongoengine/python_support.py b/mongoengine/python_support.py index a1f37bddc..5bb9038dd 100644 --- a/mongoengine/python_support.py +++ b/mongoengine/python_support.py @@ -4,10 +4,8 @@ import pymongo -IS_PYMONGO_27 = False if pymongo.version_tuple[0] < 3: IS_PYMONGO_3 = False - IS_PYMONGO_27 = pymongo.version_tuple[0] == 2 and pymongo.version_tuple[1] == 7 else: IS_PYMONGO_3 = True From a3fff95ba9bbb8b3a120ef6f3b33349cd99f4938 Mon Sep 17 00:00:00 2001 From: Stanislav Tomilov Date: Thu, 1 Dec 2016 23:17:47 +0500 Subject: [PATCH 9/9] pass source and mechanism as kwargs in authenticate() method --- mongoengine/connection.py | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/mongoengine/connection.py b/mongoengine/connection.py index 8d136d76f..b4e852d46 100644 --- a/mongoengine/connection.py +++ b/mongoengine/connection.py @@ -59,9 +59,8 @@ def register_connection(alias, name=None, host=None, port=None, 'username': username, 'password': password, 'authentication_source': authentication_source, + 'authentication_mechanism': authentication_mechanism } - if authentication_mechanism is not None: - conn_settings.update(authentication_mechanism=authentication_mechanism) # Handle uri style connections conn_host = conn_settings['host'] @@ -188,19 +187,13 @@ def get_db(alias=DEFAULT_CONNECTION_NAME, reconnect=False): conn = get_connection(alias) conn_settings = _connection_settings[alias] db = conn[conn_settings['name']] + auth_kwargs = {'source': conn_settings['authentication_source']} + if conn_settings['authentication_mechanism'] is not None: + auth_kwargs['mechanism'] = conn_settings['authentication_mechanism'] # Authenticate if necessary - if 'authentication_mechanism' in conn_settings: - if conn_settings['username'] and (conn_settings['password'] or - conn_settings['authentication_mechanism'] == 'MONGODB-X509'): - db.authenticate(conn_settings['username'], - conn_settings['password'], - source=conn_settings['authentication_source'], - mechanism=conn_settings['authentication_mechanism']) - else: - if conn_settings['username'] and conn_settings['password']: - db.authenticate(conn_settings['username'], - conn_settings['password'], - source=conn_settings['authentication_source']) + if conn_settings['username'] and (conn_settings['password'] or + conn_settings['authentication_mechanism'] == 'MONGODB-X509'): + db.authenticate(conn_settings['username'], conn_settings['password'], **auth_kwargs) _dbs[alias] = db return _dbs[alias]