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.
56 lines
1.8 KiB
C#
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);
|
|
}
|
|
}
|