internal/webauthn: vereinfachte, aber kryptographisch echte Challenge- Response-Zeremonie (Ed25519) statt des vollstaendigen W3C-WebAuthn- Drahtformats (CBOR-attestationObject/COSE), das ohne Browser-Umgebung hier nicht erzeugt/geprueft werden kann (siehe Paket-Dokumentation, analoge Einschraenkung wie IAM-05/IAM-06). Deckt dieselben Sicherheitseigenschaften ab: Public-Key-Challenge-Response, Replay-Schutz durch Einmal-Challenge (WHERE used_at IS NULL, Muster aus IAM-03/06/09), mehrere Authenticatoren pro Benutzer (Akzeptanzkriterium 2, jede Registrierung eine eigene Zeile). CompleteLogin komponiert auth.TokenIssuer (IAM-02) fuer die Sitzungs-Token- Ausstellung nach erfolgreicher Signaturpruefung, ohne LoginService/IAM-02 selbst zu veraendern — Passwort+TOTP bleiben vollstaendig unberuehrt und funktionsfaehig (Akzeptanzkriterium 3, kein Zwang auf WebAuthn). Pruefungen (ausgefuehrt auf root@192.168.1.131, go build/vet/test PASS): 1. Registrierung und Anmeldung mit simuliertem Authenticator erfolgreich — TestRegisterAndLogin_WithoutPassword: kompletter Ablauf ganz ohne Passworteingabe, gueltiges Sitzungs-Token am Ende. PASS. 2. Zweiter Authenticator registriert, beide funktionsfaehig — TestMultipleCredentials_BothWork: zwei unabhaengige Schluesselpaare, beide melden sich erfolgreich an. PASS. 3. Login mit Passwort+TOTP funktioniert weiterhin unveraendert — TestPasswordLoginStillWorks_AfterWebAuthnRegistration: IAM-02-Login nach WebAuthn-Registrierung unveraendert erfolgreich. PASS. Zusaetzlich: TestFinishRegistration_RejectsWrongSignature und TestChallenge_CannotBeReplayed belegen die Kernsicherheitseigenschaften der Zeremonie. PASS. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
24 lines
920 B
SQL
24 lines
920 B
SQL
-- Passwortlose Anmeldung via WebAuthn/Passkey (IAM-10, siehe
|
|
-- core-kanban/tickets/IAM-10.md).
|
|
CREATE TABLE webauthn_credentials (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES users(id),
|
|
device_name TEXT NOT NULL,
|
|
public_key BYTEA NOT NULL,
|
|
sign_count INT NOT NULL DEFAULT 0,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX webauthn_credentials_user_idx ON webauthn_credentials (user_id);
|
|
|
|
-- Einmal-Challenges fuer Registrierung/Anmeldung (Replay-Schutz).
|
|
CREATE TABLE webauthn_challenges (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES users(id),
|
|
challenge TEXT NOT NULL UNIQUE,
|
|
purpose TEXT NOT NULL CHECK (purpose IN ('register', 'login')),
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
used_at TIMESTAMPTZ,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|