save progress
This commit is contained in:
@@ -51,9 +51,20 @@ public sealed record AuthorityPluginManifest(
|
||||
return false;
|
||||
}
|
||||
|
||||
var normalized = capability.Trim();
|
||||
if (normalized.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var entry in Capabilities)
|
||||
{
|
||||
if (string.Equals(entry, capability, StringComparison.OrdinalIgnoreCase))
|
||||
if (string.IsNullOrWhiteSpace(entry))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.Equals(entry.Trim(), normalized, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11,8 +11,7 @@ namespace StellaOps.Authority.Plugins.Abstractions;
|
||||
/// </summary>
|
||||
public static class AuthoritySecretHasher
|
||||
{
|
||||
private static ICryptoHash? configuredHash;
|
||||
private static string defaultAlgorithm = HashAlgorithms.Sha256;
|
||||
private static AuthoritySecretHasherConfiguration configuration = AuthoritySecretHasherConfiguration.Default;
|
||||
|
||||
/// <summary>
|
||||
/// Configures the shared crypto hash service used for secret hashing.
|
||||
@@ -20,13 +19,29 @@ public static class AuthoritySecretHasher
|
||||
public static void Configure(ICryptoHash hash, string? algorithmId = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(hash);
|
||||
Volatile.Write(ref configuredHash, hash);
|
||||
if (!string.IsNullOrWhiteSpace(algorithmId))
|
||||
{
|
||||
defaultAlgorithm = NormalizeAlgorithm(algorithmId);
|
||||
}
|
||||
Volatile.Write(ref configuration, AuthoritySecretHasherConfiguration.Create(hash, algorithmId));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures the shared crypto hash service for a scoped duration.
|
||||
/// </summary>
|
||||
public static AuthoritySecretHasherScope BeginScope(ICryptoHash hash, string? algorithmId = null)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(hash);
|
||||
var previous = Volatile.Read(ref configuration);
|
||||
Volatile.Write(ref configuration, AuthoritySecretHasherConfiguration.Create(hash, algorithmId));
|
||||
return new AuthoritySecretHasherScope(previous);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the configuration to the default SHA-256 implementation.
|
||||
/// </summary>
|
||||
public static void Reset()
|
||||
=> Volatile.Write(ref configuration, AuthoritySecretHasherConfiguration.Default);
|
||||
|
||||
internal static void ResetTo(AuthoritySecretHasherConfiguration previous)
|
||||
=> Volatile.Write(ref configuration, previous);
|
||||
|
||||
/// <summary>
|
||||
/// Computes a stable hash for the provided secret using the configured crypto provider.
|
||||
/// </summary>
|
||||
@@ -37,11 +52,12 @@ public static class AuthoritySecretHasher
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var config = Volatile.Read(ref configuration);
|
||||
var algorithm = string.IsNullOrWhiteSpace(algorithmId)
|
||||
? defaultAlgorithm
|
||||
: NormalizeAlgorithm(algorithmId);
|
||||
? config.DefaultAlgorithm
|
||||
: AuthoritySecretHasherConfiguration.NormalizeAlgorithm(algorithmId);
|
||||
|
||||
var hasher = Volatile.Read(ref configuredHash);
|
||||
var hasher = config.Hash;
|
||||
if (hasher is not null)
|
||||
{
|
||||
var digest = hasher.ComputeHash(Encoding.UTF8.GetBytes(secret), algorithm);
|
||||
@@ -58,8 +74,55 @@ public static class AuthoritySecretHasher
|
||||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
private static string NormalizeAlgorithm(string algorithmId)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restores the previous AuthoritySecretHasher configuration when disposed.
|
||||
/// </summary>
|
||||
public readonly struct AuthoritySecretHasherScope : IDisposable
|
||||
{
|
||||
private readonly Action? restore;
|
||||
|
||||
internal AuthoritySecretHasherScope(AuthoritySecretHasherConfiguration previous)
|
||||
{
|
||||
restore = () => AuthoritySecretHasher.ResetTo(previous);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
restore?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a scoped AuthoritySecretHasher configuration.
|
||||
/// </summary>
|
||||
public sealed record AuthoritySecretHasherConfiguration
|
||||
{
|
||||
public ICryptoHash? Hash { get; }
|
||||
public string DefaultAlgorithm { get; }
|
||||
|
||||
private AuthoritySecretHasherConfiguration(ICryptoHash? hash, string defaultAlgorithm)
|
||||
{
|
||||
Hash = hash;
|
||||
DefaultAlgorithm = defaultAlgorithm;
|
||||
}
|
||||
|
||||
public static AuthoritySecretHasherConfiguration Default { get; } =
|
||||
new(null, HashAlgorithms.Sha256);
|
||||
|
||||
public static AuthoritySecretHasherConfiguration Create(ICryptoHash hash, string? algorithmId = null)
|
||||
{
|
||||
var algorithm = NormalizeAlgorithm(algorithmId);
|
||||
return new AuthoritySecretHasherConfiguration(hash, algorithm);
|
||||
}
|
||||
|
||||
internal static string NormalizeAlgorithm(string? algorithmId)
|
||||
=> string.IsNullOrWhiteSpace(algorithmId)
|
||||
? HashAlgorithms.Sha256
|
||||
: algorithmId.Trim().ToUpperInvariant();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restores the previous AuthoritySecretHasher configuration when disposed.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading;
|
||||
@@ -240,7 +241,7 @@ public sealed record AuthorityPluginHealthResult
|
||||
=> new(AuthorityPluginHealthStatus.Unavailable, message, details ?? EmptyDetails);
|
||||
|
||||
private static readonly IReadOnlyDictionary<string, string?> EmptyDetails =
|
||||
new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
|
||||
new ReadOnlyDictionary<string, string?>(new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<GenerateMSBuildEditorConfigFile>false</GenerateMSBuildEditorConfigFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<EditorConfigFiles Remove="$(IntermediateOutputPath)$(MSBuildProjectName).GeneratedMSBuildEditorConfig.editorconfig" />
|
||||
</ItemGroup>
|
||||
<Target Name="EnsureGeneratedEditorConfig" BeforeTargets="ResolveEditorConfigFiles">
|
||||
<WriteLinesToFile File="$(IntermediateOutputPath)$(MSBuildProjectName).GeneratedMSBuildEditorConfig.editorconfig" Lines="" Overwrite="false" />
|
||||
</Target>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="10.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="10.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.Cryptography/StellaOps.Cryptography.csproj" />
|
||||
<ProjectReference Include="../../../__Libraries/StellaOps.Plugin/StellaOps.Plugin.csproj" />
|
||||
<ProjectReference Include="..\StellaOps.Auth.Abstractions\StellaOps.Auth.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -7,4 +7,4 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
|
||||
| --- | --- | --- |
|
||||
| AUDIT-0098-M | DONE | Maintainability audit for StellaOps.Authority.Plugins.Abstractions. |
|
||||
| AUDIT-0098-T | DONE | Test coverage audit for StellaOps.Authority.Plugins.Abstractions. |
|
||||
| AUDIT-0098-A | TODO | Pending approval for changes. |
|
||||
| AUDIT-0098-A | DONE | Pending approval for changes. |
|
||||
|
||||
Reference in New Issue
Block a user