Modify

Opened 14 years ago

Last modified 5 years ago

#5996 new defect

LdapPlugin should cascade group memberships

Reported by: simon@… Owned by: Emmanuel Blot
Priority: high Component: LdapPlugin
Severity: normal Keywords:
Cc: Trac Release: 0.11

Description

Groups can be defined either through its direct members (which can be users or other groups), or through the memberOf attribute of users or other groups. LdapPlugin should support both methods. Also, LdapPlugin should support indirect membership of a group (where a user is a member of a group that is in its turn member of another group). Where supported matching syntax 0.113556.1.4.1941 should be used.

Typically, the LDAP query could look something like:

(&(objectClass=user)(memberOf:1.2.840.113556.1.4.1941:=CN=groupName))

Attachments (0)

Change History (2)

comment:1 Changed 5 years ago by Damien Clabaut

Directive 1.2.840.113556.1.4.1941 is only handled by Active Directory and Samba4. OpenLDAP does not support it as of 2019 (Even though I can find requests for this function dating 2002).

I have a quick patch that enables recursive LDAP search. It is not optimized in terms of performance, but it works:

diff --git a/0.12/ldapplugin/api.py b/0.12/ldapplugin/api.py
index 4d6f6e2..890eb53 100644
--- a/0.12/ldapplugin/api.py
+++ b/0.12/ldapplugin/api.py
@@ -572,6 +572,16 @@ class LdapConnection(object):
             cr = self._compare(groupdn, self.groupmember, udn)
             if self._ds:
                 return cr
+            else:
+                subgroups = self._search(self.basedn,
+                                         'objectclass=' + self.groupname,
+                                         [self.groupattr],
+                                         ldap.SCOPE_SUBTREE)
+                if subgroups:
+                    for (dn, attrs) in subgroups:
+                        cr = self.is_in_groups(userdn, dn)
+                        if cr:
+                            return cr
         return False

comment:2 Changed 5 years ago by Damien Clabaut

Ok, so turns out my previous patch does not work. Based on the code provided in ticket #7339, I made recursive groups in a more efficient way:

  • 0.12/ldapplugin/api.py

    diff --git a/0.12/ldapplugin/api.py b/0.12/ldapplugin/api.py
    index 4d6f6e2..3642517 100644
    a b class LdapPermissionGroupProvider(Component): 
    145145            del self._cache[username]
    146146
    147147    # Private API
    148 
    149148    def _get_user_groups(self, username):
    150149        """Returns a list of all groups a user belongs to"""
    151         ldap_groups = self._ldap.get_groups()
    152150        groups = []
    153         for group in ldap_groups:
    154             if self._ldap.is_in_group(self.util.user_attrdn(username), group):
    155                 m = DN_RE.search(group)
    156                 if m:
    157                     groupname = GROUP_PREFIX + m.group('rdn')
    158                     if groupname not in groups:
    159                         groups.append(groupname)
    160         return groups
     151        grouprdns = []
     152        srfilter = "(&(objectclass=%s)(%s=%s))" % (self._ldap.groupname, self._ldap.groupmember, self.util.user_attrdn(username))
     153        srresult = self._ldap.get_dn(self._ldap.basedn, srfilter)
     154        if srresult:
     155            groups.extend(srresult)
     156            for group in srresult:
     157                groups = groups + self._get_group_parents(group)
     158
     159        # Return only the RDN
     160        for group in groups:
     161            m = DN_RE.search(group)
     162            if m:
     163                grouprdn = GROUP_PREFIX + m.group('rdn')
     164                if grouprdn not in grouprdns:
     165                    grouprdns.append(grouprdn)
     166        return grouprdns
     167
     168    def _get_group_parents(self, groupdn):
     169        parents = []
     170        srfilter = "(&(objectclass=%s)(%s=%s))" % (self._ldap.groupname, self._ldap.groupmember, groupdn)
     171        srresult = self._ldap.get_dn(self._ldap.basedn, srfilter)
     172        if srresult:
     173            parents.extend(srresult)
     174            for groupdn in srresult:
     175                parents = parents + self._get_group_parents(groupdn)
     176        return parents
     177
Last edited 5 years ago by Ryan J Ollos (previous) (diff)

Modify Ticket

Change Properties
Set your email in Preferences
Action
as new The owner will remain Emmanuel Blot.

Add Comment


E-mail address and name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.