Skip to content

Commit

Permalink
Improve testing TCs that are automated only with 'su' (#34)
Browse files Browse the repository at this point in the history
First automated tests used 'su' as a mean of testing smart card authentication.
However, these tests were usually supposed to test login (not su), but support
for any direct or indirect testing of login was not implemented yet. Testing
logins in TTY and also in GUI is already supported. It's time to check test
coverage and cover TCs that still use 'su' also with TTY and GUI logins.

Co-authored-by: George Pantelakis <gpantela@redhat.com>
  • Loading branch information
mahavrila and GeorgePantelakis committed Dec 22, 2023
1 parent eab1f05 commit 291fd07
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 17 deletions.
6 changes: 3 additions & 3 deletions Graphical/local-user-graphical-login.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
This module contains tests for logging into GUI using GDM.
Most of the tests are parametrized to test both
optional and required smart card in authselect.
Lock-on-removal option is not set as it is irrelevant for present tests.
The tests within the module try logging in both using password and
smart card with PIN. Both wrong password and wrong PIN are tested too.
All tests depend on SCAutolib GUI module.
Expand Down Expand Up @@ -163,7 +162,8 @@ def test_login_password_wrong(local_user):
gui.assert_text('Password')


def test_insert_card_prompt(local_user):
@pytest.mark.parametrize("lock_on_removal", [True, False])
def test_insert_card_prompt(local_user, lock_on_removal):
"""Local user tries to log in with GDM before inserting card,
with sc required.
Expand All @@ -180,7 +180,7 @@ def test_insert_card_prompt(local_user):
C. GDM shows "insert PIN" prompt
D. User is logged in successfully.
"""
with (Authselect(required=True),
with (Authselect(required=True, lock_on_removal=lock_on_removal),
local_user.card(insert=False) as card,
GUI() as gui):
gui.assert_text('insert')
Expand Down
19 changes: 12 additions & 7 deletions Local-user/test_local_user_login.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"""Note: as all tests are executed from root user, first login to any user
do not require any credentials!
"""
import pytest
from SCAutolib.models.authselect import Authselect


def test_su_login_with_sc(local_user, user_shell):
@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.
Setup
Expand Down Expand Up @@ -38,7 +40,7 @@ def test_su_login_with_sc(local_user, user_shell):
- User is successfully logged in
"""

with Authselect(required=False):
with Authselect(required=required):
with local_user.card(insert=True):
cmd = f'su {local_user.username} -c "whoami"'
user_shell.sendline(cmd)
Expand All @@ -47,7 +49,8 @@ def test_su_login_with_sc(local_user, user_shell):
user_shell.expect_exact(local_user.username)


def test_su_login_with_sc_wrong(local_user, user_shell):
@pytest.mark.parametrize("required", [True, False])
def test_su_login_with_sc_wrong(local_user, user_shell, required):
"""Basic su login to the user with a smartcard when user inters wrong PIN.
Setup
Expand Down Expand Up @@ -80,7 +83,7 @@ def test_su_login_with_sc_wrong(local_user, user_shell):
- User inserts wrong PIN
- User is not logged in and error message is written to the console
"""
with Authselect(required=False):
with Authselect(required=required):
with local_user.card(insert=True):
cmd = f'su {local_user.username} -c "whoami"'
user_shell.sendline(cmd)
Expand Down Expand Up @@ -172,8 +175,10 @@ def test_su_login_without_sc(local_user, user_shell):
user_shell.sendline(local_user.password)
user_shell.expect_exact(local_user.username)


def test_su_to_root(local_user, user_shell, root_user):
@pytest.mark.parametrize(
"required,lock_on_removal", [(True, True), (True, False), (False, True), (False, False),]
)
def test_su_to_root(local_user, user_shell, root_user, required, lock_on_removal):
"""Test for smartcard login to the local user and then switching to root (su -).
Setup
Expand Down Expand Up @@ -207,7 +212,7 @@ def test_su_to_root(local_user, user_shell, root_user):
- User insert correct root password
- User is switched to the root user
"""
with Authselect():
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}:")
Expand Down
8 changes: 5 additions & 3 deletions Local-user/test_local_user_passwd.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from SCAutolib.models.authselect import Authselect


@pytest.mark.parametrize("required", [True, False])
def test_change_local_user_passwd(local_user, user_shell, required):
@pytest.mark.parametrize(
"required,lock_on_removal", [(True, True), (True, False), (False, True), (False, False),]
)
def test_change_local_user_passwd(local_user, user_shell, required, lock_on_removal):
"""Run 'passwd' command when smartcard login is enforced and after user is
authenticated in with a smartcard.
Expand Down Expand Up @@ -37,7 +39,7 @@ def test_change_local_user_passwd(local_user, user_shell, required):
- Users is asked to change it local password
- No mentioning of the smart card
"""
with Authselect(required=required):
with Authselect(required=required, lock_on_removal=lock_on_removal):
with local_user.card(insert=True):
cmd = f"su {local_user.username} -c 'passwd'"
user_shell.sendline(cmd)
Expand Down
180 changes: 176 additions & 4 deletions Sanity/test_ttylogin.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from time import sleep

import pexpect
import pytest

from SCAutolib.models.authselect import Authselect

Expand Down Expand Up @@ -96,6 +97,48 @@ def test_login_without_sc(user):
login_shell.close()


def test_login_without_sc_wrong(user):
"""Basic login to the user without a smartcard when user enters wrong password.
Setup
1. Create local CA
2. Create virtual smart card with certs signed by created CA
3. Update /etc/sssd/sssd.conf so it contains following fields
[sssd]
debug_level = 9
services = nss, pam,
domains = shadowutils
certificate_verification = no_ocsp
[pam]
debug_level = 9
pam_cert_auth = True
[domain/shadowutils]
debug_level = 9
id_provider = files
[certmap/shadowutils/username]
matchrule = <SUBJECT>.*CN=username.*
4. Setup authselect: authselect select sssd with-smartcard
5. Insert the card
6. Try to switch user (su login) to the smartcard user
Expected result
- Users is asked for smartcard PIN
- User inserts wrong PIN
- User is not logged in and error message is written to the console
"""
with Authselect():
login_shell = login_shell_factory(user.username)
login_shell.expect(f"Password:")
login_shell.sendline("wrong")
login_shell.expect("Login incorrect")
login_shell.sendline("exit")
login_shell.close()


def test_login_with_sc_required(user):
"""Console-like login to the user with a smart card; smartcard required.
Setup
Expand Down Expand Up @@ -134,7 +177,8 @@ def test_login_with_sc_required(user):
login_shell.close()


def test_login_with_sc_wrong(user):
@pytest.mark.parametrize("required", [True, False])
def test_login_with_sc_wrong(user, required):
"""Console-like login to the user with a smart card.
Setup
Expand Down Expand Up @@ -163,7 +207,7 @@ def test_login_with_sc_wrong(user):
- User inserts wrong PIN
- User is told that the PIN is incorrect
"""
with Authselect():
with Authselect(required=required):
with user.card(insert=True):
login_shell = login_shell_factory(user.username)
login_shell.expect(f"PIN for {user.username}:")
Expand All @@ -173,7 +217,8 @@ def test_login_with_sc_wrong(user):
login_shell.close()


def test_login_sc_required(user):
@pytest.mark.parametrize("lock_on_removal", [True, False])
def test_login_sc_required(user, lock_on_removal):
"""Console-like login to the user with a smart card.
Setup
Expand Down Expand Up @@ -204,7 +249,7 @@ def test_login_sc_required(user):
- User types PIN the PIN
- User is successfully logged in
"""
with Authselect(required=True):
with Authselect(required=True, lock_on_removal=lock_on_removal):
login_shell = login_shell_factory(user.username)
login_shell.expect("Please insert smart card")

Expand All @@ -215,3 +260,130 @@ def test_login_sc_required(user):
login_shell.sendline("exit")
login_shell.close()

@pytest.mark.parametrize(
"required,lock_on_removal", [(True, True), (True, False), (False, True), (False, False),]
)
def test_login_local_user_passwd(user, required, lock_on_removal):
"""Run 'passwd' command when smartcard login is enforced and after user is
authenticated in with a smartcard.
Setup
1. Create local CA
2. Create virtual smart card with certs signed by created CA
3. Update /etc/sssd/sssd.conf so it contains following fields
[sssd]
debug_level = 9
services = nss, pam,
domains = shadowutils
certificate_verification = no_ocsp
[pam]
debug_level = 9
pam_cert_auth = True
[domain/shadowutils]
debug_level = 9
id_provider = files
[certmap/shadowutils/username]
matchrule = <SUBJECT>.*CN=username.*
4. Setup authselect: authselect select sssd with-smartcard (with-smartcard-required)
5. Login to the smart card user
6. Run 'passwd'
Expected result
- Users is asked to change it local password
- No mentioning of the smart card
"""

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("passwd")
login_shell.expect_exact(f"Changing password for user {user.username}.")

@pytest.mark.parametrize(
"required,lock_on_removal", [(True, True), (True, False), (False, True), (False, False),]
)
def test_login_local_su_to_root(user, root_user, required, lock_on_removal):
"""Test for smartcard login to the local user and then switching to root (su -).
Setup
1. Create local CA
2. Create virtual smart card with certs signed by created CA
3. Update /etc/sssd/sssd.conf so it contains following fields
[sssd]
debug_level = 9
services = nss, pam,
domains = shadowutils
certificate_verification = no_ocsp
[pam]
debug_level = 9
pam_cert_auth = True
[domain/shadowutils]
debug_level = 9
id_provider = files
[certmap/shadowutils/username]
matchrule = <SUBJECT>.*CN=username.*
4. Setup authselect: authselect select sssd with-smartcard
5. Insert the card
6. Switch user with 'su' command to the smartcard user
7. User is asked for smartcard PIN -> insert correct PIN
8. After successful login, try to switch to root user with 'su -'
Expected result
- Users is asked for root password
- User insert correct root password
- 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")

@pytest.mark.parametrize("required", [True, False])
def test_login_kerberos_su_to_root(ipa_user, root_user, required):
"""Kerberos user tries to switch to the root user with root password after
kerberos user is logged in with smart card.
Setup
1. General setup
2. Setup authselect: authselect select sssd with-smartcard with-smartcard-required
3. Insert the card
4. Login to kerberos user
5. System asks for smartcard PIN -> insert correct smartcard PIN
6. User is successfully logged in
7. Try to switch to root (su -)
Expected result
- User is asked to insert root password
- User inserts root password
- User is switched to the root user
"""
with Authselect(required=required):
with ipa_user.card(insert=True):
login_shell = login_shell_factory(ipa_user.username)
login_shell.expect([f"PIN for {ipa_user.username}:"])
login_shell.sendline(ipa_user.pin)
login_shell.expect([ipa_user.username])
login_shell.sendline("whoami")
login_shell.expect_exact(ipa_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")

0 comments on commit 291fd07

Please sign in to comment.