Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ require (
golang.org/x/sys v0.39.0
golang.org/x/term v0.38.0
google.golang.org/grpc v1.77.0
google.golang.org/protobuf v1.36.10
google.golang.org/protobuf v1.36.11
gopkg.in/ini.v1 v1.67.0
gopkg.in/yaml.v3 v3.0.1
gorbe.io/go/osrelease v0.3.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
29 changes: 28 additions & 1 deletion pam/integration-tests/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ func TestCLIAuthenticate(t *testing.T) {
tape string
tapeSettings []tapeSetting
tapeVariables map[string]string
tapeCommand string

clientOptions clientOptions
socketPath string
Expand Down Expand Up @@ -109,6 +110,10 @@ func TestCLIAuthenticate(t *testing.T) {
"Authenticate_user_with_mfa": {
tape: "mfa_auth",
},
"Authenticate_user_with_mfa_required": {
tape: "mfa_auth",
tapeCommand: strings.Join([]string{tapeCommand, "require_mfa=true"}, " "),
},
"Authenticate_user_with_form_mode_with_button": {
tape: "form_with_button",
},
Expand Down Expand Up @@ -149,6 +154,13 @@ func TestCLIAuthenticate(t *testing.T) {
{vhsWaitTimeout, 15 * time.Second},
},
},
"Authenticate_user_with_qr_code_requiring_mfa_auth": {
tape: "qr_code",
clientOptions: clientOptions{
PamUser: examplebroker.UserIntegrationPrefix + "qr-code-require-mfa",
},
tapeCommand: strings.Join([]string{tapeCommand, "require_mfa=true"}, " "),
},
"Authenticate_user_and_reset_password_while_enforcing_policy": {
tape: "mandatory_password_reset",
},
Expand Down Expand Up @@ -220,6 +232,17 @@ func TestCLIAuthenticate(t *testing.T) {
"Deny_authentication_if_newpassword_does_not_match_required_criteria": {
tape: "bad_password",
},
"Deny_authentication_if_MFA_authentication_is_required_with_password": {
tape: "simple_auth",
tapeVariables: map[string]string{
vhsTapeUserVariable: vhsTestUserName(t, "simple-mfa-required"),
},
tapeCommand: strings.Join([]string{tapeCommand, "require_mfa=true"}, " "),
},
"Deny_authentication_if_MFA_authentication_is_required_with_password_reset": {
tape: "mandatory_password_reset",
tapeCommand: strings.Join([]string{tapeCommand, "require_mfa=true"}, " "),
},

"Exit_authd_if_local_broker_is_selected": {
tape: "local_broker",
Expand Down Expand Up @@ -282,8 +305,12 @@ func TestCLIAuthenticate(t *testing.T) {
socketPath = tc.socketPath
}

if tc.tapeCommand == "" {
tc.tapeCommand = tapeCommand
}

td := newTapeData(tc.tape, outDir, tc.tapeSettings...)
td.Command = tapeCommand
td.Command = tc.tapeCommand
td.Variables = tc.tapeVariables
td.Env[vhsTapeSocketVariable] = socketPath
td.Env["AUTHD_TEST_PID_FILE"] = pidFile
Expand Down
29 changes: 29 additions & 0 deletions pam/integration-tests/native_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,14 @@ func TestNativeAuthenticate(t *testing.T) {
PamUser: examplebroker.UserIntegrationMfaPrefix + "auth",
},
},
"Authenticate_user_with_mfa_required": {
tape: "mfa_auth",
tapeSettings: []tapeSetting{{vhsHeight, 1200}},
clientOptions: clientOptions{
PamUser: examplebroker.UserIntegrationMfaPrefix + "auth-mfa-required",
},
tapeCommand: strings.Join([]string{tapeCommand, "require_mfa=true"}, " "),
},
"Authenticate_user_with_form_mode_with_button": {
tape: "form_with_button",
tapeSettings: []tapeSetting{{vhsHeight, 700}},
Expand Down Expand Up @@ -199,6 +207,15 @@ func TestNativeAuthenticate(t *testing.T) {
PamServiceName: "sshd",
},
},
"Authenticate_user_with_qr_code_requiring_mfa_auth": {
tape: "qr_code",
tapeSettings: []tapeSetting{{vhsHeight, 3000}},
tapeVariables: map[string]string{
"AUTHD_QRCODE_TAPE_ITEM": "7",
"AUTHD_QRCODE_TAPE_ITEM_NAME": "QR code",
},
tapeCommand: strings.Join([]string{tapeCommand, "require_mfa=true"}, " "),
},
"Authenticate_user_and_reset_password_while_enforcing_policy": {
tape: "mandatory_password_reset",
tapeSettings: []tapeSetting{{vhsHeight, 550}},
Expand Down Expand Up @@ -361,6 +378,18 @@ func TestNativeAuthenticate(t *testing.T) {
PamUser: examplebroker.UserIntegrationNeedsResetPrefix + "bad-password",
},
},
"Deny_authentication_if_MFA_authentication_is_required_with_password": {
tape: "simple_auth",
tapeCommand: strings.Join([]string{tapeCommand, "require_mfa=true"}, " "),
},
"Deny_authentication_if_MFA_authentication_is_required_with_password_reset": {
tape: "mandatory_password_reset",
tapeSettings: []tapeSetting{{vhsHeight, 550}},
clientOptions: clientOptions{
PamUser: examplebroker.UserIntegrationNeedsResetPrefix + "mandatory-mfa-required",
},
tapeCommand: strings.Join([]string{tapeCommand, "require_mfa=true"}, " "),
},

"Prevent_preset_user_from_switching_username": {
tape: "switch_preset_username",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Username: user name
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Username: user-mfa
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Select your provider

> 1. local
2. ExampleBroker

Press escape key to go back to user selection
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Gimme your password:
>

Press escape key to go back to select the authentication method
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Select your authentication method

> 1. Password authentication
2. Send URL to [email protected]
3. Use your fido device foo
4. Use your phone +33...
5. Use your phone +1...
6. Use a QR code
7. Authentication code

Press escape key to go back to choose the provider
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Gimme your password:
>

Press escape key to go back to select the authentication method
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Gimme your password:
> ********

Press escape key to go back to select the authentication method
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Plug your fido device and press with your thumb

Press escape key to go back to select the authentication method
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Select your authentication method

> 1. Use your fido device foo
2. Use your phone +33...
3. Authentication code

Press escape key to go back to choose the provider
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Plug your fido device and press with your thumb

Press escape key to go back to select the authentication method
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Unlock your phone +33... or accept request on web interface

Press escape key to go back to select the authentication method
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Select your authentication method

> 1. Use your phone +33...
2. Authentication code

Press escape key to go back to choose the provider
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
Unlock your phone +33... or accept request on web interface

Press escape key to go back to select the authentication method
────────────────────────────────────────────────────────────────────────────────
> ./pam_authd login socket=${AUTHD_TEST_TAPE_SOCKET} require_mfa=true
PAM Error Message: Additional authentication factors are required
PAM Authenticate()
User: "user-mfa"
Result: error: PAM exit code: 8
Insufficient credentials to access authentication data
PAM Info Message: acct=incomplete
PAM AcctMgmt()
User: "user-mfa"
Result: error: PAM exit code: 25
The return value should be ignored by PAM dispatch
>
────────────────────────────────────────────────────────────────────────────────
Loading
Loading