mirror of
https://github.com/azaion/admin.git
synced 2026-06-21 17:41:09 +00:00
4bf2e689cb
AZ-556 collapses every /login rejection (unknown email, wrong password, disabled account, lockout, per-account rate limit) to a single opaque InvalidCredentials (70) → 401 response. Timing equalised by a new Security.VerifyDummy using the same Argon2id parameters. Audit log keeps the rejection category internally (login_failed_unknown_email, login_failed_disabled). AZ-557 wires /login/mfa into the existing per-account lockout + rate-limit pipeline. MFA failures now feed UserService's shared failure accounting (RegisterMfaFailedLogin → RegisterFailedLoginCore) and CountRecentFailedLogins aggregates both login_failed and mfa_login_failed rows. Successful TOTP / recovery resets the counter. Deprecated five legacy ExceptionEnum members (NoEmailFound, WrongPassword, UserDisabled, AccountLocked, LoginRateLimited) — kept defined for cross-workspace verifier compatibility during the deprecation window. E2E coverage updated: AuthTests (byte-identical body assertion + disabled-account audit row), LoginRateLimitTests, PasswordHashingTests, SecurityTests, plus four new MfaLoginTests (AC1, AC2, AC5, AC7). Code review verdict: PASS_WITH_WARNINGS (batch_06_cycle2_review.md). Co-authored-by: Cursor <cursoragent@cursor.com>
33 lines
1.4 KiB
C#
33 lines
1.4 KiB
C#
namespace Azaion.Common.Entities;
|
|
|
|
public class AuditEvent
|
|
{
|
|
public long Id { get; set; }
|
|
public string EventType { get; set; } = null!;
|
|
public DateTime OccurredAt { get; set; }
|
|
public string? Email { get; set; }
|
|
public string? Ip { get; set; }
|
|
public string? Metadata { get; set; }
|
|
}
|
|
|
|
public static class AuditEventTypes
|
|
{
|
|
public const string LoginFailed = "login_failed";
|
|
public const string LoginLockout = "login_lockout";
|
|
public const string LoginSuccess = "login_success";
|
|
|
|
// AZ-556 — per-category internal forensics for unified `InvalidCredentials` wire
|
|
// response. SecOps can distinguish these in the audit_events table even though the
|
|
// /login response cannot be distinguished by an attacker.
|
|
public const string LoginFailedUnknownEmail = "login_failed_unknown_email";
|
|
public const string LoginFailedDisabled = "login_failed_disabled";
|
|
|
|
// AZ-534 — MFA lifecycle + login events.
|
|
public const string MfaEnroll = "mfa_enroll";
|
|
public const string MfaConfirm = "mfa_confirm";
|
|
public const string MfaDisable = "mfa_disable";
|
|
public const string MfaLoginSuccess = "mfa_login_success";
|
|
public const string MfaLoginFailed = "mfa_login_failed";
|
|
public const string MfaRecoveryUsed = "mfa_recovery_used";
|
|
}
|