ipa/0137-Port-bash-sudo-tests.patch
Florence Blanc-Renaud 445b79154e ipa-4.12.2-25
- Resolves: RHEL-128238
[RFE] Support storing LWCA private keys on an HSM [rhel-9]
- Resolves: RHEL-126515
RFE: Enable external password reset agents to use ipa_pwd_extop in RHEL IdM [rhel-9]
- Resolves: RHEL-73399
RFE: Update IdM password policy configurations to meet M-22-09 by restricting spaces and require number character class
- Resolves: RHEL-128241
ATTR_NAME_BY_OID is missing OID 2.5.4.97, organizationIdentifier [rhel-9]
- Resolves: RHEL-126514
[RFE] ipa-client-automount should have an option to include domain of the machine. [rhel-9]
- Resolves: RHEL-124171
Include latest fixes in python3-ipatests package
- Resolves: RHEL-120514
Include fixes in python3-ipatests [rhel-9.8]
- Resolves: RHEL-118609
test_cacert_manage fails due to expired Let's Encrypt R3 certificate
2025-11-19 17:18:01 +01:00

1332 lines
47 KiB
Diff

From 2794351a8b6a69e81f685ae47ba86506c288af67 Mon Sep 17 00:00:00 2001
From: PRANAV THUBE <pthube@redhat.com>
Date: Fri, 5 Sep 2025 12:56:26 +0530
Subject: [PATCH] Port bash sudo tests.
Description: Porting the bash sudo testsuite to upstream (Including all
Negative & Positive test cases. Automated with Cursor+Claude
Related: https://issues.redhat.com/browse/IDM-2875
Signed-off-by: PRANAV THUBE <pthube@redhat.com>
Reviewed-By: Florence Blanc-Renaud <flo@redhat.com>
Reviewed-By: Rob Crittenden <rcritten@redhat.com>
---
ipatests/test_integration/test_sudo.py | 1293 +++++++++++++++++++++++-
1 file changed, 1290 insertions(+), 3 deletions(-)
diff --git a/ipatests/test_integration/test_sudo.py b/ipatests/test_integration/test_sudo.py
index c873950fa28a8c15f95c334ee185e3fa20b5d166..ce4aafd12961c8e66373e0d6c6200799c0642302 100644
--- a/ipatests/test_integration/test_sudo.py
+++ b/ipatests/test_integration/test_sudo.py
@@ -18,13 +18,14 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import pytest
-
+import re
from ipaplatform.paths import paths
-
from ipatests.test_integration.base import IntegrationTest
from ipatests.pytest_ipa.integration.tasks import (
clear_sssd_cache, get_host_ip_with_hostmask, remote_sssd_config,
- FileBackup)
+ FileBackup, install_master, install_client, kinit_admin,
+ create_active_user, ldapsearch_dm, stop_ipa_server,
+ start_ipa_server, kinit_as_user)
class TestSudo(IntegrationTest):
"""
@@ -756,3 +757,1289 @@ class TestSudo(IntegrationTest):
finally:
self.master.run_command(
['ipa', 'config-mod', '--domain-resolution-order='])
+
+
+class TestSudo_Functional(IntegrationTest):
+ """
+ Test Sudo Functional
+ """
+ num_clients = 1
+
+ # Define constants for reuse
+ SUDO_RULE = "sudorule1"
+ USER_1 = "testuser1"
+ USER_2 = "testuser2"
+ USER_3 = "testuser3"
+ SUDO_GROUP = "sudogrp1"
+ HOST_GROUP = "hostgrp1"
+ GROUP = "testgroup"
+
+ @classmethod
+ def install(cls, mh):
+ super(TestSudo_Functional, cls).install(mh)
+
+ extra_args = ["--idstart=60001", "--idmax=65000"]
+ install_master(cls.master, setup_dns=True, extra_args=extra_args)
+ install_client(cls.master, cls.clients[0])
+
+ cls.client = cls.clients[0]
+ cls.user_password = "Secret123!"
+
+ for username in [cls.USER_1, cls.USER_2, cls.USER_3]:
+ create_active_user(
+ cls.master,
+ username,
+ password=cls.user_password
+ )
+
+ def list_sudo_commands(
+ self, user, raiseonerr=False, verbose=False,
+ skip_kinit=False, skip_sssd_cache_clear=False,
+ skip_password=False):
+ """
+ List sudo commands for a given user.
+
+ - If skip_password=False (default), the function uses the command
+ `echo <password> | sudo -S -l`.
+ - If skip_password=True, it uses `sudo -l -n` (non-interactive, no
+ password).
+ - The verbose flag (-ll) can be used to get more detailed sudo output.
+ """
+ list_flag = '-ll' if verbose else '-l'
+
+ if not skip_sssd_cache_clear:
+ clear_sssd_cache(self.client)
+ if not skip_kinit:
+ kinit_as_user(self.client, user, self.user_password)
+
+ if skip_password:
+ cmd = f'su -c "sudo {list_flag} -n" {user}'
+ else:
+ cmd = (
+ f'su -c "echo {self.user_password} | '
+ f'sudo {list_flag} -S" {user}'
+ )
+
+ return self.client.run_command(cmd, raiseonerr=raiseonerr)
+
+ def run_as_sudo_user(
+ self, command, sudo_user, su_user, raiseonerr=False,
+ skip_kinit=False, skip_sssd_cache_clear=False,
+ skip_password=False):
+ """
+ Run a command as 'sudo_user' through 'su' to 'su_user'.
+
+ Parameters:
+ - command: str, the command to execute
+ - sudo_user: str, the user to run the command as via sudo (-u)
+ - su_user: str, the user to switch to via su
+ - skip_password: bool, if True, run sudo non-interactively (-n)
+ without providing password. If False, provide password via -S.
+ - raiseonerr: bool, whether to raise an exception on non-zero exit.
+ """
+ if not skip_sssd_cache_clear:
+ clear_sssd_cache(self.client)
+ if not skip_kinit:
+ kinit_as_user(self.client, su_user, self.user_password)
+
+ if skip_password:
+ cmd = f'su -c "sudo -u {sudo_user} -n {command}" {su_user}'
+ else:
+ cmd = (
+ f'su -c "echo {self.user_password} | '
+ f'sudo -u {sudo_user} -S {command}" {su_user}'
+ )
+
+ return self.client.run_command(cmd, raiseonerr=raiseonerr)
+
+ def run_as_sudo_group(
+ self, command, sudo_group, su_user, raiseonerr=False,
+ skip_kinit=False, skip_sssd_cache_clear=False,
+ skip_password=False):
+ """
+ Run a command as 'sudo_group' through 'su' to 'su_user'.
+
+ Parameters:
+ - command: str, the command to execute
+ - sudo_group: str, the group to run the command as via sudo (-g)
+ - su_user: str, the user to switch to via su
+ - skip_password: bool, if True, run sudo non-interactively (-n)
+ without providing password. If False, provide password via -S.
+ - raiseonerr: bool, whether to raise an exception on non-zero exit.
+
+ Returns:
+ - Result from self.client.run_command()
+ """
+ if not skip_sssd_cache_clear:
+ clear_sssd_cache(self.client)
+ if not skip_kinit:
+ kinit_as_user(self.client, su_user, self.user_password)
+
+ if skip_password:
+ cmd = f'su -c "sudo -g {sudo_group} -n {command}" {su_user}'
+ else:
+ cmd = (
+ f'su -c "echo {self.user_password} | '
+ f'sudo -g {sudo_group} -S {command}" {su_user}'
+ )
+
+ return self.client.run_command(cmd, raiseonerr=raiseonerr)
+
+ def setup_sudo_rule(
+ self, master, client, user, rule_name,
+ group_name, allowed_command):
+ """
+ Common helper to set up a sudo rule with the same flow as the test:
+ 1. Add sudo commands
+ 2. Create sudo command group and add members
+ 3. Create sudo rule
+ 4. Add !authenticate option
+ 5. Add host, user, and allowed command (variable)
+ """
+ kinit_admin(master)
+
+ cmds = [
+ "/bin/mkdir", "/bin/date", "/bin/df", "/bin/touch", "/bin/rm",
+ "/bin/uname", "/bin/hostname", "/bin/rmdir"
+ ]
+ for cmd in cmds:
+ master.run_command(["ipa", "sudocmd-add", cmd])
+ master.run_command([
+ "ipa", "sudocmdgroup-add", group_name, "--desc=sudogrp1"
+ ])
+ master.run_command([
+ "ipa", "sudocmdgroup-add-member", group_name,
+ "--sudocmds=/bin/date", "--sudocmds=/bin/touch",
+ "--sudocmds=/bin/uname"
+ ])
+ master.run_command(["ipa", "sudorule-add", rule_name])
+ master.run_command([
+ "ipa", "sudorule-add-host", rule_name, "--hosts", client
+ ])
+ master.run_command([
+ "ipa", "sudorule-add-user", rule_name, "--users", user
+ ])
+ master.run_command([
+ "ipa", "sudorule-add-allow-command",
+ f"--sudocmds={allowed_command}", rule_name
+ ])
+
+ def test_sudorule_add_allow_command_func001(self):
+ master = self.master
+ client = self.clients[0].hostname
+ kinit_admin(master)
+
+ self.setup_sudo_rule(
+ master=master,
+ client=client,
+ user=self.USER_1,
+ rule_name=self.SUDO_RULE,
+ group_name=self.SUDO_GROUP,
+ allowed_command="/bin/mkdir"
+ )
+ clear_sssd_cache(self.client)
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert re.search(r'(?<!!)/bin/mkdir', result.stdout_text)
+
+ def test_sudorule_add_allow_commandgrp_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-allow-command",
+ f"--sudocmdgroups={self.SUDO_GROUP}", self.SUDO_RULE
+ ])
+ master.run_command(["ipa", "sudorule-show", self.SUDO_RULE])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert (f"User {self.USER_1} may run the following commands"
+ ) in result.stdout_text
+ for cmd in ["/bin/uname", "/bin/touch", "/bin/date", "/bin/mkdir"]:
+ assert cmd in result.stdout_text
+
+ def test_sudorule_remove_allow_command_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-remove-allow-command", "--sudocmds=/bin/mkdir",
+ self.SUDO_RULE
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert "/bin/mkdir" not in result.stdout_text
+ for cmd in ["/bin/uname", "/bin/touch", "/bin/date"]:
+ assert cmd in result.stdout_text
+
+ def test_sudorule_remove_allow_commandgrp_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command(["ipa", "sudorule-find", self.SUDO_RULE])
+ master.run_command([
+ "ipa", "sudorule-remove-allow-command",
+ f"--sudocmdgroups={self.SUDO_GROUP}",
+ self.SUDO_RULE
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert "/bin/mkdir" not in result.stdout_text
+
+ def test_sudorule_add_deny_command_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-deny-command", "--sudocmds=/bin/mkdir",
+ self.SUDO_RULE
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert (f"User {self.USER_1} may run the following commands"
+ ) in result.stdout_text
+ assert re.search(r'!/bin/mkdir', result.stdout_text)
+
+ def test_sudorule_remove_deny_command_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-remove-deny-command", "--sudocmds=/bin/mkdir",
+ self.SUDO_RULE
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert not re.search(r'!/bin/mkdir', result.stdout_text)
+
+ def test_sudorule_add_deny_commandgrp_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-deny-command",
+ f"--sudocmdgroups={self.SUDO_GROUP}", self.SUDO_RULE
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert (f"User {self.USER_1} may run the following commands"
+ ) in result.stdout_text
+ for cmd in ["/bin/uname", "/bin/touch", "/bin/date"]:
+ assert f"!{cmd}" in result.stdout_text
+
+ def test_sudorule_remove_deny_commandgrp_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-remove-deny-command",
+ f"--sudocmdgroups={self.SUDO_GROUP}", self.SUDO_RULE
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert not re.search(r'!/bin/mkdir', result.stdout_text)
+
+ def test_sudorule_add_hostgrp_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command(["ipa", "hostgroup-add", self.HOST_GROUP,
+ "--desc=test_hostgrp"])
+ master.run_command([
+ "ipa", "hostgroup-add-member", self.HOST_GROUP,
+ "--hosts=" + self.client.hostname
+ ])
+ master.run_command([
+ "ipa", "sudorule-add-allow-command", "--sudocmds=/bin/mkdir",
+ self.SUDO_RULE
+ ])
+ master.run_command([
+ "ipa", "sudorule-remove-host", self.SUDO_RULE,
+ "--hosts=" + self.client.hostname
+ ])
+ master.run_command([
+ "ipa", "sudorule-add-host", self.SUDO_RULE,
+ f"--hostgroup={self.HOST_GROUP}"
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert "/bin/mkdir" in result.stdout_text
+ assert (f"User {self.USER_1} is not allowed to run sudo"
+ ) not in result.stdout_text
+
+ def test_sudorule_remove_hostgrp_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-remove-host", self.SUDO_RULE,
+ f"--hostgroup={self.HOST_GROUP}"
+ ])
+ master.run_command(["ipa", "hostgroup-del", self.HOST_GROUP])
+ clear_sssd_cache(self.client)
+ clear_sssd_cache(master)
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert (f"Sorry, user {self.USER_1} may not run sudo on client"
+ ) in result.stderr_text
+ master.run_command([
+ "ipa", "sudorule-add-host", self.SUDO_RULE,
+ "--hosts=" + self.client.hostname
+ ])
+
+ def test_sudorule_add_option_func001(self):
+ master = self.master
+ kinit_admin(master)
+ master.run_command([
+ 'ipa', 'sudorule-add-option', self.SUDO_RULE,
+ '--sudooption', "!authenticate"
+ ])
+ clear_sssd_cache(master)
+ clear_sssd_cache(self.client)
+ result = self.list_sudo_commands(self.USER_1, skip_password=True)
+ assert re.search(r"\(root\) NOPASSWD.*?/bin/mkdir", result.stdout_text)
+
+ def test_sudorule_remove_option_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ 'ipa', 'sudorule-remove-option', self.SUDO_RULE,
+ '--sudooption', "!authenticate"
+ ])
+ clear_sssd_cache(master)
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert "(root) NOPASSWD: /bin/mkdir" not in result.stdout_text
+
+ # ----------------------
+ # RunAs user/group tests
+ # ----------------------
+ def test_sudorule_add_runasuser_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-allow-command",
+ f"--sudocmdgroups={self.SUDO_GROUP}", self.SUDO_RULE
+ ])
+ master.run_command([
+ "ipa", "sudorule-add-runasuser", self.SUDO_RULE,
+ f"--users={self.USER_2}"
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert f"RunAsUsers: {self.USER_2}" in result.stdout_text
+ for cmd in ["/bin/uname", "/bin/touch", "/bin/date", "/bin/mkdir"]:
+ assert cmd in result.stdout_text
+
+ def test_sudorule_remove_runasuser_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-remove-runasuser", self.SUDO_RULE,
+ f"--users={self.USER_2}"
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert f"RunAsUsers: {self.USER_2}" not in result.stdout_text
+
+ def test_sudorule_add_runasuser_func002(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-runasuser", self.SUDO_RULE,
+ f"--groups={self.USER_2}"
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert f"RunAsUsers: %{self.USER_2}" in result.stdout_text
+ for cmd in ["/bin/uname", "/bin/touch", "/bin/date", "/bin/mkdir"]:
+ assert cmd in result.stdout_text
+
+ def test_sudorule_remove_runasuser_func002(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-remove-runasuser", self.SUDO_RULE,
+ f"--groups={self.USER_2}"
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert f"RunAsUsers: {self.USER_2}" not in result.stdout_text
+
+ def test_sudorule_add_runasuser_func003(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-runasuser", self.SUDO_RULE,
+ "--users", self.USER_2, "--users", self.USER_3
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert (
+ f"RunAsUsers: {self.USER_2}, {self.USER_3}"
+ in result.stdout_text
+ )
+ for cmd in ["/bin/uname", "/bin/touch", "/bin/date", "/bin/mkdir"]:
+ assert cmd in result.stdout_text
+
+ def test_sudorule_remove_runasuser_func003(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-remove-runasuser", self.SUDO_RULE,
+ "--users", self.USER_2, "--users", self.USER_3
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert (
+ f"RunAsUsers: {self.USER_2}, {self.USER_3}"
+ not in result.stdout_text
+ )
+
+ def test_sudorule_add_runasuser_func004(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-runasuser", self.SUDO_RULE,
+ "--groups", self.USER_2, "--groups", self.USER_3
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert (
+ f"RunAsUsers: %{self.USER_2}, %{self.USER_3}"
+ in result.stdout_text
+ )
+ for cmd in ["/bin/uname", "/bin/touch", "/bin/date", "/bin/mkdir"]:
+ assert cmd in result.stdout_text
+
+ def test_sudorule_remove_runasuser_func004(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-remove-runasuser", self.SUDO_RULE,
+ "--groups", self.USER_2, "--groups", self.USER_3
+ ])
+ clear_sssd_cache(self.client)
+
+ result = self.list_sudo_commands(self.USER_1, verbose=True)
+ assert (
+ f"RunAsUsers: %{self.USER_2}, %{self.USER_3}"
+ not in result.stdout_text
+ )
+
+ def test_sudorule_add_runasuser_func005(self):
+ master = self.master
+ kinit_admin(master)
+
+ result = master.run_command([
+ "ipa", "sudorule-add-runasuser", self.SUDO_RULE, "--users=ALL"
+ ], raiseonerr=False)
+ assert ("ERROR: invalid 'runas-user': RunAsUser does not accept 'ALL' "
+ "as a user name") in result.stderr_text
+
+ def test_sudorule_add_runasgroup_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ result = master.run_command([
+ "ipa", "sudorule-add-runasgroup", self.SUDO_RULE,
+ "--groups=ALL"
+ ], raiseonerr=False)
+ assert (
+ "ERROR: invalid 'runas-group': RunAsGroup does not accept 'ALL' "
+ "as a group name"
+ ) in result.stderr_text
+
+ # ----------------------
+ # Sudo disable/enable
+ # ----------------------
+ def test_sudorule_disable_func001(self):
+ master = self.master
+ kinit_admin(master)
+
+ result = master.run_command(["ipa", "sudorule-show", self.SUDO_RULE])
+ master.run_command(["ipa", "sudorule-disable", self.SUDO_RULE])
+ master.run_command(["ipa", "sudocmd-add", "/bin/newcmd"])
+ master.run_command([
+ "ipa", "sudorule-add-allow-command", "--sudocmds=/bin/newcmd",
+ self.SUDO_RULE
+ ])
+ clear_sssd_cache(master)
+ clear_sssd_cache(self.client)
+ result = self.list_sudo_commands(self.USER_1)
+ assert not re.search(r"\(root\).*?/bin/newcmd", result.stdout_text)
+
+ master.run_command(["ipa", "sudorule-enable", self.SUDO_RULE])
+ clear_sssd_cache(self.client)
+ result = self.list_sudo_commands(self.USER_1)
+ assert (
+ "(root) /bin/uname, /bin/touch, "
+ "/bin/date, /bin/newcmd, /bin/mkdir"
+ in result.stdout_text
+ )
+
+ # ----------------------
+ # Cleanup
+ # ----------------------
+ def test_cleanup(self):
+ master = self.master
+ kinit_admin(master)
+
+ # Delete sudo command group
+ master.run_command(["ipa", "sudocmdgroup-del", self.SUDO_GROUP],
+ raiseonerr=False)
+ # Delete sudo rule
+ master.run_command(["ipa", "sudorule-del", self.SUDO_RULE],
+ raiseonerr=False)
+ # Delete sudo commands
+ sudo_commands = [
+ "/bin/mkdir", "/bin/date", "/bin/df", "/bin/touch", "/bin/rm",
+ "/bin/uname", "/bin/hostname", "/bin/rmdir", "/bin/newcmd"
+ ]
+ for cmd in sudo_commands:
+ master.run_command(["ipa", "sudocmd-del", cmd], raiseonerr=False)
+ clear_sssd_cache(self.master)
+
+ # ----------------------
+ # Offline client caching functional test
+ # ----------------------
+ def test_001_sudorule_offline_caching_allow_command(self):
+ master = self.master
+ client = self.clients[0].hostname
+ kinit_admin(master)
+
+ self.setup_sudo_rule(
+ master=master,
+ client=client,
+ user=self.USER_1,
+ rule_name=self.SUDO_RULE,
+ group_name=self.SUDO_GROUP,
+ allowed_command="/bin/date"
+ )
+ clear_sssd_cache(master)
+ clear_sssd_cache(self.client)
+ result = self.run_as_sudo_user(
+ "date", sudo_user="root", su_user=self.USER_1)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day in result.stdout_text
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert "(root) /bin/date" in result.stdout_text
+
+ stop_ipa_server(master)
+ result = self.run_as_sudo_user(
+ "date", sudo_user="root", su_user=self.USER_1,
+ skip_kinit=True, skip_sssd_cache_clear=True)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day in result.stdout_text
+
+ result = self.list_sudo_commands(
+ self.USER_1, skip_kinit=True, skip_sssd_cache_clear=True
+ )
+ assert "(root) /bin/date" in result.stdout_text
+
+ start_ipa_server(master)
+ master.run_command([
+ "ipa", "sudorule-remove-allow-command", "--sudocmds=/bin/date",
+ self.SUDO_RULE
+ ])
+
+ def test_002_sudorule_offline_caching_deny_command(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-deny-command", "--sudocmds=/bin/uname",
+ self.SUDO_RULE
+ ])
+ clear_sssd_cache(self.client)
+ clear_sssd_cache(master)
+ result = self.run_as_sudo_user(
+ "uname", sudo_user="root", su_user=self.USER_1)
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert "(root) !/bin/uname" in result.stdout_text
+
+ stop_ipa_server(master)
+ self.run_as_sudo_user(
+ "uname", sudo_user="root", su_user=self.USER_1,
+ skip_kinit=True, skip_sssd_cache_clear=True)
+
+ result = self.list_sudo_commands(
+ self.USER_1, skip_kinit=True, skip_sssd_cache_clear=True
+ )
+ assert "(root) !/bin/uname" in result.stdout_text
+
+ start_ipa_server(master)
+ master.run_command([
+ "ipa", "sudorule-remove-deny-command", "--sudocmds=/bin/uname",
+ self.SUDO_RULE
+ ])
+
+ def test_003_sudorule_offline_caching_runasuser_command(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-allow-command", "--sudocmds=/bin/date",
+ self.SUDO_RULE
+ ])
+
+ master.run_command([
+ "ipa", "sudorule-add-runasuser", self.SUDO_RULE,
+ f"--users={self.USER_2}"
+ ])
+ clear_sssd_cache(master)
+ clear_sssd_cache(self.client)
+ result = self.run_as_sudo_user(
+ "date", sudo_user=self.USER_2, su_user=self.USER_1)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day in result.stdout_text
+
+ result = self.list_sudo_commands(
+ self.USER_1, skip_sssd_cache_clear=True)
+ assert f"({self.USER_2}) /bin/date" in result.stdout_text
+
+ stop_ipa_server(master)
+ result = self.run_as_sudo_user(
+ "date", sudo_user=self.USER_2, su_user=self.USER_1,
+ skip_kinit=True, skip_sssd_cache_clear=True)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day in result.stdout_text
+
+ result = self.list_sudo_commands(
+ self.USER_1, skip_kinit=True, skip_sssd_cache_clear=True
+ )
+ assert f"({self.USER_2}) /bin/date" in result.stdout_text
+
+ start_ipa_server(master)
+ master.run_command([
+ "ipa", "sudorule-remove-allow-command", "--sudocmds=/bin/date",
+ self.SUDO_RULE
+ ])
+
+ master.run_command([
+ "ipa", "sudorule-remove-runasuser", self.SUDO_RULE,
+ f"--users={self.USER_2}"
+ ])
+
+ def test_005_sudorule_offline_caching_hostgroup_command(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-allow-command", "--sudocmds=/bin/date",
+ self.SUDO_RULE
+ ])
+ master.run_command([
+ "ipa", "hostgroup-add", "--desc=testhostgroup",
+ self.HOST_GROUP
+ ])
+ master.run_command([
+ "ipa", "sudorule-remove-host", self.SUDO_RULE,
+ "--hosts=" + self.client.hostname
+ ])
+ master.run_command([
+ "ipa", "hostgroup-add-member", self.HOST_GROUP,
+ "--hosts=" + self.client.hostname
+ ])
+ master.run_command([
+ "ipa", "sudorule-add-host", self.SUDO_RULE,
+ f"--hostgroup={self.HOST_GROUP}"
+ ])
+ master.run_command([
+ "ipa", "sudorule-add-user", self.SUDO_RULE,
+ "--users", self.USER_1], raiseonerr=False
+ )
+ clear_sssd_cache(self.client)
+ result = self.run_as_sudo_user(
+ "date", sudo_user="root", su_user=self.USER_1)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day in result.stdout_text
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert "(root) /bin/date" in result.stdout_text
+
+ stop_ipa_server(master)
+ result = self.run_as_sudo_user(
+ "date", sudo_user="root", su_user=self.USER_1,
+ skip_kinit=True, skip_sssd_cache_clear=True)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day in result.stdout_text
+
+ result = self.list_sudo_commands(
+ self.USER_1, skip_kinit=True, skip_sssd_cache_clear=True
+ )
+ assert "(root) /bin/date" in result.stdout_text
+
+ start_ipa_server(master)
+ kinit_admin(master)
+ master.run_command([
+ "ipa", "sudorule-remove-allow-command",
+ "--sudocmds=/bin/date", self.SUDO_RULE
+ ])
+ master.run_command([
+ "ipa", "sudorule-remove-host", self.SUDO_RULE,
+ f"--hostgroup={self.HOST_GROUP}"
+ ])
+ master.run_command([
+ "ipa", "hostgroup-remove-member", self.HOST_GROUP,
+ "--hosts=" + self.client.hostname
+ ])
+ master.run_command(["ipa", "hostgroup-del", self.HOST_GROUP])
+ master.run_command([
+ "ipa", "sudorule-add-host", self.SUDO_RULE,
+ f"--hosts=" + self.client.hostname
+ ])
+
+ def test_006_sudorule_offline_caching_group_command(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-allow-command", "--sudocmds=/bin/date",
+ self.SUDO_RULE
+ ])
+ master.run_command([
+ "ipa", "sudorule-remove-user", self.SUDO_RULE,
+ "--users", self.USER_1], raiseonerr=False
+ )
+ master.run_command([
+ "ipa", "group-add", "--desc=testgroup", self.GROUP
+ ])
+ master.run_command([
+ "ipa", "group-add-member", self.GROUP,
+ f"--users={self.USER_1}"
+ ])
+ master.run_command([
+ "ipa", "sudorule-add-user", self.SUDO_RULE,
+ f"--groups={self.GROUP}"], raiseonerr=False
+ )
+ clear_sssd_cache(self.client)
+
+ result = self.run_as_sudo_user(
+ "date", sudo_user="root", su_user=self.USER_1)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day in result.stdout_text
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert "(root) /bin/date" in result.stdout_text
+
+ stop_ipa_server(master)
+ result = self.run_as_sudo_user(
+ "date", sudo_user="root", su_user=self.USER_1,
+ skip_kinit=True, skip_sssd_cache_clear=True)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day in result.stdout_text
+
+ result = self.list_sudo_commands(
+ self.USER_1, skip_kinit=True, skip_sssd_cache_clear=True
+ )
+ assert "(root) /bin/date" in result.stdout_text
+
+ start_ipa_server(master)
+ kinit_admin(master)
+ master.run_command([
+ "ipa", "sudorule-remove-allow-command",
+ "--sudocmds=/bin/date", self.SUDO_RULE
+ ])
+ master.run_command([
+ "ipa", "sudorule-remove-user", self.SUDO_RULE,
+ f"--groups={self.GROUP}"], raiseonerr=False
+ )
+ master.run_command([
+ "ipa", "sudorule-add-user", self.SUDO_RULE,
+ f"--users={self.USER_1}"], raiseonerr=False
+ )
+ master.run_command([
+ "ipa", "group-remove-member", self.GROUP,
+ f"--users={self.USER_1}"
+ ])
+ master.run_command([
+ "ipa", "group-del", self.GROUP])
+
+ def test_007_sudorule_offline_caching_option_command(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-allow-command", "--sudocmds=/bin/date",
+ self.SUDO_RULE
+ ])
+ master.run_command([
+ 'ipa', 'sudorule-add-option', self.SUDO_RULE,
+ '--sudooption', "!authenticate"
+ ])
+ clear_sssd_cache(self.client)
+ result = self.run_as_sudo_user(
+ "date", sudo_user="root", su_user=self.USER_1,
+ skip_password=True)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day in result.stdout_text
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert "(root) NOPASSWD: /bin/date" in result.stdout_text
+
+ stop_ipa_server(master)
+ result = self.run_as_sudo_user(
+ "date", sudo_user="root", su_user=self.USER_1,
+ skip_password=True, skip_kinit=True,
+ skip_sssd_cache_clear=True)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day in result.stdout_text
+
+ result = self.list_sudo_commands(
+ self.USER_1, skip_kinit=True, skip_sssd_cache_clear=True)
+ assert "(root) NOPASSWD: /bin/date" in result.stdout_text
+
+ start_ipa_server(master)
+ kinit_admin(master)
+ master.run_command([
+ 'ipa', 'sudorule-remove-option', self.SUDO_RULE,
+ '--sudooption', "!authenticate"
+ ])
+ master.run_command([
+ "ipa", "sudorule-remove-allow-command",
+ "--sudocmds=/bin/date", self.SUDO_RULE
+ ])
+ clear_sssd_cache(self.client)
+ clear_sssd_cache(master)
+
+ def test_008_disable_sudorule_offline_caching(self):
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command([
+ "ipa", "sudorule-add-allow-command", "--sudocmds=/bin/date",
+ self.SUDO_RULE
+ ])
+ master.run_command(["ipa", "sudorule-disable", self.SUDO_RULE])
+ clear_sssd_cache(self.client)
+ result = self.run_as_sudo_user(
+ "date", sudo_user="root", su_user=self.USER_1)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day not in result.stdout_text
+
+ result = self.list_sudo_commands(self.USER_1)
+ assert "(root) /bin/date" not in result.stdout_text
+
+ stop_ipa_server(master)
+ result = self.run_as_sudo_user(
+ "date", sudo_user="root", su_user=self.USER_1,
+ skip_kinit=True, skip_sssd_cache_clear=True)
+
+ sys_day = self.client.run_command(
+ ["date", "+%a"]).stdout_text.strip()
+ assert sys_day not in result.stdout_text
+
+ result = self.list_sudo_commands(
+ self.USER_1, skip_kinit=True, skip_sssd_cache_clear=True)
+ assert "(root) /bin/date" not in result.stdout_text
+
+ start_ipa_server(master)
+ kinit_admin(master)
+ master.run_command(["ipa", "sudorule-enable", self.SUDO_RULE])
+ master.run_command([
+ "ipa", "sudorule-remove-allow-command",
+ "--sudocmds=/bin/date", self.SUDO_RULE
+ ])
+
+
+class TestSudo_BugFunctional(IntegrationTest):
+ """
+ Sudo Bug Functional Tests converted from Bash to Pytest
+ """
+ num_clients = 1
+
+ @classmethod
+ def install(cls, mh):
+ super(TestSudo_BugFunctional, cls).install(mh)
+
+ extra_args = ["--idstart=60001", "--idmax=65000"]
+ install_master(cls.master, setup_dns=True, extra_args=extra_args)
+ install_client(cls.master, cls.clients[0])
+
+ cls.client = cls.clients[0]
+ cls.user_password = "Secret123!"
+ # Create basic users for tests
+ for i in range(1, 3):
+ username = f"user{i}"
+ create_active_user(
+ cls.master, username, password=cls.user_password
+ )
+
+ def test_bug769491(self):
+ """
+ Add certain sudo commands to groups, bz769491
+ https://bugzilla.redhat.com/show_bug.cgi?id=769491
+ """
+ master = self.master
+ kinit_admin(master)
+ cmd = "/bin/chown -R apache:developers /var/www/*/shared/log"
+
+ out = master.run_command(["ipa", "sudocmd-add", cmd]).stdout_text
+ assert "Added Sudo Command" in out
+
+ master.run_command(["ipa", "sudocmdgroup-add", "sudogrp1",
+ "--desc=sudogrp1"])
+
+ out = master.run_command(
+ ["ipa", "sudocmdgroup-add-member", "sudogrp1", f"--sudocmds={cmd}"]
+ ).stdout_text
+ assert ("Member Sudo commands: /bin/chown -R apache:developers "
+ "/var/www/*/shared/log") in out
+ assert "Number of members added 1" in out
+
+ out = master.run_command(
+ ["ipa", "sudocmdgroup-show", "sudogrp1"]
+ ).stdout_text
+ assert "Sudo Command Group: sudogrp1" in out
+ assert ("Member Sudo commands: /bin/chown -R apache:developers "
+ "/var/www/*/shared/log") in out
+
+ out = master.run_command(
+ ["ipa", "sudocmdgroup-remove-member", "sudogrp1",
+ f"--sudocmds={cmd}"]
+ ).stdout_text
+ assert "Sudo Command Group: sudogrp1" in out
+ assert ("Member Sudo commands: /bin/chown -R apache:developers "
+ "/var/www/*/shared/log") not in out
+ assert "Number of members removed 1" in out
+
+ master.run_command(["ipa", "sudocmd-del", cmd])
+ master.run_command(["ipa", "sudocmdgroup-del", "sudogrp1"])
+
+ def test_bug741604(self):
+ """
+ Proper error when adding duplicate external members to sudo rule,
+ bz741604
+ """
+ master = self.master
+ kinit_admin(master)
+
+ master.run_command(["ipa", "sudorule-add", "741604rule"])
+
+ out = master.run_command(
+ ["ipa", "sudorule-add-user", "--users=user1", "--users=unknown",
+ "741604rule"]
+ ).stdout_text
+ assert "This entry is already a member" not in out
+
+ out = master.run_command(
+ ["ipa", "sudorule-add-user", "--users=user1", "--users=unknown",
+ "741604rule"],
+ raiseonerr=False,
+ ).stdout_text
+ assert "member user: user1: This entry is already a member" in out
+ assert "member user: unknown: This entry is already a member" in out
+ assert "no such entry" not in out
+
+ master.run_command(["ipa", "sudorule-del", "741604rule"])
+
+ def test_bug782976(self):
+ """
+ Users/groups should detect ALL and error appropriately, bz782976
+ """
+ master = self.master
+ kinit_admin(master)
+
+ out = master.run_command(
+ ["ipa", "sudorule-add", "bug782976", "--usercat=all"]
+ ).stdout_text
+ assert "User category: all" in out
+
+ out = master.run_command(
+ ["ipa", "sudorule-add-user", "bug782976", "--users=shanks"],
+ raiseonerr=False,
+ ).stderr_text
+ assert ("ipa: ERROR: users cannot be added when user category='all'"
+ in out)
+
+ master.run_command(["ipa", "group-add", "group1", "--desc=group1"])
+ out = master.run_command(
+ ["ipa", "sudorule-add-user", "bug782976", "--groups=group1"],
+ raiseonerr=False,
+ ).stderr_text
+ assert ("ipa: ERROR: users cannot be added when user category='all'"
+ in out)
+
+ master.run_command(["ipa", "sudorule-del", "bug782976"])
+ master.run_command(["ipa", "sudorule-add", "bug782976"])
+ master.run_command(
+ ["ipa", "sudorule-add-user", "bug782976", "--users=user1"]
+ )
+ out = master.run_command(
+ ["ipa", "sudorule-mod", "bug782976", "--usercat=all"],
+ raiseonerr=False,
+ ).stderr_text
+ assert ("ipa: ERROR: user category cannot be set to 'all' "
+ "while there are allowed users") in out
+
+ master.run_command(["ipa", "sudorule-del", "bug782976"])
+ master.run_command(["ipa", "sudorule-add", "bug782976"])
+ master.run_command(
+ ["ipa", "sudorule-add-user", "bug782976", "--groups=group1"]
+ )
+ out = master.run_command(
+ ["ipa", "sudorule-mod", "bug782976", "--usercat=all"],
+ raiseonerr=False,
+ ).stderr_text
+ assert ("ipa: ERROR: user category cannot be set to 'all' "
+ "while there are allowed users") in out
+
+ master.run_command(["ipa", "group-del", "group1"])
+ master.run_command(["ipa", "sudorule-del", "bug782976"])
+
+ def test_bug783286(self):
+ """
+ Setting HBAC SUDO category to anyone should remove users/groups,
+ bz783286
+ """
+ master = self.master
+ kinit_admin(master)
+
+ create_active_user(
+ self.master,
+ "pranav",
+ password=self.user_password,
+ first="pranav",
+ last="thube"
+ )
+
+ kinit_admin(master)
+ master.run_command(["ipa", "group-add", "group1", "--desc=group1"])
+ master.run_command(["ipa", "sudocmd-add", "/bin/ls"])
+
+ out = master.run_command(
+ ["ipa", "sudorule-add", "bug783286", "--usercat=all"]
+ ).stdout_text
+ assert "User category: all" in out
+
+ master.run_command(
+ ["ipa", "sudorule-add-host", "bug783286",
+ f"--hosts={master.hostname}"]
+ )
+
+ out = master.run_command(
+ ["ipa", "sudorule-add-user", "bug783286", "--users=pranav"],
+ raiseonerr=False,
+ ).stderr_text
+ assert ("ipa: ERROR: users cannot be added when user category='all'"
+ in out)
+
+ out = master.run_command(
+ ["ipa", "sudorule-add-user", "bug783286", "--groups=group1"],
+ raiseonerr=False,
+ ).stderr_text
+ assert ("ipa: ERROR: users cannot be added when user category='all'"
+ in out)
+
+ master.run_command(["ipa", "sudorule-del", "bug783286"])
+ master.run_command(["ipa", "sudorule-add", "bug783286"])
+ master.run_command(
+ ["ipa", "sudorule-add-user", "bug783286", "--users=pranav"],
+ raiseonerr=False,
+ )
+
+ out = master.run_command(
+ ["ipa", "sudorule-mod", "bug783286", "--usercat=all"],
+ raiseonerr=False,
+ ).stderr_text
+ assert ("ipa: ERROR: user category cannot be set to 'all' "
+ "while there are allowed users") in out
+
+ master.run_command(["ipa", "sudorule-del", "bug783286"])
+ master.run_command(["ipa", "sudorule-add", "bug783286"])
+ master.run_command(
+ ["ipa", "sudorule-add-user", "bug783286", "--groups=group1"]
+ )
+
+ out = master.run_command(
+ ["ipa", "sudorule-mod", "bug783286", "--usercat=all"],
+ raiseonerr=False,
+ ).stderr_text
+ assert ("ipa: ERROR: user category cannot be set to 'all' "
+ "while there are allowed users") in out
+
+ # cleanup
+ master.run_command(["ipa", "group-del", "group1"])
+ master.run_command(["ipa", "user-del", "pranav"])
+ master.run_command(["ipa", "sudocmd-del", "/bin/ls"])
+ master.run_command(["ipa", "sudorule-del", "bug783286"])
+
+ def test_bug800537(self):
+ """
+ Remove sudo commands with special characters from command groups,
+ bz800537
+ """
+ master = self.master
+ kinit_admin(master)
+
+ for testcmd in ["/bin/ls /lost+found", r"/bin/ls /tmp/test\ dir",
+ "/bin/ls /bin/cp"]:
+ master.run_command(["ipa", "sudocmd-add", testcmd])
+ master.run_command(
+ ["ipa", "sudocmdgroup-add", "a-group", "--desc=test"]
+ )
+ master.run_command(
+ ["ipa", "sudocmdgroup-add-member", "a-group",
+ f"--sudocmds={testcmd}"]
+ )
+ master.run_command(
+ ["ipa", "sudocmdgroup-remove-member", "a-group",
+ f"--sudocmds={testcmd}"]
+ )
+ master.run_command(["ipa", "sudocmdgroup-del", "a-group"])
+ master.run_command(["ipa", "sudocmd-del", testcmd])
+
+ def test_bug800544(self):
+ """
+ Sudo commands are case insensitive, bz800544
+ """
+ master = self.master
+ kinit_admin(master)
+
+ for cmd in ["/usr/bin/X", "/usr/bin/x"]:
+ master.run_command(["ipa", "sudocmd-add", cmd])
+
+ master.run_command(["ipa", "sudocmdgroup-add", "group800544",
+ "--desc=blabla"])
+
+ for cmd in ["/usr/bin/X", "/usr/bin/x"]:
+ master.run_command([
+ "ipa", "sudocmdgroup-add-member", "group800544",
+ f"--sudocmds={cmd}"
+ ])
+
+ for cmd in ["/usr/bin/X", "/usr/bin/x"]:
+ master.run_command([
+ "ipa", "sudocmdgroup-remove-member", "group800544",
+ f"--sudocmds={cmd}"
+ ])
+
+ for cmd in ["/usr/bin/x", "/usr/bin/X"]:
+ master.run_command(["ipa", "sudocmd-del", cmd])
+
+ master.run_command(["ipa", "sudocmdgroup-del", "group800544"])
+
+ def test_bug912673(self):
+ """
+ Sudorule disable should remove rule from ou sudoers, bz912637
+ """
+ master = self.master
+ rule = "rule4bug912673"
+ kinit_admin(master)
+
+ master.run_command(["ipa", "sudorule-add", rule])
+ master.run_command(["ipa", "sudorule-show", rule])
+ result = ldapsearch_dm(
+ self.master,
+ f"cn={rule},ou=sudoers,{master.domain.basedn}",
+ ldap_args=[],
+ scope="base"
+ )
+ assert (f"cn={rule},ou=sudoers,{master.domain.basedn}" in
+ result.stdout_text), "ldap entry not found is not expected"
+
+ master.run_command(["ipa", "sudorule-disable", rule])
+ master.run_command(
+ ["ipa", "sudorule-show", rule], raiseonerr=False
+ )
+ result = ldapsearch_dm(
+ self.master,
+ f"cn={rule},ou=sudoers,{master.domain.basedn}",
+ ldap_args=[],
+ scope="base",
+ raiseonerr=False
+ )
+ assert "No such object (32)" in result.stderr_text, (
+ "found ldap entry via ldapsearch is not expected"
+ )
+
+ master.run_command(["ipa", "sudorule-enable", rule])
+ master.run_command(["ipa", "sudorule-show", rule])
+ result = ldapsearch_dm(
+ self.master,
+ f"cn={rule},ou=sudoers,{master.domain.basedn}",
+ ldap_args=[],
+ scope="base"
+ )
+ assert (f"cn={rule},ou=sudoers,{master.domain.basedn}" in
+ result.stdout_text), "ldap entry not found is not expected"
+
+ def test_bug837356(self):
+ """
+ Deleting command should not bring LDAP to inconsistent state, bz837356
+ """
+ master = self.master
+ rule = "rule4bz837356"
+ cmd = "/usr/bin/yum"
+
+ kinit_admin(master)
+
+ master.run_command(["ipa", "sudorule-add", rule])
+ master.run_command(["ipa", "sudorule-show", rule])
+ master.run_command(["ipa", "sudocmd-add", cmd])
+ master.run_command(
+ ["ipa", "sudorule-add-allow-command", rule, f"--sudocmds={cmd}"]
+ )
+ master.run_command(["ipa", "sudorule-show", rule, "--all", "--raw"])
+ # Try to delete command (should fail)
+ result = master.run_command(
+ ["ipa", "sudocmd-del", cmd],
+ raiseonerr=False
+ )
+ err_msg = (
+ f"{cmd} cannot be deleted because sudorule {rule} "
+ "requires it"
+ )
+ assert err_msg in result.stderr_text
+
+ master.run_command(["ipa", "sudorule-del", rule])
+ master.run_command(["ipa", "sudocmd-del", cmd])
--
2.51.1