mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Optimize and dynamically verify group membership
Rather than doing full searches for members read each member individually to determine if it is direct or indirect. Also add a fail-safe when calculating indirect membership so removing a member will log enough information for debugging (ticket 1133). https://fedorahosted.org/freeipa/ticket/1139 https://fedorahosted.org/freeipa/ticket/1133
This commit is contained in:
committed by
Rob Crittenden
parent
46a3411420
commit
cc0e6680b9
@@ -35,6 +35,7 @@ import tempfile
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
import krbV
|
import krbV
|
||||||
|
import logging
|
||||||
import ldap as _ldap
|
import ldap as _ldap
|
||||||
import ldap.filter as _ldap_filter
|
import ldap.filter as _ldap_filter
|
||||||
import ldap.sasl as _ldap_sasl
|
import ldap.sasl as _ldap_sasl
|
||||||
@@ -580,10 +581,14 @@ class ldap2(CrudBackend, Encoder):
|
|||||||
|
|
||||||
if attrs_list and ('memberindirect' in attrs_list or '*' in attrs_list):
|
if attrs_list and ('memberindirect' in attrs_list or '*' in attrs_list):
|
||||||
for r in res:
|
for r in res:
|
||||||
indirect = self.get_members(r[0], membertype=MEMBERS_INDIRECT,
|
if not 'member' in r[1]:
|
||||||
time_limit=time_limit, size_limit=size_limit, normalize=normalize)
|
continue
|
||||||
if len(indirect) > 0:
|
else:
|
||||||
r[1]['memberindirect'] = indirect
|
members = r[1]['member']
|
||||||
|
indirect = self.get_members(r[0], members, membertype=MEMBERS_INDIRECT,
|
||||||
|
time_limit=time_limit, size_limit=size_limit, normalize=normalize)
|
||||||
|
if len(indirect) > 0:
|
||||||
|
r[1]['memberindirect'] = indirect
|
||||||
if attrs_list and ('memberofindirect' in attrs_list or '*' in attrs_list):
|
if attrs_list and ('memberofindirect' in attrs_list or '*' in attrs_list):
|
||||||
for r in res:
|
for r in res:
|
||||||
if 'memberof' in r[1]:
|
if 'memberof' in r[1]:
|
||||||
@@ -904,7 +909,7 @@ class ldap2(CrudBackend, Encoder):
|
|||||||
# update group entry
|
# update group entry
|
||||||
self.update_entry(group_dn, group_entry_attrs)
|
self.update_entry(group_dn, group_entry_attrs)
|
||||||
|
|
||||||
def get_members(self, group_dn, attr_list=[], membertype=MEMBERS_ALL, time_limit=None, size_limit=None, normalize=True):
|
def get_members(self, group_dn, members, attr_list=[], membertype=MEMBERS_ALL, time_limit=None, size_limit=None, normalize=True):
|
||||||
"""Do a memberOf search of groupdn and return the attributes in
|
"""Do a memberOf search of groupdn and return the attributes in
|
||||||
attr_list (an empty list returns all attributes).
|
attr_list (an empty list returns all attributes).
|
||||||
|
|
||||||
@@ -925,21 +930,17 @@ class ldap2(CrudBackend, Encoder):
|
|||||||
|
|
||||||
attr_list.append("member")
|
attr_list.append("member")
|
||||||
|
|
||||||
# We have to do two searches because netgroups are not within the
|
# Verify group membership
|
||||||
# accounts container.
|
|
||||||
try:
|
results = []
|
||||||
(results, truncated) = self.find_entries(searchfilter, attr_list,
|
for member in members:
|
||||||
api.env.container_accounts, time_limit=time_limit,
|
try:
|
||||||
size_limit=size_limit, normalize=normalize)
|
(result, truncated) = self.find_entries(searchfilter, attr_list,
|
||||||
except errors.NotFound:
|
member, time_limit=time_limit,
|
||||||
results = []
|
size_limit=size_limit, normalize=normalize)
|
||||||
try:
|
results.append(list(result[0]))
|
||||||
(netresults, truncated) = self.find_entries(searchfilter, attr_list,
|
except errors.NotFound:
|
||||||
api.env.container_netgroup, time_limit=time_limit,
|
pass
|
||||||
size_limit=size_limit, normalize=normalize)
|
|
||||||
except errors.NotFound:
|
|
||||||
netresults = []
|
|
||||||
results = results + netresults
|
|
||||||
|
|
||||||
if membertype == MEMBERS_ALL:
|
if membertype == MEMBERS_ALL:
|
||||||
entries = []
|
entries = []
|
||||||
@@ -988,45 +989,34 @@ class ldap2(CrudBackend, Encoder):
|
|||||||
searchfilter = "(|(member=%s)(memberhost=%s)(memberuser=%s))" % (
|
searchfilter = "(|(member=%s)(memberhost=%s)(memberuser=%s))" % (
|
||||||
search_entry_dn, search_entry_dn, search_entry_dn)
|
search_entry_dn, search_entry_dn, search_entry_dn)
|
||||||
|
|
||||||
# We have to do three searches because netgroups and pbac are not
|
# Search only the groups for which the object is a member to
|
||||||
# within the accounts container.
|
# determine if it is directly or indirectly associated.
|
||||||
try:
|
|
||||||
(results, truncated) = self.find_entries(searchfilter, attr_list,
|
results = []
|
||||||
api.env.container_accounts, time_limit=time_limit,
|
for group in memberof:
|
||||||
size_limit=size_limit, normalize=normalize)
|
try:
|
||||||
except errors.NotFound:
|
(result, truncated) = self.find_entries(searchfilter, attr_list,
|
||||||
results = []
|
group, time_limit=time_limit,size_limit=size_limit,
|
||||||
try:
|
normalize=normalize)
|
||||||
(netresults, truncated) = self.find_entries(searchfilter, attr_list,
|
results.extend(list(result))
|
||||||
api.env.container_netgroup, time_limit=time_limit,
|
except errors.NotFound:
|
||||||
size_limit=size_limit, normalize=normalize)
|
pass
|
||||||
except errors.NotFound:
|
|
||||||
netresults = []
|
|
||||||
results = results + netresults
|
|
||||||
try:
|
|
||||||
(pbacresults, truncated) = self.find_entries(searchfilter,
|
|
||||||
attr_list, 'cn=pbac,%s' % api.env.basedn,
|
|
||||||
time_limit=time_limit, size_limit=size_limit,
|
|
||||||
normalize=normalize)
|
|
||||||
except errors.NotFound:
|
|
||||||
pbacresults = []
|
|
||||||
results = results + pbacresults
|
|
||||||
try:
|
|
||||||
(sudoresults, truncated) = self.find_entries(searchfilter,
|
|
||||||
attr_list, 'cn=sudo,%s' % api.env.basedn,
|
|
||||||
time_limit=time_limit, size_limit=size_limit,
|
|
||||||
normalize=normalize)
|
|
||||||
except errors.NotFound:
|
|
||||||
sudoresults = []
|
|
||||||
results = results + sudoresults
|
|
||||||
|
|
||||||
direct = []
|
direct = []
|
||||||
indirect = []
|
indirect = []
|
||||||
|
# If there is an exception here, it is likely due to a failure in
|
||||||
|
# referential integrity. All members should have corresponding
|
||||||
|
# memberOf entries.
|
||||||
for m in memberof:
|
for m in memberof:
|
||||||
indirect.append(m.lower())
|
indirect.append(m.lower())
|
||||||
for r in results:
|
for r in results:
|
||||||
direct.append(r[0])
|
direct.append(r[0])
|
||||||
indirect.remove(r[0].lower())
|
try:
|
||||||
|
indirect.remove(r[0].lower())
|
||||||
|
except ValueError, e:
|
||||||
|
logging.info('Failed to remove'
|
||||||
|
' indirect entry %s from %s' % r[0], entry_dn)
|
||||||
|
raise e
|
||||||
|
|
||||||
return (direct, indirect)
|
return (direct, indirect)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user