diff --git a/Proculite.GpioRest/Middlewares/SecurityMiddleware.cs b/Proculite.GpioRest/Middlewares/SecurityMiddleware.cs new file mode 100644 index 0000000..3a2b414 --- /dev/null +++ b/Proculite.GpioRest/Middlewares/SecurityMiddleware.cs @@ -0,0 +1,64 @@ +using System.Text; + +namespace Proculite.GpioRest.Middlewares +{ + public class SecurityMiddleware + { + private readonly RequestDelegate _next; + private readonly IConfiguration _configuration; + private readonly ILogger _logger; + + public SecurityMiddleware( + RequestDelegate next, + IConfiguration configuration, + ILogger logger + ) + { + _logger = logger; + _configuration = configuration; + _next = next; + } + + public async Task InvokeAsync(HttpContext context) + { + IConfigurationSection keySection = _configuration.GetSection("Key"); + if (!keySection.Exists()) + { + _logger.LogWarning( + "Configuration does not contain a key. Running in insecure mode." + ); + await _next(context); + return; + } + + string? accessKey = keySection.Get(); + if (accessKey is null) + { + _logger.LogError("Key is expected but is not set."); + return; + } + + string? requestKey = context.Request.Headers.Authorization.FirstOrDefault(); + + if (requestKey == accessKey) + { + await _next(context); + return; + } + + context.Response.StatusCode = StatusCodes.Status401Unauthorized; + context.Response.ContentType = "text/plain; charset=utf-8"; + byte[] messageBytes = Encoding.UTF8.GetBytes("Invalid key is used. Access denied."); + context.Response.ContentLength = messageBytes.Length; + await context.Response.Body.WriteAsync(messageBytes); + } + } + + public static class SecurityMiddlewareExtensions + { + public static IApplicationBuilder UseSecurity(this IApplicationBuilder builder) + { + return builder.UseMiddleware(); + } + } +} diff --git a/Proculite.GpioRest/Program.cs b/Proculite.GpioRest/Program.cs index 6d84ad7..678cbf4 100644 --- a/Proculite.GpioRest/Program.cs +++ b/Proculite.GpioRest/Program.cs @@ -1,3 +1,4 @@ +using Proculite.GpioRest.Middlewares; using Proculite.GpioRest.Services; var builder = WebApplication.CreateBuilder(args); @@ -12,6 +13,9 @@ builder.Services.AddSingleton(); var app = builder.Build(); +// Custom security. Expects traffic to be secure (HTTPS). +app.UseSecurity(); + app.MapControllers(); app.UseSwagger(); app.UseSwaggerUI();