From 4846715b350b536fb9ca19f74cf700913eb329c8 Mon Sep 17 00:00:00 2001 From: louis Date: Sat, 31 Oct 2026 23:31:09 +0100 Subject: [PATCH] Sign in with security keys Users with security keys get a "Use security key" button in the code step. userli.js passes the options from Userli to the browser and submits the assertion, which the plugin sends to Userli with the challenge from its session. Co-Authored-By: Claude Opus 5.5 --- README.md | 4 +- localization/de_DE.inc | 4 ++ localization/en_US.inc | 4 ++ screenshots/security-key.png | Bin 0 -> 89971 bytes tests/UserliLoginTest.php | 87 +++++++++++++++++++++++++++++++++++ tests/bootstrap.php | 28 +++++++++++ userli.js | 87 +++++++++++++++++++++++++++++++++++ userli.php | 79 +++++++++++++++++++++++++++---- 8 files changed, 283 insertions(+), 10 deletions(-) create mode 100644 screenshots/security-key.png create mode 100644 userli.js diff --git a/README.md b/README.md index c5f4dbe..eb87d29 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,11 @@ A Roundcube plugin for [Userli](https://github.com/systemli/userli): -* **Login with two-factor authentication:** the plugin checks the password and, for users with 2FA, asks for the TOTP or backup code in a second step. Userli then issues a webmail credential, which Roundcube uses for IMAP and SMTP instead of the password. It is valid for 12 hours; the Roundcube session ends with it. Logging out revokes it. With a Userli version without the webmail login endpoint, the plugin keeps logging in with the password. +* **Login with two-factor authentication:** the plugin checks the password and, for users with 2FA, asks for the TOTP or backup code in a second step. Users with security keys can use their key there instead. This needs a Userli version with security keys, a common parent domain of Userli and Roundcube as *Security Key Domain*, and the Roundcube origin in *Additional Security Key Origins* (see the [Userli documentation](https://systemli.github.io/userli/operations/integrations/roundcube/#security-keys)). Userli then issues a webmail credential, which Roundcube uses for IMAP and SMTP instead of the password. It is valid for 12 hours; the Roundcube session ends with it. Logging out revokes it. With a Userli version without the webmail login endpoint, the plugin keeps logging in with the password. ![Two-factor code step](screenshots/twofactor.png) + + ![Security key step](screenshots/security-key.png) * **Alias identities:** at login, the plugin creates a Roundcube identity for each alias of the user. ![Alias identities](screenshots/aliases.png) diff --git a/localization/de_DE.inc b/localization/de_DE.inc index a1a2aae..7ef8a36 100644 --- a/localization/de_DE.inc +++ b/localization/de_DE.inc @@ -2,6 +2,7 @@ $labels = []; $labels['twofactor_code'] = 'Zwei-Faktor-Code'; +$labels['use_security_key'] = 'Sicherheitsschlüssel verwenden'; $labels['use_another_account'] = 'Anderes Konto verwenden'; $messages = []; @@ -11,3 +12,6 @@ $messages['twofactor_expired'] = 'Die Anmeldung hat zu lange gedauert. Bitte gib $messages['too_many_attempts'] = 'Zu viele Anmeldeversuche. Bitte versuche es später erneut.'; $messages['password_change_required'] = 'Bitte ändere zuerst dein Passwort in deinen Kontoeinstellungen.'; $messages['login_unavailable'] = 'Die Anmeldung ist gerade nicht möglich. Bitte versuche es später erneut.'; +$messages['twofactor_required_webauthn'] = 'Verwende deinen Sicherheitsschlüssel oder gib den Code aus deiner Authenticator-App oder einen Backup-Code ein.'; +$messages['webauthn_invalid'] = 'Der Sicherheitsschlüssel konnte nicht überprüft werden. Bitte versuche es erneut.'; +$messages['webauthn_failed'] = 'Der Sicherheitsschlüssel wurde nicht verwendet. Bitte versuche es erneut oder gib einen Code ein.'; diff --git a/localization/en_US.inc b/localization/en_US.inc index b68c44f..ceac7fc 100644 --- a/localization/en_US.inc +++ b/localization/en_US.inc @@ -2,6 +2,7 @@ $labels = []; $labels['twofactor_code'] = 'Two-factor code'; +$labels['use_security_key'] = 'Use security key'; $labels['use_another_account'] = 'Use another account'; $messages = []; @@ -11,3 +12,6 @@ $messages['twofactor_expired'] = 'The login took too long. Please enter your pas $messages['too_many_attempts'] = 'Too many login attempts. Please try again later.'; $messages['password_change_required'] = 'Please change your password in your account settings first.'; $messages['login_unavailable'] = 'Login is currently not possible. Please try again later.'; +$messages['twofactor_required_webauthn'] = 'Use your security key, or enter the code from your authenticator app or a backup code.'; +$messages['webauthn_invalid'] = 'The security key could not be verified. Please try again.'; +$messages['webauthn_failed'] = 'The security key was not used. Please try again or enter a code.'; diff --git a/screenshots/security-key.png b/screenshots/security-key.png new file mode 100644 index 0000000000000000000000000000000000000000..c54b73171be22ec84bb6c923c9ce73c7241fc25c GIT binary patch literal 89971 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 literal 0 HcmV?d00001 diff --git a/tests/UserliLoginTest.php b/tests/UserliLoginTest.php index 39aa1da..953970f 100644 --- a/tests/UserliLoginTest.php +++ b/tests/UserliLoginTest.php @@ -197,6 +197,93 @@ public function testWrongCodeKeepsCodeForm(): void $this->assertSame('totp@example.org', $_SESSION['userli_2fa']['user']); } + public function testCodeFormWithoutSecurityKeysHasNoKeyButton(): void + { + $this->client(new FakeResponse(401, ['message' => 'twofactor required'])); + + $this->login('totp@example.org', 'password'); + $form = $this->plugin->modify_login_form(['hidden' => [], 'inputs' => [], 'buttons' => []]); + + $this->assertArrayNotHasKey('userli_webauthn', $form['buttons']); + $this->assertSame([], $this->plugin->scripts); + $this->assertNull($_SESSION['userli_2fa']['webauthn']); + } + + public function testTwofactorRequiredWithSecurityKeyOffersKey(): void + { + $options = ['challenge' => 'Y2hhbGxlbmdl', 'rpId' => 'example.org', 'allowCredentials' => [['type' => 'public-key', 'id' => 'Y3JlZA']]]; + $this->client(new FakeResponse(401, ['message' => 'twofactor required', 'webauthn' => $options])); + + $args = $this->login('key@example.org', 'password'); + $form = $this->plugin->modify_login_form(['hidden' => [], 'inputs' => [], 'buttons' => []]); + + $this->assertSame('userli.twofactor_required_webauthn', $args['error']); + $this->assertSame(['userli.js'], $this->plugin->scripts); + $this->assertSame($options, $this->plugin->api->output->env['userli_webauthn']); + $this->assertContains('userli.webauthn_failed', $this->plugin->api->output->labels); + $this->assertStringContainsString('name="_userli_webauthn"', $form['hidden']['userli_webauthn']); + $this->assertStringContainsString('id="rcmloginuserlikey"', $form['buttons']['userli_webauthn']['content']); + $this->assertSame($options, $_SESSION['userli_2fa']['webauthn']); + } + + public function testSecurityKeyStepSendsAssertionWithIssuedChallenge(): void + { + $_SESSION['userli_2fa'] = ['user' => 'key@example.org', 'pass' => $this->rcmail->encrypt('password'), 'time' => time(), 'webauthn' => ['challenge' => 'aXNzdWVk']]; + $_POST['_userli_webauthn'] = json_encode([ + 'challenge' => 'b3RoZXI', + 'credentialId' => 'Y3JlZA', + 'clientDataJSON' => 'Y2xpZW50', + 'authenticatorData' => 'YXV0aA', + 'signature' => 'c2ln', + 'userHandle' => null, + ]); + $client = $this->client(new FakeResponse(200, ['password' => 'credential'])); + + $this->plugin->startup(['task' => 'login', 'action' => 'login']); + $args = $this->login('key@example.org', ''); + + $this->assertSame('credential', $args['pass']); + $this->assertSame([ + 'email' => 'key@example.org', + 'password' => 'password', + 'code' => '', + 'webauthn' => [ + 'credentialId' => 'Y3JlZA', + 'clientDataJSON' => 'Y2xpZW50', + 'authenticatorData' => 'YXV0aA', + 'signature' => 'c2ln', + 'challenge' => 'aXNzdWVk', + ], + ], $client->calls[0]['json']); + } + + public function testRejectedSecurityKeyKeepsStepWithNewChallenge(): void + { + $_SESSION['userli_2fa'] = ['user' => 'key@example.org', 'pass' => $this->rcmail->encrypt('password'), 'time' => time(), 'webauthn' => ['challenge' => 'b2xk']]; + $_POST['_userli_webauthn'] = json_encode(['credentialId' => 'Y3JlZA']); + $this->client(new FakeResponse(401, ['message' => 'authentication failed', 'webauthn' => ['challenge' => 'bmV3']])); + + $this->plugin->startup(['task' => 'login', 'action' => 'login']); + $args = $this->login('key@example.org', ''); + $this->plugin->modify_login_form(['hidden' => [], 'inputs' => [], 'buttons' => []]); + + $this->assertSame('userli.webauthn_invalid', $args['error']); + $this->assertSame(['challenge' => 'bmV3'], $_SESSION['userli_2fa']['webauthn']); + $this->assertSame(401, $this->plugin->unauthenticated(['task' => 'login', 'http_code' => 401])['http_code']); + } + + public function testSecurityKeyWithoutPendingLoginIsNotSent(): void + { + $_POST['_userli_webauthn'] = json_encode(['credentialId' => 'Y3JlZA']); + $client = $this->client(); + + $this->plugin->startup(['task' => 'login', 'action' => 'login']); + $args = $this->login('key@example.org', ''); + + $this->assertSame([], $client->calls); + $this->assertSame('userli.twofactor_expired', $args['error']); + } + public function testCodeFormOffersAnotherAccount(): void { $this->client(new FakeResponse(401, ['message' => 'twofactor required'])); diff --git a/tests/bootstrap.php b/tests/bootstrap.php index c44b143..3375fcf 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -12,15 +12,29 @@ class rcube_plugin { public $task; public $api; + public $scripts = []; private $hooks = []; public function __construct() { $this->api = new stdClass(); $this->api->output = new class { + public $env = []; + public $labels = []; + public function add_script($script) { } + + public function set_env($name, $value) + { + $this->env[$name] = $value; + } + + public function add_label(...$names) + { + array_push($this->labels, ...$names); + } }; } @@ -28,6 +42,11 @@ protected function add_texts($dir) { } + public function include_script($fn) + { + $this->scripts[] = $fn; + } + public function gettext($name) { return $name; @@ -156,6 +175,15 @@ public static function a($attrib, $content) return '' . $content . ''; } + public static function tag($tagname, $attrib = [], $content = '') + { + $attrs = ''; + foreach ($attrib as $key => $value) { + $attrs .= ' ' . $key . '="' . htmlspecialchars((string) $value) . '"'; + } + return '<' . $tagname . $attrs . '>' . $content . ''; + } + public static function quote($str) { return htmlspecialchars((string) $str); diff --git a/userli.js b/userli.js new file mode 100644 index 0000000..1cea169 --- /dev/null +++ b/userli.js @@ -0,0 +1,87 @@ +/** + * Userli: sign in with a security key in the two-factor step + * + * Passes the options from userli (env userli_webauthn) to the browser and + * submits the assertion, base64url encoded, in the hidden field _userli_webauthn. + */ + +(function () { + function decode(value) { + var base64 = value.replace(/-/g, "+").replace(/_/g, "/"); + var binary = atob(base64 + "===".slice((base64.length + 3) % 4)); + return Uint8Array.from(binary, function (c) { + return c.charCodeAt(0); + }); + } + + function encode(buffer) { + var binary = String.fromCharCode.apply(null, new Uint8Array(buffer)); + return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); + } + + function useSecurityKey(button) { + var options = rcmail.env.userli_webauthn; + var field = document.getElementById("rcmloginuserliwebauthn"); + var form = field.form; + var publicKey = Object.assign({}, options, { + challenge: decode(options.challenge), + allowCredentials: (options.allowCredentials || []).map(function (credential) { + return Object.assign({}, credential, { id: decode(credential.id) }); + }), + }); + + button.disabled = true; + navigator.credentials + .get({ publicKey: publicKey }) + .then(function (credential) { + var response = credential.response; + field.value = JSON.stringify({ + credentialId: encode(credential.rawId), + clientDataJSON: encode(response.clientDataJSON), + authenticatorData: encode(response.authenticatorData), + signature: encode(response.signature), + userHandle: response.userHandle ? encode(response.userHandle) : null, + }); + + // The code is not needed with a security key + if (form.elements._userli_code) { + form.elements._userli_code.required = false; + form.elements._userli_code.value = ""; + } + + // Like the submit button, so Roundcube shows its loading state + if (form.requestSubmit) { + form.requestSubmit(); + } else { + form.submit(); + } + }) + .catch(function () { + button.disabled = false; + rcmail.display_message(rcmail.get_label("webauthn_failed", "userli"), "error"); + }); + } + + function init() { + var button = document.getElementById("rcmloginuserlikey"); + if (!button) { + return; + } + + if (!window.PublicKeyCredential || !rcmail.env.userli_webauthn) { + button.hidden = true; + return; + } + + button.addEventListener("click", function () { + useSecurityKey(button); + }); + } + + // Roundcube's init event may have fired before plugin scripts run, the env is set once the DOM is parsed + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); + } else { + init(); + } +})(); diff --git a/userli.php b/userli.php index d59ba0f..daaa97d 100644 --- a/userli.php +++ b/userli.php @@ -3,8 +3,8 @@ /** * Userli * - * Logs in with two-factor authentication through the userli API and - * updates user identities from userli aliases at login + * Logs in with two-factor authentication (code or security key) through the + * userli API and updates user identities from userli aliases at login * * @version 0.2 * @author systemli @@ -87,6 +87,7 @@ public function modify_login_form(array $args): array $_SESSION["userli_2fa"] = $this->pending; $user = new html_hiddenfield(["name" => "_user", "value" => $this->pending["user"]]); + $webauthn = $this->pending["webauthn"] ?? null; $code = new html_inputfield([ "name" => "_userli_code", "id" => "rcmloginuserlicode", @@ -103,6 +104,22 @@ public function modify_login_form(array $args): array "content" => $code->show(), ], ]; + if (is_array($webauthn)) { + // userli.js passes the options to the browser and submits the assertion in _userli_webauthn + $this->include_script("userli.js"); + $this->api->output->set_env("userli_webauthn", $webauthn); + $this->api->output->add_label("userli.webauthn_failed"); + $assertion = new html_hiddenfield(["name" => "_userli_webauthn", "id" => "rcmloginuserliwebauthn"]); + $args["hidden"]["userli_webauthn"] = $assertion->show(); + $args["buttons"]["userli_webauthn"] = [ + "outterclass" => "formbuttons", + "content" => html::tag( + "button", + ["type" => "button", "id" => "rcmloginuserlikey", "class" => "button"], + html::quote($this->gettext("use_security_key")), + ), + ]; + } $args["buttons"]["userli_cancel"] = [ "outterclass" => "formbuttons", "content" => html::a(["href" => "./?_task=login&_userli_cancel=1"], html::quote($this->gettext("use_another_account"))), @@ -112,7 +129,7 @@ public function modify_login_form(array $args): array } /** - * Exchange the password (and 2FA code) for a webmail credential, which is used for IMAP and SMTP + * Exchange the password (and 2FA code or security key assertion) for a webmail credential, which is used for IMAP and SMTP */ public function authenticate(array $args): array { @@ -123,10 +140,11 @@ public function authenticate(array $args): array $rcmail = rcmail::get_instance(); $code = trim((string) rcube_utils::get_input_string("_userli_code", rcube_utils::INPUT_POST)); + $assertion = $this->get_webauthn_assertion(); $pending = $this->pending; $this->pending = null; - if ($code !== "") { + if ($code !== "" || $assertion !== null) { if ($pending === null || $pending["user"] !== $args["user"]) { $args["abort"] = true; $args["error"] = "userli.twofactor_expired"; @@ -135,6 +153,10 @@ public function authenticate(array $args): array } $args["pass"] = (string) $rcmail->decrypt($pending["pass"]); + if ($assertion !== null) { + // The challenge userli issued for this login, not one from the browser + $assertion["challenge"] = (string) ($pending["webauthn"]["challenge"] ?? ""); + } } else { $pending = null; } @@ -142,11 +164,16 @@ public function authenticate(array $args): array // The aliases API needs the password, the credential is rejected there $this->pass = $args["pass"]; - $response = $this->request_api("login", [ + $data = [ "email" => $args["user"], "password" => $args["pass"], "code" => $code, - ]); + ]; + if ($assertion !== null) { + $data["webauthn"] = $assertion; + } + + $response = $this->request_api("login", $data); $status = $response["status"] ?? null; $body = $response["body"] ?? []; @@ -169,16 +196,18 @@ public function authenticate(array $args): array $message = $body["message"] ?? ""; if ($status === 401 && $pending !== null) { - // Wrong code: let the user try again until the pending login expires + // Wrong code or key: let the user try again until the pending login expires, with a new challenge + $pending["webauthn"] = $this->get_webauthn_options($body); $this->pending = $pending; - $args["error"] = "userli.twofactor_invalid"; + $args["error"] = $assertion !== null ? "userli.webauthn_invalid" : "userli.twofactor_invalid"; } elseif ($status === 401 && $message === "twofactor required") { $this->pending = [ "user" => $args["user"], "pass" => $rcmail->encrypt($args["pass"]), "time" => time(), + "webauthn" => $this->get_webauthn_options($body), ]; - $args["error"] = "userli.twofactor_required"; + $args["error"] = $this->pending["webauthn"] !== null ? "userli.twofactor_required_webauthn" : "userli.twofactor_required"; $this->twofactor_required = true; } elseif ($status === 429) { $args["error"] = "userli.too_many_attempts"; @@ -338,6 +367,38 @@ public function login_after_update_identities(): void } } + /** + * Options for navigator.credentials.get() that userli sends for users with security keys + */ + private function get_webauthn_options(array $body): ?array + { + $options = $body["webauthn"] ?? null; + + return is_array($options) && is_string($options["challenge"] ?? null) ? $options : null; + } + + /** + * The assertion that userli.js submitted, base64url encoded, or null without one + */ + private function get_webauthn_assertion(): ?array + { + $json = (string) rcube_utils::get_input_string("_userli_webauthn", rcube_utils::INPUT_POST); + if ($json === "") { + return null; + } + + $data = json_decode($json, true); + $assertion = []; + foreach (["credentialId", "clientDataJSON", "authenticatorData", "signature", "userHandle"] as $key) { + if (is_array($data) && is_string($data[$key] ?? null) && $data[$key] !== "") { + $assertion[$key] = $data[$key]; + } + } + + // Incomplete assertions are sent anyway, userli rejects them + return $assertion; + } + /** * POST to the userli Roundcube API, without throwing on 4xx/5xx responses */