Files
SIG-CM2.0/src/api/SIGCM2.Infrastructure/Audit/SecurityEventLogger.cs
dmolinari a9838427a4 feat(udt-011): T400.30 — inject TimeProvider into Infrastructure critical services
AuditLogger, SecurityEventLogger: inject TimeProvider and use
_timeProvider.GetUtcNow().UtcDateTime for occurredAt timestamps.
JwtService: inject TimeProvider; use GetUtcNow() for token IssuedAt/Expires.
DI: update JwtService factory to pass sp.GetRequiredService<TimeProvider>().
Repositories: remove ?? DateTime.UtcNow fallback in UpdateAsync since callers
always provide FechaModificacion via domain mutators.
2026-04-18 10:12:24 -03:00

56 lines
1.8 KiB
C#

using Microsoft.Extensions.Options;
using SIGCM2.Application.Audit;
namespace SIGCM2.Infrastructure.Audit;
/// UDT-010 — ISecurityEventLogger implementation. Unlike AuditLogger this is NOT
/// fail-closed on missing actor: login failures have no ActorUserId by design.
/// Ip/UserAgent are pulled from IAuditContext when available (null in pre-auth paths).
public sealed class SecurityEventLogger : ISecurityEventLogger
{
private readonly ISecurityEventRepository _repo;
private readonly IAuditContext _context;
private readonly IOptions<AuditOptions> _options;
private readonly TimeProvider _timeProvider;
public SecurityEventLogger(
ISecurityEventRepository repo,
IAuditContext context,
IOptions<AuditOptions> options,
TimeProvider timeProvider)
{
_repo = repo;
_context = context;
_options = options;
_timeProvider = timeProvider;
}
public async Task LogAsync(
string action,
string result,
int? actorUserId = null,
string? attemptedUsername = null,
Guid? sessionId = null,
string? failureReason = null,
object? metadata = null,
CancellationToken ct = default)
{
var sanitized = metadata is null
? null
: JsonSanitizer.Sanitize(metadata, _options.Value.SanitizedKeys);
await _repo.InsertAsync(
occurredAt: _timeProvider.GetUtcNow().UtcDateTime,
actorUserId: actorUserId,
attemptedUsername: attemptedUsername,
sessionId: sessionId,
action: action,
result: result,
failureReason: failureReason,
ipAddress: _context.Ip,
userAgent: _context.UserAgent,
metadata: sanitized,
ct: ct);
}
}