mirror of
https://github.com/azaion/admin.git
synced 2026-06-21 16:21:10 +00:00
a77b3f8a59
Refreshes _docs/02_document/ to reflect the cycle-2 auth-modernization
+ CMMC hardening landings (AZ-531..AZ-538). Authoritative source for
the ripple set is ripple_log_cycle2.md.
Covered:
- architecture.md (section 1 rewritten, ADRs 6-9 added)
- data_model.md (sessions, audit_events, user columns, migrations)
- system-flows.md (F1 rewritten; F11-F17 added; F2/F7/F9 minor)
- module-layout.md (cycle-2 sub-component table)
- diagrams/flows/flow_login.md (dual-token + MFA)
- components/{01_data_layer,03_auth_and_security,05_admin_api}
- modules/ (12 new, 8 modified — full Argon2id/ES256/MFA/refresh
/mission/session/audit/jwks rollup)
- tests/{blackbox,security,traceability-matrix}
Step 13 (Update Docs) output for cycle 2.
Co-authored-by: Cursor <cursoragent@cursor.com>
3.7 KiB
3.7 KiB
Module: Azaion.Services.AuditLog
Purpose
Append-only audit trail for security-relevant events (login attempts, lockouts, MFA lifecycle). Also exposes the per-account sliding-window failed-login count consumed by UserService.ValidateUser's rate limit.
Added in cycle 2 (2026-05-14). Initially shipped with AZ-537 (login lockout + per-account rate-limit feed); MFA event types added by AZ-534 in the same cycle.
Public Interface
IAuditLog
| Method | Signature | Description |
|---|---|---|
RecordLoginFailed |
Task RecordLoginFailed(string email, CancellationToken ct = default) |
Inserts audit_events row with event_type='login_failed'. |
RecordLoginLockout |
Task RecordLoginLockout(string email, CancellationToken ct = default) |
Inserts event_type='login_lockout' (AZ-537 AC-6). |
RecordLoginSuccess |
Task RecordLoginSuccess(string email, CancellationToken ct = default) |
Inserts event_type='login_success'. |
RecordMfaEnroll / RecordMfaConfirm / RecordMfaDisable |
Task ...(string email, CancellationToken ct = default) |
MFA enrollment lifecycle. |
RecordMfaLoginSuccess / RecordMfaLoginFailed / RecordMfaRecoveryUsed |
Task ...(string email, CancellationToken ct = default) |
MFA login outcomes. |
CountRecentFailedLogins |
Task<int> CountRecentFailedLogins(string email, int windowSeconds, CancellationToken ct = default) |
Number of login_failed rows for the email within the last windowSeconds. Drives the per-account sliding-window rate limit (AZ-537 AC-2). |
Internal Logic
- Email normalisation — every insert and read lowercases the email (
ToLowerInvariant) so case-variant addresses can't bypass the rate limit. - IP capture — pulls
HttpContext.Connection.RemoteIpAddressviaIHttpContextAccessor. Null when there is no current request (background task). Null IPs are persisted as null, not omitted. - Insert path uses
dbFactory.RunAdmin(write privilege required); count usesdbFactory.Run(read-only). - Backing table —
public.audit_events, defined byenv/db/07_auth_lockout_and_audit.sql. Supporting indexaudit_events_event_type_email_idx (event_type, email, occurred_at DESC)makes the per-account sliding-window count O(window-rows).
Dependencies
IDbFactory— read + admin connectionsIHttpContextAccessor— for the request IPAuditEvententity,AuditEventTypesconstants
Consumers
UserService.ValidateUser— callsCountRecentFailedLogins(per-account rate limit),RecordLoginFailed,RecordLoginSuccess,RecordLoginLockout.MfaService— calls everyRecordMfa*method along the enroll/confirm/disable/login paths.
Data Models
Operates on the AuditEvent entity via AzaionDb.AuditEvents table.
Configuration
None directly. The window/threshold constants live on AuthConfig.RateLimit and AuthConfig.Lockout, consumed by the caller (UserService.ValidateUser).
External Integrations
PostgreSQL via IDbFactory.
Security
- Append-only by convention — no UPDATE/DELETE in code, and
azaion_adminonly hasINSERT, SELECTon the table. - The IP and email are PII; access to the table is gated to
azaion_admin(insert + read) andazaion_reader(read-only). No public endpoint surfaces audit rows directly. - The per-account sliding-window count is the foundation of CMMC AC.L2-3.1.8 enforcement; tampering with
audit_eventsbypasses the rate limit.
Tests
e2e/Azaion.E2E/Tests/RateLimitLockoutTests.cs— exercisesRecordLoginFailed+CountRecentFailedLoginsend-to-end via the lockout/rate-limit ACs.e2e/Azaion.E2E/Tests/MfaEnrollmentTests.csandMfaLoginTests.cs— assert the corresponding MFAaudit_eventsrows after each lifecycle event.