Files
git.stella-ops.org/src/AirGap/StellaOps.AirGap.Controller/Security/AirGapPolicies.cs

65 lines
2.6 KiB
C#

// Copyright (c) StellaOps. Licensed under the BUSL-1.1.
using Microsoft.AspNetCore.Authorization;
using StellaOps.Auth.Abstractions;
namespace StellaOps.AirGap.Controller.Security;
/// <summary>
/// Named authorization policy constants for the AirGap Controller service.
/// Policies are registered via assertion-based policies in Program.cs using
/// <see cref="AirGapScopeAssertion"/> to evaluate claims from the HeaderScope
/// authentication handler.
/// </summary>
internal static class AirGapPolicies
{
/// <summary>Policy for reading air-gap status and staleness information. Requires airgap:status:read scope.</summary>
public const string StatusRead = "AirGap.StatusRead";
/// <summary>Policy for sealing and unsealing the air-gap environment. Requires airgap:seal scope.</summary>
public const string Seal = "AirGap.Seal";
/// <summary>Policy for importing offline bundles while in air-gapped mode. Requires airgap:import scope.</summary>
public const string Import = "AirGap.Import";
/// <summary>Policy for verifying air-gap state against policy hash and replay evidence. Requires airgap:verify scope.</summary>
public const string Verify = "AirGap.Verify";
}
/// <summary>
/// Scope assertion helper for AirGap policies. Evaluates scope claims populated by
/// the HeaderScope authentication handler against a required scope string.
/// </summary>
internal static class AirGapScopeAssertion
{
/// <summary>
/// Returns <c>true</c> when the authenticated principal carries the required scope
/// in either <see cref="StellaOpsClaimTypes.ScopeItem"/> or space-delimited
/// <see cref="StellaOpsClaimTypes.Scope"/> / <c>scp</c> claims.
/// </summary>
public static bool HasScope(AuthorizationHandlerContext context, string requiredScope)
{
var user = context.User;
if (user.HasClaim(c => c.Type == StellaOpsClaimTypes.ScopeItem))
{
return user.FindAll(StellaOpsClaimTypes.ScopeItem)
.Select(c => c.Value)
.Contains(requiredScope, StringComparer.OrdinalIgnoreCase);
}
var scopes = user.FindAll(StellaOpsClaimTypes.Scope)
.SelectMany(c => c.Value.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
.ToArray();
if (scopes.Length == 0)
{
scopes = user.FindAll("scp")
.SelectMany(c => c.Value.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
.ToArray();
}
return scopes.Contains(requiredScope, StringComparer.OrdinalIgnoreCase);
}
}