using System; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; namespace AMWD.Common.AspNetCore.BasicAuthentication { /// /// Implements a basic authentication. /// public class BasicAuthenticationMiddleware { private readonly RequestDelegate next; private readonly string realm; private readonly IBasicAuthenticationValidator validator; /// /// Initializes a new instance of the class. /// /// The following delegate in the process chain. /// The realm to display when requesting for credentials. /// A basic authentication validator. public BasicAuthenticationMiddleware(RequestDelegate next, string realm, IBasicAuthenticationValidator validator) { this.next = next; this.realm = realm; this.validator = validator; } /// /// The delegate invokation. /// Performs the authentication check. /// /// The corresponding HTTP context. /// An awaitable task. public async Task InvokeAsync(HttpContext httpContext) { if (httpContext.Request.Headers.TryGetValue("Authorization", out var authHeader) && ((string)authHeader).StartsWith("Basic ")) { string encoded = ((string)authHeader).Split(' ', StringSplitOptions.RemoveEmptyEntries).LastOrDefault() ?? ""; string decoded = Encoding.UTF8.GetString(Convert.FromBase64String(encoded)); string[] parts = decoded.Split(':', 2); var principal = validator.ValidateAsync(parts[0], parts[1], httpContext.GetRemoteIpAddress()); if (principal != null) { await next.Invoke(httpContext); return; } } httpContext.Response.Headers["WWW-Authenticate"] = "Basic"; if (!string.IsNullOrWhiteSpace(realm)) { httpContext.Response.Headers["WWW-Authenticate"] += $" realm=\"{realm}\""; } httpContext.Response.StatusCode = StatusCodes.Status401Unauthorized; } } }