From c686e92cd808957ea5759e93eec1668055caeb1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 29 Aug 2024 15:48:54 +0200 Subject: [PATCH 1/5] pam: Add PAM disable_qrcode_rendering option to test client without qrcode support Simulate clients without qrcode rendering support --- pam/integration-tests/cli_test.go | 1 + .../golden/authenticate_user_with_login_code | 330 ++++++++++++++++++ .../testdata/tapes/cli/login_code.tape | 63 ++++ pam/internal/adapter/authentication.go | 8 +- pam/internal/adapter/model.go | 3 + pam/internal/adapter/qrcodemodel.go | 24 +- pam/pam.go | 22 +- 7 files changed, 430 insertions(+), 21 deletions(-) create mode 100644 pam/integration-tests/testdata/TestCLIAuthenticate/golden/authenticate_user_with_login_code create mode 100644 pam/integration-tests/testdata/tapes/cli/login_code.tape diff --git a/pam/integration-tests/cli_test.go b/pam/integration-tests/cli_test.go index 747e760bf..292072216 100644 --- a/pam/integration-tests/cli_test.go +++ b/pam/integration-tests/cli_test.go @@ -48,6 +48,7 @@ func TestCLIAuthenticate(t *testing.T) { "Authenticate user with qr code in a TTY session": {tape: "qr_code", pamUser: "user-integration-qr-code-tty-session", termEnv: "xterm-256color", sessionEnv: "tty"}, "Authenticate user with qr code in screen": {tape: "qr_code", pamUser: "user-integration-qr-code-screen", termEnv: "screen"}, "Authenticate user with qr code after many regenerations": {tape: "qr_code_quick_regenerate"}, + "Authenticate user with login code": {tape: "login_code"}, "Authenticate user and reset password while enforcing policy": {tape: "mandatory_password_reset"}, "Authenticate user with mfa and reset password while enforcing policy": {tape: "mfa_reset_pwquality_auth"}, "Authenticate user and offer password reset": {tape: "optional_password_reset_skip"}, diff --git a/pam/integration-tests/testdata/TestCLIAuthenticate/golden/authenticate_user_with_login_code b/pam/integration-tests/testdata/TestCLIAuthenticate/golden/authenticate_user_with_login_code new file mode 100644 index 000000000..f9e4781b4 --- /dev/null +++ b/pam/integration-tests/testdata/TestCLIAuthenticate/golden/authenticate_user_with_login_code @@ -0,0 +1,330 @@ +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t +rue +Username: user name + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t +rue +Username: user-integration-login-code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t +rue + Select your provider + +> 1. local + 2. ExampleBroker + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t +rue +Gimme your password +> + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t +rue + Select your authentication method + +> 1. Password authentication + 2. Send URL to user-integration-login-code@gmail.com + 3. Use your fido device foo + 4. Use your phone +33… + 5. Use your phone +1… + 6. Use a QR code + 7. Authentication code + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t +rue +Scan the qrcode or enter the code in the login page + +https://ubuntu.com +1337 + + [ Regenerate code ] + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t +rue +Scan the qrcode or enter the code in the login page + +https://ubuntu.com +1337 + + [ Regenerate code ] + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t +rue +Scan the qrcode or enter the code in the login page + +https://ubuntu.fr/ +1338 + + [ Regenerate code ] + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t +rue +Scan the qrcode or enter the code in the login page + +https://ubuntu.fr/ +1338 + +PAM Authenticate() for user "user-integration-login-code" exited with success +PAM AcctMgmt() exited with success +> + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t +rue +Scan the qrcode or enter the code in the login page + +https://ubuntu.fr/ +1338 + +PAM Authenticate() for user "user-integration-login-code" exited with success +PAM AcctMgmt() exited with success +> + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── diff --git a/pam/integration-tests/testdata/tapes/cli/login_code.tape b/pam/integration-tests/testdata/tapes/cli/login_code.tape new file mode 100644 index 000000000..2f9640f31 --- /dev/null +++ b/pam/integration-tests/testdata/tapes/cli/login_code.tape @@ -0,0 +1,63 @@ +Output login_code.txt +Output login_code.gif # If we don't specify a .gif output, it will create a default out.gif file. + +# Configuration header to standardize the output. +# Does not work with the "Source" command. +Set Width 800 +Set Height 500 +# TODO: Ideally, we should use Ubuntu Mono. However, the github runner is still on Jammy, which does not have it. +# We should update this to use Ubuntu Mono once the runner is updated. +Set FontFamily "Monospace" +Set FontSize 13 +Set Padding 0 +Set Margin 0 +Set Shell bash + +Hide +Type "./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=true" +Enter +Sleep 300ms +Show + +Hide +Escape +Backspace +Type "user-integration-login-code" +Sleep 300ms +Show + +Hide +Enter +Sleep 300ms +Show + +Hide +Type "2" +Sleep 300ms +Show + +Hide +Escape +Sleep 300ms +Show + +Hide +Type "6" +Sleep 300ms +Show + +Hide +Tab +Sleep 300ms +Show + +Hide +Enter +Sleep 1s +Show + +Hide +Sleep 5s +Show + +Sleep 300ms diff --git a/pam/internal/adapter/authentication.go b/pam/internal/adapter/authentication.go index 7a3a6749f..a3f341e3c 100644 --- a/pam/internal/adapter/authentication.go +++ b/pam/internal/adapter/authentication.go @@ -370,7 +370,8 @@ func (m *authenticationModel) Blur() { // Compose initialize the authentication model to be used. // It creates and attaches the sub layout models based on UILayout. -func (m *authenticationModel) Compose(brokerID, sessionID string, encryptionKey *rsa.PublicKey, layout *authd.UILayout) tea.Cmd { +func (m *authenticationModel) Compose(brokerID, sessionID string, + encryptionKey *rsa.PublicKey, disableQrCodeRendering bool, layout *authd.UILayout) tea.Cmd { m.currentBrokerID = brokerID m.currentSessionID = sessionID m.encryptionKey = encryptionKey @@ -389,8 +390,9 @@ func (m *authenticationModel) Compose(brokerID, sessionID string, encryptionKey m.currentModel = form case "qrcode": - qrcodeModel, err := newQRCodeModel(layout.GetContent(), layout.GetCode(), - layout.GetLabel(), layout.GetButton(), layout.GetWait() == "true") + qrcodeModel, err := newQRCodeModel(disableQrCodeRendering, + layout.GetContent(), layout.GetCode(), layout.GetLabel(), + layout.GetButton(), layout.GetWait() == "true") if err != nil { return sendEvent(pamError{status: pam.ErrSystem, msg: err.Error()}) } diff --git a/pam/internal/adapter/model.go b/pam/internal/adapter/model.go index fea959de8..7f6b2c1b9 100644 --- a/pam/internal/adapter/model.go +++ b/pam/internal/adapter/model.go @@ -49,6 +49,8 @@ type UIModel struct { ClientType PamClientType // SessionMode is the mode of the session invoked by the module. SessionMode authd.SessionMode + // DisableQrCodeRendering is the flag to disable qrcode rendering + DisableQrCodeRendering bool sessionStartingForBroker string currentSession *sessionInfo @@ -272,6 +274,7 @@ func (m *UIModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { m.currentSession.brokerID, m.currentSession.sessionID, m.currentSession.encryptionKey, + m.DisableQrCodeRendering, msg.layout, ), modelCmd, diff --git a/pam/internal/adapter/qrcodemodel.go b/pam/internal/adapter/qrcodemodel.go index 3162d2496..eff65e6df 100644 --- a/pam/internal/adapter/qrcodemodel.go +++ b/pam/internal/adapter/qrcodemodel.go @@ -1,7 +1,7 @@ package adapter import ( - "fmt" + "context" "os" "strings" @@ -10,6 +10,7 @@ import ( "github.com/muesli/termenv" "github.com/skip2/go-qrcode" "github.com/ubuntu/authd" + "github.com/ubuntu/authd/internal/log" ) var centeredStyle = lipgloss.NewStyle().Align(lipgloss.Center, lipgloss.Top) @@ -27,15 +28,19 @@ type qrcodeModel struct { } // newQRCodeModel initializes and return a new qrcodeModel. -func newQRCodeModel(content, code, label, buttonLabel string, wait bool) (qrcodeModel, error) { +func newQRCodeModel(disableRendering bool, content, code, label, buttonLabel string, wait bool) (qrcodeModel, error) { var button *buttonModel if buttonLabel != "" { button = &buttonModel{label: buttonLabel} } - qrCode, err := qrcode.New(content, qrcode.Medium) - if err != nil { - return qrcodeModel{}, fmt.Errorf("can't generate QR code: %v", err) + var qrCode *qrcode.QRCode + if !disableRendering { + var err error + qrCode, err = qrcode.New(content, qrcode.Medium) + if err != nil { + log.Errorf(context.TODO(), "can't generate QR code: %v", err) + } } return qrcodeModel{ @@ -106,9 +111,12 @@ func (m qrcodeModel) View() string { fields = append(fields, m.label, "") } - qr := m.renderQrCode() - fields = append(fields, qr) - qrcodeWidth := lipgloss.Width(qr) + qrcodeWidth := 0 + if m.qrCode != nil { + qr := m.renderQrCode() + fields = append(fields, qr) + qrcodeWidth = lipgloss.Width(qr) + } style := centeredStyle.Width(qrcodeWidth) renderedContent := m.content diff --git a/pam/pam.go b/pam/pam.go index cd0b11d43..8f63b9aad 100644 --- a/pam/pam.go +++ b/pam/pam.go @@ -49,12 +49,13 @@ const ( ) 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. - "disable_journal", // Disable logging on systemd journal (this is implicit when `logfile` is set). - "socket", // The authd socket to connect to. - "force_native_client", // Use native PAM client instead of custom UIs. - "force_reauth", // Whether the authentication should be performed again even if it has been already completed. + "debug", // When this is set to "true", then debug logging is enabled. + "logfile", // The path of the file that will be used for logging. + "disable_journal", // Disable logging on systemd journal (this is implicit when `logfile` is set). + "disable_qrcode_rendering", // Whether qrcode rendering should be disabled. + "socket", // The authd socket to connect to. + "force_native_client", // Use native PAM client instead of custom UIs. + "force_reauth", // Whether the authentication should be performed again even if it has been already completed. } // parseArgs parses the PAM arguments and returns a map of them and a function that logs the parsing issues. @@ -314,10 +315,11 @@ func (h *pamModule) handleAuthRequest(mode authd.SessionMode, mTx pam.ModuleTran defer closeConn() appState := adapter.UIModel{ - PamMTx: mTx, - Client: authd.NewPAMClient(conn), - ClientType: pamClientType, - SessionMode: mode, + PamMTx: mTx, + Client: authd.NewPAMClient(conn), + ClientType: pamClientType, + DisableQrCodeRendering: parsedArgs["disable_qrcode_rendering"] == "true", + SessionMode: mode, } if pamClientType == adapter.Native && isSSHSession(mTx) { From ac571ac2a6c95af8fc672907da27dcab68abd2ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 29 Aug 2024 15:56:14 +0200 Subject: [PATCH 2/5] authmodeselection: Mark qrcode content as optional if rendering is not supported --- examplebroker/broker.go | 12 +++++++--- .../golden/authenticate_user_with_login_code | 20 ++++++++-------- .../testdata/tapes/cli/login_code.tape | 2 +- pam/internal/adapter/authentication.go | 6 +---- pam/internal/adapter/authmodeselection.go | 24 ++++++++++++------- pam/internal/adapter/model.go | 2 +- pam/internal/adapter/qrcodemodel.go | 4 ++-- 7 files changed, 40 insertions(+), 30 deletions(-) diff --git a/examplebroker/broker.go b/examplebroker/broker.go index 5d7a74cab..5afd6c8d2 100644 --- a/examplebroker/broker.go +++ b/examplebroker/broker.go @@ -359,13 +359,19 @@ func getSupportedModes(sessionInfo sessionInfo, supportedUILayouts []map[string] case "qrcode": modeName := "qrcodewithtypo" + modeSelectionLabel := "Use a QR code" modeLabel := "Enter the following code after flashing the address: " if layout["code"] != "" { modeName = "qrcodeandcodewithtypo" modeLabel = "Scan the qrcode or enter the code in the login page" } + if layout["content"] == "optional" { + modeName = "codewithtypo" + modeSelectionLabel = "Use a Login code" + modeLabel = "Enter the code in the login page" + } allModes[modeName] = map[string]string{ - "selection_label": "Use a QR code", + "selection_label": modeSelectionLabel, "ui": mapToJSON(map[string]string{ "type": "qrcode", "label": modeLabel, @@ -468,7 +474,7 @@ func (b *Broker) SelectAuthenticationMode(ctx context.Context, sessionID, authen // send request to sessionInfo.allModes[authenticationModeName]["phone"] case "fidodevice1": // start transaction with fido device - case "qrcodeandcodewithtypo": + case "qrcodeandcodewithtypo", "codewithtypo": uiLayoutInfo["content"], uiLayoutInfo["code"] = qrcodeData(&sessionInfo) case "qrcodewithtypo": // generate the url and finish the prompt on the fly. @@ -616,7 +622,7 @@ func (b *Broker) handleIsAuthenticated(ctx context.Context, sessionInfo sessionI return AuthCancelled, "", nil } - case "qrcodewithtypo", "qrcodeandcodewithtypo": + case "qrcodewithtypo", "qrcodeandcodewithtypo", "codewithtypo": if authData["wait"] != "true" { return AuthDenied, fmt.Sprintf(`{"message": "%s should have wait set to true"}`, sessionInfo.currentAuthMode), nil } diff --git a/pam/integration-tests/testdata/TestCLIAuthenticate/golden/authenticate_user_with_login_code b/pam/integration-tests/testdata/TestCLIAuthenticate/golden/authenticate_user_with_login_code index f9e4781b4..7f2dd1c99 100644 --- a/pam/integration-tests/testdata/TestCLIAuthenticate/golden/authenticate_user_with_login_code +++ b/pam/integration-tests/testdata/TestCLIAuthenticate/golden/authenticate_user_with_login_code @@ -135,11 +135,11 @@ rue Select your authentication method > 1. Password authentication - 2. Send URL to user-integration-login-code@gmail.com - 3. Use your fido device foo - 4. Use your phone +33… - 5. Use your phone +1… - 6. Use a QR code + 2. Use a Login code + 3. Send URL to user-integration-login-code@gmail.com + 4. Use your fido device foo + 5. Use your phone +33… + 6. Use your phone +1… 7. Authentication code @@ -165,7 +165,7 @@ rue ──────────────────────────────────────────────────────────────────────────────── > ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t rue -Scan the qrcode or enter the code in the login page +Enter the code in the login page https://ubuntu.com 1337 @@ -198,7 +198,7 @@ https://ubuntu.com ──────────────────────────────────────────────────────────────────────────────── > ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t rue -Scan the qrcode or enter the code in the login page +Enter the code in the login page https://ubuntu.com 1337 @@ -231,7 +231,7 @@ https://ubuntu.com ──────────────────────────────────────────────────────────────────────────────── > ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t rue -Scan the qrcode or enter the code in the login page +Enter the code in the login page https://ubuntu.fr/ 1338 @@ -264,7 +264,7 @@ https://ubuntu.fr/ ──────────────────────────────────────────────────────────────────────────────── > ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t rue -Scan the qrcode or enter the code in the login page +Enter the code in the login page https://ubuntu.fr/ 1338 @@ -297,7 +297,7 @@ PAM AcctMgmt() exited with success ──────────────────────────────────────────────────────────────────────────────── > ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} disable_qrcode_rendering=t rue -Scan the qrcode or enter the code in the login page +Enter the code in the login page https://ubuntu.fr/ 1338 diff --git a/pam/integration-tests/testdata/tapes/cli/login_code.tape b/pam/integration-tests/testdata/tapes/cli/login_code.tape index 2f9640f31..57c14f81a 100644 --- a/pam/integration-tests/testdata/tapes/cli/login_code.tape +++ b/pam/integration-tests/testdata/tapes/cli/login_code.tape @@ -42,7 +42,7 @@ Sleep 300ms Show Hide -Type "6" +Type "2" Sleep 300ms Show diff --git a/pam/internal/adapter/authentication.go b/pam/internal/adapter/authentication.go index a3f341e3c..7d4b27753 100644 --- a/pam/internal/adapter/authentication.go +++ b/pam/internal/adapter/authentication.go @@ -390,13 +390,9 @@ func (m *authenticationModel) Compose(brokerID, sessionID string, m.currentModel = form case "qrcode": - qrcodeModel, err := newQRCodeModel(disableQrCodeRendering, + m.currentModel = newQRCodeModel(disableQrCodeRendering, layout.GetContent(), layout.GetCode(), layout.GetLabel(), layout.GetButton(), layout.GetWait() == "true") - if err != nil { - return sendEvent(pamError{status: pam.ErrSystem, msg: err.Error()}) - } - m.currentModel = qrcodeModel case "newpassword": newPasswordModel := newNewPasswordModel(layout.GetLabel(), layout.GetEntry(), layout.GetButton()) diff --git a/pam/internal/adapter/authmodeselection.go b/pam/internal/adapter/authmodeselection.go index 25419f677..460b44f6d 100644 --- a/pam/internal/adapter/authmodeselection.go +++ b/pam/internal/adapter/authmodeselection.go @@ -20,6 +20,7 @@ type authModeSelectionModel struct { focused bool clientType PamClientType + disableQrCodeRendering bool supportedUILayouts []*authd.UILayout supportedUILayoutsMu *sync.Mutex availableAuthModes []*authd.GAMResponse_AuthenticationMode @@ -51,13 +52,14 @@ func selectAuthMode(id string) tea.Cmd { } // newAuthModeSelectionModel initializes an empty list with default options of authModeSelectionModel. -func newAuthModeSelectionModel(clientType PamClientType) authModeSelectionModel { +func newAuthModeSelectionModel(clientType PamClientType, disableQrCode bool) authModeSelectionModel { // FIXME: decouple UI from data model. if clientType != InteractiveTerminal { return authModeSelectionModel{ - Model: list.New(nil, itemLayout{}, 0, 0), - clientType: clientType, - supportedUILayoutsMu: &sync.Mutex{}, + Model: list.New(nil, itemLayout{}, 0, 0), + clientType: clientType, + disableQrCodeRendering: disableQrCode, + supportedUILayoutsMu: &sync.Mutex{}, } } @@ -72,9 +74,10 @@ func newAuthModeSelectionModel(clientType PamClientType) authModeSelectionModel l.Styles.HelpStyle = helpStyle*/ return authModeSelectionModel{ - Model: l, - clientType: clientType, - supportedUILayoutsMu: &sync.Mutex{}, + Model: l, + clientType: clientType, + disableQrCodeRendering: disableQrCode, + supportedUILayoutsMu: &sync.Mutex{}, } } @@ -90,6 +93,11 @@ func (m *authModeSelectionModel) Init() tea.Cmd { requiredWithBooleans := "required:true,false" optionalWithBooleans := "optional:true,false" + qrcodeContentSupportMode := required + if m.disableQrCodeRendering { + qrcodeContentSupportMode = optional + } + return supportedUILayoutsReceived{ layouts: []*authd.UILayout{ { @@ -101,7 +109,7 @@ func (m *authModeSelectionModel) Init() tea.Cmd { }, { Type: "qrcode", - Content: &required, + Content: &qrcodeContentSupportMode, Code: &optional, Wait: &requiredWithBooleans, Label: &optional, diff --git a/pam/internal/adapter/model.go b/pam/internal/adapter/model.go index 7f6b2c1b9..cc59a6387 100644 --- a/pam/internal/adapter/model.go +++ b/pam/internal/adapter/model.go @@ -122,7 +122,7 @@ func (m *UIModel) Init() tea.Cmd { m.brokerSelectionModel = newBrokerSelectionModel(m.Client, m.ClientType) cmds = append(cmds, m.brokerSelectionModel.Init()) - m.authModeSelectionModel = newAuthModeSelectionModel(m.ClientType) + m.authModeSelectionModel = newAuthModeSelectionModel(m.ClientType, m.DisableQrCodeRendering) cmds = append(cmds, m.authModeSelectionModel.Init()) m.authenticationModel = newAuthenticationModel(m.Client, m.ClientType) diff --git a/pam/internal/adapter/qrcodemodel.go b/pam/internal/adapter/qrcodemodel.go index eff65e6df..baeb85803 100644 --- a/pam/internal/adapter/qrcodemodel.go +++ b/pam/internal/adapter/qrcodemodel.go @@ -28,7 +28,7 @@ type qrcodeModel struct { } // newQRCodeModel initializes and return a new qrcodeModel. -func newQRCodeModel(disableRendering bool, content, code, label, buttonLabel string, wait bool) (qrcodeModel, error) { +func newQRCodeModel(disableRendering bool, content, code, label, buttonLabel string, wait bool) qrcodeModel { var button *buttonModel if buttonLabel != "" { button = &buttonModel{label: buttonLabel} @@ -50,7 +50,7 @@ func newQRCodeModel(disableRendering bool, content, code, label, buttonLabel str code: code, qrCode: qrCode, wait: wait, - }, nil + } } // Init initializes qrcodeModel. From 3985e044ed57c31ece42adac7d62544e67d17ea5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 29 Aug 2024 15:56:35 +0200 Subject: [PATCH 3/5] pam: Add debug logging or the parsed option arguments --- pam/pam.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pam/pam.go b/pam/pam.go index 8f63b9aad..34cd48dec 100644 --- a/pam/pam.go +++ b/pam/pam.go @@ -75,6 +75,7 @@ func parseArgs(args []string) (map[string]string, func()) { } return parsed, func() { + log.Debugf(context.TODO(), "Parsed PAM arguments %v", parsed) for _, warn := range warnings { log.Warning(context.TODO(), warn) } From d0c18093b261e9f541dbdd317b99620228da4a99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 29 Aug 2024 16:20:34 +0200 Subject: [PATCH 4/5] nativemodel: Do not mention qrcode if the rendering is not supported --- .../authenticate_user_with_qr_code_in_polkit | 120 +++++++++--------- pam/internal/adapter/nativemodel.go | 10 +- 2 files changed, 68 insertions(+), 62 deletions(-) diff --git a/pam/integration-tests/testdata/TestNativeAuthenticate/golden/authenticate_user_with_qr_code_in_polkit b/pam/integration-tests/testdata/TestNativeAuthenticate/golden/authenticate_user_with_qr_code_in_polkit index ae0f5d486..9aeade108 100644 --- a/pam/integration-tests/testdata/TestNativeAuthenticate/golden/authenticate_user_with_qr_code_in_polkit +++ b/pam/integration-tests/testdata/TestNativeAuthenticate/golden/authenticate_user_with_qr_code_in_polkit @@ -718,8 +718,8 @@ Scan the qrcode or enter the code in the login page https://ubuntu.com 1337 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: @@ -951,16 +951,16 @@ Scan the qrcode or enter the code in the login page https://ubuntu.com 1337 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.fr/ 1338 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: @@ -1184,24 +1184,24 @@ Scan the qrcode or enter the code in the login page https://ubuntu.com 1337 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.fr/ 1338 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntuforum-br.org/ 1339 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: @@ -1417,32 +1417,32 @@ Scan the qrcode or enter the code in the login page https://ubuntu.com 1337 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.fr/ 1338 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntuforum-br.org/ 1339 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://www.ubuntu-it.org/ 1340 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: @@ -1650,40 +1650,40 @@ Scan the qrcode or enter the code in the login page https://ubuntu.com 1337 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.fr/ 1338 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntuforum-br.org/ 1339 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://www.ubuntu-it.org/ 1340 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.com 1341 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: @@ -1883,40 +1883,40 @@ Scan the qrcode or enter the code in the login page https://ubuntu.com 1337 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.fr/ 1338 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntuforum-br.org/ 1339 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://www.ubuntu-it.org/ 1340 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.com 1341 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 1 @@ -2116,40 +2116,40 @@ Scan the qrcode or enter the code in the login page https://ubuntu.com 1337 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.fr/ 1338 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntuforum-br.org/ 1339 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://www.ubuntu-it.org/ 1340 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.com 1341 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 1 PAM Authenticate() for user "user-integration-qr-code-screen" exited with success @@ -2349,40 +2349,40 @@ Scan the qrcode or enter the code in the login page https://ubuntu.com 1337 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.fr/ 1338 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntuforum-br.org/ 1339 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://www.ubuntu-it.org/ 1340 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 2 Scan the qrcode or enter the code in the login page https://ubuntu.com 1341 -== Qr Code authentication (use 'r' to go back) == -1 - Wait for the QR code scan result +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result 2 - Regenerate code Select action: 1 PAM Authenticate() for user "user-integration-qr-code-screen" exited with success diff --git a/pam/internal/adapter/nativemodel.go b/pam/internal/adapter/nativemodel.go index c31a4d957..ef82da406 100644 --- a/pam/internal/adapter/nativemodel.go +++ b/pam/internal/adapter/nativemodel.go @@ -659,14 +659,20 @@ func (m nativeModel) handleQrCode() tea.Cmd { return cmd } + authLabel := "Qr Code authentication" + choiceLabel := "Wait for the QR code scan result" + if !m.isQrcodeRenderingSupported() { + authLabel = "Login Code authentication" + choiceLabel = "Wait for the login code result" + } choices := []choicePair{ - {id: "wait", label: "Wait for the QR code scan result"}, + {id: "wait", label: choiceLabel}, } if buttonLabel := m.uiLayout.GetButton(); buttonLabel != "" { choices = append(choices, choicePair{id: "button", label: buttonLabel}) } - id, err := m.promptForChoice("Qr Code authentication", choices, "Select action") + id, err := m.promptForChoice(authLabel, choices, "Select action") if errors.Is(err, errGoBack) { return sendEvent(nativeGoBack{}) } From 0eecb865ac09b2b3a7760384d1b5db6afb57ed04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= Date: Thu, 29 Aug 2024 16:30:08 +0200 Subject: [PATCH 5/5] nativemodel: Support disable qrcode rendering PAM option --- pam/integration-tests/native_test.go | 1 + .../golden/authenticate_user_with_login_code | 910 ++++++++++++++++++ .../testdata/tapes/native/login_code.tape | 86 ++ pam/internal/adapter/model.go | 6 +- pam/internal/adapter/nativemodel.go | 12 +- 5 files changed, 1013 insertions(+), 2 deletions(-) create mode 100644 pam/integration-tests/testdata/TestNativeAuthenticate/golden/authenticate_user_with_login_code create mode 100644 pam/integration-tests/testdata/tapes/native/login_code.tape diff --git a/pam/integration-tests/native_test.go b/pam/integration-tests/native_test.go index 93bb6ec8e..aee6f1314 100644 --- a/pam/integration-tests/native_test.go +++ b/pam/integration-tests/native_test.go @@ -45,6 +45,7 @@ func TestNativeAuthenticate(t *testing.T) { "Authenticate user with qr code in a TTY session": {tape: "qr_code", pamUser: "user-integration-qr-code-tty-session", termEnv: "xterm-256color", sessionEnv: "tty"}, "Authenticate user with qr code in screen": {tape: "qr_code", pamUser: "user-integration-qr-code-screen", termEnv: "screen"}, "Authenticate user with qr code in polkit": {tape: "qr_code", pamUser: "user-integration-qr-code-screen", pamServiceName: "polkit-1"}, + "Authenticate user with login code": {tape: "login_code"}, "Authenticate user and reset password while enforcing policy": {tape: "mandatory_password_reset"}, "Authenticate user with mfa and reset password while enforcing policy": {tape: "mfa_reset_pwquality_auth"}, "Authenticate user and offer password reset": {tape: "optional_password_reset_skip"}, diff --git a/pam/integration-tests/testdata/TestNativeAuthenticate/golden/authenticate_user_with_login_code b/pam/integration-tests/testdata/TestNativeAuthenticate/golden/authenticate_user_with_login_code new file mode 100644 index 000000000..5048289a3 --- /dev/null +++ b/pam/integration-tests/testdata/TestNativeAuthenticate/golden/authenticate_user_with_login_code @@ -0,0 +1,910 @@ +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: 2 +Insert 'r' to cancel the request and go back +Gimme your password: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: 2 +Insert 'r' to cancel the request and go back +Gimme your password: +== Authentication mode selection (use 'r' to go back) == +1 - Password authentication +2 - Use a Login code +3 - Send URL to user-integration-login-code@gmail.com +4 - Use your fido device foo +5 - Use your phone +33… +6 - Use your phone +1… +7 - Pin code +8 - Authentication code +Select authentication mode: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: 2 +Insert 'r' to cancel the request and go back +Gimme your password: +== Authentication mode selection (use 'r' to go back) == +1 - Password authentication +2 - Use a Login code +3 - Send URL to user-integration-login-code@gmail.com +4 - Use your fido device foo +5 - Use your phone +33… +6 - Use your phone +1… +7 - Pin code +8 - Authentication code +Select authentication mode: 2 +Enter the code in the login page +https://ubuntu.com + 1337 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: 2 +Insert 'r' to cancel the request and go back +Gimme your password: +== Authentication mode selection (use 'r' to go back) == +1 - Password authentication +2 - Use a Login code +3 - Send URL to user-integration-login-code@gmail.com +4 - Use your fido device foo +5 - Use your phone +33… +6 - Use your phone +1… +7 - Pin code +8 - Authentication code +Select authentication mode: 2 +Enter the code in the login page +https://ubuntu.com + 1337 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.fr/ + 1338 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: 2 +Insert 'r' to cancel the request and go back +Gimme your password: +== Authentication mode selection (use 'r' to go back) == +1 - Password authentication +2 - Use a Login code +3 - Send URL to user-integration-login-code@gmail.com +4 - Use your fido device foo +5 - Use your phone +33… +6 - Use your phone +1… +7 - Pin code +8 - Authentication code +Select authentication mode: 2 +Enter the code in the login page +https://ubuntu.com + 1337 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.fr/ + 1338 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntuforum-br.org/ + 1339 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: 2 +Insert 'r' to cancel the request and go back +Gimme your password: +== Authentication mode selection (use 'r' to go back) == +1 - Password authentication +2 - Use a Login code +3 - Send URL to user-integration-login-code@gmail.com +4 - Use your fido device foo +5 - Use your phone +33… +6 - Use your phone +1… +7 - Pin code +8 - Authentication code +Select authentication mode: 2 +Enter the code in the login page +https://ubuntu.com + 1337 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.fr/ + 1338 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntuforum-br.org/ + 1339 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://www.ubuntu-it.org/ + 1340 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: 2 +Insert 'r' to cancel the request and go back +Gimme your password: +== Authentication mode selection (use 'r' to go back) == +1 - Password authentication +2 - Use a Login code +3 - Send URL to user-integration-login-code@gmail.com +4 - Use your fido device foo +5 - Use your phone +33… +6 - Use your phone +1… +7 - Pin code +8 - Authentication code +Select authentication mode: 2 +Enter the code in the login page +https://ubuntu.com + 1337 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.fr/ + 1338 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntuforum-br.org/ + 1339 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://www.ubuntu-it.org/ + 1340 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.com + 1341 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: 2 +Insert 'r' to cancel the request and go back +Gimme your password: +== Authentication mode selection (use 'r' to go back) == +1 - Password authentication +2 - Use a Login code +3 - Send URL to user-integration-login-code@gmail.com +4 - Use your fido device foo +5 - Use your phone +33… +6 - Use your phone +1… +7 - Pin code +8 - Authentication code +Select authentication mode: 2 +Enter the code in the login page +https://ubuntu.com + 1337 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.fr/ + 1338 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntuforum-br.org/ + 1339 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://www.ubuntu-it.org/ + 1340 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.com + 1341 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 1 + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: 2 +Insert 'r' to cancel the request and go back +Gimme your password: +== Authentication mode selection (use 'r' to go back) == +1 - Password authentication +2 - Use a Login code +3 - Send URL to user-integration-login-code@gmail.com +4 - Use your fido device foo +5 - Use your phone +33… +6 - Use your phone +1… +7 - Pin code +8 - Authentication code +Select authentication mode: 2 +Enter the code in the login page +https://ubuntu.com + 1337 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.fr/ + 1338 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntuforum-br.org/ + 1339 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://www.ubuntu-it.org/ + 1340 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.com + 1341 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 1 +PAM Authenticate() for user "user-integration-login-code" exited with success +PAM AcctMgmt() exited with success +> + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true d +isable_qrcode_rendering=true +Username: user-integration-login-code +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: 2 +Insert 'r' to cancel the request and go back +Gimme your password: +== Authentication mode selection (use 'r' to go back) == +1 - Password authentication +2 - Use a Login code +3 - Send URL to user-integration-login-code@gmail.com +4 - Use your fido device foo +5 - Use your phone +33… +6 - Use your phone +1… +7 - Pin code +8 - Authentication code +Select authentication mode: 2 +Enter the code in the login page +https://ubuntu.com + 1337 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.fr/ + 1338 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntuforum-br.org/ + 1339 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://www.ubuntu-it.org/ + 1340 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 2 +Enter the code in the login page +https://ubuntu.com + 1341 + +== Login Code authentication (use 'r' to go back) == +1 - Wait for the login code result +2 - Regenerate code +Select action: 1 +PAM Authenticate() for user "user-integration-login-code" exited with success +PAM AcctMgmt() exited with success +> + + + + + + + +──────────────────────────────────────────────────────────────────────────────── diff --git a/pam/integration-tests/testdata/tapes/native/login_code.tape b/pam/integration-tests/testdata/tapes/native/login_code.tape new file mode 100644 index 000000000..d6e06a1c2 --- /dev/null +++ b/pam/integration-tests/testdata/tapes/native/login_code.tape @@ -0,0 +1,86 @@ +Output login_code.txt +Output login_code.gif # If we don't specify a .gif output, it will create a default out.gif file. + +# Configuration header to standardize the output. +# Does not work with the "Source" command. +Set Width 800 +# We need high terminal view, as vhs doesn't scroll: +# https://github.com/charmbracelet/vhs/issues/404 +Set Height 1050 +# TODO: Ideally, we should use Ubuntu Mono. However, the github runner is still on Jammy, which does not have it. +# We should update this to use Ubuntu Mono once the runner is updated. +Set FontFamily "Monospace" +Set FontSize 13 +Set Padding 0 +Set Margin 0 +Set Shell bash + +Hide +Type "./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true disable_qrcode_rendering=true" +Enter +Sleep 300ms +Show + +Hide +Type "user-integration-login-code" +Sleep 300ms +Show + +Hide +Enter +Sleep 300ms +Show + +Hide +Type "2" +Enter +Sleep 500ms +Show + +Hide +Type "r" +Enter +Sleep 300ms +Show + +Hide +Type "2" +Enter +Sleep 300ms +Show + +Hide +Type "2" +Enter +Sleep 500ms +Show + +Hide +Type "2" +Enter +Sleep 500ms +Show + +Hide +Type "2" +Enter +Sleep 500ms +Show + +Hide +Type "2" +Enter +Sleep 500ms +Show + +Hide +Type "1" +Enter +Sleep 300ms +Show + +Hide +Sleep 3s +Show + +Sleep 300ms diff --git a/pam/internal/adapter/model.go b/pam/internal/adapter/model.go index cc59a6387..abe08bce6 100644 --- a/pam/internal/adapter/model.go +++ b/pam/internal/adapter/model.go @@ -112,7 +112,11 @@ func (m *UIModel) Init() tea.Cmd { m.gdmModel = gdmModel{pamMTx: m.PamMTx} cmds = append(cmds, m.gdmModel.Init()) case Native: - m.nativeModel = nativeModel{pamMTx: m.PamMTx, nssClient: m.NssClient} + m.nativeModel = nativeModel{ + pamMTx: m.PamMTx, + nssClient: m.NssClient, + disableQrCodeRendering: m.DisableQrCodeRendering, + } cmds = append(cmds, m.nativeModel.Init()) } diff --git a/pam/internal/adapter/nativemodel.go b/pam/internal/adapter/nativemodel.go index ef82da406..f66d686a2 100644 --- a/pam/internal/adapter/nativemodel.go +++ b/pam/internal/adapter/nativemodel.go @@ -24,6 +24,8 @@ type nativeModel struct { pamMTx pam.ModuleTransaction nssClient authd.NSSClient + disableQrCodeRendering bool + availableBrokers []*authd.ABResponse_BrokerInfo authModes []*authd.GAMResponse_AuthenticationMode selectedAuthMode string @@ -81,6 +83,11 @@ func (m *nativeModel) Init() tea.Cmd { requiredWithBooleans := "required:true,false" optionalWithBooleans := "optional:true,false" + qrcodeContentSupportMode := required + if m.disableQrCodeRendering { + qrcodeContentSupportMode = optional + } + return supportedUILayoutsReceived{ layouts: []*authd.UILayout{ { @@ -92,7 +99,7 @@ func (m *nativeModel) Init() tea.Cmd { }, { Type: "qrcode", - Content: &required, + Content: &qrcodeContentSupportMode, Code: &optional, Wait: &requiredWithBooleans, Label: &optional, @@ -694,6 +701,9 @@ func (m nativeModel) handleQrCode() tea.Cmd { } func (m nativeModel) isQrcodeRenderingSupported() bool { + if m.disableQrCodeRendering { + return false + } switch m.serviceName { case polkitServiceName: return false