From 137d02f4d79bedd074bd0950c088205a9a6549d2 Mon Sep 17 00:00:00 2001 From: Jose Manuel Lopez Lujan Date: Tue, 12 May 2020 14:32:20 -0400 Subject: [PATCH] Adds get_users method to provide an interface for listing all available users in the ldap directory based on the filter defined in LDAP_USERS_OBJECT_FILTER The get_users method has two arguments fields and dn_only to customize the result. i.e. get_users(fields=['uid']) provide a list of dict with uid included. if only get_users(dn_only=True) is provided, a list of available users dn is returned. If no users in directory, an empty list is returned. Signed-off-by: JM Lopez --- docs/index.rst | 2 ++ examples/basic_auth/app.py | 3 +++ examples/basic_auth/app_oldap.py | 1 + flask_simpleldap/__init__.py | 41 +++++++++++++++++++++++++++++++- 4 files changed, 46 insertions(+), 1 deletion(-) diff --git a/docs/index.rst b/docs/index.rst index 2ab3e2c..03b99b3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -78,6 +78,8 @@ directives: object details. Default: ``list`` (all). ``LDAP_USER_OBJECT_FILTER`` The filter to use when searching for a user object. Default: '(&(objectclass=Person)(userPrincipalName=%s))' +``LDAP_USERS_OBJECT_FILTER`` The filter to use when searching for users objects. + Default: 'objectclass=Person' ``LDAP_USER_GROUPS_FIELD`` The field to return when searching for a user's groups. Default: 'memberOf'. ``LDAP_GROUPS_OBJECT_FILTER`` The filter to use when searching for groups objects. diff --git a/examples/basic_auth/app.py b/examples/basic_auth/app.py index e9e745f..9f8536e 100644 --- a/examples/basic_auth/app.py +++ b/examples/basic_auth/app.py @@ -6,6 +6,9 @@ app.config['LDAP_BASE_DN'] = 'OU=users,dc=example,dc=org' app.config['LDAP_USERNAME'] = 'CN=user,OU=Users,DC=example,DC=org' app.config['LDAP_PASSWORD'] = 'password' +app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=inetOrgPerson)(uid=%s))' +app.config['LDAP_USERS_OBJECT_FILTER'] = 'objectclass=inetOrgPerson' +app.config['LDAP_USER_FIELDS'] = ['cn', 'uid'] ldap = LDAP(app) diff --git a/examples/basic_auth/app_oldap.py b/examples/basic_auth/app_oldap.py index 99aa789..a190b54 100644 --- a/examples/basic_auth/app_oldap.py +++ b/examples/basic_auth/app_oldap.py @@ -14,6 +14,7 @@ app.config['LDAP_OPENLDAP'] = True app.config['LDAP_OBJECTS_DN'] = 'dn' app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=inetOrgPerson)(uid=%s))' +app.config['LDAP_USERS_OBJECT_FILTER'] = 'objectclass=inetOrgPerson' # Groups configuration app.config['LDAP_GROUP_MEMBERS_FIELD'] = 'uniquemember' diff --git a/flask_simpleldap/__init__.py b/flask_simpleldap/__init__.py index 7eff2c8..94cc7df 100644 --- a/flask_simpleldap/__init__.py +++ b/flask_simpleldap/__init__.py @@ -45,6 +45,8 @@ def init_app(app): app.config.setdefault('LDAP_BASE_DN', None) app.config.setdefault('LDAP_OBJECTS_DN', 'distinguishedName') app.config.setdefault('LDAP_USER_FIELDS', []) + app.config.setdefault('LDAP_USERS_OBJECT_FILTER', + 'objectclass=Person') app.config.setdefault('LDAP_USER_OBJECT_FILTER', '(&(objectclass=Person)(userPrincipalName=%s))') app.config.setdefault('LDAP_USER_GROUPS_FIELD', 'memberOf') @@ -155,6 +157,43 @@ def bind_user(self, username, password): except ldap.LDAPError: return + def get_users(self, fields=None, dn_only=False): + """Returns a ``list`` with the users in base dn + or empty ``list`` if unsuccessful. + + LDAP query setting is ``LDAP_USERS_OBJECT_FILTER`` + + :param fields: list of user fields to retrieve. + if ``None`` or empty, default user fields + ``LDAP_USER_FIELDS`` is used + :param bool dn_only: If we should only retrieve the object's + distinguished name or not. Default: ``False``. + :type fields: list + """ + conn = self.bind + try: + fields = fields or current_app.config['LDAP_USER_FIELDS'] + if current_app.config['LDAP_OPENLDAP']: + records = conn.search_s( + current_app.config['LDAP_BASE_DN'], ldap.SCOPE_SUBTREE, + current_app.config['LDAP_USERS_OBJECT_FILTER'], + fields) + else: + records = conn.search_s( + current_app.config['LDAP_BASE_DN'], ldap.SCOPE_SUBTREE, + current_app.config['LDAP_USERS_OBJECT_FILTER'], + fields) + conn.unbind_s() + if records: + if dn_only: + return [r[0] for r in records] + else: + return [r[1] for r in records] + else: + return [] + except ldap.LDAPError as e: + raise LDAPException(self.error(e.args)) + def get_object_details(self, user=None, group=None, query_filter=None, dn_only=False): """Returns a ``dict`` with the object's (user or group) details. @@ -337,7 +376,7 @@ def login_required(func): @wraps(func) def wrapped(*args, **kwargs): if g.user is None: - next_path=request.full_path or request.path + next_path = request.full_path or request.path if next_path == '/?': return redirect( url_for(current_app.config['LDAP_LOGIN_VIEW']))