Prevent the admin user from being deleted

admin is required for trust operations

Note that testing for removing the last member is now
irrelevant because admin must always exist so the test
for it was removed, but the code check remains. It is done
after the protected member check.

Fixes: https://pagure.io/freeipa/issue/8878

Signed-off-by: Rob Crittenden <rcritten@redhat.com>
Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
This commit is contained in:
Rob Crittenden
2023-05-25 18:24:29 -04:00
committed by Florence Blanc-Renaud
parent 69e4397421
commit dea35922cd
2 changed files with 37 additions and 22 deletions

View File

@@ -140,14 +140,23 @@ MEMBEROF_ADMINS = "(memberOf={})".format(
) )
NOT_MEMBEROF_ADMINS = '(!{})'.format(MEMBEROF_ADMINS) NOT_MEMBEROF_ADMINS = '(!{})'.format(MEMBEROF_ADMINS)
PROTECTED_USERS = ('admin',)
def check_protected_member(user, protected_group_name=u'admins'): def check_protected_member(user, protected_group_name=u'admins'):
''' '''
Ensure the last enabled member of a protected group cannot be deleted or Ensure admin and the last enabled member of a protected group cannot
disabled by raising LastMemberError. 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 # Get all users in the protected group
result = api.Command.user_find(in_group=protected_group_name) 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): def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
dn, oc = self.obj.get_either_dn(*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: if 'objectclass' not in entry_attrs and 'rename' not in options:
entry_attrs.update({'objectclass': oc}) entry_attrs.update({'objectclass': oc})
self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys, self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys,

View File

@@ -979,22 +979,32 @@ class TestManagers(XMLRPC_test):
@pytest.mark.tier1 @pytest.mark.tier1
class TestAdmins(XMLRPC_test): class TestAdmins(XMLRPC_test):
def test_remove_original_admin(self): def test_delete_admin(self):
""" Try to remove the only admin """ """ Try to delete the protected admin user """
tracker = Tracker() tracker = Tracker()
command = tracker.make_command('user_del', [admin1]) command = tracker.make_command('user_del', admin1)
with raises_exact(errors.LastMemberError( with raises_exact(errors.ProtectedEntryError(label=u'user',
key=admin1, label=u'group', container=admin_group)): 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() command()
def test_disable_original_admin(self): def test_disable_original_admin(self):
""" Try to disable the only admin """ """ Try to disable the original admin """
tracker = Tracker() tracker = Tracker()
command = tracker.make_command('user_disable', admin1) command = tracker.make_command('user_disable', admin1)
with raises_exact(errors.LastMemberError( with raises_exact(errors.ProtectedEntryError(label=u'user',
key=admin1, label=u'group', container=admin_group)): key=admin1, reason='privileged user')):
command() command()
def test_create_admin2(self, admin2): def test_create_admin2(self, admin2):
@@ -1012,21 +1022,11 @@ class TestAdmins(XMLRPC_test):
admin2.disable() admin2.disable()
tracker = Tracker() tracker = Tracker()
with raises_exact(errors.LastMemberError( with raises_exact(errors.ProtectedEntryError(label=u'user',
key=admin1, label=u'group', container=admin_group)): key=admin1, reason='privileged user')):
tracker.run_command('user_disable', admin1) 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() 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 @pytest.mark.tier1
class TestPreferredLanguages(XMLRPC_test): class TestPreferredLanguages(XMLRPC_test):