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/

Reply via email to