save progress

This commit is contained in:
StellaOps Bot
2026-01-02 21:06:27 +02:00
parent f46bde5575
commit 3f197814c5
441 changed files with 21545 additions and 4306 deletions

View File

@@ -35,9 +35,13 @@ internal static class DpopNonceUtilities
ArgumentException.ThrowIfNullOrWhiteSpace(clientId);
ArgumentException.ThrowIfNullOrWhiteSpace(keyThumbprint);
var normalizedAudience = audience.Trim().ToLowerInvariant();
var normalizedClientId = clientId.Trim().ToLowerInvariant();
var normalizedThumbprint = keyThumbprint.Trim().ToLowerInvariant();
return string.Create(
"dpop-nonce:".Length + audience.Length + clientId.Length + keyThumbprint.Length + 2,
(audience.Trim(), clientId.Trim(), keyThumbprint.Trim()),
"dpop-nonce:".Length + normalizedAudience.Length + normalizedClientId.Length + normalizedThumbprint.Length + 2,
(normalizedAudience, normalizedClientId, normalizedThumbprint),
static (span, parts) =>
{
var index = 0;

View File

@@ -27,10 +27,8 @@ public sealed class DpopProofValidator : IDpopProofValidator
{
ArgumentNullException.ThrowIfNull(options);
var cloned = options.Value ?? throw new InvalidOperationException("DPoP options must be provided.");
cloned.Validate();
this.options = cloned;
var snapshot = options.Value ?? throw new InvalidOperationException("DPoP options must be provided.");
this.options = snapshot.Snapshot();
this.replayCache = replayCache ?? NullReplayCache.Instance;
this.timeProvider = timeProvider ?? TimeProvider.System;
this.logger = logger;
@@ -50,12 +48,14 @@ public sealed class DpopProofValidator : IDpopProofValidator
return DpopValidationResult.Failure("invalid_header", headerError ?? "Unable to decode header.");
}
if (!headerElement.TryGetProperty("typ", out var typElement) || !string.Equals(typElement.GetString(), ProofType, StringComparison.OrdinalIgnoreCase))
if (!headerElement.TryGetProperty("typ", out var typElement) ||
typElement.ValueKind != JsonValueKind.String ||
!string.Equals(typElement.GetString(), ProofType, StringComparison.OrdinalIgnoreCase))
{
return DpopValidationResult.Failure("invalid_header", "DPoP proof missing typ=dpop+jwt header.");
}
if (!headerElement.TryGetProperty("alg", out var algElement))
if (!headerElement.TryGetProperty("alg", out var algElement) || algElement.ValueKind != JsonValueKind.String)
{
return DpopValidationResult.Failure("invalid_header", "DPoP proof missing alg header.");
}
@@ -88,7 +88,7 @@ public sealed class DpopProofValidator : IDpopProofValidator
return DpopValidationResult.Failure("invalid_payload", payloadError ?? "Unable to decode payload.");
}
if (!payloadElement.TryGetProperty("htm", out var htmElement))
if (!payloadElement.TryGetProperty("htm", out var htmElement) || htmElement.ValueKind != JsonValueKind.String)
{
return DpopValidationResult.Failure("invalid_payload", "DPoP proof missing htm claim.");
}
@@ -99,7 +99,7 @@ public sealed class DpopProofValidator : IDpopProofValidator
return DpopValidationResult.Failure("invalid_payload", "DPoP htm does not match request method.");
}
if (!payloadElement.TryGetProperty("htu", out var htuElement))
if (!payloadElement.TryGetProperty("htu", out var htuElement) || htuElement.ValueKind != JsonValueKind.String)
{
return DpopValidationResult.Failure("invalid_payload", "DPoP proof missing htu claim.");
}

View File

@@ -42,6 +42,25 @@ public sealed class DpopValidationOptions
/// </summary>
public IReadOnlySet<string> NormalizedAlgorithms { get; private set; } = ImmutableHashSet<string>.Empty;
internal DpopValidationOptions Snapshot()
{
var clone = new DpopValidationOptions
{
ProofLifetime = ProofLifetime,
AllowedClockSkew = AllowedClockSkew,
ReplayWindow = ReplayWindow
};
clone.allowedAlgorithms.Clear();
foreach (var algorithm in allowedAlgorithms)
{
clone.allowedAlgorithms.Add(algorithm);
}
clone.Validate();
return clone;
}
public void Validate()
{
if (ProofLifetime <= TimeSpan.Zero)

View File

@@ -4,7 +4,7 @@
<LangVersion>preview</LangVersion>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup>
<Description>Sender-constrained authentication primitives (DPoP, mTLS) shared across StellaOps services.</Description>
@@ -35,6 +35,11 @@
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="" />
</ItemGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>StellaOps.Auth.Security.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Router\__Libraries\StellaOps.Messaging\StellaOps.Messaging.csproj" />
</ItemGroup>

View File

@@ -7,4 +7,4 @@ Source of truth: `docs/implplan/SPRINT_20251229_049_BE_csproj_audit_maint_tests.
| --- | --- | --- |
| AUDIT-0082-M | DONE | Maintainability audit for StellaOps.Auth.Security. |
| AUDIT-0082-T | DONE | Test coverage audit for StellaOps.Auth.Security. |
| AUDIT-0082-A | TODO | Pending approval for changes. |
| AUDIT-0082-A | DONE | DPoP validation hardening, nonce normalization, and tests added. |