diff options
Diffstat (limited to 'src/tests/multihost/basic/test_kcm.py')
-rw-r--r-- | src/tests/multihost/basic/test_kcm.py | 340 |
1 files changed, 340 insertions, 0 deletions
diff --git a/src/tests/multihost/basic/test_kcm.py b/src/tests/multihost/basic/test_kcm.py new file mode 100644 index 0000000..8f527f6 --- /dev/null +++ b/src/tests/multihost/basic/test_kcm.py @@ -0,0 +1,340 @@ +""" KCM Responder Sanity Test Cases + +:requirement: IDM-SSSD-REQ :: SSSD KCM as default Kerberos CCACHE provider +:casecomponent: sssd +:subsystemteam: sst_idm_sssd +:upstream: yes +:status: approved +""" +import os +import re +import pytest +from pexpect import pxssh +from utils_config import set_param +from sssd.testlib.common.utils import sssdTools + + +class TestSanityKCM(object): + """ KCM Sanity Test cases """ + def _kcm_service_op(self, multihost, svc_op): + systemd_kcm_op = 'systemctl %s sssd-kcm' % (svc_op) + multihost.master[0].run_command(systemd_kcm_op) + + def _start_kcm(self, multihost): + self._kcm_service_op(multihost, 'start') + + def _stop_kcm(self, multihost): + self._kcm_service_op(multihost, 'stop') + + def _restart_kcm(self, multihost): + self._kcm_service_op(multihost, 'restart') + + def _remove_kcm_log_file(self, multihost): + multihost.master[0].run_command('rm -f /var/log/sssd/sssd_kcm.log') + + def _kcm_log_length(self, multihost): + basename = 'sssd_kcm.log' + kcm_log_file = '/var/log/sssd/' + basename + local_kcm_log_file = '/tmp/kcm.log' + try: + multihost.master[0].transport.get_file(kcm_log_file, + local_kcm_log_file) + except FileNotFoundError: + return 0 + + nlines = sum(1 for line in open(local_kcm_log_file)) + os.remove(local_kcm_log_file) + return nlines + + def _remove_secret_db(self, multihost): + multihost.master[0].run_command( + 'rm -f /var/lib/sss/secrets/secrets.ldb') + self._restart_kcm(multihost) + + @pytest.mark.usefixtures("enable_kcm") + def test_kinit_kcm(self, multihost): + """ + :title: kcm: Run kinit with KRB5CCNAME=KCM + :id: 245eecf6-04b9-4c9f-8685-681d184fbbcf + """ + self._start_kcm(multihost) + + user = 'foo3' + cmd = multihost.master[0].run_command( + f'su - {user} -c "KRB5CCNAME=KCM:; kinit"', stdin_text='Secret123', + raiseonerr=False) + assert cmd.returncode == 0, "kinit failed!" + + cmd2 = multihost.master[0].run_command( + f'su - {user} -c "KRB5CCNAME=KCM:; klist"', raiseonerr=False) + assert cmd2.returncode == 0, "klist failed!" + assert 'Ticket cache: KCM:14583103' in cmd2.stdout_text + + @staticmethod + @pytest.mark.usefixtures("enable_kcm") + def test_ssh_login_kcm(multihost): + """ + :title: kcm: Verify ssh logins are successuful with kcm as default + :id: 458ed1e4-b908-40d3-b2fd-392e8d2dcf4b + """ + # pylint: disable=unused-argument + client = sssdTools(multihost.master[0]) + ssh0 = client.auth_from_client("foo4", 'Secret123') == 3 + if not ssh0: + multihost.master[0].run_command( + 'journalctl -u sssd -n 50 --no-pager') + assert ssh0, "Authentication Failed as user foo4" + + @pytest.mark.usefixtures("enable_kcm") + def test_kcm_debug_level_set(self, multihost): + """ + :title: kcm: After kcm section with debug + level set restaring sssd-kcm service enables kcm debugging + :id: 31c74bfc-69d5-46bd-aef8-a5581970832e + :description: Test that just adding a [kcm] section and restarting + the kcm service enables debugging without having to restart the + whole sssd + """ + # Start from a known-good state where the configuration is refreshed + # by the monitor and logging is completely disabled + multihost.master[0].service_sssd('stop') + self._stop_kcm(multihost) + self._remove_kcm_log_file(multihost) + set_param(multihost, 'kcm', 'debug_level', '0') + multihost.master[0].service_sssd('start') + self._start_kcm(multihost) + + log_lines_pre = self._kcm_log_length(multihost) + + # Debugging is disabled, kinit and make sure that no debug messages + # were produced + user = 'foo3' + client = sssdTools(multihost.master[0]) + ssh0 = client.auth_from_client(user, 'Secret123') == 3 + assert ssh0, f"Authentication Failed as user {user}." + + multihost.master[0].run_command( + f'su - {user} -c "kdestroy"', raiseonerr=False) + + log_lines_nodebug = self._kcm_log_length(multihost) + assert log_lines_nodebug == log_lines_pre + + # Enable debugging, restart only the kcm service, make sure some + # debug messages were produced + set_param(multihost, 'kcm', 'debug_level', '9') + self._restart_kcm(multihost) + + ssh1 = client.auth_from_client(user, 'Secret123') == 3 + assert ssh1, f"Authentication Failed as user {user}." + + multihost.master[0].run_command( + f'su - {user} -c "kdestroy"', raiseonerr=False) + + log_lines_debug = self._kcm_log_length(multihost) + assert log_lines_debug > log_lines_pre + 100 + + @staticmethod + @pytest.mark.usefixtures("enable_kcm") + def test_kdestroy_retval(multihost): + """ + :title: kcm: Test that destroying an empty cache does + not return a non-zero return code + :id: 2826097f-e6d7-4d99-ac85-3ee081aa681a + """ + + user = 'foo3' + client = sssdTools(multihost.master[0]) + ssh0 = client.auth_from_client(user, 'Secret123') == 3 + assert ssh0, f"Authentication Failed as user {user}." + + kd1 = multihost.master[0].run_command( + f'su -l {user} -c "kdestroy"', raiseonerr=False) + assert kd1.returncode == 0, "First kdestroy failed!" + + # Run the command again in case there was something in the ccache + # previously + kd2 = multihost.master[0].run_command( + f'su -l {user} -c "kdestroy"', raiseonerr=False) + assert kd2.returncode == 0, "Second kdestroy failed!" + + @staticmethod + @pytest.mark.usefixtures("enable_kcm") + def test_ssh_forward_creds(multihost): + """ + :title: kcm: Test that SSH can forward credentials with KCM + :id: f4b0c785-a895-48a1-a55e-7519cf221393 + :ticket: https://github.com/SSSD/sssd/issues/4863 + """ + ssh = pxssh.pxssh(options={"StrictHostKeyChecking": "no", + "UserKnownHostsFile": "/dev/null"}) + ssh.force_password = True + try: + ssh.login(multihost.master[0].sys_hostname, 'foo3', 'Secret123') + ssh.sendline('kdestroy -A -q') + ssh.prompt(timeout=5) + ssh.sendline('kinit foo9') + ssh.expect('Password for .*:', timeout=10) + ssh.sendline('Secret123') + ssh.prompt(timeout=5) + ssh.sendline('klist') + ssh.prompt(timeout=5) + klist = str(ssh.before) + ssh.sendline(f'ssh -v -o StrictHostKeyChecking=no -K -l foo9 ' + f'{multihost.master[0].sys_hostname} klist') + ssh.prompt(timeout=30) + ssh_output = str(ssh.before) + ssh.logout() + except pxssh.ExceptionPxssh as ex: + pytest.fail(ex) + # Note: The cache is based on uid so for foo3 it is 14583103 and + # for foo9 it is 14583109 (see create_posix_usersgroups fixture) + assert 'KCM:14583103' in klist, "kinit did not work!" + assert 'KCM:14583109' in ssh_output, "Ticket not forwarded!" + + @staticmethod + @pytest.mark.usefixtures("enable_kcm") + def test_kvno_display(multihost): + """ + :title: kcm: Test kvno correctly displays version numbers of principals + :id: 7c9178e6-fea5-44a1-b473-76667624cee2 + :ticket: https://github.com/SSSD/sssd/issues/4763 + """ + host_princ = f'host/{multihost.master[0].sys_hostname}@EXAMPLE.TEST' + kvno_cmd = f'kvno {host_princ}' + + client = sssdTools(multihost.master[0]) + client.auth_from_client('foo4', 'Secret123') + + kvno = multihost.master[0].run_command( + f'su -l foo4 -c "{kvno_cmd}"', raiseonerr=False) + assert kvno.returncode == 0, "kvno failed!" + + for line in kvno.stdout_text.splitlines(): + kvno_check = re.search(r'%s: kvno = (\d+)' % host_princ, line) + if kvno_check: + print(kvno_check.group()) + else: + pytest.fail("kvno display was improper") + + @pytest.mark.usefixtures("enable_kcm", "create_many_user_principals") + def test_kcm_peruid_quota(self, multihost): + """ + :title: kcm: Make sure the quota limits a client, but only that client + :id: 3ac8f62e-05e4-4ca7-b588-145fd6258c2a + """ + # It is easier to keep these tests stable and independent from others + # if they start from a clean slate + self._remove_secret_db(multihost) + + client = sssdTools(multihost.master[0]) + client.auth_from_client('foo2', 'Secret123') + client.auth_from_client('foo3', 'Secret123') + + # The loop would request 63 users, plus there is foo3 we authenticated + # earlier, so this should exactly deplete the quota, but should succeed + for i in range(1, 64): + username = "user%04d" % i + kinit = multihost.master[0].run_command( + f'su -l foo3 -c "kinit {username}"', + stdin_text='Secret123', raiseonerr=False) + assert kinit.returncode == 0 + + # this kinit should be exactly one over the peruid limit + kinit_f = multihost.master[0].run_command( + 'su -l foo3 -c "kinit user0064"', + stdin_text='Secret123', raiseonerr=False) + assert kinit_f.returncode != 0 + + # Since this is a per-uid limit, another user should be able to kinit + # just fine + # this kinit should be exactly one over the peruid limit + kinit_o = multihost.master[0].run_command( + 'su -l foo2 -c "kinit user0064"', + stdin_text='Secret123', raiseonerr=False) + assert kinit_o.returncode == 0 + + # kdestroy as the original user, the quota should allow a subsequent + # kinit + multihost.master[0].run_command( + 'su -l foo3 -c "kdestroy -A"', raiseonerr=False) + kinit_p = multihost.master[0].run_command( + 'su -l foo3 -c "kinit user0064"', + stdin_text='Secret123', raiseonerr=False) + assert kinit_p.returncode == 0 + + multihost.master[0].run_command( + 'su -l foo2 -c "kdestroy -A"', raiseonerr=False) + + multihost.master[0].run_command( + 'su -l foo3 -c "kdestroy -A"', raiseonerr=False) + + @pytest.mark.usefixtures("enable_kcm", "create_many_user_principals") + def test_kcm_peruid_quota_increase(self, multihost): + """ + :title: kcm: Quota increase + :id: 0b3cab49-befb-4ab2-bb12-b102d94249aa + :description: Increasing the peruid quota allows a client to store + more data + """ + # It is easier to keep these tests stable and independent from others + # if they start from a clean slate + self._remove_secret_db(multihost) + user = 'foo3' + client = sssdTools(multihost.master[0]) + client.auth_from_client(user, 'Secret123') + + # The loop would request 63 users, plus there is foo3 we authenticated + # earlier, so this should exactly deplete the quota, but should succeed + for i in range(1, 64): + username = "user%04d" % i + kinit = multihost.master[0].run_command( + f'su -l {user} -c "kinit {username}"', + stdin_text='Secret123', raiseonerr=False) + assert kinit.returncode == 0 + + # this kinit should be exactly one over the peruid limit + kinit_f = multihost.master[0].run_command( + f'su -l {user} -c "kinit user0064"', + stdin_text='Secret123', raiseonerr=False) + assert kinit_f.returncode != 0 + + set_param(multihost, 'kcm', 'max_uid_ccaches', '65') + self._restart_kcm(multihost) + + # Now the kinit should work as we increased the limit + kinit_p = multihost.master[0].run_command( + f'su -l {user} -c "kinit user0064"', + stdin_text='Secret123', raiseonerr=False) + assert kinit_p.returncode == 0 + + multihost.master[0].run_command( + f'su -l {user} -c "kdestroy -A"', raiseonerr=False) + + @pytest.mark.usefixtures("enable_kcm") + def test_kcm_payload_low_quota(self, multihost): + """ + :title: kcm: Quota enforcement + :id: cb3daadb-c5e7-48f8-b419-11c616f0d602 + :description: Set a prohibitive quota for the per-ccache payload + limit and make sure it gets enforced + """ + # It is easier to keep these tests stable and independent from others + # if they start from a clean slate + self._remove_secret_db(multihost) + user = 'foo3' + client = sssdTools(multihost.master[0]) + client.auth_from_client(user, 'Secret123') + + multihost.master[0].run_command( + f'su -l {user} -c "kdestroy -A"', raiseonerr=False) + + set_param(multihost, 'kcm', 'max_ccache_size', '1') + self._restart_kcm(multihost) + + # We use kinit to exceed the maximum ccache size as it creates payload + # of 1280 bytes by acquiring tgt and also some control credentials. + # SSH authentication is not sufficient as it stores only tgt. + kv_p = multihost.master[0].run_command( + f'su -l foo3 -c "kinit {user}@EXAMPLE.TEST"', + stdin_text='Secret123', raiseonerr=False) + assert kv_p.returncode != 0 |