Modify

Opened 15 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:

diff --git a/0.12/ldapplugin/api.py b/0.12/ldapplugin/api.py index 4d6f6e2..3642517 100644 --- a/0.12/ldapplugin/api.py +++ b/0.12/ldapplugin/api.py @@ -145,19 +145,36 @@ class LdapPermissionGroupProvider(Component):

del self._cache[username]

# Private API

-

def _get_user_groups(self, username):

"""Returns a list of all groups a user belongs to"""

  • ldap_groups = self._ldap.get_groups()

groups = []

  • for group in ldap_groups:
  • if self._ldap.is_in_group(self.util.user_attrdn(username), group):
  • m = DN_RE.search(group)
  • if m:
  • groupname = GROUP_PREFIX + m.group('rdn')
  • if groupname not in groups:
  • groups.append(groupname)
  • return groups

+ grouprdns = [] + srfilter = "(&(objectclass=%s)(%s=%s))" % (self._ldap.groupname, self._ldap.groupmember, self.util.user_attrdn(username)) + srresult = self._ldap.get_dn(self._ldap.basedn, srfilter) + if srresult: + groups.extend(srresult) + for group in srresult: + groups = groups + self._get_group_parents(group) + + # Return only the RDN + for group in groups: + m = DN_RE.search(group) + if m: + grouprdn = GROUP_PREFIX + m.group('rdn') + if grouprdn not in grouprdns: + grouprdns.append(grouprdn) + return grouprdns + + def _get_group_parents(self, groupdn): + parents = [] + srfilter = "(&(objectclass=%s)(%s=%s))" % (self._ldap.groupname, self._ldap.groupmember, groupdn) + srresult = self._ldap.get_dn(self._ldap.basedn, srfilter) + if srresult: + parents.extend(srresult) + for groupdn in srresult: + parents = parents + self._get_group_parents(groupdn) + return parents +

Version 0, edited 5 years ago by Damien Clabaut (next)

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.