diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs index 098c50d..5979118 100644 --- a/DI/XDIHelperExtension.cs +++ b/DI/XDIHelperExtension.cs @@ -204,7 +204,7 @@ namespace xIds.DI { // source.AddXApiKeyConfiguration(configuration); - + // source.AddMemoryCache(); source.AddScoped(); @@ -407,33 +407,53 @@ namespace xIds.DI ) { // + // Adding Requirements ... services.AddXIdentityResourceConfiguration(configuration); // + // Create Authentication Builder ... var authBuilder = services.AddAuthentication(); - + + // + // For Best Support we Have to Add ApiKey Authentication First ... + if (addApiKeyAuthentication) + { + // + authBuilder + .AddScheme( + XAuthenticationScheme.XApiKey.GetStringValue(), + options => { }); + } + // - // Add JWT Bearer ... + // Add JwtBearer by Smart Schema ForwardDefaultSelector ... authBuilder.AddJwtBearer(options => { // options.SaveToken = true; options.RequireHttpsMetadata = false; + // options.ForwardDefault = XAuthentication.IDENTITY_SERVER_LOCAL_API; // - options.ForwardDefault = XAuthentication.IDENTITY_SERVER_LOCAL_API; + // Selecting Authentication Schema Based On Header ... + options.ForwardDefaultSelector = context => + { + // + // if Header Contains X-Api-Key use Scheme XApiKey ... + var apiKeyHeader = XHeader.ApiKey + .GetStringValue() + .ToNormalString(); + if (context.Request.Headers.ContainsKey(apiKeyHeader)) + { + return XAuthenticationScheme.XApiKey.GetStringValue(); + } + + // + // If Not, Use Local Api ... + return XAuthentication.IDENTITY_SERVER_LOCAL_API; + }; }) .AddLocalApi(); - - // - if (addApiKeyAuthentication) - { - // - authBuilder.AddScheme( - XAuthenticationScheme.XApiKey.GetStringValue(), - options => {} - ); - } } /// diff --git a/Providers/XApiKeyAuthenticationHandler.cs b/Providers/XApiKeyAuthenticationHandler.cs index 6d7c629..9f36f61 100644 --- a/Providers/XApiKeyAuthenticationHandler.cs +++ b/Providers/XApiKeyAuthenticationHandler.cs @@ -1,11 +1,12 @@ -using System.Linq; 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 xIdentityService.Constants; +using System.Collections.Generic; using Microsoft.Extensions.Options; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Authentication; @@ -41,25 +42,30 @@ namespace xIds.Providers protected override async Task HandleAuthenticateAsync() { // - var apiKey = - !Request.Headers.ContainsKey(HeaderName) - ? string.Empty - : Request.Headers[HeaderName].ToString(); + var apiKeyHeader = HeaderName; + if (!Request.Headers.ContainsKey(apiKeyHeader)) + { + return AuthenticateResult.NoResult(); + } + + // + var apiKey = Request.Headers[apiKeyHeader].ToString(); if (apiKey.IsNullOrEmpty()) { return AuthenticateResult.NoResult(); } - // + // Extract Client IP ... var clientIP = Request.HttpContext.Connection.RemoteIpAddress?.ToString(); // - var validationResult = await applicationProvider.ValidateApiKey( - apiKey: apiKey, - clientIP: clientIP - ); - var isValid = !validationResult.Errors.HasChild(); - if (!isValid) + // Validating ApiKey ... + var validationResult = await applicationProvider + .ValidateApiKey( + apiKey: apiKey, + clientIP: clientIP + ); + if (validationResult.Errors.HasChild()) { // var message = validationResult.Errors.ToListString('\n'); @@ -67,32 +73,35 @@ namespace xIds.Providers } // - var claims = new[] - { - new Claim(ClaimTypes.Name, validationResult.OwnerId), - new Claim("application_id", validationResult.ApplicationId.ToString()), - new Claim("auth_type", "apikey"), - new Claim(JwtClaimTypes.Scope, "apikey"), + // 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"), }; - - // - var scopeClaims = validationResult.Scopes - .Select(s => new Claim(JwtClaimTypes.Scope, s)); - - // - var identity = new ClaimsIdentity( - claims.Union(scopeClaims), - AuthenticationScheme - ); // - var principal = new ClaimsPrincipal(identity); - + // Add Scopes ... + if (validationResult.Scopes != null) + { + foreach (var scope in validationResult.Scopes) + { + claims.Add(new Claim(JwtClaimTypes.Scope, scope)); + } + } + // - var ticket = new AuthenticationTicket( - principal, - AuthenticationScheme - ); + // 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);