feat(auth): Program.cs integration for Audit Logging (AEG-AUTH-001 Part 2)
- Register IAuthAuditSql (AuthAuditSql) in DI - Add AuthAuditMiddleware to pipeline after authentication - Fix AuthAuditSql using statement + NpgsqlInet construction - Fix GetAuditLogsEndpoint response mapping (AuthAuditLogEntry → AuditLogItem) - Build verified (Release mode, 0 errors) Implements audit trail for all /api/auth/* endpoints: - Captures event type, status, IP, user agent, endpoint, error details - Immutable append-only storage with compliance views - Async non-blocking logging with graceful failure handling - Ready for 0047 migration application and testing WBS: AEG-X-005 (JWT/OIDC/fail-closed) + AEG-AUTH-001 (Audit) Gate: G3 (Shadow Run API) Status: CODE_COMPLETE → MIGRATION_READY Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using Dapper;
|
||||
using System.Data;
|
||||
using NpgsqlTypes;
|
||||
using KArtSell.BuildingBlocks.Data;
|
||||
|
||||
namespace KArtSell.Host.Features.Audit;
|
||||
|
||||
@@ -46,7 +47,7 @@ public sealed class AuthAuditSql : IAuthAuditSql
|
||||
entry.IdentityId,
|
||||
entry.Username,
|
||||
entry.Role,
|
||||
IpAddress = entry.IpAddress != null ? NpgsqlInet.Parse(entry.IpAddress) : (NpgsqlInet?)null,
|
||||
IpAddress = entry.IpAddress != null ? new NpgsqlInet(entry.IpAddress) : (NpgsqlInet?)null,
|
||||
entry.UserAgent,
|
||||
entry.Endpoint,
|
||||
entry.HttpMethod,
|
||||
|
||||
@@ -47,13 +47,29 @@ public sealed class GetAuditLogsEndpoint : Endpoint<GetAuditLogsRequest, GetAudi
|
||||
ct: ct
|
||||
);
|
||||
|
||||
var items = logs.Select(entry => new AuditLogItem
|
||||
{
|
||||
AuditId = entry.AuditId,
|
||||
EventType = entry.EventType,
|
||||
IdentityId = entry.IdentityId,
|
||||
Username = entry.Username,
|
||||
Role = entry.Role,
|
||||
IpAddress = entry.IpAddress,
|
||||
Endpoint = entry.Endpoint,
|
||||
HttpMethod = entry.HttpMethod,
|
||||
Status = entry.Status,
|
||||
ErrorCode = entry.ErrorCode,
|
||||
ErrorMessage = entry.ErrorMessage,
|
||||
OccurredAt = entry.OccurredAt
|
||||
}).ToList();
|
||||
|
||||
await Send.OkAsync(new GetAuditLogsResponse
|
||||
{
|
||||
Items = logs.ToList(),
|
||||
Items = items,
|
||||
Total = total,
|
||||
Page = req.Page,
|
||||
PageSize = req.PageSize
|
||||
}, 200, ct);
|
||||
}, ct);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ using KArtSell.Host.Infrastructure;
|
||||
using KArtSell.Host.OpenApi;
|
||||
using KArtSell.Host.Observability;
|
||||
using KArtSell.Host.Features.Observability;
|
||||
using KArtSell.Host.Features.Audit;
|
||||
using KArtSell.Host.Middleware;
|
||||
using KArtSell.BuildingBlocks.Data;
|
||||
using KArtSell.BuildingBlocks.Reliability;
|
||||
using KArtSell.BuildingBlocks.Time;
|
||||
@@ -233,6 +235,9 @@ builder.Services.AddScoped<KArtSell.Modules.ModelOperations.Compliance.LogAuditE
|
||||
builder.Services.AddScoped<KArtSell.Modules.ModelOperations.Compliance.ProcessGdprRequestHandler>();
|
||||
builder.Services.AddScoped<KArtSell.Modules.ModelOperations.Compliance.GdprRedactionJob>();
|
||||
|
||||
// Authentication Audit Logging (AEG-AUTH-001)
|
||||
builder.Services.AddScoped<IAuthAuditSql, AuthAuditSql>();
|
||||
|
||||
builder.Services.AddProblemDetails();
|
||||
|
||||
const string authenticationScheme = "KArtSell";
|
||||
@@ -342,6 +347,7 @@ if (app.Environment.IsDevelopment())
|
||||
}
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseMiddleware<AuthAuditMiddleware>();
|
||||
app.UseAuthorization();
|
||||
app.UseFastEndpoints(config => config.Endpoints.RoutePrefix = "api");
|
||||
app.MapHub<KArtSell.Host.Consumers.ShadowRunHub>("/api/hubs/shadow-run");
|
||||
|
||||
Reference in New Issue
Block a user