diff --git a/e2e-tests/AGENTS.md b/e2e-tests/AGENTS.md index a010b52b16..0f8ee19039 100644 --- a/e2e-tests/AGENTS.md +++ b/e2e-tests/AGENTS.md @@ -33,12 +33,16 @@ exist to close that gap: observable over SSH or in the journal, assert it there — it's deterministic and fast. The suite already does this where it can: see `Check Home Directory` and `Check If Owner Was Registered` in `resources/broker.resource`, which use - `SSH.Execute` instead of reading the screen. + `SSH.Execute` and `getent` instead of reading the screen. 2. **OCR (`Match Text` / `Find Text` / `Read Text`).** Use this only when the behavior is genuinely only observable on screen (GDM, the PAM CLI/TUI inside a `machinectl` session, terminal output you can't reach over SSH). Follow the OCR hygiene rules below. +Note that SSH is often *not* possible — e.g. anything happening inside the GDM +greeter or a `machinectl login` session before the user's shell exists. Don't +force an SSH assertion where it doesn't fit; use OCR and make it robust. + ## Don't sleep — poll instead Avoid `Builtin.Sleep` to wait for asynchronous work to finish (e.g. authd's @@ -145,6 +149,27 @@ file. The console history is saved to `rfdebug_history.log` in the output dir. For a region that OCR keeps misreading, the console also exposes `Grab Templates` and a region-of-interest selector to crop and scope matches. +## OCR hygiene rules + +These come straight from patterns the existing suite relies on — reproduce them: + +- **Strip spaces and normalize case** when matching machine-generated codes. The + device user code handling in `Continue Log In With Remote User: Authenticate + In External Browser` removes OCR-inserted spaces and upper-cases the result, + because OCR adds phantom spaces and mis-cases characters. +- **Prefer `regex:` matches** for anything variable. `Find Text` / `Match Text` + accept `regex:`; use it instead of brittle exact strings when the + text contains values that vary or that OCR renders inconsistently. +- **Scope with a `region`** when a short string risks matching elsewhere on + screen, or when OCR is unreliable over the full frame. +- **Give realistic timeouts.** `Match Text` waits up to its timeout for text to + appear; remote/network-dependent screens use generous timeouts (e.g. `120`) + in the existing tests — match that, don't use the short default for slow + screens. +- **Don't match the command echo.** When checking terminal output, use the + `base64 cmd-finished` trick (above) so you don't match the typed command + before it has run. + ## Running and reading results Run a single test (or omit the file to run all) using the existing script. It automatically loads the diff --git a/e2e-tests/resources/SSH.py b/e2e-tests/resources/SSH.py index 7083228a26..455f63c3c8 100644 --- a/e2e-tests/resources/SSH.py +++ b/e2e-tests/resources/SSH.py @@ -53,7 +53,8 @@ async def execute_as_user(self, user:str, command: str, timeout: int|None = 30) command = (f"sudo -u {user} " f"XDG_RUNTIME_DIR=/run/user/$(id -u {user}) " f"DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u {user})/bus " - f"{command}") + "-- " + f"sh -c \"{command}\"") return await self.execute(command, timeout) @keyword diff --git a/e2e-tests/resources/authd.resource b/e2e-tests/resources/authd.resource index e485dded9b..98f32ecd09 100644 --- a/e2e-tests/resources/authd.resource +++ b/e2e-tests/resources/authd.resource @@ -72,3 +72,23 @@ Check That Remote User Can Run Sudo Commands SSH.Execute echo ${local_password} | sudo -S touch sudo-test.txt ${output} = SSH.Execute ls -l sudo-test.txt Should Contain ${output} sudo-test.txt + + +Check that GNOME keyring is unlocked + SSH.Execute As Current User echo '' | secret-tool store --label=test test key + + +Store Secret In GNOME Keyring + [Arguments] ${secret} + # Storing succeeds only if the keyring is unlocked, so this both seeds a + # known secret and asserts the keyring is currently unlocked. + SSH.Execute As Current User printf '%s' '${secret}' | secret-tool store --label=e2e-test e2e-test keyring-persistence + + +Check Secret In GNOME Keyring + [Arguments] ${expected_secret} + # Looking up the secret succeeds only if the *same* keyring that stored it is + # unlocked. If the password change re-created the keyring instead of re-keying + # it, the secret is gone and this fails. + ${secret} = SSH.Execute As Current User secret-tool lookup e2e-test keyring-persistence + Should Be Equal ${secret} ${expected_secret} diff --git a/e2e-tests/resources/utils.resource b/e2e-tests/resources/utils.resource index 8ce4e85182..5044660e8d 100644 --- a/e2e-tests/resources/utils.resource +++ b/e2e-tests/resources/utils.resource @@ -215,7 +215,7 @@ Submit Run Command Dialog Launch App [Arguments] ${app-id} - SSH.Execute As Current User gtk-launch ${app-id} + SSH.Execute As Current User gtk-launch ${app-id} timeout=60 Cancel Operation diff --git a/e2e-tests/tests/login_gdm.robot b/e2e-tests/tests/login_gdm.robot index 30e2dc9746..4284f932c7 100644 --- a/e2e-tests/tests/login_gdm.robot +++ b/e2e-tests/tests/login_gdm.robot @@ -22,6 +22,7 @@ Test login with GDM # Log in with remote user with device code flow via GDM Log In With Remote User Through GDM: QR Code ${username} ${local_password} + Check that GNOME keyring is unlocked # Check remote user is properly added to the system Check If User Was Added Properly ${username} @@ -30,3 +31,4 @@ Test login with GDM # Log in with remote user with local password via GDM Log In With Remote User Through GDM: Local Password ${username} ${local_password} + Check that GNOME keyring is unlocked diff --git a/e2e-tests/tests/passwd_changes_keyring_password.robot b/e2e-tests/tests/passwd_changes_keyring_password.robot new file mode 100644 index 0000000000..69a69a1c62 --- /dev/null +++ b/e2e-tests/tests/passwd_changes_keyring_password.robot @@ -0,0 +1,48 @@ +*** Settings *** +Resource resources/utils.resource +Resource resources/authd.resource + +Resource resources/broker.resource + +# Test Tags robot:exit-on-failure + +Test Setup utils.Test Setup snapshot=%{BROKER}-installed +Test Teardown utils.Test Teardown + + +*** Variables *** +${snapshot} %{BROKER}-installed +${username} %{E2E_USER} +${local_password} qwer1234 +${new_password} passwd1234 +${keyring_secret} s3cr3t-survives-passwd + + +*** Test Cases *** +Changing the local password also changes the keyring password + [Documentation] Changing a remote user's local password with `passwd` must re-key the + ... GNOME login keyring so it keeps unlocking with the new password. + ... + ... Regression guard: the keyring is unlocked from PAM_AUTHTOK at login. If the + ... password change does not propagate the old/new password to the keyring's PAM + ... module, the next login creates a fresh keyring and any previously stored secret + ... is lost. We seed a secret before the change and require it to still be there + ... after logging in again with the new password. + + # Log in with device authentication. This creates the login keyring and + # unlocks it with ${local_password}. + Log In With Remote User Through GDM: QR Code ${username} ${local_password} + Check that GNOME keyring is unlocked + Store Secret In GNOME Keyring ${keyring_secret} + + # Change the local password with `passwd`. + Open Terminal + Change Password ${local_password} ${new_password} + Close Focused Window + Log Out + + # Log in again with the new local password. The keyring must unlock with it + # and still contain the secret stored before the change. + Log In With Remote User Through GDM: Local Password ${username} ${new_password} + Check that GNOME keyring is unlocked + Check Secret In GNOME Keyring ${keyring_secret} diff --git a/e2e-tests/vm/cloud-init-template-noble.yaml b/e2e-tests/vm/cloud-init-template-noble.yaml index dc640bdd97..14a31b9a6e 100644 --- a/e2e-tests/vm/cloud-init-template-noble.yaml +++ b/e2e-tests/vm/cloud-init-template-noble.yaml @@ -29,6 +29,8 @@ packages: - gnome-terminal - gsettings-ubuntu-schemas - libpam-pwquality + # Required to test that the keyring is unlocked (ships secret-tool) + - libsecret-tools - openssh-server - policykit-desktop-privileges # Required to get the VM's IP address diff --git a/e2e-tests/vm/cloud-init-template-resolute.yaml b/e2e-tests/vm/cloud-init-template-resolute.yaml index 8a0f284ac2..41916c9a96 100644 --- a/e2e-tests/vm/cloud-init-template-resolute.yaml +++ b/e2e-tests/vm/cloud-init-template-resolute.yaml @@ -28,6 +28,8 @@ packages: - gnome-shell-ubuntu-extensions - gsettings-ubuntu-schemas - libpam-pwquality + # Required to test that the keyring is unlocked (ships secret-tool) + - libsecret-tools - openssh-server - policykit-desktop-privileges # Required to get the VM's IP address diff --git a/e2e-tests/vm/cloud-init-template-stonking.yaml b/e2e-tests/vm/cloud-init-template-stonking.yaml index 97a27aa719..cb46df010a 100644 --- a/e2e-tests/vm/cloud-init-template-stonking.yaml +++ b/e2e-tests/vm/cloud-init-template-stonking.yaml @@ -28,6 +28,8 @@ packages: - gnome-shell-ubuntu-extensions - gsettings-ubuntu-schemas - libpam-pwquality + # Required to test that the keyring is unlocked (ships secret-tool) + - libsecret-tools - openssh-server - policykit-desktop-privileges # Required to get the VM's IP address diff --git a/e2e-tests/vm/provision-authd.sh b/e2e-tests/vm/provision-authd.sh index 103f0c83b6..9fe2cb25bc 100755 --- a/e2e-tests/vm/provision-authd.sh +++ b/e2e-tests/vm/provision-authd.sh @@ -141,7 +141,7 @@ assert_env_vars RELEASE BROKER ARTIFACTS_DIR="${ARTIFACTS_DIR:-${DATA_DIR}/${RELEASE}}" if [ -z "${VM_NAME:-}" ]; then - VM_NAME="${VM_NAME_BASE}-${RELEASE}" + export VM_NAME="${VM_NAME_BASE}-${RELEASE}" fi export VM_NAME diff --git a/e2e-tests/vm/provision-ubuntu.sh b/e2e-tests/vm/provision-ubuntu.sh index dca684fcca..3a55c4b8f2 100755 --- a/e2e-tests/vm/provision-ubuntu.sh +++ b/e2e-tests/vm/provision-ubuntu.sh @@ -113,7 +113,7 @@ ARTIFACTS_DIR="${ARTIFACTS_DIR:-${DATA_DIR}/${RELEASE}}" CLOUD_INIT_TEMPLATE="${SCRIPT_DIR}/cloud-init-template-${RELEASE_NAME}.yaml" if [ -z "${VM_NAME:-}" ]; then - VM_NAME="${VM_NAME_BASE}-${RELEASE}" + export VM_NAME="${VM_NAME_BASE}-${RELEASE}" fi function cloud_init_finished() { diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_add_it_to_local_group b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_add_it_to_local_group index 045ae0cd42..c35c4317ab 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_add_it_to_local_group +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_add_it_to_local_group @@ -19,6 +19,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-local-groups-integration-auth-cli@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_offer_password_reset b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_offer_password_reset index 9de5dba592..34ef12826a 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_offer_password_reset +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_offer_password_reset @@ -34,6 +34,7 @@ New password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-can-reset@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_reset_password_while_enforcing_policy b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_reset_password_while_enforcing_policy index 52afcb4cc6..27585dbc5a 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_reset_password_while_enforcing_policy +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_reset_password_while_enforcing_policy @@ -57,6 +57,7 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-needs-reset-integration-mandatory@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_reset_password_with_case_insensitive_user_selection b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_reset_password_with_case_insensitive_user_selection index 7af3a74caa..dea592798c 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_reset_password_with_case_insensitive_user_selection +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_and_reset_password_with_case_insensitive_user_selection @@ -58,6 +58,7 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-needs-reset-integration-case-insensitive-authenticate-user-and-reset-password-with-case-insensitive-user-selection@example.com" Result: success @@ -78,6 +79,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-needs-reset-integration-case-insensitive-authenticate-user-and-reset-password-with-case-insensitive-user-selection@example.com" Result: success @@ -98,6 +100,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-needs-reset-integration-case-insensitive-authenticate-user-and-reset-password-with-case-insensitive-user-selection@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully index 557b532819..c1a9fd920c 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully @@ -19,6 +19,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-simple-testcliauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_after_trying_empty_user b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_after_trying_empty_user index 52729238e3..3a607f1e8a 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_after_trying_empty_user +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_after_trying_empty_user @@ -23,6 +23,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-was-empty@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_invalid_connection_timeout b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_invalid_connection_timeout index c5adeb289d..a1e1096596 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_invalid_connection_timeout +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_invalid_connection_timeout @@ -19,6 +19,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-invalid-timeout-testcliauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_password_only_supported_method b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_password_only_supported_method index e5b0bf8d58..6c7af33864 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_password_only_supported_method +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_password_only_supported_method @@ -19,6 +19,7 @@ Gimme your password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-auth-modes-password-integration-cli@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_preset_user b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_preset_user index 30c79ac43f..7bc3c84723 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_preset_user +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_preset_user @@ -13,6 +13,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-preset-testcliauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_upper_case b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_upper_case index cb21aec151..2de2bc95b1 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_upper_case +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_upper_case @@ -19,6 +19,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-upper-case-testcliauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_upper_case_preset_user b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_upper_case_preset_user index d58650a01a..976726a5e7 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_upper_case_preset_user +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_successfully_with_upper_case_preset_user @@ -13,6 +13,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-preset-upper-case-testcliauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_switching_auth_mode b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_switching_auth_mode index 2148a0fce3..a7d8ee0c1e 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_switching_auth_mode +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_switching_auth_mode @@ -69,6 +69,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-switch-mode@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_switching_username b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_switching_username index 4057bf1cfb..3820797705 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_switching_username +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_switching_username @@ -28,6 +28,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-username-switched@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_form_mode_with_button b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_form_mode_with_button index d5b9b8db74..5944f09ad7 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_form_mode_with_button +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_form_mode_with_button @@ -47,6 +47,7 @@ Enter your one time credential: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "temporary pass00" PAM Authenticate() User: "user-integration-form-w-button@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_mfa b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_mfa index deeafa5253..13d489e0c7 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_mfa +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_mfa @@ -67,6 +67,7 @@ Unlock your phone +33... or accept request on web interface Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-mfa@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_mfa_and_reset_password_while_enforcing_policy b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_mfa_and_reset_password_while_enforcing_policy index 8e294f8969..32dc3dd285 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_mfa_and_reset_password_while_enforcing_policy +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_user_with_mfa_and_reset_password_while_enforcing_policy @@ -114,6 +114,7 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-mfa-with-reset@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_with_warnings_on_unsupported_arguments b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_with_warnings_on_unsupported_arguments index 3df5add7b0..e0ae897313 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_with_warnings_on_unsupported_arguments +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Authenticate_with_warnings_on_unsupported_arguments @@ -19,6 +19,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user2@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Deny_authentication_if_newpassword_does_not_match_required_criteria b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Deny_authentication_if_newpassword_does_not_match_required_criteria index fdc1d6eeb2..cd0a18a6a1 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Deny_authentication_if_newpassword_does_not_match_required_criteria +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Deny_authentication_if_newpassword_does_not_match_required_criteria @@ -132,6 +132,7 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-needs-reset@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Prevent_user_from_switching_username b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Prevent_user_from_switching_username index e5c174dd22..7a04276a30 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Prevent_user_from_switching_username +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Prevent_user_from_switching_username @@ -35,6 +35,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-pam-preset@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Remember_last_successful_broker_and_mode b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Remember_last_successful_broker_and_mode index f1fa136ccf..f963fb0b55 100644 --- a/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Remember_last_successful_broker_and_mode +++ b/pam/integration-tests/testdata/golden/TestCLIAuthenticate/Remember_last_successful_broker_and_mode @@ -41,6 +41,7 @@ Enter your one time credential: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "temporary pass0" PAM Authenticate() User: "user-integration-remember-mode@example.com" Result: success @@ -65,6 +66,7 @@ Enter your one time credential: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "temporary pass0" PAM Authenticate() User: "user-integration-remember-mode@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_passwd_after_MFA_auth b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_passwd_after_MFA_auth index 2d5706519b..ce3c89173e 100644 --- a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_passwd_after_MFA_auth +++ b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_passwd_after_MFA_auth @@ -99,6 +99,8 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-mfa-integration-cli-passwd@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one index 2638ecea9c..303e75dbd3 100644 --- a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one +++ b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one @@ -52,6 +52,8 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-cli-passwd-change-password-successfully-and-authenticate-with-new-one@example.com" Result: success @@ -72,6 +74,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-integration-cli-passwd-change-password-successfully-and-authenticate-with-new-one@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_different_case b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_different_case index 9dae08fd47..adca04257a 100644 --- a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_different_case +++ b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_different_case @@ -52,6 +52,8 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-case-insensitive-testclichangeauthtok@example.com" Result: success @@ -72,6 +74,7 @@ Gimme your password: Press escape key to go back to select the authentication method ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-integration-case-insensitive-testclichangeauthtok@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_does_not_match_quality_criteria b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_does_not_match_quality_criteria index aa9bd20f87..09bc88f9b9 100644 --- a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_does_not_match_quality_criteria +++ b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_does_not_match_quality_criteria @@ -126,6 +126,8 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-cli-passwd-retry-if-new-password-does-not-match-quality-criteria@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_is_rejected_by_broker b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_is_rejected_by_broker index ea03b3d5f6..156775f767 100644 --- a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_is_rejected_by_broker +++ b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_is_rejected_by_broker @@ -85,6 +85,8 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-cli-passwd-retry-if-new-password-is-rejected-by-broker@example.com" Result: success @@ -169,6 +171,8 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "goodpass" + PAM_OLDAUTHTOK: "authd2404" PAM ChangeAuthTok() User: "user-integration-cli-passwd-retry-if-new-password-is-rejected-by-broker@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_is_same_of_previous b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_is_same_of_previous index fe1906bd6b..da8320897e 100644 --- a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_is_same_of_previous +++ b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_new_password_is_same_of_previous @@ -67,6 +67,8 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-cli-passwd-retry-if-new-password-is-same-of-previous@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_password_confirmation_is_not_the_same b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_password_confirmation_is_not_the_same index c26b508b4c..3d6933ff11 100644 --- a/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_password_confirmation_is_not_the_same +++ b/pam/integration-tests/testdata/golden/TestCLIChangeAuthTok/Retry_if_password_confirmation_is_not_the_same @@ -85,6 +85,8 @@ Confirm password: Press escape key to go back to choose the provider ──────────────────────────────────────────────────────────────────────────────── + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-cli-passwd-retry-if-password-confirmation-is-not-the-same@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_accept_password_reset b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_accept_password_reset index e9af1ce633..52205e48de 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_accept_password_reset +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_accept_password_reset @@ -20,6 +20,7 @@ Enter your new password (3 days until mandatory): > Confirm Password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-can-reset-integration-accept-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_add_it_to_local_group b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_add_it_to_local_group index 467155af4b..6a83eb59b0 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_add_it_to_local_group +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_add_it_to_local_group @@ -7,6 +7,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-local-groups-integration-auth-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_offer_password_reset b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_offer_password_reset index 7bdb0e373b..c7d4c40577 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_offer_password_reset +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_offer_password_reset @@ -14,6 +14,7 @@ Password reset, 1 step(s) missing Or enter 'r' to go back to choose the provider Choose action: > 2 + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-can-reset-integration-skip-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_reset_password_while_enforcing_policy b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_reset_password_while_enforcing_policy index 7fbc125505..522580e941 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_reset_password_while_enforcing_policy +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_reset_password_while_enforcing_policy @@ -14,6 +14,7 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-needs-reset-integration-mandatory-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_reset_password_with_case_insensitive_user_selection b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_reset_password_with_case_insensitive_user_selection index 9e1f8ce3b3..9623faa7cd 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_reset_password_with_case_insensitive_user_selection +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_and_reset_password_with_case_insensitive_user_selection @@ -16,6 +16,7 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-needs-reset-integration-case-insensitive-native-testnativeauthenticate@example.com" Result: success @@ -25,6 +26,7 @@ Username: USER-NEEDS-RESET-INTEGRATION-CASE-INSENSITIVE-NATIVE-TESTNATIVEAUTHENT Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-needs-reset-integration-case-insensitive-native-testnativeauthenticate@example.com" Result: success @@ -34,6 +36,7 @@ Username: user-needs-reset-integration-Case-INSENSITIVE-native-testnativeauthent Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-needs-reset-integration-case-insensitive-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service index cfec047d41..8ca837696f 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service @@ -7,6 +7,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-pre-check-ssh-service-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service_with_custom_name_and_auth_info_env b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service_with_custom_name_and_auth_info_env index 73f310afad..ebae0c11f9 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service_with_custom_name_and_auth_info_env +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service_with_custom_name_and_auth_info_env @@ -7,6 +7,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-pre-check-ssh-auth-info-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service_with_custom_name_and_connection_env b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service_with_custom_name_and_connection_env index 7f5db7b541..bebb0a7dfc 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service_with_custom_name_and_connection_env +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_on_ssh_service_with_custom_name_and_connection_env @@ -7,6 +7,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-pre-check-ssh-connection-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully index bd5850d2ce..304eba6242 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully @@ -7,6 +7,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-native-authenticate-user-successfully@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_using_upper_case_with_user_selection b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_using_upper_case_with_user_selection index 22503cc904..d6212fb5b5 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_using_upper_case_with_user_selection +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_using_upper_case_with_user_selection @@ -9,6 +9,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-selection-upper-case-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_invalid_connection_timeout b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_invalid_connection_timeout index 39aee02516..d82da599c5 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_invalid_connection_timeout +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_invalid_connection_timeout @@ -7,6 +7,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-native-authenticate-user-successfully-with-invalid-connection-timeout@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_password_only_supported_method b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_password_only_supported_method index 643e4da66b..bfa00b5e9b 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_password_only_supported_method +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_password_only_supported_method @@ -7,6 +7,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to choose the provider Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-auth-modes-password-integration-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_password_only_supported_method_in_polkit b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_password_only_supported_method_in_polkit index b9f46ceb97..39e924fffc 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_password_only_supported_method_in_polkit +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_password_only_supported_method_in_polkit @@ -1,6 +1,7 @@ == Password authentication == Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-auth-modes-password-integration-polkit-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_upper_case b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_upper_case index 7fe15fd1a8..72b47bffdf 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_upper_case +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_upper_case @@ -7,6 +7,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-upper-case-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_user_selection b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_user_selection index fc9de3aa1f..ac709d37ac 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_user_selection +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_successfully_with_user_selection @@ -9,6 +9,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-user-selection-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_switching_auth_mode b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_switching_auth_mode index ea4b7e8cc0..cdde95ba6d 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_switching_auth_mode +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_switching_auth_mode @@ -177,6 +177,7 @@ Choose your authentication method: Enter 'r' to cancel the request and go back to select the authentication method Enter your pin code: > 4242 + PAM_AUTHTOK: "4242" PAM Authenticate() User: "user-integration-switch-mode-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_switching_username b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_switching_username index 463ad5583b..de502e1c14 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_switching_username +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_switching_username @@ -16,6 +16,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-native-username-switched-authenticate-user-switching-username@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button index c7bf941026..04206da176 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button @@ -35,6 +35,7 @@ Choose action: Enter 'r' to cancel the request and go back to select the authentication method Enter your one time credential: > temporary pass00 + PAM_AUTHTOK: "temporary pass00" PAM Authenticate() User: "user-integration-native-authenticate-user-with-form-mode-with-button@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button_in_polkit b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button_in_polkit index 8efc9f9c2b..1a14999263 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button_in_polkit +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button_in_polkit @@ -28,6 +28,7 @@ Choose action: Enter 'r' to cancel the request and go back to select the authentication method Enter your one time credential: > temporary pass00 + PAM_AUTHTOK: "temporary pass00" PAM Authenticate() User: "user-integration-native-authenticate-user-with-form-mode-with-button-in-polkit@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button_two_supported_methods b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button_two_supported_methods index f8b0855010..7a14863723 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button_two_supported_methods +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_form_mode_with_button_two_supported_methods @@ -29,6 +29,7 @@ Choose action: Enter 'r' to cancel the request and go back to select the authentication method Enter your one time credential: > temporary pass00 + PAM_AUTHTOK: "temporary pass00" PAM Authenticate() User: "user-auth-modes-totp_with_button,password-integration-native@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa index 9ccc44170b..88fa1340c1 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa @@ -53,6 +53,7 @@ Unlock your phone +33... or accept request on web interface: Press Enter to wait for authentication or enter 'r' to go back to select the authentication method Plug your fido device and press with your thumb: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-mfa-integration-auth-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa_and_reset_password_while_enforcing_policy b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa_and_reset_password_while_enforcing_policy index d68b1689ca..1ad4b1d7b1 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa_and_reset_password_while_enforcing_policy +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa_and_reset_password_while_enforcing_policy @@ -35,6 +35,7 @@ Enter your new password (3 days until mandatory): > Confirm Password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-mfa-with-reset-integration-pwquality-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa_and_reset_same_password b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa_and_reset_same_password index 9c3a3c38c3..524a67ddb2 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa_and_reset_same_password +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_user_with_mfa_and_reset_same_password @@ -25,6 +25,7 @@ Enter your new password (3 days until mandatory): > Confirm Password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-mfa-with-reset-integration-same-password-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_with_warnings_on_unsupported_arguments b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_with_warnings_on_unsupported_arguments index 04637db022..705ae53645 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_with_warnings_on_unsupported_arguments +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Authenticate_with_warnings_on_unsupported_arguments @@ -7,6 +7,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-native-authenticate-with-warnings-on-unsupported-arguments@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Deny_authentication_if_newpassword_does_not_match_required_criteria b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Deny_authentication_if_newpassword_does_not_match_required_criteria index 4a66ffdc1b..e5b9cf0e0c 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Deny_authentication_if_newpassword_does_not_match_required_criteria +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Deny_authentication_if_newpassword_does_not_match_required_criteria @@ -36,6 +36,7 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-needs-reset-integration-bad-password-native-testnativeauthenticate@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Prevent_preset_user_from_switching_username b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Prevent_preset_user_from_switching_username index b4f52fcf48..b1089301bc 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Prevent_preset_user_from_switching_username +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Prevent_preset_user_from_switching_username @@ -37,6 +37,7 @@ Choose your provider: Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "goodpass" PAM Authenticate() User: "user-integration-native-prevent-preset-user-from-switching-username@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Remember_last_successful_broker_and_mode b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Remember_last_successful_broker_and_mode index 8f80ce59f6..5ac13b6f9d 100644 --- a/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Remember_last_successful_broker_and_mode +++ b/pam/integration-tests/testdata/golden/TestNativeAuthenticate/Remember_last_successful_broker_and_mode @@ -29,6 +29,7 @@ Choose action: Enter 'r' to cancel the request and go back to select the authentication method Enter your one time credential: > temporary pass0 + PAM_AUTHTOK: "temporary pass0" PAM Authenticate() User: "user-integration-native-remember-last-successful-broker-and-mode@example.com" Result: success @@ -43,6 +44,7 @@ Choose action: Enter 'r' to cancel the request and go back to select the authentication method Enter your one time credential: > temporary pass0 + PAM_AUTHTOK: "temporary pass0" PAM Authenticate() User: "user-integration-native-remember-last-successful-broker-and-mode@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_passwd_after_MFA_auth b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_passwd_after_MFA_auth index d151f5e767..093870bc16 100644 --- a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_passwd_after_MFA_auth +++ b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_passwd_after_MFA_auth @@ -60,6 +60,8 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-mfa-integration-native-passwd-testnativechangeauthtok@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one index fedf0a9fc3..9054bf2802 100644 --- a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one +++ b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one @@ -15,6 +15,8 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-simple-testnativechangeauthtok@example.com" Result: success @@ -24,6 +26,7 @@ Username: user-integration-simple-testnativechangeauthtok@example.com Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-integration-simple-testnativechangeauthtok@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_different_case b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_different_case index 7974c0c245..bfedca8e6b 100644 --- a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_different_case +++ b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_different_case @@ -15,6 +15,8 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-case-insensitive-testnativechangeauthtok@example.com" Result: success @@ -24,6 +26,7 @@ Username: user-integration-case-insensitive-testnativechangeauthtok@example.com Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-integration-case-insensitive-testnativechangeauthtok@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_single_broker_and_password_only_supported_method b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_single_broker_and_password_only_supported_method index f20234f494..125fbaf680 100644 --- a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_single_broker_and_password_only_supported_method +++ b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Change_password_successfully_and_authenticate_with_new_one_with_single_broker_and_password_only_supported_method @@ -6,6 +6,8 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-auth-modes-password,mandatoryreset-integration-polkit-testnativechangeauthtok@example.com" Result: success @@ -14,6 +16,7 @@ PAM ChangeAuthTok() Enter 'r' to cancel the request and go back to select the authentication method Gimme your password: > + PAM_AUTHTOK: "authd2404" PAM Authenticate() User: "user-auth-modes-password,mandatoryreset-integration-polkit-testnativechangeauthtok@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_does_not_match_quality_criteria b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_does_not_match_quality_criteria index 73fd925105..c947bfdba1 100644 --- a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_does_not_match_quality_criteria +++ b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_does_not_match_quality_criteria @@ -42,6 +42,8 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-native-passwd-retry-if-new-password-does-not-match-quality-criteria@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_is_rejected_by_broker b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_is_rejected_by_broker index 91dfee1622..ae69fc2333 100644 --- a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_is_rejected_by_broker +++ b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_is_rejected_by_broker @@ -22,6 +22,8 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-native-passwd-retry-if-new-password-is-rejected-by-broker@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_is_same_of_previous b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_is_same_of_previous index f643fbd924..66e4543900 100644 --- a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_is_same_of_previous +++ b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_new_password_is_same_of_previous @@ -20,6 +20,8 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-native-passwd-retry-if-new-password-is-same-of-previous@example.com" Result: success diff --git a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_password_confirmation_is_not_the_same b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_password_confirmation_is_not_the_same index 30fccea2e8..bf220761e3 100644 --- a/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_password_confirmation_is_not_the_same +++ b/pam/integration-tests/testdata/golden/TestNativeChangeAuthTok/Retry_if_password_confirmation_is_not_the_same @@ -22,6 +22,8 @@ Enter your new password: > Confirm Password: > + PAM_AUTHTOK: "authd2404" + PAM_OLDAUTHTOK: "goodpass" PAM ChangeAuthTok() User: "user-integration-native-passwd-retry-if-password-confirmation-is-not-the-same@example.com" Result: success diff --git a/pam/internal/adapter/authentication.go b/pam/internal/adapter/authentication.go index 8caa6ac35b..2e2580525d 100644 --- a/pam/internal/adapter/authentication.go +++ b/pam/internal/adapter/authentication.go @@ -240,6 +240,8 @@ func (m authenticationModel) Update(msg tea.Msg) (authModel authenticationModel, // If the session is for authentication, we allow the user to set the same password again, to avoid // that the user is forced to change their password if e.g. device code flow is forced when // the refresh token is expired. + // TODO: This will not select the correct secret in case the last authentication step uses a secret + // which is not the local password (e.g. OTP). oldPassword = m.currentSecret } @@ -361,7 +363,35 @@ func (m authenticationModel) Update(msg tea.Msg) (authModel authenticationModel, switch msg.access { case auth.Granted: - return m, sendEvent(PamSuccess{BrokerID: m.currentBrokerID, msg: authMsg}) + var secret string + // TODO: This will not select the correct secret in case the last authentication step uses a secret + // which is not the local password (e.g. OTP). + if msg.secret != nil { + secret = *msg.secret + } else if m.currentSecret != "" { + secret = m.currentSecret + } else { + log.Warningf(context.Background(), "authentication granted, but no secret is available, cannot set PAM_AUTHTOK") + } + + // During a password change the user authenticates with their old local + // password before setting the new one, so the previous step's secret is + // the old password. Pass it along as PAM_OLDAUTHTOK so pam_gnome_keyring + // can re-key the existing keyring instead of leaving it locked under the + // old password. We only do this when the old and new secrets differ and + // the new one came from this step (msg.secret), to avoid setting a + // spurious PAM_OLDAUTHTOK during plain authentication. + var oldSecret string + if m.mode == authd.SessionMode_CHANGE_PASSWORD && msg.secret != nil && + m.currentSecret != "" && m.currentSecret != secret { + oldSecret = m.currentSecret + } + return m, sendEvent(PamSuccess{ + BrokerID: m.currentBrokerID, + AuthTok: secret, + OldAuthTok: oldSecret, + msg: authMsg, + }) case auth.Retry: m.errorMsg = authMsg diff --git a/pam/internal/adapter/gdmmodel.go b/pam/internal/adapter/gdmmodel.go index 9b8d8e8708..d9cbcefce1 100644 --- a/pam/internal/adapter/gdmmodel.go +++ b/pam/internal/adapter/gdmmodel.go @@ -25,7 +25,7 @@ type gdmModel struct { waitingAuth bool // Given the bubbletea async nature we may end up receiving and forwarding - // events after we've got a PamReturnStatus and even after the PAM module + // events after we've got a PamReturnValue and even after the PAM module // has returned to libpam caller (since go goroutines can still be alive). // However, after the quit point we should really not interact anymore with // GDM or we'll make it crash (as it doesn't expect any conversation diff --git a/pam/internal/adapter/gdmmodel_test.go b/pam/internal/adapter/gdmmodel_test.go index b91f65ad56..b4167f358d 100644 --- a/pam/internal/adapter/gdmmodel_test.go +++ b/pam/internal/adapter/gdmmodel_test.go @@ -48,7 +48,7 @@ func TestGdmModel(t *testing.T) { // However we do return a PAM error in such case because that's what we're // going to return to the PAM stack in case authentication process has not // been completed fully. - gdmTestEarlyStopExitStatus := errNoExitStatus + gdmTestEarlyStopReturnValue := pamNoReturnValue gdmTestIgnoreStage := proto.Stage(-1) @@ -101,7 +101,7 @@ func TestGdmModel(t *testing.T) { convError map[string]error timeout time.Duration - wantExitStatus PamReturnStatus + wantPAMReturnValue PamReturnValue wantGdmRequests []gdm.RequestType wantGdmEvents []gdm.EventType wantGdmAuthRes []*authd.IAResponse @@ -129,7 +129,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Broker_selection_stage_caused_by_PAM_user_selection": { pamUser: "pam-preset-user", @@ -148,8 +148,8 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantStage: proto.Stage_brokerSelection, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_brokerSelection, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Broker_selection_stage_caused_by_client_side_user_selection": { gdmEvents: []*gdm.EventData{ @@ -171,8 +171,8 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantStage: proto.Stage_brokerSelection, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_brokerSelection, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Challenge_stage_caused_by_server_side_broker_and_authMode_selection": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -199,8 +199,8 @@ func TestGdmModel(t *testing.T) { wantNoGdmEvents: []gdm.EventType{ gdm.EventType_authEvent, }, - wantStage: proto.Stage_challenge, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_challenge, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Challenge_stage_caused_by_client_side_broker_and_authMode_selection": { gdmEvents: []*gdm.EventData{ @@ -235,8 +235,8 @@ func TestGdmModel(t *testing.T) { wantNoGdmEvents: []gdm.EventType{ gdm.EventType_authEvent, }, - wantStage: proto.Stage_challenge, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_challenge, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Authenticated_with_preset_PAM_user_and_server_side_broker_and_authMode_selection": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -269,9 +269,9 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Granted}}, - wantStage: proto.Stage_challenge, - wantExitStatus: PamSuccess{BrokerID: firstBrokerInfo.Id}, + wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Granted}}, + wantStage: proto.Stage_challenge, + wantPAMReturnValue: PamSuccess{BrokerID: firstBrokerInfo.Id, AuthTok: "gdm-good-password"}, }, "Authenticated_with_preset_PAM_user_using_legacy_challenge_and_server_side_broker_and_authMode_selection": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -304,9 +304,9 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Granted}}, - wantStage: proto.Stage_challenge, - wantExitStatus: PamSuccess{BrokerID: firstBrokerInfo.Id}, + wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Granted}}, + wantStage: proto.Stage_challenge, + wantPAMReturnValue: PamSuccess{BrokerID: firstBrokerInfo.Id, AuthTok: "gdm-good-password"}, }, "Authenticated_with_preset_PAM_user_updated_and_server_side_broker_and_authMode_selection": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -360,9 +360,9 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Granted}}, - wantStage: proto.Stage_challenge, - wantExitStatus: PamSuccess{BrokerID: firstBrokerInfo.Id}, + wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Granted}}, + wantStage: proto.Stage_challenge, + wantPAMReturnValue: PamSuccess{BrokerID: firstBrokerInfo.Id, AuthTok: "gdm-good-password"}, }, "Authenticated_with_message_with_preset_PAM_user_and_server_side_broker_and_authMode_selection": { clientOptions: append(slices.Clone(multiBrokerClientOptions), @@ -404,8 +404,9 @@ func TestGdmModel(t *testing.T) { Access: auth.Granted, Msg: "Hi GDM, it's a pleasure to get you in!", }}, - wantExitStatus: PamSuccess{ + wantPAMReturnValue: PamSuccess{ BrokerID: firstBrokerInfo.Id, + AuthTok: "gdm-good-password", msg: "Hi GDM, it's a pleasure to get you in!", }, }, @@ -451,8 +452,9 @@ func TestGdmModel(t *testing.T) { Access: auth.Granted, Msg: "", }}, - wantExitStatus: PamSuccess{ + wantPAMReturnValue: PamSuccess{ BrokerID: firstBrokerInfo.Id, + AuthTok: "gdm-good-password", }, }, "New_password_changed_after_server_side_broker_and_authMode_selection": { @@ -494,8 +496,9 @@ func TestGdmModel(t *testing.T) { wantGdmAuthRes: []*authd.IAResponse{{ Access: auth.Granted, }}, - wantExitStatus: PamSuccess{ + wantPAMReturnValue: PamSuccess{ BrokerID: firstBrokerInfo.Id, + AuthTok: "gdm-good-password", }, }, "New_password_changed_with_message_with_preset_PAM_user_and_server_side_broker_and_authMode_selection": { @@ -539,8 +542,9 @@ func TestGdmModel(t *testing.T) { Access: auth.Granted, Msg: "Hi GDM, it's a pleasure to change your password!", }}, - wantExitStatus: PamSuccess{ + wantPAMReturnValue: PamSuccess{ BrokerID: firstBrokerInfo.Id, + AuthTok: "gdm-good-password", msg: "Hi GDM, it's a pleasure to change your password!", }, }, @@ -605,8 +609,9 @@ func TestGdmModel(t *testing.T) { Msg: "Hi GDM, it's a pleasure to change your password!", }, }, - wantExitStatus: PamSuccess{ + wantPAMReturnValue: PamSuccess{ BrokerID: firstBrokerInfo.Id, + AuthTok: "gdm-good-password", msg: "Hi GDM, it's a pleasure to change your password!", }, }, @@ -716,7 +721,7 @@ func TestGdmModel(t *testing.T) { Msg: "The password is the same as the old one", }, }, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Authentication_is_ignored_if_not_requested_by_model_first": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -743,8 +748,8 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantStage: proto.Stage_userSelection, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_userSelection, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Cancelled_with_preset_PAM_user_and_server_side_broker_and_authMode_selection": { clientOptions: append(slices.Clone(multiBrokerClientOptions), @@ -775,9 +780,9 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantStage: proto.Stage_challenge, - wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Cancelled}}, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_challenge, + wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Cancelled}}, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Explicitly_cancelled_with_preset_PAM_user_and_server_side_broker_and_authMode_selection": { clientOptions: append(slices.Clone(multiBrokerClientOptions), @@ -807,8 +812,8 @@ func TestGdmModel(t *testing.T) { gdm.EventType_uiLayoutReceived, gdm.EventType_startAuthentication, }, - wantStage: proto.Stage_challenge, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_challenge, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Explicitly_cancelled_for_a_waiting_auth_mode_with_preset_PAM_user_and_server_side_broker_and_authMode_selection": { clientOptions: append(slices.Clone(multiBrokerClientOptions), @@ -847,9 +852,9 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Cancelled}}, - wantStage: proto.Stage_challenge, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Cancelled}}, + wantStage: proto.Stage_challenge, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Implicitly_cancelled_for_a_waiting_auth_mode_with_preset_PAM_user_and_server_side_broker_and_authMode_selection": { clientOptions: append(slices.Clone(multiBrokerClientOptions), @@ -892,9 +897,9 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Cancelled}}, - wantStage: proto.Stage_brokerSelection, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Cancelled}}, + wantStage: proto.Stage_brokerSelection, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Authenticated_with_preset_PAM_user_and_server_side_broker_and_authMode_selection_and_after_various_retries": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -948,8 +953,8 @@ func TestGdmModel(t *testing.T) { {Access: auth.Retry}, {Access: auth.Granted}, }, - wantStage: proto.Stage_challenge, - wantExitStatus: PamSuccess{BrokerID: firstBrokerInfo.Id}, + wantStage: proto.Stage_challenge, + wantPAMReturnValue: PamSuccess{BrokerID: firstBrokerInfo.Id, AuthTok: "gdm-good-password"}, }, "Authenticated_after_client_side_user_and_broker_and_authMode_selection": { clientOptions: append(slices.Clone(multiBrokerClientOptions), @@ -988,9 +993,9 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantStage: proto.Stage_challenge, - wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Granted}}, - wantExitStatus: PamSuccess{BrokerID: secondBrokerInfo.Id}, + wantStage: proto.Stage_challenge, + wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Granted}}, + wantPAMReturnValue: PamSuccess{BrokerID: secondBrokerInfo.Id, AuthTok: "gdm-good-password"}, }, "Authenticated_after_client_side_user_and_broker_and_authMode_selection_and_after_various_retries": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -1052,8 +1057,8 @@ func TestGdmModel(t *testing.T) { {Access: auth.Retry}, {Access: auth.Granted}, }, - wantStage: proto.Stage_challenge, - wantExitStatus: PamSuccess{BrokerID: firstBrokerInfo.Id}, + wantStage: proto.Stage_challenge, + wantPAMReturnValue: PamSuccess{BrokerID: firstBrokerInfo.Id, AuthTok: "gdm-good-password"}, }, "Cancelled_auth_after_client_side_user_and_broker_and_authMode_selection": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -1095,9 +1100,9 @@ func TestGdmModel(t *testing.T) { wantMessages: []tea.Msg{ startAuthentication{}, }, - wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Cancelled}}, - wantStage: proto.Stage_challenge, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Cancelled}}, + wantStage: proto.Stage_challenge, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "AuthMode_selection_stage_from_client_after_server_side_broker_and_auth_mode_selection_if_there_is_only_one_auth_mode": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -1135,8 +1140,8 @@ func TestGdmModel(t *testing.T) { wantNoGdmEvents: []gdm.EventType{ gdm.EventType_authEvent, }, - wantStage: proto.Stage_authModeSelection, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_authModeSelection, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "AuthMode_selection_stage_from_client_after_server_side_broker_and_auth_mode_selection_with_multiple_auth_modes": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -1175,8 +1180,8 @@ func TestGdmModel(t *testing.T) { wantNoGdmEvents: []gdm.EventType{ gdm.EventType_authEvent, }, - wantStage: proto.Stage_authModeSelection, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_authModeSelection, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "AuthMode_selection_stage_from_client_after_client_side_broker_and_auth_mode_selection_if_there_is_only_one_auth_mode": { gdmEvents: []*gdm.EventData{ @@ -1221,8 +1226,8 @@ func TestGdmModel(t *testing.T) { gdm.EventType_startAuthentication, gdm.EventType_authEvent, }, - wantStage: proto.Stage_authModeSelection, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_authModeSelection, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "Authenticated_after_auth_selection_stage_from_client_after_client_side_broker_and_auth_mode_selection_if_there_is_only_one_auth_mode": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -1288,7 +1293,7 @@ func TestGdmModel(t *testing.T) { wantGdmAuthRes: []*authd.IAResponse{ {Access: auth.Granted}, }, - wantExitStatus: PamSuccess{BrokerID: firstBrokerInfo.Id}, + wantPAMReturnValue: PamSuccess{BrokerID: firstBrokerInfo.Id, AuthTok: "gdm-good-password"}, }, "Authenticated_after_auth_selection_stage_from_client_after_client_side_broker_and_auth_mode_selection_with_multiple_auth_modes": { clientOptions: append(slices.Clone(singleBrokerClientOptions), @@ -1355,7 +1360,7 @@ func TestGdmModel(t *testing.T) { wantGdmAuthRes: []*authd.IAResponse{ {Access: auth.Granted}, }, - wantExitStatus: PamSuccess{BrokerID: firstBrokerInfo.Id}, + wantPAMReturnValue: PamSuccess{BrokerID: firstBrokerInfo.Id, AuthTok: "1234"}, }, "Authenticated_with_qrcode_after_auth_selection_stage_from_client_after_client_side_broker_and_auth_mode_selection": { supportedLayouts: []*authd.UILayout{ @@ -1426,7 +1431,7 @@ func TestGdmModel(t *testing.T) { wantGdmAuthRes: []*authd.IAResponse{ {Access: auth.Granted}, }, - wantExitStatus: PamSuccess{BrokerID: firstBrokerInfo.Id}, + wantPAMReturnValue: PamSuccess{BrokerID: firstBrokerInfo.Id}, }, "Authenticated_with_qrcode_regenerated_after_auth_selection_stage_from_client_after_client_side_broker_and_auth_mode_selection": { timeout: 30 * time.Second, @@ -1513,7 +1518,7 @@ func TestGdmModel(t *testing.T) { {Access: auth.Cancelled}, {Access: auth.Granted}, }, - wantExitStatus: PamSuccess{BrokerID: firstBrokerInfo.Id}, + wantPAMReturnValue: PamSuccess{BrokerID: firstBrokerInfo.Id}, }, "Authenticated_with_qrcode_regenerated_after_wait_started_at_auth_selection_stage_from_client_after_client_side_broker_and_auth_mode_selection": { supportedLayouts: []*authd.UILayout{ @@ -1602,7 +1607,7 @@ func TestGdmModel(t *testing.T) { {Access: auth.Cancelled}, {Access: auth.Granted}, }, - wantExitStatus: PamSuccess{BrokerID: firstBrokerInfo.Id}, + wantPAMReturnValue: PamSuccess{BrokerID: firstBrokerInfo.Id}, }, "Broker_selection_stage_from_client_after_client_side_broker_and_auth_mode_selection_if_there_is_only_one_auth_mode": { gdmEvents: []*gdm.EventData{ @@ -1655,8 +1660,8 @@ func TestGdmModel(t *testing.T) { wantNoGdmEvents: []gdm.EventType{ gdm.EventType_authEvent, }, - wantStage: proto.Stage_brokerSelection, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_brokerSelection, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, "User_selection_stage_from_client_after_client_side_broker_and_auth_mode_selection_if_there_is_only_one_auth_mode": { gdmEvents: []*gdm.EventData{ @@ -1718,8 +1723,8 @@ func TestGdmModel(t *testing.T) { wantNoGdmEvents: []gdm.EventType{ gdm.EventType_authEvent, }, - wantStage: proto.Stage_userSelection, - wantExitStatus: gdmTestEarlyStopExitStatus, + wantStage: proto.Stage_userSelection, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, }, // Error cases @@ -1733,7 +1738,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_brokersReceived, gdm.EventType_userSelected, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrCredUnavail, msg: "UI does not support any layouts", }, @@ -1749,15 +1754,15 @@ func TestGdmModel(t *testing.T) { gdm.EventType_brokersReceived, gdm.EventType_userSelected, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrAuthinfoUnavail, msg: "could not get current available brokers: brokers loading failed", }, wantNoBrokers: true, }, "Error_on_forced_quit": { - messages: []tea.Msg{tea.Quit()}, - wantExitStatus: gdmTestEarlyStopExitStatus, + messages: []tea.Msg{tea.Quit()}, + wantPAMReturnValue: gdmTestEarlyStopReturnValue, wantNoGdmEvents: []gdm.EventType{ gdm.EventType_userSelected, }, @@ -1777,7 +1782,7 @@ func TestGdmModel(t *testing.T) { wantNoGdmEvents: []gdm.EventType{ gdm.EventType_userSelected, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "Sending GDM poll failed: Conversation error: poll response data member 0 invalid: missing event data", }, @@ -1793,7 +1798,7 @@ func TestGdmModel(t *testing.T) { wantNoGdmEvents: []gdm.EventType{ gdm.EventType_userSelected, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "Sending GDM poll failed: Conversation error: poll response data member 0 invalid: missing event type", }, @@ -1809,7 +1814,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_brokersReceived, gdm.EventType_userSelected, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrAuthinfoUnavail, msg: "No brokers available", }, @@ -1828,7 +1833,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_userSelected, gdm.EventType_brokersReceived, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "error during broker selection", }, @@ -1849,7 +1854,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_brokersReceived, gdm.EventType_brokerSelected, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "no session ID returned by broker", }, @@ -1869,7 +1874,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_brokersReceived, gdm.EventType_brokerSelected, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "no encryption key returned by broker", }, @@ -1891,7 +1896,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_userSelected, gdm.EventType_brokersReceived, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "encryption key sent by broker is not a valid base64 encoded string: illegal base64 data at input byte 2", }, @@ -1914,7 +1919,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_userSelected, gdm.EventType_brokersReceived, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: gdmTestIgnoredMessage, }, @@ -1945,7 +1950,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_brokerSelected, }, wantStage: gdmTestIgnoreStage, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "invalid empty UI Layout information from broker", }, @@ -1976,7 +1981,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_brokerSelected, }, wantStage: gdmTestIgnoreStage, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrCredUnavail, msg: "no supported authentication mode available for this provider", }, @@ -2006,7 +2011,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_brokersReceived, }, wantStage: gdmTestIgnoreStage, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "can't select authentication mode: error selecting auth mode", }, @@ -2043,7 +2048,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_uiLayoutReceived, }, wantStage: gdmTestIgnoreStage, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: `Sending GDM event failed: Conversation error: unknown layout type: "invalid layout"`, }, @@ -2080,7 +2085,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_uiLayoutReceived, }, wantStage: proto.Stage_challenge, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "some authentication error", }, @@ -2115,7 +2120,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_uiLayoutReceived, }, wantStage: gdmTestIgnoreStage, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "invalid json data from provider: invalid character 'i' looking for beginning of value", }, @@ -2163,7 +2168,7 @@ func TestGdmModel(t *testing.T) { Access: auth.Denied, Msg: "you're not allowed!", }}, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrAuth, msg: "you're not allowed!", }, @@ -2207,7 +2212,7 @@ func TestGdmModel(t *testing.T) { }, wantStage: gdmTestIgnoreStage, wantGdmAuthRes: []*authd.IAResponse{{Access: auth.Denied}}, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrAuth, msg: "Access denied", }, @@ -2260,7 +2265,7 @@ func TestGdmModel(t *testing.T) { {Access: auth.Retry}, {Access: auth.Denied}, }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrAuth, msg: "Access denied", }, @@ -2302,7 +2307,7 @@ func TestGdmModel(t *testing.T) { Access: auth.Denied, Msg: `Access "" is not valid`, }}, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: `Unknown authentication access: ""`, }, @@ -2347,7 +2352,7 @@ func TestGdmModel(t *testing.T) { Access: auth.Denied, Msg: `Access "no way you get here!" is not valid`, }}, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: `Unknown authentication access: "no way you get here!"`, }, @@ -2374,7 +2379,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_authEvent, }, wantStage: gdmTestIgnoreStage, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: `unknown PAM stage: "-1"`, }, @@ -2385,14 +2390,14 @@ func TestGdmModel(t *testing.T) { Type: gdm.DataType_hello, }): errors.New("this is an hello error"), }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrCredUnavail, msg: "GDM initialization failed: Conversation error: this is an hello error", }, }, "Error_during_hello_on_protocol_mismatch": { protoVersion: 99999999, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrCredUnavail, msg: "GDM protocol initialization failed, type hello, version 99999999", }, @@ -2401,7 +2406,7 @@ func TestGdmModel(t *testing.T) { convError: map[string]error{ gdm_test.DataToJSON(t, &gdm.Data{Type: gdm.DataType_poll}): errors.New("this is a poll error"), }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "Sending GDM poll failed: Conversation error: this is a poll error", }, @@ -2423,7 +2428,7 @@ func TestGdmModel(t *testing.T) { gdmEvents: []*gdm.EventData{ gdm_test.ChangeStageEvent(proto.Stage_brokerSelection), }, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "Changing GDM stage failed: Conversation error: this is a stage change error", }, @@ -2439,7 +2444,7 @@ func TestGdmModel(t *testing.T) { }): errors.New("this is an UI capabilities request error"), }, wantNoBrokers: true, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrSystem, msg: "Sending GDM UI capabilities Request failed: Conversation error: this is an UI capabilities request error", }, @@ -2483,7 +2488,7 @@ func TestGdmModel(t *testing.T) { gdm.EventType_authEvent, }, wantStage: proto.Stage_userSelection, - wantExitStatus: pamError{ + wantPAMReturnValue: pamError{ status: pam.ErrPermDenied, msg: `Changing username "gdm-pam-preset-user" to "another-selected-user" is not allowed`, }, @@ -2506,8 +2511,8 @@ func TestGdmModel(t *testing.T) { messagesToSend := tc.messages messagesToWait := append(tc.messages, tc.wantMessages...) - if tc.wantExitStatus != gdmTestEarlyStopExitStatus { - messagesToWait = append(messagesToWait, tc.wantExitStatus) + if tc.wantPAMReturnValue != gdmTestEarlyStopReturnValue { + messagesToWait = append(messagesToWait, tc.wantPAMReturnValue) } gdmMutex := sync.Mutex{} @@ -2527,9 +2532,9 @@ func TestGdmModel(t *testing.T) { wantRequests: tc.wantGdmRequests, } - var exitStatus PamReturnStatus + var pamReturnValue PamReturnValue uiModel := newUIModelForClients(pam_test.NewModuleTransactionDummy(gdmHandler), - Gdm, tc.sessionMode, tc.client, nil, &exitStatus) + Gdm, tc.sessionMode, tc.client, nil, &pamReturnValue) appState := gdmTestUIModel{ uiModel: uiModel, @@ -2673,20 +2678,20 @@ func TestGdmModel(t *testing.T) { appState.mu.Lock() defer appState.mu.Unlock() - if tc.wantExitStatus.Message() == gdmTestIgnoredMessage { - switch wantRet := tc.wantExitStatus.(type) { + if tc.wantPAMReturnValue.Message() == gdmTestIgnoredMessage { + switch wantRet := tc.wantPAMReturnValue.(type) { case PamReturnError: - exitErr, ok := exitStatus.(PamReturnError) - require.True(t, ok, "exit status should be an error") - require.Equal(t, wantRet.Status(), exitErr.Status()) + pamErr, ok := pamReturnValue.(PamReturnError) + require.True(t, ok, "Expected PAM return value to be an error") + require.Equal(t, wantRet.Status(), pamErr.Status()) case PamSuccess: - _, ok := exitStatus.(PamSuccess) - require.True(t, ok, "exit status should be a success") + _, ok := pamReturnValue.(PamSuccess) + require.True(t, ok, "Expected PAM return value to be a success") default: - t.Fatalf("Unexpected exit status: %v", wantRet) + t.Fatalf("Unexpected type for wantPAMReturnValue: %T", tc.wantPAMReturnValue) } } else { - require.Equal(t, tc.wantExitStatus, exitStatus) + require.Equal(t, tc.wantPAMReturnValue, pamReturnValue) } require.True(t, appState.gdmModel.conversationsStopped, @@ -2728,14 +2733,14 @@ func TestGdmModel(t *testing.T) { gdm_test.RequireEqualData(t, tc.wantGdmAuthRes, gdmHandler.authEvents) - if r, ok := tc.wantExitStatus.(PamReturnError); ok { - // If the model exited with error and that matches, we don't - // care much comparing all the expectations, since the final exit status + if r, ok := tc.wantPAMReturnValue.(PamReturnError); ok { + // If the model returned an error and that matches, we don't + // care much comparing all the expectations, since the final return value // is matching what we expect. switch r.Status() { case pam.ErrIgnore, pam.ErrAuth: default: - if r != gdmTestEarlyStopExitStatus { + if r != gdmTestEarlyStopReturnValue { return } if slices.Contains(tc.messages, tea.Quit()) { diff --git a/pam/internal/adapter/model.go b/pam/internal/adapter/model.go index 26a054b33f..d2c897b9cd 100644 --- a/pam/internal/adapter/model.go +++ b/pam/internal/adapter/model.go @@ -78,9 +78,9 @@ type uiModel struct { gdmModel gdmModel nativeModel nativeModel - // exitStatus is a pointer to the [PamReturnStatus] value where the - // exit status will be written to. - exitStatus *PamReturnStatus + // pamReturnValue is a pointer to the [PamReturnValue] where the + // return value will be written to. + pamReturnValue *PamReturnValue } /* global events */ @@ -128,29 +128,29 @@ type ChangeStage struct { type StageChanged ChangeStage // NewUIModel creates and initializes the main model orchestrator. -func NewUIModel(mTx pam.ModuleTransaction, clientType PamClientType, mode authd.SessionMode, conn *grpc.ClientConn, exitStatus *PamReturnStatus) tea.Model { +func NewUIModel(mTx pam.ModuleTransaction, clientType PamClientType, mode authd.SessionMode, conn *grpc.ClientConn, pamReturnValue *PamReturnValue) tea.Model { var userServiceClient authd.UserServiceClient if conn != nil && isSSHSession(mTx) { userServiceClient = authd.NewUserServiceClient(conn) } - m := newUIModelForClients(mTx, clientType, mode, authd.NewPAMClient(conn), userServiceClient, exitStatus) + m := newUIModelForClients(mTx, clientType, mode, authd.NewPAMClient(conn), userServiceClient, pamReturnValue) m.conn = conn return m } // newUIModelForClients is the internal implementation of [NewUIModel] for testing purposes. -func newUIModelForClients(mTx pam.ModuleTransaction, clientType PamClientType, mode authd.SessionMode, pamClient authd.PAMClient, userServiceClient authd.UserServiceClient, exitStatus *PamReturnStatus) uiModel { +func newUIModelForClients(mTx pam.ModuleTransaction, clientType PamClientType, mode authd.SessionMode, pamClient authd.PAMClient, userServiceClient authd.UserServiceClient, pamReturnValue *PamReturnValue) uiModel { m := uiModel{ - pamMTx: mTx, - clientType: clientType, - sessionMode: mode, - exitStatus: exitStatus, - client: pamClient, + pamMTx: mTx, + clientType: clientType, + sessionMode: mode, + pamReturnValue: pamReturnValue, + client: pamClient, } - if m.exitStatus != nil { - *m.exitStatus = errNoExitStatus + if m.pamReturnValue != nil { + *m.pamReturnValue = pamNoReturnValue } switch m.clientType { @@ -261,16 +261,16 @@ func (m uiModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { return m, m.startHealthCheck() // Exit cases - case PamReturnStatus: + case PamReturnValue: safeMessageDebug(msg) - if m.exitStatus == nil { + if m.pamReturnValue == nil { return m, m.quit() } - if *m.exitStatus != errNoExitStatus { + if *m.pamReturnValue != pamNoReturnValue { // Nothing to do, we're already exiting... return m, nil } - *m.exitStatus = msg + *m.pamReturnValue = msg return m, m.quit() // Events @@ -560,7 +560,7 @@ func MsgFilter(model tea.Model, msg tea.Msg) tea.Msg { return msg } -var errNoExitStatus = pamError{status: pam.ErrSystem, msg: "model did not return anything"} +var pamNoReturnValue = pamError{status: pam.ErrSystem, msg: "model did not return anything"} // username returns currently selected user name. func (m uiModel) username() string { diff --git a/pam/internal/adapter/return.go b/pam/internal/adapter/return.go index 824f574885..eb1f1a49cd 100644 --- a/pam/internal/adapter/return.go +++ b/pam/internal/adapter/return.go @@ -6,21 +6,27 @@ import ( // Various signalling return messaging to PAM. -// PamReturnStatus is the interface that all PAM return types should implement. -type PamReturnStatus interface { +// PamReturnValue is the interface that all PAM return types should implement. +type PamReturnValue interface { Message() string } // PamReturnError is an interface that PAM errors return types should implement. type PamReturnError interface { - PamReturnStatus + PamReturnValue Status() pam.Error } // PamSuccess signals PAM module to return with provided pam.Success and Quit tea.Model. type PamSuccess struct { BrokerID string - msg string + AuthTok string + // OldAuthTok is the previous local password, set only when the user changed + // their password (chauthtok) and entered the old one as part of the flow. It + // lets PAM_OLDAUTHTOK be set so modules like pam_gnome_keyring can re-key an + // existing secret store instead of orphaning it. + OldAuthTok string + msg string } // Message returns the message that should be sent to pam as info message. diff --git a/pam/pam.go b/pam/pam.go index 89b2b4a168..fde673441c 100644 --- a/pam/pam.go +++ b/pam/pam.go @@ -48,6 +48,15 @@ const ( defaultConnectionTimeout = 2 * time.Second ) +// reportAuthtok is called after PAM_AUTHTOK is set. It is a no-op by default; +// the pam_debug build overrides it to print the token so it appears in golden +// files. +var reportAuthtok = func(authtok string) {} + +// reportOldAuthtok is called after PAM_OLDAUTHTOK is set. Like reportAuthtok it +// is a no-op by default and overridden by the pam_debug build. +var reportOldAuthtok = func(oldAuthtok string) {} + var supportedArgs = []string{ "debug", // When this is set to "true", then debug logging is enabled. "logfile", // The path of the file that will be used for logging. @@ -94,7 +103,7 @@ func showPamMessage(mTx pam.ModuleTransaction, style pam.Style, msg string) erro return nil } -func sendReturnMessageToPam(mTx pam.ModuleTransaction, retStatus adapter.PamReturnStatus) { +func sendReturnMessageToPam(mTx pam.ModuleTransaction, retStatus adapter.PamReturnValue) { msg := retStatus.Message() if msg == "" { return @@ -324,8 +333,8 @@ func (h *pamModule) handleAuthRequest(mode authd.SessionMode, mTx pam.ModuleTran } defer closeConn() - var exitStatus adapter.PamReturnStatus - appState := adapter.NewUIModel(mTx, pamClientType, mode, conn, &exitStatus) + var pamReturnValue adapter.PamReturnValue + appState := adapter.NewUIModel(mTx, pamClientType, mode, conn, &pamReturnValue) teaOpts = append(teaOpts, tea.WithFilter(adapter.MsgFilter)) p := tea.NewProgram(appState, teaOpts...) if _, err := p.Run(); err != nil { @@ -333,24 +342,36 @@ func (h *pamModule) handleAuthRequest(mode authd.SessionMode, mTx pam.ModuleTran return pam.ErrAbort } - switch exitStatus := exitStatus.(type) { + switch returnValue := pamReturnValue.(type) { case adapter.PamSuccess: - if shouldSendAuthMessage(pamClientType, exitStatus.Message(), true) { - sendReturnMessageToPam(mTx, exitStatus) + if shouldSendAuthMessage(pamClientType, returnValue.Message(), true) { + sendReturnMessageToPam(mTx, returnValue) + } + if returnValue.AuthTok != "" { + if err := mTx.SetItem(pam.Authtok, returnValue.AuthTok); err != nil { + return err + } + reportAuthtok(returnValue.AuthTok) + } + if returnValue.OldAuthTok != "" { + if err := mTx.SetItem(pam.Oldauthtok, returnValue.OldAuthTok); err != nil { + return err + } + reportOldAuthtok(returnValue.OldAuthTok) } return nil case adapter.PamReturnError: - if shouldSendAuthMessage(pamClientType, exitStatus.Message(), false) { - sendReturnMessageToPam(mTx, exitStatus) + if shouldSendAuthMessage(pamClientType, returnValue.Message(), false) { + sendReturnMessageToPam(mTx, returnValue) } - return fmt.Errorf("%w: %s", exitStatus.Status(), exitStatus.Message()) + return fmt.Errorf("%w: %s", returnValue.Status(), returnValue.Message()) default: // Preserve the previous behavior of showing any message associated with // unexpected exit statuses before returning the system error. - sendReturnMessageToPam(mTx, exitStatus) - return fmt.Errorf("%w: unknown exit code: %#v", pam.ErrSystem, exitStatus) + sendReturnMessageToPam(mTx, returnValue) + return fmt.Errorf("%w: unknown exit code: %#v", pam.ErrSystem, returnValue) } } diff --git a/pam/pam_authtok_debug.go b/pam/pam_authtok_debug.go new file mode 100644 index 0000000000..3b101cbf7a --- /dev/null +++ b/pam/pam_authtok_debug.go @@ -0,0 +1,14 @@ +//go:build pam_debug + +package main + +import "fmt" + +func init() { + reportAuthtok = func(authtok string) { + fmt.Printf(" PAM_AUTHTOK: %q\n", authtok) + } + reportOldAuthtok = func(oldAuthtok string) { + fmt.Printf(" PAM_OLDAUTHTOK: %q\n", oldAuthtok) + } +}