https://bugs.koha-community.org/bugzilla3/show_bug.cgi?id=39601
Paul Derscheid <[email protected]> changed: What |Removed |Added ---------------------------------------------------------------------------- Attachment #185297|0 |1 is obsolete| | --- Comment #18 from Paul Derscheid <[email protected]> --- Created attachment 194697 --> https://bugs.koha-community.org/bugzilla3/attachment.cgi?id=194697&action=edit Bug 39601: Add staff passkeys (WebAuthn) support Introduce staff passkey (WebAuthn) registration and authentication in Koha. Provides REST endpoints, persistence, UI hooks, and session integration so staff can register a passkey against a patron record and authenticate on the staff login screen using platform authenticators. Implementation: - New helper module Koha::Auth::WebAuthn encapsulating origin/RP ID derivation, challenge generation and validation, patron resolution, base64url encoding utilities, and session management - New controller Koha::REST::V1::Webauthn with endpoints: - POST /api/v1/webauthn/register/challenge - POST /api/v1/webauthn/register - POST /api/v1/webauthn/authenticate/challenge - POST /api/v1/webauthn/authenticate - New typed exception classes in Koha::Exceptions::WebAuthn - Use Authen::WebAuthn validate_registration/validate_assertion - Generate cryptographically secure challenges via Bytes::Random::Secure; store challenge, patron_id and timestamp in the session with 10-minute TTL and consume-after-use to prevent replay - Handle base64url consistently for WebAuthn fields; convert to/from standard base64 at the API boundary - Derive origin and rp_id from StaffClientBaseURL (or the request URL) to enforce correct WebAuthn origins; support reverse proxy headers and http->https origin upgrade - Persist credentials (credential_id, public_key as raw bytes) in the new webauthn_credentials table; update sign_count and last_used_date after successful authentication - Build allowCredentials from stored credential IDs for authentication challenges - On successful authentication, verify account is not locked, issue a staff session and set the CGISESSID cookie so the user is logged in to the staff interface Security: - Challenge TTL (10 min) and single-use consumption prevent replay attacks - Fail-closed patron match guard rejects if either patron ID is undefined - Explicit credential pubkey existence check before assertion validation - account_locked check before issuing session - $is_https derived from already-upgraded origin (not recomputed) API: - Add api/v1/swagger/paths/webauthn.yaml defining the WebAuthn endpoints, request/response schemas (including rp_id/rpId, allowCredentials) - Register endpoints require catalogue permission - Authenticate endpoints are public (no x-koha-authorization) since they are login endpoints DB: - Add webauthn_credentials table via installer/data/mysql/atomicupdate/ bug_39601_add_passkey_support.pl and kohastructure.sql - PK: webauthn_credential_id (per SQL7), COLLATE=utf8mb4_unicode_ci, column COMMENTs, ON UPDATE CASCADE, VARBINARY(1024) for credential_id - Date columns: created_date (timestamp), last_used_date (datetime) per SQL14 - Add Koha::WebauthnCredential(s) object classes UI: - Staff login: add JS helper (auth-webauthn.inc) to request a challenge, convert base64url to bytes, call navigator.credentials.get, send results with credentials: "same-origin", and redirect to mainpage on success - Patron page: add JS helper (passkey-register.inc) to request a registration challenge, include RS256 in pubKeyCredParams for compatibility, convert base64url to bytes, and submit attestation for storage - Modern JS throughout (const/let, arrow functions, JSDoc, loop-based toBase64 to avoid stack overflow on large buffers) - aria-label on passkey login button for accessibility - __x() for translatable strings with placeholders Tests: - t/db_dependent/api/v1/webauthn.t: verify challenge endpoints accept patron_id and userid; return 404 when no credentials; include a mocked registration negative path; follow Koha testing conventions - t/db_dependent/Koha/WebauthnCredentials.t: cover ORM add/search/update/ delete with per-subtest transaction isolation Test plan: 1) Apply patches 2) Run database updates to create webauthn_credentials (updatedatabase). 3) Set StaffClientBaseURL to your staff URL (e.g., http://<name>-intra.localhost when using ktd_proxy, haven't tested with unproxied ktd) and ensure the staff interface is served over the same origin. 4) As a staff user, open a patron record and click Register Passkey from More. Complete the OS-native passkey dialog. Verify a row is stored in webauthn_credentials. - This worked well in Zen (Firefox under the hood), less so with Chromium. - Unsure whether ungoogled Chromium supports using the system password manager, worked with a browser-based password manager, though. - Best to test with many browsers! 5) Navigate to the staff login page and choose Sign in with passkey. Verify a challenge is returned, the browser prompts, and you are logged into the staff interface (redirect to mainpage). 6) Call authenticate_challenge for a patron without credentials and verify a 404 response. 7) Run: - prove t/db_dependent/Koha/WebauthnCredentials.t - prove t/db_dependent/api/v1/webauthn.t 8) Sign off or review and FQA. -- You are receiving this mail because: You are watching all bug changes. _______________________________________________ Koha-bugs mailing list [email protected] https://lists.koha-community.org/cgi-bin/mailman/listinfo/koha-bugs website : http://www.koha-community.org/ git : http://git.koha-community.org/ bugs : http://bugs.koha-community.org/
