summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Viktorin <pviktori@redhat.com>2012-05-23 05:44:53 -0400
committerRob Crittenden <rcritten@redhat.com>2012-06-06 21:57:12 -0400
commitf8e7b516d923142a23058cb23ee817522686cfe3 (patch)
tree9987a2ea8abd8579c4852ad813d00861351e54bf
parentcf72738b214d115bb930f4e323512fd57a426a63 (diff)
downloadfreeipa-f8e7b516d923142a23058cb23ee817522686cfe3.zip
freeipa-f8e7b516d923142a23058cb23ee817522686cfe3.tar.gz
freeipa-f8e7b516d923142a23058cb23ee817522686cfe3.tar.xz
Prevent deletion of the last admin
Raise an error when trying to delete the last user in the 'admins' group, or remove the last member from the group, or delete the group itself. https://fedorahosted.org/freeipa/ticket/2564
-rw-r--r--ipalib/errors.py32
-rw-r--r--ipalib/plugins/group.py16
-rw-r--r--ipalib/plugins/user.py9
-rw-r--r--tests/test_xmlrpc/test_group_plugin.py55
-rw-r--r--tests/test_xmlrpc/test_user_plugin.py41
5 files changed, 150 insertions, 3 deletions
diff --git a/ipalib/errors.py b/ipalib/errors.py
index df4ab41..407d9f7 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 1320854..6565736 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 b48e680..7e98bba 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 c0abcb9..abee7ba 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 4b2be5c..355a4cb 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,
+ ),
+ ),
+
]