Compare commits
2
Commits
bfd60e9bb3
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d2193c3b9 | ||
|
|
e86b50163c |
@@ -159,7 +159,7 @@ namespace xIds.Controllers
|
|||||||
|
|
||||||
[RequireXPowered]
|
[RequireXPowered]
|
||||||
[HttpGet("Test/HiApiKeyAccess")]
|
[HttpGet("Test/HiApiKeyAccess")]
|
||||||
[Authorize(LocalApi.PolicyName)]
|
// [Authorize(LocalApi.PolicyName)]
|
||||||
[Authorize(Policy = XPolicies.ApiKeyAccess)]
|
[Authorize(Policy = XPolicies.ApiKeyAccess)]
|
||||||
public ActionResult<string> HiApiKeyAccess()
|
public ActionResult<string> HiApiKeyAccess()
|
||||||
{
|
{
|
||||||
|
|||||||
+49
-32
@@ -399,11 +399,9 @@ namespace xIds.DI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="services"></param>
|
/// <param name="services"></param>
|
||||||
/// <param name="configuration"></param>
|
/// <param name="configuration"></param>
|
||||||
/// <param name="addApiKeyAuthentication"></param>
|
|
||||||
public static void AddXIdentityServerAuthentication(
|
public static void AddXIdentityServerAuthentication(
|
||||||
this IServiceCollection services,
|
this IServiceCollection services,
|
||||||
IConfiguration configuration,
|
IConfiguration configuration
|
||||||
bool addApiKeyAuthentication = false
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
@@ -415,15 +413,47 @@ namespace xIds.DI
|
|||||||
var authBuilder = services.AddAuthentication();
|
var authBuilder = services.AddAuthentication();
|
||||||
|
|
||||||
//
|
//
|
||||||
// For Best Support we Have to Add ApiKey Authentication First ...
|
// Create Authentication Builder ...
|
||||||
if (addApiKeyAuthentication)
|
// var authBuilder = services.AddAuthentication(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(
|
||||||
|
// displayName: XAuthentication.SMART_SCHEME,
|
||||||
|
// authenticationScheme: 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;
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
//
|
//
|
||||||
authBuilder
|
// authBuilder.AddScheme<AuthenticationSchemeOptions, XApiKeyAuthenticationHandler>(
|
||||||
.AddScheme<AuthenticationSchemeOptions, XApiKeyAuthenticationHandler>(
|
// XAuthenticationScheme.XApiKey.GetStringValue(),
|
||||||
XAuthenticationScheme.XApiKey.GetStringValue(),
|
// options => { });
|
||||||
options => { });
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Add JwtBearer by Smart Schema ForwardDefaultSelector ...
|
// Add JwtBearer by Smart Schema ForwardDefaultSelector ...
|
||||||
@@ -432,26 +462,7 @@ namespace xIds.DI
|
|||||||
//
|
//
|
||||||
options.SaveToken = true;
|
options.SaveToken = true;
|
||||||
options.RequireHttpsMetadata = false;
|
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();
|
.AddLocalApi();
|
||||||
}
|
}
|
||||||
@@ -505,7 +516,13 @@ namespace xIds.DI
|
|||||||
options.AddPolicy(IdentityServerConstants.LocalApi.PolicyName, policy =>
|
options.AddPolicy(IdentityServerConstants.LocalApi.PolicyName, policy =>
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
policy.AddAuthenticationSchemes(IdentityServerConstants.LocalApi.AuthenticationScheme);
|
policy.AddAuthenticationSchemes(
|
||||||
|
[
|
||||||
|
// XAuthenticationScheme.XApiKey.GetStringValue(),
|
||||||
|
IdentityServerConstants.LocalApi.AuthenticationScheme
|
||||||
|
]);
|
||||||
|
|
||||||
|
//
|
||||||
policy.RequireAuthenticatedUser();
|
policy.RequireAuthenticatedUser();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
using xIdentityModels.Constants;
|
||||||
|
using xIdentityHelper;
|
||||||
|
|
||||||
namespace xIds.Helpers
|
namespace xIds.Helpers
|
||||||
{
|
{
|
||||||
@@ -73,5 +75,35 @@ namespace xIds.Helpers
|
|||||||
var hash = ComputeHash(plainKey);
|
var hash = ComputeHash(plainKey);
|
||||||
return hash == storedHash;
|
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 IdentityModel;
|
||||||
using xIds.Interfaces;
|
using xIds.Interfaces;
|
||||||
using xCommons.Constants;
|
using xCommons.Constants;
|
||||||
@@ -5,10 +7,12 @@ using xCommons.Extensions;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.Encodings.Web;
|
using System.Text.Encodings.Web;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using xIdentityService.Constants;
|
using xIdentityService.Constants;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Authentication;
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
|
||||||
namespace xIds.Providers
|
namespace xIds.Providers
|
||||||
@@ -41,18 +45,49 @@ namespace xIds.Providers
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
|
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;
|
var apiKeyHeader = HeaderName;
|
||||||
if (!Request.Headers.ContainsKey(apiKeyHeader))
|
if (!Request.Headers.ContainsKey(apiKeyHeader))
|
||||||
{
|
{
|
||||||
return AuthenticateResult.NoResult();
|
return AuthenticateResult.Fail("ApiKey not Exists ...");
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
var apiKey = Request.Headers[apiKeyHeader].ToString();
|
var apiKey = Request.Headers[apiKeyHeader].ToString();
|
||||||
if (apiKey.IsNullOrEmpty())
|
if (apiKey.IsNullOrEmpty())
|
||||||
{
|
{
|
||||||
return AuthenticateResult.NoResult();
|
return AuthenticateResult.Fail("ApiKey not Provided ...");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract Client IP ...
|
// 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 ...
|
// Register Authentication ...
|
||||||
services.AddXIdentityServerAuthentication(
|
services.AddXIdentityServerAuthentication(Configuration);
|
||||||
configuration: Configuration,
|
|
||||||
addApiKeyAuthentication: true
|
|
||||||
);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Register Authorization ...
|
// Register Authorization ...
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using xIds.Interfaces;
|
||||||
|
using xCommons.Extensions;
|
||||||
|
using xExceptions.Constants;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using IdentityServer4.Events;
|
using IdentityServer4.Events;
|
||||||
using IdentityServer4.Models;
|
using IdentityServer4.Models;
|
||||||
using IdentityServer4.Services;
|
using IdentityServer4.Services;
|
||||||
using IdentityServer4.Validation;
|
using IdentityServer4.Validation;
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
using xCommons.Extensions;
|
|
||||||
using xExceptions.Constants;
|
|
||||||
using xIdentityModels.Navigations;
|
using xIdentityModels.Navigations;
|
||||||
using xIds.Interfaces;
|
using Microsoft.Extensions.Logging;
|
||||||
using static IdentityModel.OidcConstants;
|
using static IdentityModel.OidcConstants;
|
||||||
|
|
||||||
namespace xIds.Validators
|
namespace xIds.Validators
|
||||||
|
|||||||
Reference in New Issue
Block a user