Consolidate external member code into two functions in baseldap.py

External members (users and hosts) are assumed when doing member
management on certain attributes. If the member isn't in IPA it
is assumed to be external. When doing member management we need
to sift through the list of failures and pull out all those
that were simply not found in IPA.

https://fedorahosted.org/freeipa/ticket/1734
This commit is contained in:
Rob Crittenden 2012-02-01 16:20:54 -05:00 committed by Martin Kosek
parent cca80c7c8c
commit 304b70843a
5 changed files with 95 additions and 283 deletions

View File

@ -178,6 +178,12 @@ global_output_params = (
label=_('Failed to remove'),
flags=['suppress_empty'],
),
Str('ipasudorunas',
label=_('Failed RunAs'),
),
Str('ipasudorunasgroup',
label=_('Failed RunAsGroup'),
),
)
@ -306,6 +312,81 @@ def wait_for_value(ldap, dn, attr, value):
return entry_attrs
def add_external_post_callback(memberattr, membertype, externalattr, ldap, completed, failed, dn, entry_attrs, *keys, **options):
"""
Post callback to add failed members as external members.
This should be called by a commands post callback directly.
memberattr is one of memberuser,
membertype is the type of member: user,
externalattr is one of externaluser,
"""
completed_external = 0
# Sift through the failures. We assume that these are all
# entries that aren't stored in IPA, aka external entries.
if memberattr in failed and membertype in failed[memberattr]:
(dn, entry_attrs_) = ldap.get_entry(dn, [externalattr])
members = entry_attrs.get(memberattr, [])
external_entries = entry_attrs_.get(externalattr, [])
failed_entries = []
for entry in failed[memberattr][membertype]:
membername = entry[0].lower()
member_dn = api.Object[membertype].get_dn(membername)
if membername not in external_entries and \
member_dn not in members:
# Not an IPA entry, assume external
external_entries.append(membername)
completed_external += 1
elif membername in external_entries and \
member_dn not in members:
# Already an external member, reset the error message
msg = unicode(errors.AlreadyGroupMember().message)
newerror = (entry[0], msg)
ind = failed[memberattr][membertype].index(entry)
failed[memberattr][membertype][ind] = newerror
failed_entries.append(membername)
else:
# Really a failure
failed_entries.append(membername)
if completed_external:
try:
ldap.update_entry(dn, {externalattr: external_entries})
except errors.EmptyModlist:
pass
failed[memberattr][membertype] = failed_entries
entry_attrs[externalattr] = external_entries
return (completed + completed_external, dn)
def remove_external_post_callback(memberattr, membertype, externalattr, ldap, completed, failed, dn, entry_attrs, *keys, **options):
# Run through the failures and gracefully remove any member defined
# as an external member.
if memberattr in failed and membertype in failed[memberattr]:
(dn, entry_attrs_) = ldap.get_entry(dn, [externalattr])
external_entries = entry_attrs_.get(externalattr, [])
failed_entries = []
completed_external = 0
for entry in failed[memberattr][membertype]:
membername = entry[0].lower()
if membername in external_entries:
external_entries.remove(membername)
completed_external += 1
else:
failed_entries.append(membername)
if completed_external:
try:
ldap.update_entry(dn, {externalattr: external_entries})
except errors.EmptyModlist:
pass
failed[memberattr][membertype] = failed_entries
entry_attrs[externalattr] = external_entries
return (completed + completed_external, dn)
class LDAPObject(Object):
"""
Object representing a LDAP entry.

View File

@ -501,32 +501,7 @@ class hbacrule_add_sourcehost(LDAPAddMember):
return dn
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
completed_external = 0
# Sift through the host failures. We assume that these are all
# hosts that aren't stored in IPA, aka external hosts.
if 'sourcehost' in failed and 'host' in failed['sourcehost']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['externalhost'])
members = entry_attrs.get('sourcehost', [])
external_hosts = entry_attrs_.get('externalhost', [])
failed_hosts = []
for host in failed['sourcehost']['host']:
hostname = host[0].lower()
host_dn = self.api.Object['host'].get_dn(hostname)
if hostname in external_hosts:
failed_hosts.append((hostname, unicode(errors.AlreadyGroupMember())))
elif hostname not in external_hosts and host_dn not in members:
external_hosts.append(hostname)
completed_external += 1
else:
failed_hosts.append((hostname, unicode(errors.NotFound())))
if completed_external:
try:
ldap.update_entry(dn, {'externalhost': external_hosts})
except errors.EmptyModlist:
pass
entry_attrs['externalhost'] = external_hosts
failed['sourcehost']['host'] = failed_hosts
return (completed + completed_external, dn)
return add_external_post_callback('sourcehost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(hbacrule_add_sourcehost)
@ -538,29 +513,7 @@ class hbacrule_remove_sourcehost(LDAPRemoveMember):
member_count_out = ('%i object removed.', '%i objects removed.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
# Run through the host failures and gracefully remove any defined as
# as an externalhost.
if 'sourcehost' in failed and 'host' in failed['sourcehost']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['externalhost'])
external_hosts = entry_attrs_.get('externalhost', [])
failed_hosts = []
completed_external = 0
for host in failed['sourcehost']['host']:
hostname = host[0].lower()
if hostname in external_hosts:
external_hosts.remove(hostname)
completed_external += 1
else:
failed_hosts.append(hostname)
if completed_external:
try:
ldap.update_entry(dn, {'externalhost': external_hosts})
except errors.EmptyModlist:
pass
failed['sourcehost']['host'] = failed_hosts
entry_attrs['externalhost'] = external_hosts
return (completed + completed_external, dn)
return remove_external_post_callback('sourcehost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(hbacrule_remove_sourcehost)

View File

@ -250,31 +250,7 @@ class netgroup_add_member(LDAPAddMember):
member_attributes = ['memberuser', 'memberhost', 'member']
has_output_params = LDAPAddMember.has_output_params + output_params
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
completed_external = 0
# Sift through the host failures. We assume that these are all
# hosts that aren't stored in IPA, aka external hosts.
if 'memberhost' in failed and 'host' in failed['memberhost']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['externalhost'])
members = entry_attrs.get('memberhost', [])
external_hosts = entry_attrs_.get('externalhost', [])
failed_hosts = []
for host in failed['memberhost']['host']:
hostname = host[0].lower()
host_dn = self.api.Object['host'].get_dn(hostname)
if hostname not in external_hosts and host_dn not in members:
external_hosts.append(hostname)
completed_external += 1
else:
failed_hosts.append(hostname)
if completed_external:
try:
ldap.update_entry(dn, {'externalhost': external_hosts})
except errors.EmptyModlist:
pass
failed['memberhost']['host'] = failed_hosts
entry_attrs['externalhost'] = external_hosts
return (completed + completed_external, dn)
return add_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(netgroup_add_member)
@ -285,27 +261,6 @@ class netgroup_remove_member(LDAPRemoveMember):
member_attributes = ['memberuser', 'memberhost', 'member']
has_output_params = LDAPRemoveMember.has_output_params + output_params
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
# Run through the host failures and gracefully remove any defined as
# as an externalhost.
if 'memberhost' in failed and 'host' in failed['memberhost']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['externalhost'])
external_hosts = entry_attrs_.get('externalhost', [])
failed_hosts = []
completed_external = 0
for host in failed['memberhost']['host']:
hostname = host[0].lower()
if hostname in external_hosts:
external_hosts.remove(hostname)
completed_external += 1
else:
failed_hosts.append(hostname)
if completed_external:
try:
ldap.update_entry(dn, {'externalhost': external_hosts})
except errors.EmptyModlist:
pass
failed['memberhost']['host'] = failed_hosts
entry_attrs['externalhost'] = external_hosts
return (completed + completed_external, dn)
return remove_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(netgroup_remove_member)

View File

@ -74,7 +74,7 @@ class sudorule(LDAPObject):
object_name_plural = _('sudo rules')
object_class = ['ipaassociation', 'ipasudorule']
default_attributes = [
'cn', 'ipaenabledflag',
'cn', 'ipaenabledflag', 'externaluser',
'description', 'usercategory', 'hostcategory',
'cmdcategory', 'memberuser', 'memberhost',
'memberallowcmd', 'memberdenycmd', 'ipasudoopt',
@ -393,30 +393,7 @@ class sudorule_add_user(LDAPAddMember):
return dn
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
completed_external = 0
# Sift through the user failures. We assume that these are all
# users that aren't stored in IPA, aka external users.
if 'memberuser' in failed and 'user' in failed['memberuser']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['externaluser'])
members = entry_attrs.get('memberuser', [])
external_users = entry_attrs_.get('externaluser', [])
failed_users = []
for user in failed['memberuser']['user']:
username = user[0].lower()
user_dn = self.api.Object['user'].get_dn(username)
if username not in external_users and user_dn not in members:
external_users.append(username)
completed_external += 1
else:
failed_users.append(username)
if completed_external:
try:
ldap.update_entry(dn, {'externaluser': external_users})
except errors.EmptyModlist:
pass
failed['memberuser']['user'] = failed_users
entry_attrs['externaluser'] = external_users
return (completed + completed_external, dn)
return add_external_post_callback('memberuser', 'user', 'externaluser', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_add_user)
@ -428,28 +405,7 @@ class sudorule_remove_user(LDAPRemoveMember):
member_count_out = ('%i object removed.', '%i objects removed.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
# Run through the user failures and gracefully remove any defined as
# as an externaluser.
if 'memberuser' in failed and 'user' in failed['memberuser']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['externaluser'])
external_users = entry_attrs_.get('externaluser', [])
failed_users = []
completed_external = 0
for user in failed['memberuser']['user']:
username = user[0].lower()
if username in external_users:
external_users.remove(username)
completed_external += 1
else:
failed_users.append(username)
if completed_external:
try:
ldap.update_entry(dn, {'externaluser': external_users})
except errors.EmptyModlist:
pass
failed['memberuser']['user'] = failed_users
entry_attrs['externaluser'] = external_users
return (completed + completed_external, dn)
return remove_external_post_callback('memberuser', 'user', 'externaluser', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_remove_user)
@ -470,30 +426,7 @@ class sudorule_add_host(LDAPAddMember):
return dn
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
completed_external = 0
# Sift through the host failures. We assume that these are all
# hosts that aren't stored in IPA, aka external hosts.
if 'memberhost' in failed and 'host' in failed['memberhost']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['externalhost'])
members = entry_attrs.get('memberhost', [])
external_hosts = entry_attrs_.get('externalhost', [])
failed_hosts = []
for host in failed['memberhost']['host']:
hostname = host[0].lower()
host_dn = self.api.Object['host'].get_dn(hostname)
if hostname not in external_hosts and host_dn not in members:
external_hosts.append(hostname)
completed_external += 1
else:
failed_hosts.append(hostname)
if completed_external:
try:
ldap.update_entry(dn, {'externalhost': external_hosts})
except errors.EmptyModlist:
pass
failed['memberhost']['host'] = failed_hosts
entry_attrs['externalhost'] = external_hosts
return (completed + completed_external, dn)
return add_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_add_host)
@ -505,29 +438,7 @@ class sudorule_remove_host(LDAPRemoveMember):
member_count_out = ('%i object removed.', '%i objects removed.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
# Run through the host failures and gracefully remove any defined as
# as an externalhost.
if 'memberhost' in failed and 'host' in failed['memberhost']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['externalhost'])
external_hosts = entry_attrs_.get('externalhost', [])
failed_hosts = []
completed_external = 0
for host in failed['memberhost']['host']:
hostname = host[0].lower()
if hostname in external_hosts:
external_hosts.remove(hostname)
completed_external += 1
else:
failed_hosts.append(hostname)
if completed_external:
try:
ldap.update_entry(dn, {'externalhost': external_hosts})
except errors.EmptyModlist:
pass
failed['memberhost']['host'] = failed_hosts
if external_hosts:
entry_attrs['externalhost'] = external_hosts
return (completed + completed_external, dn)
return remove_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_remove_host)
@ -568,30 +479,7 @@ class sudorule_add_runasuser(LDAPAddMember):
return dn
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
completed_external = 0
# Sift through the user failures. We assume that these are all
# users that aren't stored in IPA, aka external users.
if 'ipasudorunas' in failed and 'user' in failed['ipasudorunas']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['ipasudorunasextuser'])
members = entry_attrs.get('ipasudorunas', [])
external_users = entry_attrs_.get('ipasudorunasextuser', [])
failed_users = []
for user in failed['ipasudorunas']['user']:
username = user[0].lower()
user_dn = self.api.Object['user'].get_dn(username)
if username not in external_users and user_dn not in members:
external_users.append(username)
completed_external += 1
else:
failed_users.append(username)
if completed_external:
try:
ldap.update_entry(dn, {'ipasudorunasextuser': external_users})
except errors.EmptyModlist:
pass
failed['ipasudorunas']['user'] = failed_users
entry_attrs['ipasudorunasextuser'] = external_users
return (completed + completed_external, dn)
return add_external_post_callback('ipasudorunas', 'user', 'ipasudorunasextuser', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_add_runasuser)
@ -603,28 +491,7 @@ class sudorule_remove_runasuser(LDAPRemoveMember):
member_count_out = ('%i object removed.', '%i objects removed.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
# Run through the user failures and gracefully remove any defined as
# as an externaluser.
if 'ipasudorunas' in failed and 'user' in failed['ipasudorunas']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['ipasudorunasextuser'])
external_users = entry_attrs_.get('ipasudorunasextuser', [])
failed_users = []
completed_external = 0
for user in failed['ipasudorunas']['user']:
username = user[0].lower()
if username in external_users:
external_users.remove(username)
completed_external += 1
else:
failed_users.append(username)
if completed_external:
try:
ldap.update_entry(dn, {'ipasudorunasextuser': external_users})
except errors.EmptyModlist:
pass
failed['ipasudorunas']['user'] = failed_users
entry_attrs['ipasudorunasextuser'] = external_users
return (completed + completed_external, dn)
return remove_external_post_callback('ipasudorunas', 'user', 'ipasudorunasextuser', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_remove_runasuser)
@ -660,30 +527,7 @@ class sudorule_add_runasgroup(LDAPAddMember):
return dn
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
completed_external = 0
# Sift through the group failures. We assume that these are all
# groups that aren't stored in IPA, aka external groups.
if 'ipasudorunasgroup' in failed and 'group' in failed['ipasudorunasgroup']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['ipasudorunasextgroup'])
members = entry_attrs.get('ipasudorunasgroup', [])
external_groups = entry_attrs_.get('ipasudorunasextgroup', [])
failed_groups = []
for group in failed['ipasudorunasgroup']['group']:
groupname = group[0].lower()
group_dn = self.api.Object['group'].get_dn(groupname)
if groupname not in external_groups and group_dn not in members:
external_groups.append(groupname)
completed_external += 1
else:
failed_groups.append(groupname)
if completed_external:
try:
ldap.update_entry(dn, {'ipasudorunasextgroup': external_groups})
except errors.EmptyModlist:
pass
failed['ipasudorunasgroup']['group'] = failed_groups
entry_attrs['ipasudorunasextgroup'] = external_groups
return (completed + completed_external, dn)
return add_external_post_callback('ipasudorunasgroup', 'group', 'ipasudorunasextgroup', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_add_runasgroup)
@ -695,28 +539,7 @@ class sudorule_remove_runasgroup(LDAPRemoveMember):
member_count_out = ('%i object removed.', '%i objects removed.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
# Run through the group failures and gracefully remove any defined as
# as an external group.
if 'ipasudorunasgroup' in failed and 'group' in failed['ipasudorunasgroup']:
(dn, entry_attrs_) = ldap.get_entry(dn, ['ipasudorunasextgroup'])
external_groups = entry_attrs_.get('ipasudorunasextgroup', [])
failed_groups = []
completed_external = 0
for group in failed['ipasudorunasgroup']['group']:
groupname = group[0].lower()
if groupname in external_groups:
external_groups.remove(groupname)
completed_external += 1
else:
failed_groups.append(groupname)
if completed_external:
try:
ldap.update_entry(dn, {'ipasudorunasextgroup': external_groups})
except errors.EmptyModlist:
pass
failed['ipasudorunasgroup']['group'] = failed_groups
entry_attrs['ipasudorunasextgroup'] = external_groups
return (completed + completed_external, dn)
return remove_external_post_callback('ipasudorunasgroup', 'group', 'ipasudorunasextgroup', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_remove_runasgroup)

View File

@ -436,7 +436,7 @@ class test_sudorule(XMLRPC_test):
assert ret['completed'] == 1
failed = ret['failed']
entry = ret['result']
assert 'externalhost' not in entry
assert len(entry['externalhost']) == 0
def test_a_sudorule_add_allow_command(self):
"""