diff options
-rw-r--r-- | ipalib/errors.py | 32 | ||||
-rw-r--r-- | ipalib/plugins/group.py | 16 | ||||
-rw-r--r-- | ipalib/plugins/user.py | 9 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_group_plugin.py | 55 | ||||
-rw-r--r-- | tests/test_xmlrpc/test_user_plugin.py | 41 |
5 files changed, 150 insertions, 3 deletions
diff --git a/ipalib/errors.py b/ipalib/errors.py index df4ab4167..407d9f7db 100644 --- a/ipalib/errors.py +++ b/ipalib/errors.py @@ -1575,6 +1575,38 @@ class DependentEntry(ExecutionError): format = _('%(key)s cannot be deleted because %(label)s %(dependent)s requires it') +class LastMemberError(ExecutionError): + """ + **4308** Raised when an entry being deleted is last member of a protected group + + For example: + >>> raise LastMemberError(key=u'admin', label=u'group', container=u'admins') + Traceback (most recent call last): + ... + LastMemberError: admin cannot be deleted because it is the last member of group admins + + """ + + errno = 4308 + format = _('%(key)s cannot be deleted because it is the last member of %(label)s %(container)s') + + +class ProtectedEntryError(ExecutionError): + """ + **4309** Raised when an entry being deleted is protected + + For example: + >>> raise ProtectedEntryError(label=u'group', key=u'admins', reason=u'privileged group') + Traceback (most recent call last): + ... + ProtectedEntryError: group admins cannot be deleted: privileged group + + """ + + errno = 4309 + format = _('%(label)s %(key)s cannot be deleted: %(reason)s') + + ############################################################################## # 5000 - 5999: Generic errors diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py index 13208542c..65657363a 100644 --- a/ipalib/plugins/group.py +++ b/ipalib/plugins/group.py @@ -72,6 +72,8 @@ EXAMPLES: ipa group-show localadmins """) +protected_group_name = u'admins' + class group(LDAPObject): """ Group object. @@ -164,7 +166,9 @@ class group_del(LDAPDelete): group_attrs = self.obj.methods.show( self.obj.get_primary_key_from_dn(dn), all=True )['result'] - + if keys[0] == protected_group_name: + raise errors.ProtectedEntryError(label=_(u'group'), key=keys[0], + reason=_(u'privileged group')) if 'mepmanagedby' in group_attrs: raise errors.ManagedGroupError() return dn @@ -276,6 +280,16 @@ api.register(group_add_member) class group_remove_member(LDAPRemoveMember): __doc__ = _('Remove members from a group.') + def pre_callback(self, ldap, dn, found, not_found, *keys, **options): + if keys[0] == protected_group_name: + result = api.Command.group_show(protected_group_name) + users_left = set(result['result'].get('member_user', [])) + users_deleted = set(options['user']) + if users_left.issubset(users_deleted): + raise errors.LastMemberError(key=sorted(users_deleted)[0], + label=_(u'group'), container=protected_group_name) + return dn + api.register(group_remove_member) diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py index b48e68022..7e98bba4c 100644 --- a/ipalib/plugins/user.py +++ b/ipalib/plugins/user.py @@ -544,8 +544,13 @@ class user_del(LDAPDelete): msg_summary = _('Deleted user "%(value)s"') - def post_callback(self, ldap, dn, *keys, **options): - return True + def pre_callback(self, ldap, dn, *keys, **options): + protected_group_name = u'admins' + result = api.Command.group_show(protected_group_name) + if result['result'].get('member_user', []) == [keys[-1]]: + raise errors.LastMemberError(key=keys[-1], label=_(u'group'), + container=protected_group_name) + return dn api.register(user_del) diff --git a/tests/test_xmlrpc/test_group_plugin.py b/tests/test_xmlrpc/test_group_plugin.py index c0abcb955..abee7bac7 100644 --- a/tests/test_xmlrpc/test_group_plugin.py +++ b/tests/test_xmlrpc/test_group_plugin.py @@ -797,4 +797,59 @@ class test_group(Declarative): expected=errors.NotFound(reason=u'%s: group not found' % user1), ), + dict( + desc='Try to remove the admin user from the admins group', + command=('group_remove_member', [u'admins'], dict(user=[u'admin'])), + expected=errors.LastMemberError(key=u'admin', label=u'group', + container='admins'), + ), + + dict( + desc='Add %r to the admins group' % user1, + command=('group_add_member', [u'admins'], dict(user=user1)), + expected=dict( + completed=1, + failed=dict( + member=dict( + group=tuple(), + user=tuple(), + ), + ), + result={ + 'dn': lambda x: DN(x) == \ + DN(('cn', 'admins'), ('cn', 'groups'), + ('cn', 'accounts'), api.env.basedn), + 'member_user': [u'admin', user1], + 'gidnumber': [fuzzy_digits], + 'cn': [u'admins'], + 'description': [u'Account administrators group'], + }, + ), + ), + + dict( + desc='Try to remove admin and %r from the admins group' % user1, + command=('group_remove_member', [u'admins'], + dict(user=[u'admin', user1])), + expected=errors.LastMemberError(key=u'admin', label=u'group', + container='admins'), + ), + + dict( + desc='Try to delete the admins group', + command=('group_del', [u'admins'], {}), + expected=errors.ProtectedEntryError(label=u'group', + key='admins', reason='privileged group'), + ), + + dict( + desc='Delete %r' % user1, + command=('user_del', [user1], {}), + expected=dict( + result=dict(failed=u''), + summary=u'Deleted user "%s"' % user1, + value=user1, + ), + ), + ] diff --git a/tests/test_xmlrpc/test_user_plugin.py b/tests/test_xmlrpc/test_user_plugin.py index 4b2be5c32..355a4cbbb 100644 --- a/tests/test_xmlrpc/test_user_plugin.py +++ b/tests/test_xmlrpc/test_user_plugin.py @@ -1330,4 +1330,45 @@ class test_user(Declarative): ), expected=lambda x: True, ), + + dict( + desc='Try to remove the admin user', + command=('user_del', [u'admin'], {}), + expected=errors.LastMemberError(key=u'admin', label=u'group', + container='admins'), + ), + + dict( + desc='Add %r to the admins group' % user2, + command=('group_add_member', [u'admins'], dict(user=user2)), + expected=dict( + completed=1, + failed=dict( + member=dict( + group=tuple(), + user=tuple(), + ), + ), + result={ + 'dn': lambda x: DN(x) == \ + DN(('cn', 'admins'), ('cn', 'groups'), + ('cn', 'accounts'), api.env.basedn), + 'member_user': [u'admin', user2], + 'gidnumber': [fuzzy_digits], + 'cn': [u'admins'], + 'description': [u'Account administrators group'], + }, + ), + ), + + dict( + desc='Delete %r' % user2, + command=('user_del', [user2], {}), + expected=dict( + result=dict(failed=u''), + summary=u'Deleted user "%s"' % user2, + value=user2, + ), + ), + ] |