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);
}
}
}