Modify

Opened 14 years ago

Last modified 8 years ago

#7339 new enhancement

LdapPermissionGroupProvider.get_permission_groups() too slow

Reported by: Andy S Owned by: Emmanuel Blot
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 (2)

comment:1 Changed 10 years ago by arkinform@…

Cc: arkinform@… added; anonymous removed

comment:2 Changed 8 years ago by bluecmd

Applied to our installation with great results. Thanks for the patch!

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.