128 lines
5.1 KiB
Diff
128 lines
5.1 KiB
Diff
|
diff --git a/ipaserver/plugins/user.py b/ipaserver/plugins/user.py
|
||
|
index 6f5e349..febc22f 100644
|
||
|
--- a/ipaserver/plugins/user.py
|
||
|
+++ b/ipaserver/plugins/user.py
|
||
|
@@ -144,8 +144,7 @@ PROTECTED_USERS = ('admin',)
|
||
|
def check_protected_member(user, protected_group_name=u'admins'):
|
||
|
'''
|
||
|
Ensure admin and the last enabled member of a protected group cannot
|
||
|
- be deleted or disabled by raising ProtectedEntryError or
|
||
|
- LastMemberError as appropriate.
|
||
|
+ be deleted.
|
||
|
'''
|
||
|
|
||
|
if user in PROTECTED_USERS:
|
||
|
@@ -155,6 +154,12 @@ def check_protected_member(user, protected_group_name=u'admins'):
|
||
|
reason=_("privileged user"),
|
||
|
)
|
||
|
|
||
|
+
|
||
|
+def check_last_member(user, protected_group_name=u'admins'):
|
||
|
+ '''
|
||
|
+ Ensure the last enabled member of a protected group cannot
|
||
|
+ be disabled.
|
||
|
+ '''
|
||
|
# Get all users in the protected group
|
||
|
result = api.Command.user_find(in_group=protected_group_name)
|
||
|
|
||
|
@@ -796,6 +801,7 @@ class user_del(baseuser_del):
|
||
|
# If the target entry is a Delete entry, skip the orphaning/removal
|
||
|
# of OTP tokens.
|
||
|
check_protected_member(keys[-1])
|
||
|
+ check_last_member(keys[-1])
|
||
|
|
||
|
preserve = options.get('preserve', False)
|
||
|
|
||
|
@@ -1128,7 +1134,7 @@ class user_disable(LDAPQuery):
|
||
|
def execute(self, *keys, **options):
|
||
|
ldap = self.obj.backend
|
||
|
|
||
|
- check_protected_member(keys[-1])
|
||
|
+ check_last_member(keys[-1])
|
||
|
|
||
|
dn, _oc = self.obj.get_either_dn(*keys, **options)
|
||
|
ldap.deactivate_entry(dn)
|
||
|
diff --git a/ipatests/test_integration/test_commands.py b/ipatests/test_integration/test_commands.py
|
||
|
index c0cb4d0..c2a55b8 100644
|
||
|
--- a/ipatests/test_integration/test_commands.py
|
||
|
+++ b/ipatests/test_integration/test_commands.py
|
||
|
@@ -1530,6 +1530,30 @@ class TestIPACommand(IntegrationTest):
|
||
|
|
||
|
assert 'Discovered server %s' % self.master.hostname in result
|
||
|
|
||
|
+ def test_delete_last_enabled_admin(self):
|
||
|
+ """
|
||
|
+ The admin user may be disabled. Don't allow all other
|
||
|
+ members of admins to be removed if the admin user is
|
||
|
+ disabled which would leave the install with no
|
||
|
+ usable admins users
|
||
|
+ """
|
||
|
+ user = 'adminuser2'
|
||
|
+ passwd = 'Secret123'
|
||
|
+ tasks.create_active_user(self.master, user, passwd)
|
||
|
+ tasks.kinit_admin(self.master)
|
||
|
+ self.master.run_command(['ipa', 'group-add-member', 'admins',
|
||
|
+ '--users', user])
|
||
|
+ tasks.kinit_user(self.master, user, passwd)
|
||
|
+ self.master.run_command(['ipa', 'user-disable', 'admin'])
|
||
|
+ result = self.master.run_command(
|
||
|
+ ['ipa', 'user-del', user],
|
||
|
+ raiseonerr=False
|
||
|
+ )
|
||
|
+ self.master.run_command(['ipa', 'user-enable', 'admin'])
|
||
|
+ tasks.kdestroy_all(self.master)
|
||
|
+ assert result.returncode == 1
|
||
|
+ assert 'cannot be deleted or disabled' in result.stderr_text
|
||
|
+
|
||
|
|
||
|
class TestIPACommandWithoutReplica(IntegrationTest):
|
||
|
"""
|
||
|
diff --git a/ipatests/test_xmlrpc/test_user_plugin.py b/ipatests/test_xmlrpc/test_user_plugin.py
|
||
|
index 3c58845..68c6c48 100644
|
||
|
--- a/ipatests/test_xmlrpc/test_user_plugin.py
|
||
|
+++ b/ipatests/test_xmlrpc/test_user_plugin.py
|
||
|
@@ -1045,8 +1045,8 @@ class TestAdmins(XMLRPC_test):
|
||
|
tracker = Tracker()
|
||
|
command = tracker.make_command('user_disable', admin1)
|
||
|
|
||
|
- with raises_exact(errors.ProtectedEntryError(label=u'user',
|
||
|
- key=admin1, reason='privileged user')):
|
||
|
+ with raises_exact(errors.LastMemberError(label=u'group',
|
||
|
+ key=admin1, container=admin_group)):
|
||
|
command()
|
||
|
|
||
|
def test_create_admin2(self, admin2):
|
||
|
@@ -1064,8 +1064,8 @@ class TestAdmins(XMLRPC_test):
|
||
|
admin2.disable()
|
||
|
tracker = Tracker()
|
||
|
|
||
|
- with raises_exact(errors.ProtectedEntryError(label=u'user',
|
||
|
- key=admin1, reason='privileged user')):
|
||
|
+ with raises_exact(errors.LastMemberError(label=u'group',
|
||
|
+ key=admin1, container=admin_group)):
|
||
|
tracker.run_command('user_disable', admin1)
|
||
|
admin2.delete()
|
||
|
|
||
|
diff --git a/ipatests/test_webui/test_user.py b/ipatests/test_webui/test_user.py
|
||
|
index a8a92d0..9083e50 100644
|
||
|
--- a/ipatests/test_webui/test_user.py
|
||
|
+++ b/ipatests/test_webui/test_user.py
|
||
|
@@ -50,6 +50,8 @@ INV_FIRSTNAME = ("invalid 'first': Leading and trailing spaces are "
|
||
|
FIELD_REQ = 'Required field'
|
||
|
ERR_INCLUDE = 'may only include letters, numbers, _, -, . and $'
|
||
|
ERR_MISMATCH = 'Passwords must match'
|
||
|
+ERR_ADMIN_DISABLE = ('admin cannot be deleted or disabled because '
|
||
|
+ 'it is the last member of group admins')
|
||
|
ERR_ADMIN_DEL = ('user admin cannot be deleted/modified: privileged user')
|
||
|
USR_EXIST = 'user with name "{}" already exists'
|
||
|
ENTRY_EXIST = 'This entry already exists'
|
||
|
@@ -546,7 +548,7 @@ class test_user(user_tasks):
|
||
|
self.select_record('admin')
|
||
|
self.facet_button_click('disable')
|
||
|
self.dialog_button_click('ok')
|
||
|
- self.assert_last_error_dialog(ERR_ADMIN_DEL, details=True)
|
||
|
+ self.assert_last_error_dialog(ERR_ADMIN_DISABLE, details=True)
|
||
|
self.dialog_button_click('ok')
|
||
|
self.assert_record('admin')
|
||
|
|