Add admin authentication: local accounts, revocable sessions, mandatory TOTP #18
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/admin-auth"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What does this PR do?
Phase 8 increment 1: the admin service gains real authentication, implementing D-0032 (auth model) and D-0033 (exposure/TLS), both recorded in DECISIONS.md in this PR.
Authentication. Local accounts with a two-stage login: password, then TOTP or a recovery code. The server-side session and its cookie exist only after the second factor succeeds (fixation-safe); between stages a Data Protection-encrypted, 5-minute pending cookie carries the user id. TOTP is first-party RFC 6238 (verified against the RFC test vectors), enrollment is manual-entry via otpauth URI + base32 secret, and ten single-use SHA-256-hashed recovery codes round out the second factor - no SMS, no email, no QR dependency. Passwords hash with PasswordHasher (PBKDF2-HMAC-SHA512) at 210,000 iterations, minimum length 20.
Sessions. The cookie carries only user + session ids; every request validates against the sessions registry: idle timeout (48 h default), absolute lifetime (14 d default, 30 d configurable ceiling), revocation with sign-out-everywhere and a visible session list, and IP binding in strict | subnet | log-only modes (default strict). Step-up 2FA guards sensitive operations from day one (TOTP re-enrollment and recovery-code regeneration demand a fresh step-up).
Exposure (D-0033). Modes: loopback (default), direct (Kestrel terminates TLS from mounted PEM), proxy (fail-closed forwarded-header trust). Startup refuses misconfigured direct/proxy modes. A fail-closed AllowedSources CIDR gate runs ahead of authentication (empty list = loopback only); the compose example carries a strong warning against 0.0.0.0/0 and recommends a self-hosted VPN. Per-IP rate limiting on /auth/*, tightened Kestrel limits, CSP/nosniff/no-referrer headers, HSTS outside loopback.
Self-monitoring. Every auth event is appended to the audit ledger; failures are additionally persisted as
AdminAuthEventpipeline events and enqueued for correlation - Viegard watches attacks on its own gate, and Phase 7 action providers will be able to close that loop.Review hardening (applied after independent review of the generated implementation): unknown/locked usernames burn a real hash verification so there is no username-existence timing oracle; second-factor failures count toward the same lockout as password failures, and lockout is enforced at the 2FA stage; session revocation verifies the posted session id belongs to the caller.
Increments 2 and 3 (WebAuthn via fido2-net-lib, in-process ACME) follow after their supply-chain reviews; tracked in TODO.md.
How was this tested?
dotnet build- 0 errors, 0 warningsdotnet test- 301 passed (22 new), 9 skipped (live-PostgreSQL integration tests)Checklist