50 lines
1.5 KiB
C#
50 lines
1.5 KiB
C#
namespace StellaOps.Auth.Security.Dpop;
|
|
|
|
public sealed partial class DpopProofValidator
|
|
{
|
|
private async ValueTask<DpopValidationResult> ValidateInternalAsync(
|
|
string proof,
|
|
string httpMethod,
|
|
Uri httpUri,
|
|
string? nonce,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(proof);
|
|
ArgumentException.ThrowIfNullOrWhiteSpace(httpMethod);
|
|
ArgumentNullException.ThrowIfNull(httpUri);
|
|
|
|
var now = _timeProvider.GetUtcNow();
|
|
|
|
if (!TryReadHeader(proof, out var header, out var headerFailure))
|
|
{
|
|
return headerFailure;
|
|
}
|
|
|
|
if (!TryReadPayload(proof, httpMethod, httpUri, nonce, out var payload, out var payloadFailure))
|
|
{
|
|
return payloadFailure;
|
|
}
|
|
|
|
var timeFailure = ValidateIssuedAt(payload.IssuedAt, now);
|
|
if (timeFailure is not null)
|
|
{
|
|
return timeFailure;
|
|
}
|
|
|
|
var signatureFailure = ValidateSignature(proof, header);
|
|
if (signatureFailure is not null)
|
|
{
|
|
return signatureFailure;
|
|
}
|
|
|
|
var replayFailure = await TryRecordReplayAsync(payload.JwtId, payload.IssuedAt, cancellationToken)
|
|
.ConfigureAwait(false);
|
|
if (replayFailure is not null)
|
|
{
|
|
return replayFailure;
|
|
}
|
|
|
|
return DpopValidationResult.Success(header.Key, payload.JwtId, payload.IssuedAt, payload.Nonce);
|
|
}
|
|
}
|