using LCU.Library.Internal.ApiSecurity.Constants; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using LCU.Library.Internal.ApiSecurity.Enums; using LCU.Library.Internal.ApiSecurity.Models; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace LCU.Library.Internal.ApiSecurity.Attributes; [AttributeUsage(validOn: AttributeTargets.Method)] public class ApiKeyAttribute : Attribute, IAsyncActionFilter { public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var apiSecurityConfiguration = context.HttpContext.RequestServices.GetRequiredService(); var logger = context.HttpContext.RequestServices.GetRequiredService().CreateLogger(GetType().Name); if (apiSecurityConfiguration.ExternalApiKeySet.Any()) { if (!context.HttpContext.Request.Headers.TryGetValue(HeaderKeys.ApiKey, out var extractedApiKey)) { switch (apiSecurityConfiguration.ApiKeyAuthenticationFailureBehavior) { case ApiKeyAuthenticationFailureBehavior.Warn: logger.LogWarning(AuthMessages.NotProvidedMessage(HeaderKeys.ApiKey)); break; case ApiKeyAuthenticationFailureBehavior.Error: logger.LogError(AuthMessages.NotProvidedMessage(HeaderKeys.ApiKey)); context.Result = new ContentResult() { StatusCode = 401, Content = AuthMessages.NotProvidedMessage(HeaderKeys.ApiKey) }; return; default: throw new Exception("Invalid ApiKeyAuthenticationFailureBehavior Value"); } } if (!context.HttpContext.Request.Headers.TryGetValue(HeaderKeys.Client, out var extractedClient)) { switch (apiSecurityConfiguration.ApiKeyAuthenticationFailureBehavior) { case ApiKeyAuthenticationFailureBehavior.Warn: logger.LogWarning(AuthMessages.NotProvidedMessage(HeaderKeys.Client)); break; case ApiKeyAuthenticationFailureBehavior.Error: logger.LogError(AuthMessages.NotProvidedMessage(HeaderKeys.Client)); context.Result = new ContentResult() { StatusCode = 401, Content = AuthMessages.NotProvidedMessage(HeaderKeys.Client) }; return; default: throw new Exception("Invalid ApiKeyAuthenticationFailureBehavior Value"); } } if (!string.IsNullOrWhiteSpace(extractedClient)) { if (apiSecurityConfiguration.ExternalApiKeySet.TryGetValue(extractedClient, out var apiKey)) { if (!apiKey.Equals(extractedApiKey)) { switch (apiSecurityConfiguration.ApiKeyAuthenticationFailureBehavior) { case ApiKeyAuthenticationFailureBehavior.Warn: logger.LogWarning(AuthMessages.AuthFailureMessage(extractedClient)); break; case ApiKeyAuthenticationFailureBehavior.Error: logger.LogError(AuthMessages.AuthFailureMessage(extractedClient)); context.Result = new ContentResult() { StatusCode = 401, Content = AuthMessages.AuthFailureMessage(extractedClient) }; return; default: throw new Exception("Invalid ApiKeyAuthenticationFailureBehavior Value"); } } logger.LogInformation($"Valid auth received for Client: {extractedClient}"); } else { switch (apiSecurityConfiguration.ApiKeyAuthenticationFailureBehavior) { case ApiKeyAuthenticationFailureBehavior.Warn: logger.LogWarning(AuthMessages.ClientNotFoundMessage()); break; case ApiKeyAuthenticationFailureBehavior.Error: logger.LogError(AuthMessages.ClientNotFoundMessage()); context.Result = new ContentResult() { StatusCode = 401, Content = AuthMessages.ClientNotFoundMessage() }; return; default: throw new Exception("Invalid ApiKeyAuthenticationFailureBehavior Value"); } } } } else { switch (apiSecurityConfiguration.ApiKeyAuthenticationFailureBehavior) { case ApiKeyAuthenticationFailureBehavior.Warn: logger.LogWarning(AuthMessages.EmptyKeySetMessage("ExternalApiKeySet")); break; case ApiKeyAuthenticationFailureBehavior.Error: logger.LogError(AuthMessages.EmptyKeySetMessage("ExternalApiKeySet")); context.Result = new ContentResult() { StatusCode = 401, Content = AuthMessages.EmptyKeySetMessage("ExternalApiKeySet") }; return; default: throw new Exception("Invalid ApiKeyAuthenticationFailureBehavior Value"); } } await next(); } }