stabilizaiton work - projects rework for maintenanceability and ui livening
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using StellaOps.Messaging;
|
||||
|
||||
namespace StellaOps.Auth.Security.Dpop;
|
||||
|
||||
public sealed partial class MessagingDpopNonceStore
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async ValueTask<DpopNonceIssueResult> IssueAsync(
|
||||
string audience,
|
||||
string clientId,
|
||||
string keyThumbprint,
|
||||
TimeSpan ttl,
|
||||
int maxIssuancePerMinute,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(audience);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(clientId);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(keyThumbprint);
|
||||
|
||||
if (ttl <= TimeSpan.Zero)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(ttl), "Nonce TTL must be greater than zero.");
|
||||
}
|
||||
|
||||
if (maxIssuancePerMinute < 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(maxIssuancePerMinute), "Max issuance per minute must be at least 1.");
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
var storageKey = DpopNonceUtilities.ComputeStorageKey(audience, clientId, keyThumbprint);
|
||||
var rateKey = $"{storageKey}:rate";
|
||||
|
||||
var ratePolicy = new RateLimitPolicy(maxIssuancePerMinute, _rateLimitWindow);
|
||||
var rateLimitResult = await _rateLimiter
|
||||
.TryAcquireAsync(rateKey, ratePolicy, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (!rateLimitResult.IsAllowed)
|
||||
{
|
||||
_logger?.LogDebug(
|
||||
"DPoP nonce issuance rate-limited for key {StorageKey}. Current: {Current}, Max: {Max}",
|
||||
storageKey,
|
||||
rateLimitResult.CurrentCount,
|
||||
maxIssuancePerMinute);
|
||||
return DpopNonceIssueResult.RateLimited("rate_limited");
|
||||
}
|
||||
|
||||
var nonce = DpopNonceUtilities.GenerateNonce();
|
||||
var nonceHash = DpopNonceUtilities.EncodeHash(DpopNonceUtilities.ComputeNonceHash(nonce));
|
||||
|
||||
var now = _timeProvider.GetUtcNow();
|
||||
var expiresAt = now.Add(ttl);
|
||||
|
||||
var metadata = new DpopNonceMetadata
|
||||
{
|
||||
IssuedAt = now,
|
||||
Ttl = ttl
|
||||
};
|
||||
|
||||
var storeResult = await _tokenStore
|
||||
.StoreAsync(storageKey, nonceHash, metadata, ttl, cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
|
||||
if (!storeResult.Success)
|
||||
{
|
||||
_logger?.LogWarning("Failed to store DPoP nonce for key {StorageKey}", storageKey);
|
||||
return DpopNonceIssueResult.Failure("storage_error");
|
||||
}
|
||||
|
||||
_logger?.LogDebug("Issued DPoP nonce for key {StorageKey}, expires at {ExpiresAt:o}", storageKey, expiresAt);
|
||||
return DpopNonceIssueResult.Success(nonce, expiresAt);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user