Modify

Opened 4 years ago

Last modified 11 months ago

#7339 new enhancement

LdapPermissionGroupProvider.get_permission_groups() too slow

Reported by: AndyS Owned by: eblot
Priority: high Component: LdapPlugin
Severity: major Keywords: ldap, ldapplugin, 0.12
Cc: arkinform@… Trac Release: 0.12

Description

Hi,

we are using LdapPlugin to get group info from LDAP database. It worked
perfectly until one day I decided to enable 'restrict_owner' option.
Things became very slow with that option enabled, new ticket form took
~10 seconds to display. I did some debugging and it seems that the problem
is in the LDAP plugin, the algorithm which extracts user's groups from
LDAP is not very efficient.

From my understanding of the code it works by first exctracting the
complete list of all groups from LDAP and then checking that given user
is a member of every LDAP group. With too many groups (our LDAP server
has more than 700 groups) combinatorial complexity kills performance.

In principle the group membership for a given user name can be obtained
with a single LDAP search. Below is a patch that reimplments
_get_user_groups() method to use one LDAP operation with a filter
like "(&(objectclass=PosixGroup)(memberid=USER))". This patch was tested
and it works much faster in our environment. Would be nice if you could
include this optimization into the next plugin release.

Thanks,
Andy

*** api.py.orig 2010-07-06 08:51:52.000000000 -0700
--- api.py      2010-07-06 11:13:33.000000000 -0700
***************
*** 147,161 ****
      
      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
  
  class LdapPermissionStore(Component):
--- 147,160 ----
      
      def _get_user_groups(self, username):
          """Returns a list of all groups a user belongs to"""
!         ldap_groups = self._ldap.get_user_groups(self.util.user_attrdn(username))
          groups = []
          for group in ldap_groups:
!             m = DN_RE.search(group)
!             if m:
!                 groupname = GROUP_PREFIX + m.group('rdn')
!                 if groupname not in groups:
!                     groups.append(groupname)
          return groups
  
  class LdapPermissionStore(Component):
***************
*** 570,575 ****
--- 569,588 ----
                  return cr
          return False
  
+     def get_user_groups(self, userdn):
+         """Return a list of group dns where user is a member"""
+         if self.groupmemberisdn:
+             udn = userdn
+         else:
+             m = re.match('[^=]+=([^,]+)', userdn)
+             if m is None:
+                 self.log.warn('Malformed userdn: %s' % userdn)
+                 return []
+             udn = m.group(1)
+         filter = "(&(objectclass=%s)(%s=%s))" % (self.groupname, self.groupmember, udn)
+         groups = self.get_dn(self.basedn, filter)
+         return groups
+ 
      def get_dn(self, basedn, filterstr):
          """Return a list of dns that satisfy the LDAP filter"""
          dns = []

Attachments (0)

Change History (1)

comment:1 Changed 11 months ago by arkinform@…

  • Cc arkinform@… added

Add Comment

Modify Ticket

Action
as new .
Author


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

 
Note: See TracTickets for help on using tickets.