diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py index 819141b7f..968b1d68c 100644 --- a/ipaserver/plugins/user.py +++ b/ipaserver/plugins/user.py @@ -140,14 +140,23 @@ MEMBEROF_ADMINS = "(memberOf={})".format( ) NOT_MEMBEROF_ADMINS = '(!{})'.format(MEMBEROF_ADMINS) +PROTECTED_USERS = ('admin',) def check_protected_member(user, protected_group_name=u'admins'): ''' - Ensure the last enabled member of a protected group cannot be deleted or - disabled by raising LastMemberError. + Ensure admin and the last enabled member of a protected group cannot + be deleted or disabled by raising ProtectedEntryError or + LastMemberError as appropriate. ''' + if user in PROTECTED_USERS: + raise errors.ProtectedEntryError( + label=_("user"), + key=user, + reason=_("privileged user"), + ) + # Get all users in the protected group result = api.Command.user_find(in_group=protected_group_name) @@ -879,6 +888,12 @@ class user_mod(baseuser_mod): def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): dn, oc = self.obj.get_either_dn(*keys, **options) + if options.get('rename') and keys[-1] in PROTECTED_USERS: + raise errors.ProtectedEntryError( + label=_("user"), + key=keys[-1], + reason=_("privileged user"), + ) if 'objectclass' not in entry_attrs and 'rename' not in options: entry_attrs.update({'objectclass': oc}) self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys, diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py index d7009e797..974d256d9 100644 --- a/ipatests/test_xmlrpc/test_user_plugin.py +++ b/ipatests/test_xmlrpc/test_user_plugin.py @@ -979,22 +979,32 @@ class TestManagers(XMLRPC_test): @pytest.mark.tier1 class TestAdmins(XMLRPC_test): - def test_remove_original_admin(self): - """ Try to remove the only admin """ + def test_delete_admin(self): + """ Try to delete the protected admin user """ tracker = Tracker() - command = tracker.make_command('user_del', [admin1]) + command = tracker.make_command('user_del', admin1) - with raises_exact(errors.LastMemberError( - key=admin1, label=u'group', container=admin_group)): + with raises_exact(errors.ProtectedEntryError(label=u'user', + key=admin1, reason='privileged user')): + command() + + def test_rename_admin(self): + """ Try to rename the admin user """ + tracker = Tracker() + command = tracker.make_command('user_mod', admin1, + **dict(rename=u'newadmin')) + + with raises_exact(errors.ProtectedEntryError(label=u'user', + key=admin1, reason='privileged user')): command() def test_disable_original_admin(self): - """ Try to disable the only admin """ + """ Try to disable the original admin """ tracker = Tracker() command = tracker.make_command('user_disable', admin1) - with raises_exact(errors.LastMemberError( - key=admin1, label=u'group', container=admin_group)): + with raises_exact(errors.ProtectedEntryError(label=u'user', + key=admin1, reason='privileged user')): command() def test_create_admin2(self, admin2): @@ -1012,21 +1022,11 @@ class TestAdmins(XMLRPC_test): admin2.disable() tracker = Tracker() - with raises_exact(errors.LastMemberError( - key=admin1, label=u'group', container=admin_group)): + with raises_exact(errors.ProtectedEntryError(label=u'user', + key=admin1, reason='privileged user')): tracker.run_command('user_disable', admin1) - with raises_exact(errors.LastMemberError( - key=admin1, label=u'group', container=admin_group)): - tracker.run_command('user_del', admin1) admin2.delete() - with raises_exact(errors.LastMemberError( - key=admin1, label=u'group', container=admin_group)): - tracker.run_command('user_disable', admin1) - with raises_exact(errors.LastMemberError( - key=admin1, label=u'group', container=admin_group)): - tracker.run_command('user_del', admin1) - @pytest.mark.tier1 class TestPreferredLanguages(XMLRPC_test):