diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPJwtBearerEvents.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPJwtBearerEvents.cs
index 1b37e392e..241098f7a 100644
--- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPJwtBearerEvents.cs
+++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPJwtBearerEvents.cs
@@ -39,7 +39,7 @@ internal class DPoPJwtBearerEvents
///
public Task MessageReceived(MessageReceivedContext context)
{
- _logger.LogDebug("MessageReceived invoked in a JWT bearer authentication scheme using DPoP");
+ using var activity = Tracing.ActivitySource.StartActivity("DPoPJwtBearerEvents.MessageReceived");
var dpopOptions = _optionsMonitor.Get(context.Scheme.Name);
@@ -62,7 +62,7 @@ internal class DPoPJwtBearerEvents
///
public async Task TokenValidated(TokenValidatedContext context)
{
- _logger.LogDebug("TokenValidated invoked in a JWT bearer authentication scheme using DPoP");
+ using var activity = Tracing.ActivitySource.StartActivity("DPoPJwtBearerEvents.TokenValidated");
var dPoPOptions = _optionsMonitor.Get(context.Scheme.Name);
@@ -135,7 +135,7 @@ internal class DPoPJwtBearerEvents
///
/// Checks if the HTTP authorization header's 'scheme' is DPoP.
///
- protected static bool IsDPoPAuthorizationScheme(HttpRequest request)
+ private static bool IsDPoPAuthorizationScheme(HttpRequest request)
{
var authz = request.Headers.Authorization.FirstOrDefault();
return authz?.StartsWith(DPoPPrefix, StringComparison.OrdinalIgnoreCase) == true;
@@ -144,7 +144,7 @@ internal class DPoPJwtBearerEvents
///
/// Attempts to retrieve a DPoP access token from an .
///
- public bool TryGetDPoPAccessToken(HttpRequest request,
+ private bool TryGetDPoPAccessToken(HttpRequest request,
int maxLength,
[NotNullWhen(true)] out string? token)
{
@@ -172,7 +172,8 @@ internal class DPoPJwtBearerEvents
///
public Task Challenge(JwtBearerChallengeContext context)
{
- _logger.LogDebug("Challenge invoked in a JWT bearer authentication scheme using DPoP");
+ using var activity = Tracing.ActivitySource.StartActivity("DPoPJwtBearerEvents.Challenge");
+
var dPoPOptions = _optionsMonitor.Get(context.Scheme.Name);
if (!dPoPOptions.AllowBearerTokens)
diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs
index 88126f585..a4f4cdff9 100644
--- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs
+++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/DPoPProofValidator.cs
@@ -72,13 +72,14 @@ internal class DPoPProofValidator : IDPoPProofValidator
///
public async Task Validate(DPoPProofValidationContext context, CancellationToken cancellationToken = default)
{
- Logger.LogDebug("Validating DPoP proof token");
+ using var activity = Tracing.ActivitySource.StartActivity("DPoPProofValidator.Validate");
+
var result = new DPoPProofValidationResult();
if (string.IsNullOrEmpty(context.ProofToken))
{
Logger.LogDebug("Missing DPoP proof value");
- result.SetError("Missing DPoP proof value", OidcConstants.TokenErrors.InvalidRequest);
+ result.SetError("Missing DPoP proof token.", OidcConstants.TokenErrors.InvalidRequest);
return result;
}
@@ -115,7 +116,7 @@ internal class DPoPProofValidator : IDPoPProofValidator
await ValidateReplay(context, result, cancellationToken);
if (result.IsError)
{
- Logger.LogDebug("Detected replay of DPoP proof token");
+ Logger.LogInformation("Detected replay of DPoP proof token");
}
Logger.LogDebug("Successfully validated DPoP proof token");
diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/ReplayCache.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/ReplayCache.cs
index 601b2886c..651df3e07 100644
--- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/ReplayCache.cs
+++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/ReplayCache.cs
@@ -21,6 +21,8 @@ internal class ReplayCache : IReplayCache
public async Task Add(string handle, TimeSpan expiration, CancellationToken ct)
{
+ using var activity = Tracing.ActivitySource.StartActivity("ReplayCache.Add");
+
var options = new HybridCacheEntryOptions
{
Expiration = expiration
@@ -36,10 +38,15 @@ internal class ReplayCache : IReplayCache
| HybridCacheEntryFlags.DisableUnderlyingData
};
- public async Task Exists(string handle, CancellationToken ct) => await _cache.GetOrCreateAsync(
+ public async Task Exists(string handle, CancellationToken ct)
+ {
+ using var activity = Tracing.ActivitySource.StartActivity("ReplayCache.Exists");
+
+ return await _cache.GetOrCreateAsync(
Prefix + handle,
// The factory will never be invoked because the ReadOnlyEntryOptions set the DisableUnderlyingData flag
cancel => throw new InvalidOperationException("Can't Happen"),
ReadOnlyEntryOptions,
cancellationToken: ct);
+ }
}
diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/Tracing.cs b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/Tracing.cs
new file mode 100644
index 000000000..731c81180
--- /dev/null
+++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/DPoP/Tracing.cs
@@ -0,0 +1,19 @@
+// Copyright (c) Duende Software. All rights reserved.
+// See LICENSE in the project root for license information.
+
+using System.Diagnostics;
+
+namespace Duende.AspNetCore.Authentication.JwtBearer.DPoP;
+
+internal static class Tracing
+{
+ private static readonly Version? AssemblyVersion = typeof(Tracing).Assembly.GetName().Version;
+
+ public static string ServiceVersion =>
+ AssemblyVersion != null ? $"{AssemblyVersion.Major}.{AssemblyVersion.Minor}.{AssemblyVersion.Build}" :
+ "Unknown Version";
+
+ public static ActivitySource ActivitySource { get; } = new(
+ "Duende.AspNetCore.Authentication.JwtBearer",
+ ServiceVersion);
+}
diff --git a/identity-server/aspire/ServiceDefaults/Extensions.cs b/identity-server/aspire/ServiceDefaults/Extensions.cs
index 023d49f88..5c5d31796 100644
--- a/identity-server/aspire/ServiceDefaults/Extensions.cs
+++ b/identity-server/aspire/ServiceDefaults/Extensions.cs
@@ -62,6 +62,7 @@ public static class Extensions
.AddSource(IdentityServerConstants.Tracing.Services)
.AddSource(IdentityServerConstants.Tracing.Stores)
.AddSource(IdentityServerConstants.Tracing.Validation)
+ .AddSource("Duende.AspNetCore.Authentication.JwtBearer")
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation();
});
diff --git a/identity-server/clients/src/APIs/DPoPApi/DPoPApi.csproj b/identity-server/clients/src/APIs/DPoPApi/DPoPApi.csproj
index 78bee6dce..37fd73ef6 100644
--- a/identity-server/clients/src/APIs/DPoPApi/DPoPApi.csproj
+++ b/identity-server/clients/src/APIs/DPoPApi/DPoPApi.csproj
@@ -1,12 +1,12 @@
+
-
diff --git a/identity-server/clients/src/APIs/DPoPApi/Program.cs b/identity-server/clients/src/APIs/DPoPApi/Program.cs
index 31ddfb6c1..39cc70afe 100644
--- a/identity-server/clients/src/APIs/DPoPApi/Program.cs
+++ b/identity-server/clients/src/APIs/DPoPApi/Program.cs
@@ -32,7 +32,8 @@ try
builder.Services.ConfigureDPoPTokensForScheme("token", options =>
{
- options.TokenMode = DPoPMode.DPoPAndBearer;
+ options.AllowBearerTokens = true;
+ options.EnableReplayDetection = true;
});
var app = builder.Build();