diff --git a/pam/integration-tests/native_test.go b/pam/integration-tests/native_test.go index fd785979..709f60b4 100644 --- a/pam/integration-tests/native_test.go +++ b/pam/integration-tests/native_test.go @@ -33,6 +33,7 @@ func TestNativeAuthenticate(t *testing.T) { termEnv string sessionEnv string pamUser string + pamServiceName string }{ "Authenticate user successfully": {tape: "simple_auth"}, "Authenticate user successfully with preset user": {tape: "simple_auth_with_preset_user"}, @@ -42,6 +43,7 @@ func TestNativeAuthenticate(t *testing.T) { "Authenticate user with qr code in a TTY": {tape: "qr_code", pamUser: "user-integration-qr-code-tty", termEnv: "linux"}, "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 and reset password while enforcing policy": {tape: "mandatory_password_reset"}, "Authenticate user and offer password reset": {tape: "optional_password_reset_skip"}, "Authenticate user and accept password reset": {tape: "optional_password_reset_accept"}, @@ -102,6 +104,9 @@ func TestNativeAuthenticate(t *testing.T) { if tc.pamUser != "" { cmd.Env = append(cmd.Env, fmt.Sprintf("AUTHD_PAM_CLI_USER=%s", tc.pamUser)) } + if tc.pamServiceName != "" { + cmd.Env = append(cmd.Env, fmt.Sprintf("AUTHD_PAM_CLI_SERVICE=%s", tc.pamServiceName)) + } if tc.termEnv != "" { cmd.Env = append(cmd.Env, fmt.Sprintf("AUTHD_PAM_CLI_TERM=%s", tc.termEnv)) } 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 new file mode 100644 index 00000000..96d3b3dc --- /dev/null +++ b/pam/integration-tests/testdata/TestNativeAuthenticate/golden/authenticate_user_with_qr_code_in_polkit @@ -0,0 +1,855 @@ +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true +== Broker selection (use 'r' to go back) == +1 - local +2 - ExampleBroker +Select broker: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> if [ -v AUTHD_PAM_CLI_TERM ]; then export TERM=${AUTHD_PAM_CLI_TERM}; fi +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true +== 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: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> if [ -v AUTHD_PAM_CLI_TERM ]; then export TERM=${AUTHD_PAM_CLI_TERM}; fi +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true +== 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 - Send URL to user-integration-qr-code-screen@gmail.com +3 - Use your fido device foo +4 - Use your phone +33… +5 - Use your phone +1… +6 - Pin code +7 - Use a QR code +8 - Authentication code +Select authentication mode: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> if [ -v AUTHD_PAM_CLI_TERM ]; then export TERM=${AUTHD_PAM_CLI_TERM}; fi +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true +== 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 - Send URL to user-integration-qr-code-screen@gmail.com +3 - Use your fido device foo +4 - Use your phone +33… +5 - Use your phone +1… +6 - Pin code +7 - Use a QR code +8 - Authentication code +Select authentication mode: 7 +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 +2 - Regenerate code +Select action: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> if [ -v AUTHD_PAM_CLI_TERM ]; then export TERM=${AUTHD_PAM_CLI_TERM}; fi +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true +== 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 - Send URL to user-integration-qr-code-screen@gmail.com +3 - Use your fido device foo +4 - Use your phone +33… +5 - Use your phone +1… +6 - Pin code +7 - Use a QR code +8 - Authentication code +Select authentication mode: 7 +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 +2 - Regenerate code +Select action: 2 +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 +2 - Regenerate code +Select action: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> if [ -v AUTHD_PAM_CLI_TERM ]; then export TERM=${AUTHD_PAM_CLI_TERM}; fi +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true +== 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 - Send URL to user-integration-qr-code-screen@gmail.com +3 - Use your fido device foo +4 - Use your phone +33… +5 - Use your phone +1… +6 - Pin code +7 - Use a QR code +8 - Authentication code +Select authentication mode: 7 +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 +2 - Regenerate code +Select action: 2 +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 +2 - Regenerate code +Select action: 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> if [ -v AUTHD_PAM_CLI_TERM ]; then export TERM=${AUTHD_PAM_CLI_TERM}; fi +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true +== 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 - Send URL to user-integration-qr-code-screen@gmail.com +3 - Use your fido device foo +4 - Use your phone +33… +5 - Use your phone +1… +6 - Pin code +7 - Use a QR code +8 - Authentication code +Select authentication mode: 7 +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 +2 - Regenerate code +Select action: 2 +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 +2 - Regenerate code +Select action: 1 +PAM Authenticate() for user "user-integration-qr-code-screen" exited with success +PAM AcctMgmt() exited with success +> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── +> if [ -v AUTHD_PAM_CLI_TERM ]; then export TERM=${AUTHD_PAM_CLI_TERM}; fi +> ./pam_authd login socket=${AUTHD_TESTS_CLI_AUTHENTICATE_TESTS_SOCK} force_native_client=true +== 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 - Send URL to user-integration-qr-code-screen@gmail.com +3 - Use your fido device foo +4 - Use your phone +33… +5 - Use your phone +1… +6 - Pin code +7 - Use a QR code +8 - Authentication code +Select authentication mode: 7 +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 +2 - Regenerate code +Select action: 2 +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 +2 - Regenerate code +Select action: 1 +PAM Authenticate() for user "user-integration-qr-code-screen" exited with success +PAM AcctMgmt() exited with success +> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +──────────────────────────────────────────────────────────────────────────────── diff --git a/pam/internal/adapter/nativemodel.go b/pam/internal/adapter/nativemodel.go index 707b6d0c..a9b4ffae 100644 --- a/pam/internal/adapter/nativemodel.go +++ b/pam/internal/adapter/nativemodel.go @@ -28,11 +28,16 @@ type nativeModel struct { selectedAuthMode string uiLayout *authd.UILayout + serviceName string currentStage proto.Stage busy bool } -const nativeCancelKey = "r" +const ( + nativeCancelKey = "r" + + polkitServiceName = "polkit-1" +) // nativeBrokerSelection is the internal event to notify that a stage change is requested. type nativeChangeStage ChangeStage @@ -63,6 +68,12 @@ var errNotAnInteger = errors.New("parsed value is not an integer") func (m *nativeModel) Init() tea.Cmd { m.currentStage = proto.Stage(-1) + var err error + m.serviceName, err = m.pamMTx.GetItem(pam.Service) + if err != nil { + log.Errorf(context.TODO(), "failed to get the PAM service: %v", err) + } + return func() tea.Msg { required, optional := "required", "optional" supportedEntries := "optional:chars,chars_password,digits,digits_password" @@ -589,10 +600,16 @@ func (m nativeModel) handleQrCode() tea.Cmd { var qrcodeView []string qrcodeView = append(qrcodeView, m.uiLayout.GetLabel()) - qrcode := m.renderQrCode(qrCode) - qrcodeView = append(qrcodeView, qrcode) + var firstQrCodeLine string + if m.isQrcodeRenderingSupported() { + qrcode := m.renderQrCode(qrCode) + qrcodeView = append(qrcodeView, qrcode) + firstQrCodeLine = strings.SplitN(qrcode, "\n", 2)[0] + } + if firstQrCodeLine == "" { + firstQrCodeLine = m.uiLayout.GetContent() + } - firstQrCodeLine := strings.SplitN(qrcode, "\n", 2)[0] centeredContent := centerString(m.uiLayout.GetContent(), firstQrCodeLine) qrcodeView = append(qrcodeView, centeredContent) @@ -635,6 +652,15 @@ func (m nativeModel) handleQrCode() tea.Cmd { } } +func (m nativeModel) isQrcodeRenderingSupported() bool { + switch m.serviceName { + case polkitServiceName: + return false + default: + return true + } +} + func centerString(s string, reference string) string { sizeDiff := len([]rune(reference)) - len(s) if sizeDiff <= 0 { diff --git a/pam/main-cli.go b/pam/main-cli.go index 361ac7ec..ba25490e 100644 --- a/pam/main-cli.go +++ b/pam/main-cli.go @@ -26,6 +26,7 @@ func main() { cliPath := os.Getenv("AUTHD_PAM_CLI_PATH") testName := os.Getenv("AUTHD_PAM_CLI_TEST_NAME") pamUser := os.Getenv("AUTHD_PAM_CLI_USER") + pamService := os.Getenv("AUTHD_PAM_CLI_SERVICE") tmpDir, err := os.MkdirTemp(os.TempDir(), "pam-cli-tester-") if err != nil { @@ -65,7 +66,10 @@ func main() { action, args := os.Args[1], os.Args[2:] args = append(defaultArgs, args...) - serviceFile, err := pam_test.CreateService(tmpDir, "authd-cli", []pam_test.ServiceLine{ + if pamService == "" { + pamService = "authd-cli" + } + serviceFile, err := pam_test.CreateService(tmpDir, pamService, []pam_test.ServiceLine{ {Action: pam_test.Auth, Control: pam_test.SufficientRequisite, Module: execModule, Args: args}, {Action: pam_test.Auth, Control: pam_test.Sufficient, Module: pam_test.Ignore.String()}, {Action: pam_test.Account, Control: pam_test.SufficientRequisite, Module: execModule, Args: args},