using System.Linq; using xIds.Helpers; using IdentityModel; using xIds.Interfaces; using xCommons.Constants; using xCommons.Extensions; using System.Threading.Tasks; using System.Security.Claims; using System.Text.Encodings.Web; using Microsoft.AspNetCore.Http; using xIdentityService.Constants; using System.Collections.Generic; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authentication; namespace xIds.Providers { /// /// an Authentication Handler for ApiKey's based App's ... /// public class XApiKeyAuthenticationHandler : AuthenticationHandler { private readonly IXApplicationProvider applicationProvider; // public string HeaderName { get; } = XHeader.ApiKey.GetStringValue(); public string AuthenticationScheme { get; } = XAuthenticationScheme.XApiKey.GetStringValue(); public XApiKeyAuthenticationHandler( UrlEncoder encoder, ISystemClock clock, ILoggerFactory logger, IXApplicationProvider applicationProvider, IOptionsMonitor options ) : base(options, logger, encoder, clock) { this.applicationProvider = applicationProvider; } /// /// Handle Authentication ... /// /// protected override async Task HandleAuthenticateAsync() { // // Obtain the endpoint currently being executed var endpoint = Context.GetEndpoint(); // // Retrieve all AuthorizeAttribute metadata from the endpoint var hasApiKeyScheme = false; var apiKeyScopes = XApiKeyHelper.GetXApiKeyScopes(); var apiKeyPolicies = XApiKeyHelper.GetXApiKeyPolicies(); var authorizeAttributes = endpoint?.Metadata.GetOrderedMetadata(); if ( apiKeyPolicies.HasChild() && authorizeAttributes.HasChild() ) { // // Retrieve a List of ApiKey Policies ... hasApiKeyScheme = authorizeAttributes.Any(attr => apiKeyPolicies.Any(asc => asc.ToNormalString() == attr.Policy.ToNormalString()) || attr.AuthenticationSchemes.ToNormalString() == XAuthenticationScheme.XApiKey.GetStringValue().ToNormalString() ); } // // if there is not any Policies for ApiKey Authentication // or Authorization, pass no Result ... if (!hasApiKeyScheme) { return AuthenticateResult.NoResult(); } // var apiKeyHeader = HeaderName; if (!Request.Headers.ContainsKey(apiKeyHeader)) { return AuthenticateResult.Fail("ApiKey not Exists ..."); } // var apiKey = Request.Headers[apiKeyHeader].ToString(); if (apiKey.IsNullOrEmpty()) { return AuthenticateResult.Fail("ApiKey not Provided ..."); } // Extract Client IP ... var clientIP = Request.HttpContext.Connection.RemoteIpAddress?.ToString(); // // Validating ApiKey ... var validationResult = await applicationProvider .ValidateApiKey( apiKey: apiKey, clientIP: clientIP ); if (validationResult.Errors.HasChild()) { // var message = validationResult.Errors.ToListString('\n'); return AuthenticateResult.Fail(message); } // // Creating Claims ... var claims = new List { // // Owner Identifier of API Key ... new(ClaimTypes.Name, validationResult.OwnerId), new(JwtClaimTypes.Subject, validationResult.OwnerId), // // Application Id ... new(XCustomClaims.ApplicationId, validationResult.ApplicationId.ToString()), // // Authentication Type ... new(XCustomClaims.AuthType, "apikey"), }; // // Add Scopes ... if (validationResult.Scopes != null) { foreach (var scope in validationResult.Scopes) { claims.Add(new Claim(JwtClaimTypes.Scope, scope)); } } // // Create Principal and Ticket ... var identity = new ClaimsIdentity(claims, Scheme.Name); var principal = new ClaimsPrincipal(identity); var ticket = new AuthenticationTicket(principal, Scheme.Name); // return AuthenticateResult.Success(ticket); } } }