last ...
This commit is contained in:
+46
-34
@@ -399,31 +399,56 @@ namespace xIds.DI
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
/// <param name="configuration"></param>
|
||||
/// <param name="addApiKeyAuthentication"></param>
|
||||
public static void AddXIdentityServerAuthentication(
|
||||
this IServiceCollection services,
|
||||
IConfiguration configuration,
|
||||
bool addApiKeyAuthentication = false
|
||||
IConfiguration configuration
|
||||
)
|
||||
{
|
||||
//
|
||||
// Adding Requirements ...
|
||||
services.AddXIdentityResourceConfiguration(configuration);
|
||||
|
||||
//
|
||||
// Create Authentication Builder ...
|
||||
// var authBuilder = services.AddAuthentication();
|
||||
|
||||
//
|
||||
// Create Authentication Builder ...
|
||||
var authBuilder = services.AddAuthentication();
|
||||
|
||||
//
|
||||
// For Best Support we Have to Add ApiKey Authentication First ...
|
||||
if (addApiKeyAuthentication)
|
||||
var authBuilder = services.AddAuthentication(options =>
|
||||
{
|
||||
//
|
||||
authBuilder
|
||||
.AddScheme<AuthenticationSchemeOptions, XApiKeyAuthenticationHandler>(
|
||||
XAuthenticationScheme.XApiKey.GetStringValue(),
|
||||
options => { });
|
||||
}
|
||||
// Setting Default Authentication Schema ...
|
||||
// For Handling Smart Schema Forwarder ...
|
||||
options.DefaultScheme = XAuthentication.SMART_SCHEME;
|
||||
options.DefaultChallengeScheme = XAuthentication.SMART_SCHEME;
|
||||
options.DefaultAuthenticateScheme = XAuthentication.SMART_SCHEME;
|
||||
})
|
||||
.AddPolicyScheme(
|
||||
authenticationScheme: XAuthentication.SMART_SCHEME,
|
||||
displayName: XAuthentication.SMART_SCHEME,
|
||||
configureOptions: options =>
|
||||
{
|
||||
//
|
||||
// Configure Forward Default Selector ...
|
||||
options.ForwardDefaultSelector = context =>
|
||||
{
|
||||
//
|
||||
// Retrieve XApiKey Header Key ...
|
||||
var apiKeyHeader = XHeader.ApiKey.GetStringValue();
|
||||
|
||||
//
|
||||
// If Header Contains Key ...
|
||||
if (context.Request.Headers.ContainsKey(apiKeyHeader))
|
||||
{
|
||||
return XAuthenticationScheme.XApiKey.GetStringValue();
|
||||
}
|
||||
|
||||
//
|
||||
// If not ...
|
||||
return XAuthentication.IDENTITY_SERVER_LOCAL_API;
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
//
|
||||
// Add JwtBearer by Smart Schema ForwardDefaultSelector ...
|
||||
@@ -432,26 +457,7 @@ namespace xIds.DI
|
||||
//
|
||||
options.SaveToken = true;
|
||||
options.RequireHttpsMetadata = false;
|
||||
// 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;
|
||||
};
|
||||
options.ForwardDefault = XAuthentication.IDENTITY_SERVER_LOCAL_API;
|
||||
})
|
||||
.AddLocalApi();
|
||||
}
|
||||
@@ -505,7 +511,13 @@ namespace xIds.DI
|
||||
options.AddPolicy(IdentityServerConstants.LocalApi.PolicyName, policy =>
|
||||
{
|
||||
//
|
||||
policy.AddAuthenticationSchemes(IdentityServerConstants.LocalApi.AuthenticationScheme);
|
||||
policy.AddAuthenticationSchemes(
|
||||
[
|
||||
XAuthenticationScheme.XApiKey.GetStringValue(),
|
||||
IdentityServerConstants.LocalApi.AuthenticationScheme
|
||||
]);
|
||||
|
||||
//
|
||||
policy.RequireAuthenticatedUser();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityHelper;
|
||||
|
||||
namespace xIds.Helpers
|
||||
{
|
||||
@@ -73,5 +75,35 @@ namespace xIds.Helpers
|
||||
var hash = ComputeHash(plainKey);
|
||||
return hash == storedHash;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve All ApiKey Scopes ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static XApiKeyScope[] GetXApiKeyScopes()
|
||||
{
|
||||
//
|
||||
return [
|
||||
XApiKeyScope.Read,
|
||||
XApiKeyScope.Write,
|
||||
XApiKeyScope.Manage,
|
||||
XApiKeyScope.Admin,
|
||||
];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve All ApiKey Policies ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string[] GetXApiKeyPolicies()
|
||||
{
|
||||
return [
|
||||
XPolicies.ApiKeyAccess,
|
||||
XPolicies.ApiKeyReadAccess,
|
||||
XPolicies.ApiKeyWriteAccess,
|
||||
XPolicies.ApiKeyAdminAccess,
|
||||
XPolicies.ApiKeyManageAccess,
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Linq;
|
||||
using xIds.Helpers;
|
||||
using IdentityModel;
|
||||
using xIds.Interfaces;
|
||||
using xCommons.Constants;
|
||||
@@ -5,10 +7,12 @@ 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
|
||||
@@ -41,18 +45,49 @@ namespace xIds.Providers
|
||||
/// <returns></returns>
|
||||
protected override async Task<AuthenticateResult> 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<IAuthorizeData>();
|
||||
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.NoResult();
|
||||
return AuthenticateResult.Fail("ApiKey not Exists ...");
|
||||
}
|
||||
|
||||
//
|
||||
var apiKey = Request.Headers[apiKeyHeader].ToString();
|
||||
if (apiKey.IsNullOrEmpty())
|
||||
{
|
||||
return AuthenticateResult.NoResult();
|
||||
return AuthenticateResult.Fail("ApiKey not Provided ...");
|
||||
}
|
||||
|
||||
// Extract Client IP ...
|
||||
|
||||
@@ -0,0 +1,192 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using xIds.Helpers;
|
||||
using IdentityModel;
|
||||
using xIds.Interfaces;
|
||||
using xIdentityHelper;
|
||||
using xCommons.Constants;
|
||||
using xCommons.Extensions;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using xIdentityModels.Constants;
|
||||
using xIdentityService.Constants;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace xIds.Providers
|
||||
{
|
||||
[AttributeUsage(
|
||||
AttributeTargets.Class | AttributeTargets.Method,
|
||||
AllowMultiple = false,
|
||||
Inherited = true
|
||||
)]
|
||||
public class XApiKeyAuthorizationFilter : AuthorizeAttribute, IAuthorizationFilter
|
||||
{
|
||||
// /// <summary>
|
||||
// /// Optional required scope for this endpoint.
|
||||
// /// Example: [XApiKeyAuthorizationFilter(RequiredScope = "read")]
|
||||
// /// </summary>
|
||||
// public string RequiredScope { get; set; }
|
||||
|
||||
// /// <summary>
|
||||
// /// If false, a missing header will only result in NoResult (anonymous)
|
||||
// /// instead of a 401. Default is true (must provide a key).
|
||||
// /// </summary>
|
||||
// public bool ApiKeyRequired { get; set; } = true;
|
||||
|
||||
// /// <summary>
|
||||
// /// Optional allowed scopes. If empty, no scope enforcement.
|
||||
// /// </summary>
|
||||
// public string[] AllowedScopes { get; set; }
|
||||
|
||||
public XApiKeyAuthorizationFilter() { }
|
||||
|
||||
/// <summary>
|
||||
/// Authorization Filtering ...
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
Task.FromResult(OnAuthorizationAsync(context));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle Authorization Filtering Using Tasks ...
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
private async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||
{
|
||||
//
|
||||
// Access HttpContext ...
|
||||
var http = context.HttpContext;
|
||||
|
||||
//
|
||||
try
|
||||
{
|
||||
//
|
||||
// Obtain the endpoint currently being executed
|
||||
var endpoint = http.GetEndpoint();
|
||||
|
||||
//
|
||||
// Retrieve all AuthorizeAttribute metadata from the endpoint
|
||||
var hasApiKeyScheme = false;
|
||||
var apiKeyScopes = XApiKeyHelper.GetXApiKeyScopes();
|
||||
var apiKeyPolicies = XApiKeyHelper.GetXApiKeyPolicies();
|
||||
var authorizeAttributes = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>();
|
||||
if (
|
||||
apiKeyPolicies.HasChild() &&
|
||||
authorizeAttributes.HasChild()
|
||||
)
|
||||
{
|
||||
//
|
||||
// Retrieve a List of ApiKey Policies ...
|
||||
hasApiKeyScheme = authorizeAttributes.Any(attr =>
|
||||
apiKeyPolicies.Any(asc => asc.ToNormalString() == attr.Policy.ToNormalString())
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// if there is not any Policies for ApiKey Authentication
|
||||
// or Authorization, pass no Result ...
|
||||
if (!hasApiKeyScheme)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Retrieve the application provider from DI ...
|
||||
var applicationProvider = http.RequestServices
|
||||
.GetService(typeof(IXApplicationProvider))
|
||||
as IXApplicationProvider;
|
||||
if (applicationProvider.IsNull())
|
||||
{
|
||||
//
|
||||
context.Result = new UnauthorizedObjectResult("Provider Service Not Registered ...");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Checking Header ...
|
||||
var apiKeyHeader = XHeader.ApiKey.GetStringValue();
|
||||
var apiKeyAuthentication = XAuthenticationScheme.XApiKey.GetStringValue();
|
||||
if (!http.Request.Headers.ContainsKey(apiKeyHeader))
|
||||
{
|
||||
//
|
||||
context.Result = new UnauthorizedObjectResult("ApiKey not Exists ...");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Extract ApiKey from Header ...
|
||||
var apiKey = http.Request.Headers[apiKeyHeader].ToString();
|
||||
if (apiKey.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
context.Result = new UnauthorizedObjectResult("ApiKey not Provided ...");
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Extract Client IP ...
|
||||
var clientIP = http.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');
|
||||
context.Result = new UnauthorizedObjectResult(message);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Creating Claims ...
|
||||
var claims = new List<Claim> {
|
||||
//
|
||||
// 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, apiKeyAuthentication),
|
||||
};
|
||||
|
||||
//
|
||||
// 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, apiKeyAuthentication);
|
||||
var principal = new ClaimsPrincipal(identity);
|
||||
|
||||
//
|
||||
http.User = principal;
|
||||
}
|
||||
catch
|
||||
{
|
||||
context.Result = new UnauthorizedObjectResult("ApiKey authorization failed ...");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-4
@@ -67,10 +67,7 @@ namespace xIds
|
||||
|
||||
//
|
||||
// Register Authentication ...
|
||||
services.AddXIdentityServerAuthentication(
|
||||
configuration: Configuration,
|
||||
addApiKeyAuthentication: true
|
||||
);
|
||||
services.AddXIdentityServerAuthentication(Configuration);
|
||||
|
||||
//
|
||||
// Register Authorization ...
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
using System;
|
||||
using xIds.Interfaces;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using System.Threading.Tasks;
|
||||
using IdentityServer4.Events;
|
||||
using IdentityServer4.Models;
|
||||
using IdentityServer4.Services;
|
||||
using IdentityServer4.Validation;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xIdentityModels.Navigations;
|
||||
using xIds.Interfaces;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using static IdentityModel.OidcConstants;
|
||||
|
||||
namespace xIds.Validators
|
||||
|
||||
Reference in New Issue
Block a user