From 7c8ddf17d46e271cd17723e7a222d767df6435a4 Mon Sep 17 00:00:00 2001 From: Jose Manuel Lopez Lujan <jm.lopez@utoronto.ca> Date: Tue, 12 May 2020 15:29:34 -0400 Subject: [PATCH] Adds get_groups method to provide an interface for listing all available groups in the ldap directory based on the filter defined in LDAP_GROUPS_OBJECT_FILTER The get_groups method has two arguments fields and dn_only to customize the result. i.e. get_groups(fields=['cn', 'description']) provide a list of dict with included attributes. if only get_groups(dn_only=True) is provided, a list of available groups dn is returned. If no users in directory, an empty list is returned. --- docs/index.rst | 2 ++ examples/basic_auth/app_oldap.py | 10 ++++---- examples/groups/app_oldap.py | 8 ++++--- flask_simpleldap/__init__.py | 41 ++++++++++++++++++++++++++++++-- 4 files changed, 52 insertions(+), 9 deletions(-) diff --git a/docs/index.rst b/docs/index.rst index ab72749..2ab3e2c 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -80,6 +80,8 @@ directives: Default: '(&(objectclass=Person)(userPrincipalName=%s))' ``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. + Default: 'objectclass=Group' ``LDAP_GROUP_FIELDS`` ``list`` of fields to return when searching for a group's object details. Default: ``list`` (all). ``LDAP_GROUP_OBJECT_FILTER`` The filter to use when searching for a group object. diff --git a/examples/basic_auth/app_oldap.py b/examples/basic_auth/app_oldap.py index 4155130..99aa789 100644 --- a/examples/basic_auth/app_oldap.py +++ b/examples/basic_auth/app_oldap.py @@ -15,10 +15,12 @@ app.config['LDAP_OPENLDAP'] = True app.config['LDAP_OBJECTS_DN'] = 'dn' app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=inetOrgPerson)(uid=%s))' -# Groups -app.config['LDAP_GROUP_MEMBERS_FIELD'] = "uniquemember" -app.config['LDAP_GROUP_OBJECT_FILTER'] = "(&(objectclass=groupOfUniqueNames)(cn=%s))" -app.config['LDAP_GROUP_MEMBER_FILTER'] = "(&(cn=*)(objectclass=groupOfUniqueNames)(uniquemember=%s))" +# Groups configuration +app.config['LDAP_GROUP_MEMBERS_FIELD'] = 'uniquemember' +app.config['LDAP_GROUP_OBJECT_FILTER'] = '(&(objectclass=groupOfUniqueNames)(cn=%s))' +app.config['LDAP_GROUPS_OBJECT_FILTER'] = 'objectclass=groupOfUniqueNames' +app.config['LDAP_GROUP_FIELDS'] = ['cn', 'entryDN', 'member', 'description'] +app.config['LDAP_GROUP_MEMBER_FILTER'] = '(&(cn=*)(objectclass=groupOfUniqueNames)(member=%s))' app.config['LDAP_GROUP_MEMBER_FILTER_FIELD'] = "cn" ldap = LDAP(app) diff --git a/examples/groups/app_oldap.py b/examples/groups/app_oldap.py index c4de23c..36677f1 100644 --- a/examples/groups/app_oldap.py +++ b/examples/groups/app_oldap.py @@ -15,9 +15,11 @@ app.config['LDAP_PASSWORD'] = 'password' app.config['LDAP_USER_OBJECT_FILTER'] = '(&(objectclass=inetOrgPerson)(uid=%s))' # Group configuration -app.config['LDAP_GROUP_MEMBERS_FIELD'] = "uniquemember" -app.config['LDAP_GROUP_OBJECT_FILTER'] = "(&(objectclass=groupOfUniqueNames)(uniquemember=%s))" -app.config['LDAP_GROUP_MEMBER_FILTER'] = "(&(cn=*)(objectclass=groupOfUniqueNames)(uniquemember=%s))" +app.config['LDAP_GROUP_MEMBERS_FIELD'] = 'uniquemember' +app.config['LDAP_GROUP_OBJECT_FILTER'] = '(&(objectclass=groupOfUniqueNames)(cn=%s))' +app.config['LDAP_GROUPS_OBJECT_FILTER'] = 'objectclass=groupOfUniqueNames' +app.config['LDAP_GROUP_FIELDS'] = ['cn', 'entryDN', 'member', 'description'] +app.config['LDAP_GROUP_MEMBER_FILTER'] = '(&(cn=*)(objectclass=groupOfUniqueNames)(member=%s))' app.config['LDAP_GROUP_MEMBER_FILTER_FIELD'] = "cn" ldap = LDAP(app) diff --git a/flask_simpleldap/__init__.py b/flask_simpleldap/__init__.py index 73ab24c..0562ef3 100644 --- a/flask_simpleldap/__init__.py +++ b/flask_simpleldap/__init__.py @@ -49,6 +49,7 @@ class LDAP(object): '(&(objectclass=Person)(userPrincipalName=%s))') app.config.setdefault('LDAP_USER_GROUPS_FIELD', 'memberOf') app.config.setdefault('LDAP_GROUP_FIELDS', []) + app.config.setdefault('LDAP_GROUPS_OBJECT_FILTER', 'objectclass=Group') app.config.setdefault('LDAP_GROUP_OBJECT_FILTER', '(&(objectclass=Group)(userPrincipalName=%s))') app.config.setdefault('LDAP_GROUP_MEMBERS_FIELD', 'member') @@ -170,13 +171,13 @@ class LDAP(object): if not dn_only: fields = current_app.config['LDAP_USER_FIELDS'] query_filter = query_filter or \ - current_app.config['LDAP_USER_OBJECT_FILTER'] + current_app.config['LDAP_USER_OBJECT_FILTER'] query = ldap_filter.filter_format(query_filter, (user,)) elif group is not None: if not dn_only: fields = current_app.config['LDAP_GROUP_FIELDS'] query_filter = query_filter or \ - current_app.config['LDAP_GROUP_OBJECT_FILTER'] + current_app.config['LDAP_GROUP_OBJECT_FILTER'] query = ldap_filter.filter_format(query_filter, (group,)) conn = self.bind try: @@ -201,6 +202,42 @@ class LDAP(object): except ldap.LDAPError as e: raise LDAPException(self.error(e.args)) + def get_groups(self, fields=None, dn_only=False): + """Returns a ``list`` with the groups in base dn + or an empty``list`` if unsuccessful. + + LDAP query setting is ``LDAP_GROUPS_OBJECT_FILTER`` + + :param fields: list of group fields to retrieve. + if ``None`` or empty, default group fields is used + :type fields: list + :param bool dn_only: If we should only retrieve the object's + distinguished name or not. Default: ``False``. + """ + conn = self.bind + try: + fields = fields or current_app.config['LDAP_GROUP_FIELDS'] + if current_app.config['LDAP_OPENLDAP']: + records = conn.search_s( + current_app.config['LDAP_BASE_DN'], ldap.SCOPE_SUBTREE, + current_app.config['LDAP_GROUPS_OBJECT_FILTER'], + fields) + else: + records = conn.search_s( + current_app.config['LDAP_BASE_DN'], ldap.SCOPE_SUBTREE, + current_app.config['LDAP_GROUPS_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_user_groups(self, user): """Returns a ``list`` with the user's groups or ``None`` if unsuccessful. -- GitLab