77 lines
3.3 KiB
C#
77 lines
3.3 KiB
C#
using Microsoft.Extensions.Primitives;
|
|
|
|
namespace Nexus.Api.Services;
|
|
|
|
public static class RequestAuthorizationHelper
|
|
{
|
|
public sealed record AgentHeaderResolution(
|
|
string? AgentId,
|
|
bool HeaderProvided,
|
|
bool IsRecognized,
|
|
bool CredentialVerified,
|
|
bool IdentityHintAuthorized);
|
|
|
|
public static bool IsAuthenticatedService(HttpContext httpContext, IConfiguration configuration) =>
|
|
(httpContext.User.Identity?.IsAuthenticated == true &&
|
|
httpContext.User.IsInRole("Service")) ||
|
|
HasValidServiceKey(httpContext, configuration);
|
|
|
|
public static bool HasVerifiedAuthentication(HttpContext httpContext, IConfiguration configuration) =>
|
|
httpContext.User.Identity?.IsAuthenticated == true ||
|
|
HasValidServiceKey(httpContext, configuration);
|
|
|
|
public static bool IsPrivilegedUser(HttpContext httpContext) =>
|
|
httpContext.User.Identity?.IsAuthenticated == true &&
|
|
(httpContext.User.IsInRole("owner") || httpContext.User.IsInRole("admin"));
|
|
|
|
public static bool CanUseAgentIdentityHint(HttpContext httpContext, IConfiguration configuration) =>
|
|
IsAuthenticatedService(httpContext, configuration) ||
|
|
IsPrivilegedUser(httpContext);
|
|
|
|
public static async Task<string?> ResolveAllowedAgentHeaderAsync(
|
|
HttpContext httpContext,
|
|
IAgentService agentService,
|
|
IConfiguration configuration,
|
|
CancellationToken ct)
|
|
=> (await ResolveAgentHeaderAsync(httpContext, agentService, configuration, ct)).AgentId;
|
|
|
|
public static async Task<AgentHeaderResolution> ResolveAgentHeaderAsync(
|
|
HttpContext httpContext,
|
|
IAgentService agentService,
|
|
IConfiguration configuration,
|
|
CancellationToken ct)
|
|
{
|
|
var headerValue = httpContext.Request.Headers["X-Agent-Id"].FirstOrDefault();
|
|
if (string.IsNullOrWhiteSpace(headerValue))
|
|
return new AgentHeaderResolution(
|
|
null,
|
|
HeaderProvided: false,
|
|
IsRecognized: false,
|
|
CredentialVerified: HasVerifiedAuthentication(httpContext, configuration),
|
|
IdentityHintAuthorized: CanUseAgentIdentityHint(httpContext, configuration));
|
|
|
|
var allowed = AgentIdentityCatalog.BuildAllowedActorIds(await agentService.GetAllowedAgentIdsAsync(ct));
|
|
var normalized = AgentIdentityCatalog.NormalizeActorId(headerValue, allowed);
|
|
var credentialVerified = HasVerifiedAuthentication(httpContext, configuration);
|
|
var identityHintAuthorized = CanUseAgentIdentityHint(httpContext, configuration);
|
|
return new AgentHeaderResolution(
|
|
identityHintAuthorized ? normalized : null,
|
|
HeaderProvided: true,
|
|
IsRecognized: normalized is not null,
|
|
CredentialVerified: credentialVerified,
|
|
IdentityHintAuthorized: identityHintAuthorized);
|
|
}
|
|
|
|
public static bool HasValidServiceKey(HttpContext httpContext, IConfiguration configuration)
|
|
{
|
|
var configuredApiKey = configuration["NexusApiKey"];
|
|
if (string.IsNullOrWhiteSpace(configuredApiKey))
|
|
return false;
|
|
|
|
if (!httpContext.Request.Headers.TryGetValue("X-Nexus-Api-Key", out StringValues providedKey))
|
|
return false;
|
|
|
|
return string.Equals(configuredApiKey, providedKey.FirstOrDefault(), StringComparison.Ordinal);
|
|
}
|
|
}
|