using System.Security.Claims; using System.Security.Cryptography; using System.Text; namespace ProposalSystem.Api.Middleware; public class InternalApiKeyMiddleware { private readonly RequestDelegate _next; private readonly byte[] _apiKeyBytes; private readonly ILogger _logger; public InternalApiKeyMiddleware(RequestDelegate next, IConfiguration configuration, ILogger logger) { _next = next; _logger = logger; var key = configuration["INTERNAL_API_KEY"] ?? ""; _apiKeyBytes = Encoding.UTF8.GetBytes(key); } public async Task InvokeAsync(HttpContext context) { if (_apiKeyBytes.Length > 0 && context.Request.Headers.TryGetValue("X-Internal-Api-Key", out var providedKey) && !string.IsNullOrEmpty(providedKey.ToString())) { var providedBytes = Encoding.UTF8.GetBytes(providedKey.ToString()); if (CryptographicOperations.FixedTimeEquals(providedBytes, _apiKeyBytes)) { var claims = new[] { new Claim(ClaimTypes.NameIdentifier, "system"), new Claim("sub", "system-lambda-caller"), new Claim(ClaimTypes.Email, "system@proposal-system.internal"), new Claim("email", "system@proposal-system.internal"), new Claim("name", "System"), new Claim(ClaimTypes.Role, "admins"), new Claim("cognito:groups", "admins"), }; var identity = new ClaimsIdentity(claims, "InternalApiKey"); context.User = new ClaimsPrincipal(identity); } else { _logger.LogWarning("Invalid internal API key from {RemoteIp} on {Path}", context.Connection.RemoteIpAddress, context.Request.Path); } } await _next(context); } }