Modify

Opened 4 years ago

Last modified 14 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 14 months ago by arkinform@…

  • Cc arkinform@… added; anonymous removed

Add Comment

Modify Ticket

Action
as new The owner will remain eblot.
Author


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

 
Note: See TracTickets for help on using tickets.