From b08c75f92a590fd01743742b78423fe2ce7b1bc5 Mon Sep 17 00:00:00 2001 From: George Pantelakis Date: Tue, 25 Jun 2024 14:12:14 +0200 Subject: [PATCH 1/2] Change password expect to regex --- Kerberos/test_kerberos_ssh_login.py | 2 +- Kerberos/test_kerberos_user_change_password.py | 2 +- Local-user/test_local_user_passwd.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Kerberos/test_kerberos_ssh_login.py b/Kerberos/test_kerberos_ssh_login.py index e93abf7..f3ec0fd 100644 --- a/Kerberos/test_kerberos_ssh_login.py +++ b/Kerberos/test_kerberos_ssh_login.py @@ -67,7 +67,7 @@ def test_krb_change_passwd_ssh(ipa_user, user_shell, ipa_login): user_shell.expect_exact(ipa_user.username) user_shell.sendline(f"passwd") if isDistro(['rhel', 'centos'], '>=10') or isDistro('fedora', '>=40'): - user_shell.expect_exact(f"Current password") + user_shell.expect(r"[cC]urrent [pP]assword") else: user_shell.expect_exact(f"Changing password for user {ipa_user.username}.") diff --git a/Kerberos/test_kerberos_user_change_password.py b/Kerberos/test_kerberos_user_change_password.py index db6ae6c..620aa36 100644 --- a/Kerberos/test_kerberos_user_change_password.py +++ b/Kerberos/test_kerberos_user_change_password.py @@ -68,6 +68,6 @@ def test_kerberos_change_passwd(ipa_user, user_shell, required, insert, expect, user_shell.expect_exact(expect) user_shell.sendline(secret) if isDistro(['rhel', 'centos'], '>=10') or isDistro('fedora', '>=40'): - user_shell.expect_exact(f"Current password") + user_shell.expect(r"[cC]urrent [pP]assword") else: user_shell.expect_exact(f"Changing password for user {ipa_user.username}.") diff --git a/Local-user/test_local_user_passwd.py b/Local-user/test_local_user_passwd.py index 1a0baa2..b93c397 100644 --- a/Local-user/test_local_user_passwd.py +++ b/Local-user/test_local_user_passwd.py @@ -47,6 +47,6 @@ def test_change_local_user_passwd(local_user, user_shell, required, lock_on_remo user_shell.expect_exact(f"PIN for {local_user.username}:") user_shell.sendline(local_user.pin) if isDistro(['rhel', 'centos'], '>=10') or isDistro('fedora', '>=40'): - user_shell.expect_exact(f"Current password") + user_shell.expect(r"[cC]urrent [pP]assword") else: user_shell.expect_exact(f"Changing password for user {local_user.username}.") From 92e265c79f12f3a60684f7a4eb42b026cb59050d Mon Sep 17 00:00:00 2001 From: George Pantelakis Date: Wed, 29 Oct 2025 17:08:41 +0100 Subject: [PATCH 2/2] Update tests to match support for physical cards of SCAutolib --- Graphical/local-user-graphical-login.py | 113 +++++++------- Graphical/local-user-lock-on-removal.py | 144 +++++++++--------- Kerberos/test_kerberos_ssh_login.py | 2 +- .../test_kerberos_user_change_password.py | 2 +- Local-user/test_local_user_login.py | 75 +++++---- Local-user/test_local_user_passwd.py | 2 +- Sanity/test_certs.py | 4 +- Sanity/test_smart_card_detection.py | 15 +- Sanity/test_ttylogin.py | 29 ++-- conftest.py | 66 +++++--- fixtures.py | 8 +- 11 files changed, 255 insertions(+), 205 deletions(-) diff --git a/Graphical/local-user-graphical-login.py b/Graphical/local-user-graphical-login.py index 9894c39..edbec65 100644 --- a/Graphical/local-user-graphical-login.py +++ b/Graphical/local-user-graphical-login.py @@ -31,6 +31,7 @@ from SCAutolib.models.log import assert_log import pytest from time import sleep +from conftest import check_multicert SECURE_LOG = '/var/log/secure' @@ -56,19 +57,20 @@ def test_login_with_sc(local_user, required): expected_log = ( r'.* gdm-smartcard\]\[[0-9]+\]: ' r'pam_sss\(gdm-smartcard:auth\): authentication success;' - r'.*user=' + local_user.username + r'@shadowutils.*' + rf'.*user=({local_user.username}@shadowutils)?.*' ) - with (GUI() as gui, - Authselect(required=required), local_user.card(insert=True)): - gui.assert_text('PIN', timeout=60) - gui.kb_write(local_user.pin) + with (GUI(wait_time=10) as gui, Authselect(required=required)): + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}")(insert=True) as sc: + check_multicert(gui=gui) + gui.assert_text('PIN', timeout=60) - with assert_log(SECURE_LOG, expected_log): - gui.kb_send('enter', wait_time=20) - # Mandatory wait to switch display from GDM to GNOME - # Not waiting can actually mess up the output - gui.check_home_screen() + with assert_log(SECURE_LOG, expected_log): + gui.kb_write(sc.pin) + # Mandatory wait to switch display from GDM to GNOME + # Not waiting can actually mess up the output + gui.check_home_screen() @pytest.mark.parametrize("required", [(True), (False)]) @@ -91,20 +93,24 @@ def test_login_with_sc_wrong(local_user, required): expected_log = ( r'.* gdm-smartcard\]\[[0-9]+\]: ' r'pam_sss\(gdm-smartcard:auth\): authentication failure;' - r'.*user=' + local_user.username + r'@shadowutils.*' + rf'.*user=({local_user.username}@shadowutils)?.*' ) - with (GUI() as gui, - Authselect(required=required), local_user.card(insert=True)): - gui.assert_text('PIN', timeout=20) - gui.kb_write(local_user.pin[:-1]) + with (GUI(wait_time=10) as gui, Authselect(required=required)): + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}")(insert=True) as sc: + multicert = check_multicert(gui=gui) + gui.assert_text('PIN', timeout=20) - with assert_log(SECURE_LOG, expected_log): - gui.kb_send('enter', wait_time=20) - # Mandatory wait to switch display from GDM to GNOME - # Not waiting can actually mess up the output - gui.check_home_screen(False) - gui.assert_text('PIN', timeout=20) + with assert_log(SECURE_LOG, expected_log): + gui.kb_write(sc.pin[:-1]) + # Mandatory wait to switch display from GDM to GNOME + # Not waiting can actually mess up the output + gui.check_home_screen(False) + if multicert: + gui.assert_text('certificate', timeout=20) + else: + gui.assert_text('PIN', timeout=20) def test_login_password(local_user): @@ -123,13 +129,12 @@ def test_login_password(local_user): """ expected_log = ( r'.* pam_unix\(gdm-password:session\): session opened for user .*' - ) + ) - with GUI() as gui, Authselect(required=False): + with GUI(wait_time=10) as gui, Authselect(required=False): gui.click_on(local_user.username) - gui.kb_write(local_user.password) with assert_log(SECURE_LOG, expected_log): - gui.kb_send('enter', wait_time=20) + gui.kb_write(local_user.password) gui.check_home_screen() @@ -151,14 +156,13 @@ def test_login_password_wrong(local_user): expected_log = ( r'.* gdm-password\]\[[0-9]+\]: ' r'pam_unix\(gdm-password:auth\): authentication failure;' - r'.*user=' + local_user.username + r'.*' + rf'.*user=({local_user.username}@shadowutils)?.*' ) - with GUI() as gui, Authselect(required=False): + with GUI(wait_time=10) as gui, Authselect(required=False): gui.click_on(local_user.username) - gui.kb_write(local_user.password[:-1]) with assert_log(SECURE_LOG, expected_log): - gui.kb_send('enter', wait_time=20) + gui.kb_write(local_user.password[:-1]) gui.check_home_screen(False) gui.assert_text('Password', timeout=20) @@ -182,28 +186,29 @@ def test_insert_card_prompt(local_user, lock_on_removal): C. GDM shows "insert PIN" prompt D. User is logged in successfully. """ - with (GUI() as gui, - Authselect(required=True, lock_on_removal=lock_on_removal), - local_user.card(insert=False) as card): - try: - gui.assert_text('insert', timeout=20) - except Exception: - gui.click_on(local_user.username) - - gui.assert_text('insert', timeout=20) - card.insert() - sleep(10) - gui.assert_text('PIN') - gui.kb_write(local_user.pin) - - expected_log = ( - r'.* gdm-smartcard\]\[[0-9]+\]: ' - r'pam_sss\(gdm-smartcard:auth\): authentication success;' - r'.*user=' + local_user.username + r'(@shadowutils)?.*' - ) - - with assert_log(SECURE_LOG, expected_log): - gui.kb_send('enter', wait_time=20) - # Mandatory wait to switch display from GDM to GNOME - # Not waiting can actually mess up the output - gui.check_home_screen() + with (GUI(wait_time=10) as gui, + Authselect(required=True, lock_on_removal=lock_on_removal)): + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}")(insert=True) as sc: + try: + gui.assert_text('insert', timeout=20) + except Exception: + gui.click_on(local_user.username) + + gui.assert_text('insert', timeout=20) + sc.insert() + sleep(10) + check_multicert(gui=gui) + gui.assert_text('PIN') + + expected_log = ( + r'.* gdm-smartcard\]\[[0-9]+\]: ' + r'pam_sss\(gdm-smartcard:auth\): authentication success;' + rf'.*user=({local_user.username}@shadowutils)?.*' + ) + + with assert_log(SECURE_LOG, expected_log): + gui.kb_write(sc.pin) + # Mandatory wait to switch display from GDM to GNOME + # Not waiting can actually mess up the output + gui.check_home_screen() diff --git a/Graphical/local-user-lock-on-removal.py b/Graphical/local-user-lock-on-removal.py index ed2a152..2aaec55 100644 --- a/Graphical/local-user-lock-on-removal.py +++ b/Graphical/local-user-lock-on-removal.py @@ -28,6 +28,7 @@ from SCAutolib.models.authselect import Authselect from SCAutolib.models.gui import GUI, keyboard from time import sleep +from conftest import check_multicert import pytest @@ -50,36 +51,39 @@ def test_lock_on_removal(local_user, required): C. The system locks itself after the card is removed D. The system is unlocked """ - with (GUI() as gui, Authselect(required=required, lock_on_removal=True)): + with (GUI(wait_time=10) as gui, + Authselect(required=required, lock_on_removal=True)): # insert the card and sign in a standard way - with local_user.card(insert=True) as card: - sleep(5) - gui.assert_text('PIN', timeout=20) - gui.kb_write(local_user.pin) - gui.kb_send('enter', wait_time=20) - # confirm that you are logged in - gui.check_home_screen() - - # remove the card and wait for the screen to lock - card.remove() - sleep(5) - # Locking the screen in GNOME apparently does not generate any log. - # This could be checked by monitoring D-Bus signals - - # Wake up the black screen by pressing enter - gui.kb_send('enter', screenshot=False) - # Confirm that the screen is locked - # After the screen has been locked, there should be no Activities - gui.check_home_screen(False) - gui.assert_text('insert', timeout=20) - - card.insert() - # click on the password field - gui.click_on('PIN') - gui.kb_write(local_user.pin) - gui.kb_send('enter', wait_time=20) - # confirm that you are logged back in - gui.check_home_screen() + + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}")(insert=True) as sc: + sleep(5) + check_multicert(gui=gui) + gui.assert_text('PIN', timeout=20) + gui.kb_write(sc.pin) + # confirm that you are logged in + gui.check_home_screen() + + # remove the card and wait for the screen to lock + sc.remove() + sleep(5) + # Locking the screen in GNOME apparently does not generate any log. + # This could be checked by monitoring D-Bus signals + + # Wake up the black screen by pressing enter + gui.kb_send('enter', screenshot=False) + # Confirm that the screen is locked + # After the screen has been locked, there should be no Activities + gui.check_home_screen(False) + gui.assert_text('insert', timeout=20) + + sc.insert() + check_multicert(gui=gui) + # click on the password field + gui.click_on('PIN') + gui.kb_write(sc.pin) + # confirm that you are logged back in + gui.check_home_screen() def test_lock_on_removal_password(local_user): @@ -99,24 +103,25 @@ def test_lock_on_removal_password(local_user): C. Nothing happens D. Nothing happens - system will not lock on card removal """ - with (GUI() as gui, Authselect(required=False, lock_on_removal=True)): - with local_user.card(insert=False) as card: - gui.click_on(local_user.username) - gui.kb_write(local_user.password) - gui.kb_send('enter', wait_time=20) - gui.check_home_screen() + with (GUI(wait_time=10) as gui, + Authselect(required=False, lock_on_removal=True)): + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}")() as sc: + gui.click_on(local_user.username) + gui.kb_write(local_user.password) + gui.check_home_screen() - card.insert() - sleep(10) - card.remove() - sleep(10) + sc.insert() + sleep(10) + sc.remove() + sleep(10) - # Screen should be unlocked - gui.check_home_screen() + # Screen should be unlocked + gui.check_home_screen() @pytest.mark.parametrize("lock_on_removal", [(True), (False)]) -def test_lockscreen_password(local_user, lock_on_removal): +def test_lockscreen_password(local_user, check_multicert, lock_on_removal): """Local user unlocks screen using password, even if the smart card is inserted (after the password login). Screen unlocking requires the same method (PIN vs password) as was used for login. @@ -137,31 +142,30 @@ def test_lockscreen_password(local_user, lock_on_removal): D. The screen is locked E. Screen is unlocked successfully """ - with (GUI() as gui, - Authselect(required=False, lock_on_removal=lock_on_removal), - local_user.card(insert=False) as card): - gui.click_on(local_user.username) - gui.kb_write(local_user.password) - gui.kb_send('enter', wait_time=20) - gui.check_home_screen() - - card.insert() - sleep(10) - # press shortcut to lock the screen - # keyboard.send('windows+l') cannot be parsed properly - # this is a workaround for keyboard library - keyboard.press((125, 126),) - keyboard.send('l') - keyboard.release((125, 126),) - sleep(10) - - # Wake up the black screen by pressing enter - gui.kb_send('enter', screenshot=False) - # Confirm that the screen is locked - # After the screen has been locked, there should be no Activities - gui.check_home_screen(False) - gui.click_on('Password', check_difference=False) - gui.kb_write(local_user.password) - gui.kb_send('enter', wait_time=10) - # confirm that you are logged back in - gui.check_home_screen() + with (GUI(wait_time=10) as gui, + Authselect(required=False, lock_on_removal=lock_on_removal)): + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}")() as sc: + gui.click_on(local_user.username) + gui.kb_write(local_user.password) + gui.check_home_screen() + + sc.insert() + sleep(10) + # press shortcut to lock the screen + # keyboard.send('windows+l') cannot be parsed properly + # this is a workaround for keyboard library + keyboard.press((125, 126),) + keyboard.send('l') + keyboard.release((125, 126),) + sleep(10) + + # Wake up the black screen by pressing enter + gui.kb_send('enter', screenshot=False) + # Confirm that the screen is locked + # After the screen has been locked, there should be no Activities + gui.check_home_screen(False) + gui.click_on('Password', check_difference=False) + gui.kb_write(local_user.password) + # confirm that you are logged back in + gui.check_home_screen() diff --git a/Kerberos/test_kerberos_ssh_login.py b/Kerberos/test_kerberos_ssh_login.py index f3ec0fd..ec3b5b3 100644 --- a/Kerberos/test_kerberos_ssh_login.py +++ b/Kerberos/test_kerberos_ssh_login.py @@ -4,7 +4,7 @@ import pytest from SCAutolib.models.authselect import Authselect -from SCAutolib.isDistro import isDistro +from SCAutolib.utils import isDistro def test_krb_user_ssh(ipa_user, user_shell): diff --git a/Kerberos/test_kerberos_user_change_password.py b/Kerberos/test_kerberos_user_change_password.py index 620aa36..d0c0177 100644 --- a/Kerberos/test_kerberos_user_change_password.py +++ b/Kerberos/test_kerberos_user_change_password.py @@ -2,7 +2,7 @@ import conftest from SCAutolib.models.authselect import Authselect -from SCAutolib.isDistro import isDistro +from SCAutolib.utils import isDistro @pytest.mark.parametrize("required,insert,expect,secret", diff --git a/Local-user/test_local_user_login.py b/Local-user/test_local_user_login.py index 564b3d3..351e233 100644 --- a/Local-user/test_local_user_login.py +++ b/Local-user/test_local_user_login.py @@ -2,9 +2,10 @@ do not require any credentials! """ import pytest +import pexpect +from conftest import check_multicert from SCAutolib.models.authselect import Authselect - @pytest.mark.parametrize("required", [True, False]) def test_su_login_with_sc(local_user, user_shell, required): """Basic su login to the user with a smart card. @@ -41,12 +42,14 @@ def test_su_login_with_sc(local_user, user_shell, required): """ with Authselect(required=required): - with local_user.card(insert=True): - cmd = f'su {local_user.username} -c "whoami"' - user_shell.sendline(cmd) - user_shell.expect_exact(f"PIN for {local_user.username}:") - user_shell.sendline(local_user.pin) - user_shell.expect_exact(local_user.username) + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}")(insert=True) as sc: + cmd = f'su {local_user.username} -c "whoami"' + user_shell.sendline(cmd) + check_multicert(shell=user_shell) + user_shell.expect(f"PIN for .*{sc.label}.*:") + user_shell.sendline(sc.pin) + user_shell.expect_exact(local_user.username) @pytest.mark.parametrize("required", [True, False]) @@ -84,12 +87,14 @@ def test_su_login_with_sc_wrong(local_user, user_shell, required): - User is not logged in and error message is written to the console """ with Authselect(required=required): - with local_user.card(insert=True): - cmd = f'su {local_user.username} -c "whoami"' - user_shell.sendline(cmd) - user_shell.expect_exact(f"PIN for {local_user.username}:") - user_shell.sendline("wrong") - user_shell.expect(f"su: Authentication failure") + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}")(insert=True) as sc: + cmd = f'su {local_user.username} -c "whoami"' + user_shell.sendline(cmd) + check_multicert(shell=user_shell) + user_shell.expect(f"PIN for .*{sc.label}.*:") + user_shell.sendline(sc.pin + "extra") + user_shell.expect(f"su: Authentication failure") def test_gdm_login_sc_required(local_user, root_shell): @@ -128,14 +133,18 @@ def test_gdm_login_sc_required(local_user, root_shell): """ with Authselect(required=True): - with local_user.card as sc: - cmd = f'sssctl user-checks -s gdm-smartcard {local_user.username} -a auth' - root_shell.sendline(cmd) - root_shell.expect_exact("Please insert smart card") - sc.insert() - root_shell.expect_exact(f"PIN for {local_user.username}") - root_shell.sendline(local_user.pin) - root_shell.expect("pam_authenticate.*Success") + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}") as sc: + cmd = f'sssctl user-checks -s gdm-smartcard {local_user.username} -a auth' + root_shell.sendline(cmd) + root_shell.expect_exact("Please insert smart card") + + sc.insert() + + check_multicert(shell=root_shell) + root_shell.expect(f"PIN for .*{sc.label}.*:") + root_shell.sendline(sc.pin) + root_shell.expect("pam_authenticate.*Success") def test_su_login_without_sc(local_user, user_shell): @@ -213,14 +222,16 @@ def test_su_to_root(local_user, user_shell, root_user, required, lock_on_removal - User is switched to the root user """ with Authselect(required=required, lock_on_removal=lock_on_removal): - with local_user.card(insert=True): - user_shell.sendline(f"su - {local_user.username}") - user_shell.expect_exact(f"PIN for {local_user.username}:") - user_shell.sendline(local_user.pin) - user_shell.expect_exact(local_user.username) - user_shell.sendline("whoami") - user_shell.expect_exact(local_user.username) - user_shell.sendline('su - root -c "whoami"') - user_shell.expect_exact("Password:") - user_shell.sendline(root_user.password) - user_shell.expect_exact("root") + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}")(insert=True) as sc: + user_shell.sendline(f"su - {local_user.username}") + check_multicert(shell=user_shell) + user_shell.expect(f"PIN for .*{sc.label}.*:") + user_shell.sendline(sc.pin) + user_shell.expect_exact(local_user.username) + user_shell.sendline("whoami") + user_shell.expect_exact(local_user.username) + user_shell.sendline('su - root -c "whoami"') + user_shell.expect_exact("Password:") + user_shell.sendline(root_user.password) + user_shell.expect_exact("root") diff --git a/Local-user/test_local_user_passwd.py b/Local-user/test_local_user_passwd.py index b93c397..119ffd4 100644 --- a/Local-user/test_local_user_passwd.py +++ b/Local-user/test_local_user_passwd.py @@ -1,7 +1,7 @@ import pytest from SCAutolib.models.authselect import Authselect -from SCAutolib.isDistro import isDistro +from SCAutolib.utils import isDistro @pytest.mark.parametrize( diff --git a/Sanity/test_certs.py b/Sanity/test_certs.py index 5aa9a2c..f2ffb48 100644 --- a/Sanity/test_certs.py +++ b/Sanity/test_certs.py @@ -5,7 +5,7 @@ from SCAutolib.models.authselect import Authselect from SCAutolib.models.file import File -from SCAutolib.utils import ca_factory +from SCAutolib.models.CA import BaseCA @pytest.mark.parametrize("sssd_db", [File("/etc/sssd/pki/sssd_auth_ca_db.pem")]) @@ -33,7 +33,7 @@ def test_wrong_issuer_cert(local_user, sssd_db, user_shell, tmp_path): sssd_db.path.unlink() run(['mkdir', tmp_path.joinpath("ca")]) - ca_factory(path=tmp_path.joinpath("ca"), create=True) + BaseCA.factory(path=tmp_path.joinpath("ca"), create=True) run(['restorecon', "-v", "/etc/sssd/pki/sssd_auth_ca_db.pem"]) with Authselect(): diff --git a/Sanity/test_smart_card_detection.py b/Sanity/test_smart_card_detection.py index 4798bdc..b2c7614 100644 --- a/Sanity/test_smart_card_detection.py +++ b/Sanity/test_smart_card_detection.py @@ -1,7 +1,3 @@ -import pytest -from time import sleep -import pexpect - def test_modutil_token_info(local_user, root_shell): """Check that p11-kit module shows smart card information with modutil command""" @@ -44,3 +40,14 @@ def test_pam_services_config(local_user, root_shell, sssd): root_shell.sendline(local_user.pin) root_shell.expect_exact(f"pam_authenticate for user " f"[{local_user.username}]: Success") + + +def test_physical_card_detection(local_user, root_shell): + for i in range(local_user.total_cards): + with getattr(local_user, f"card_{i}") as sc: + cmd = "pkcs11-tool -L" + root_shell.sendline(cmd) + root_shell.expect_exact("(empty)") + sc.insert() + root_shell.sendline(cmd) + root_shell.expect_exact(sc.label) diff --git a/Sanity/test_ttylogin.py b/Sanity/test_ttylogin.py index 0600e6b..6eb41cd 100644 --- a/Sanity/test_ttylogin.py +++ b/Sanity/test_ttylogin.py @@ -9,12 +9,13 @@ """ import sys from time import sleep +from conftest import check_multicert import pexpect import pytest from SCAutolib.models.authselect import Authselect -from SCAutolib.isDistro import isDistro +from SCAutolib.utils import isDistro def login_shell_factory(username): @@ -348,17 +349,19 @@ def test_login_local_su_to_root(user, root_user, required, lock_on_removal): - User is switched to the root user """ with Authselect(required=required, lock_on_removal=lock_on_removal): - with user.card(insert=True): - login_shell = login_shell_factory(user.username) - login_shell.expect([f"PIN for {user.username}:"]) - login_shell.sendline(user.pin) - login_shell.expect([user.username]) - login_shell.sendline("whoami") - login_shell.expect_exact(user.username) - login_shell.sendline('su - root -c "whoami"') - login_shell.expect_exact("Password:") - login_shell.sendline(root_user.password) - login_shell.expect_exact("root") + for i in range(user.total_cards): + with getattr(user, f"card_{i}")(insert=True) as sc: + login_shell = login_shell_factory(user.username) + check_multicert(shell=login_shell) + login_shell.expect([f"PIN for .*{sc.label}.*:"]) + login_shell.sendline(sc.pin) + login_shell.expect([user.username]) + login_shell.sendline("whoami") + login_shell.expect_exact(user.username) + login_shell.sendline('su - root -c "whoami"') + login_shell.expect_exact("Password:") + login_shell.sendline(root_user.password) + login_shell.expect_exact("root") @pytest.mark.parametrize("required", [True, False]) def test_login_kerberos_su_to_root(ipa_user, root_user, required): @@ -390,4 +393,4 @@ def test_login_kerberos_su_to_root(ipa_user, root_user, required): login_shell.sendline('su - root -c "whoami"') login_shell.expect_exact("Password:") login_shell.sendline(root_user.password) - login_shell.expect_exact("root") \ No newline at end of file + login_shell.expect_exact("root") diff --git a/conftest.py b/conftest.py index cbd1b8d..225d772 100644 --- a/conftest.py +++ b/conftest.py @@ -1,8 +1,9 @@ import logging -from SCAutolib.utils import load_user, ipa_factory, load_token, \ - ca_factory +from SCAutolib.models.CA import BaseCA, IPAServerCA +from SCAutolib.models.card import Card +from SCAutolib.models.user import User from fixtures import * from pathlib import Path @@ -13,26 +14,33 @@ ipa_server = None local_user = None tokens = None +multicert = None def load_tokens(user, token_list, update_sssd): log.info("Loading tokens") + user.total_cards = len(token_list) for index, token in enumerate(token_list): log.debug("Loading %s. token", index) setattr( - user, f"card_{index}", load_token(token, update_sssd = update_sssd) + user, f"card_{index}", Card.load( + card_name = token, update_sssd = update_sssd) ) log.debug(f"Token %s is loaded", index) -def update_ca(user, token_list): - log.info("Loading local CA") - for index, token in enumerate(token_list): - card_name = f"card_{index}" - card = getattr(user, card_name, None) - ca = ca_factory(ca_name=card.ca_name) - ca.update_ca_db() - log.debug("CA database is updated") +def check_multicert(shell = None, gui = None): + global multicert + if multicert: + # For if the card has multiple certs and you need to choose + if shell: + shell.expect_exact(f"select a certificate") + shell.sendline(multicert) + if gui: + gui.assert_text('select a certificate', timeout=10) + gui.click_on("Certificate for", click_on_match=int(multicert)) + return True + return False def pytest_configure(config): @@ -40,8 +48,10 @@ def pytest_configure(config): global ipa_server global local_user global tokens + global multicert user_type = config.getoption("user_type") tokens = config.getoption("tokens") + multicert = config.getoption("select_cert") # workaround to set default token as parser.addoption defining tokens # is a list that needs to be empty by default @@ -50,24 +60,24 @@ def pytest_configure(config): if user_type in ["ipa", "all"]: log.debug("Loading IPA client") - ipa_server = ipa_factory() + ipa_server = IPAServerCA.factory() log.debug("IPA client is loaded") log.debug("Loading IPA user") - ipa_user = load_user( - config.getoption("ipa_username"), + ipa_user = User.load( + username = config.getoption("ipa_username"), ipa_server=ipa_server) assert ipa_user.user_type == "ipa" log.debug("IPA user is loaded") - load_tokens(ipa_user, tokens, config.getoption("keep_sssd")) + load_tokens(ipa_user, tokens, config.getoption("update_sssd")) ipa_user.card = ipa_user.card_0 ipa_user.pin = ipa_user.card.pin if user_type in ["local", "all"]: log.debug("Loading local user") - local_user = load_user(config.getoption( + local_user = User.load(username = config.getoption( "local_username")) assert local_user.user_type == "local" log.debug("Local user is loaded") - load_tokens(local_user, tokens, config.getoption("keep_sssd")) + load_tokens(local_user, tokens, config.getoption("update_sssd")) # backwards compatibility fix. Older tests expected one virtual card # as attribute of user - i.e. user.card and approached card this way. # As of now we expect user can have multiple cards, they are marked @@ -79,8 +89,6 @@ def pytest_configure(config): # pin was moved to card. For backwards compatibility: local_user.pin = local_user.card.pin - update_ca(local_user, tokens) - def pytest_addoption(parser): """ @@ -116,10 +124,20 @@ def pytest_addoption(parser): help="List of tokens to be prepared" ) parser.addoption( - "--keep-sssd", - action="store_false", - dest="keep_sssd", - help="Prevents the forced change of sssd.conf" + "--update-sssd", + action="store_true", + default=False, + dest="update_sssd", + help="Force change of sssd.conf" + ) + parser.addoption( + "--select-cert", + action="store", + default=None, + dest="select_cert", + help="Use if card has multiple certs stored. " + "Provide which cert to use. " + "Note that this selection will apply to all tokens!" ) @@ -161,3 +179,5 @@ def pytest_generate_tests(metafunc): metafunc.parametrize("ipa_server", [ipa_server]) if "tokens" in metafunc.fixturenames: metafunc.parametrize("tokens", [tokens]) + if "check_multicert" in metafunc.fixturenames: + metafunc.parametrize("check_multicert", [check_multicert]) diff --git a/fixtures.py b/fixtures.py index 8a67962..1690d94 100644 --- a/fixtures.py +++ b/fixtures.py @@ -5,7 +5,7 @@ from SCAutolib import run from SCAutolib.models.file import SSSDConf -from SCAutolib.utils import load_user +from SCAutolib.models.user import User @pytest.fixture(scope="function") @@ -26,7 +26,7 @@ def root_shell(): @pytest.fixture(scope="function") def allow_sudo_commands(ipa_user): """ - Modifying the IPA server's sudo rules to allow the test user to + Modifying the IPA server's sudo rules to allow the test user to run sudo commands and restore the original state afterward. """ logger = logging.getLogger() @@ -44,12 +44,12 @@ def allow_sudo_commands(ipa_user): @pytest.fixture(scope="session") def root_user(): - return load_user("root") + return User.load(username="root") @pytest.fixture(scope="session") def base_user(): - return load_user("base-user") + return User.load(username="base-user") @pytest.fixture(scope="session")