Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/tests/system/tests/test_ipa.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,3 +397,47 @@ def test_ipa__idview_fails_to_apply_on_ipa_master(ipa: IPA):
assert (
"ID View cannot be applied to IPA master" in result.stdout
), "Did not get an error message when trying to apply ID view on server!"


@pytest.mark.importance("high")
@pytest.mark.topology(KnownTopology.IPA)
@pytest.mark.builtwith(client="virtualsmartcard")
def test_ipa__switch_user_with_smartcard_authentication(client: Client, ipa: IPA):
"""
:title: Smart card authentication allows nested 'su' as IPA user
:setup:
1. Create IPA user with key pair and certificate
2. Copy certificate to client and initialize virtual smart card
3. Configure SSSD with smart card support and start SSSD services
:steps:
1. Execute 'su - ipacertuser1' as root (no authentication required due to pam_rootok.so)
2. From within the user session, execute nested 'su - ipacertuser1 -c whoami' as ordinary user
:expectedresults:
1. First 'su' succeeds without authentication as it's executed by root
2. Second 'su' prompts for PIN and successfully authenticates with smart card
a. PIN prompt appears, indicating smart card authentication is triggered for ordinary user
b. 'whoami' command returns 'ipacertuser1', confirming successful smart card authentication
:customerscenario: False
"""
ipa.user("ipacertuser1").add()
cert, key, _ = ipa.ca.request("ipacertuser1")
cert_content = ipa.fs.read(cert)
key_content = ipa.fs.read(key)

client.fs.write("/opt/test_ca/ipacertuser1.crt", cert_content)
client.fs.write("/opt/test_ca/ipacertuser1.key", key_content)
client.smartcard.initialize_card()
client.smartcard.add_key("/opt/test_ca/ipacertuser1.key")
client.smartcard.add_cert("/opt/test_ca/ipacertuser1.crt")

client.authselect.select("sssd", ["with-smartcard"])
client.sssd.pam["pam_cert_auth"] = "True"
client.sssd.start()
client.svc.restart("virt_cacard.service")
time.sleep(1)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using a fixed time.sleep(1) can lead to flaky tests. The test might fail if the service takes longer than 1 second to restart, or it might wait unnecessarily if the service restarts faster. It's more robust to poll for the service status in a loop with a timeout to ensure it's active before proceeding.

Suggested change
time.sleep(1)
for _ in range(10):
result = client.host.conn.run("systemctl is-active virt_cacard.service")
if result.rc == 0:
break
time.sleep(1)
else:
pytest.fail("virt_cacard.service did not become active in time.")


result = client.host.conn.run("su - ipacertuser1 -c 'su - ipacertuser1 -c whoami'", input="123456")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Hardcoding the smartcard PIN '123456' directly in the test logic is a security risk and a bad practice, even in tests. It's better to define it as a constant at the module level (e.g., SMARTCARD_PIN = "123456") and use the constant here. This makes it easier to manage and change if needed, and improves code readability.

assert "PIN" in result.stderr, f"String 'PIN' was not found in stderr! Stderr content: {result.stderr}"
assert (
"ipacertuser1" in result.stdout
), f"'ipacertuser1' not found in 'whoami' output! Stdout content: {result.stdout}"
Loading