using System; using System.Linq; using System.Net.Http.Headers; using System.Security.Claims; using System.Text; using System.Text.Encodings.Web; using System.Threading.Tasks; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace AMWD.Common.AspNetCore.BasicAuthentication { /// /// Implements the for Basic Authentication. /// public class BasicAuthenticationHandler : AuthenticationHandler { private readonly ILogger logger; private readonly IBasicAuthenticationValidator validator; /// /// Initializes a new instance of the class. /// /// The authentication scheme options. /// The logger factory. /// The URL encoder. /// The system clock. /// An basic autentication validator implementation. public BasicAuthenticationHandler(IOptionsMonitor options, ILoggerFactory loggerFactory, UrlEncoder encoder, ISystemClock clock, IBasicAuthenticationValidator validator) : base(options, loggerFactory, encoder, clock) { logger = loggerFactory.CreateLogger(); this.validator = validator; } /// protected override async Task HandleAuthenticateAsync() { var endpoint = Context.GetEndpoint(); if (endpoint?.Metadata?.GetMetadata() != null) return AuthenticateResult.NoResult(); if (!Request.Headers.ContainsKey("Authorization")) return AuthenticateResult.Fail("Authorization header missing"); ClaimsPrincipal principal; try { var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]); string plain = Encoding.UTF8.GetString(Convert.FromBase64String(authHeader.Parameter)); string[] credentials = plain.Split(':', 2, StringSplitOptions.RemoveEmptyEntries); var ipAddress = Context.GetRemoteIpAddress(); principal = await validator.ValidateAsync(credentials.First(), credentials.Last(), ipAddress); } catch (Exception ex) { logger.LogError(ex, $"Handling the Basic Authentication failed: {ex.Message}"); return AuthenticateResult.Fail("Authorization header invalid"); } if (principal == null) return AuthenticateResult.Fail("Invalid credentials"); var ticket = new AuthenticationTicket(principal, Scheme.Name); return AuthenticateResult.Success(ticket); } } }