Return invalid_request when DPoP access token sent without proof

This commit is contained in:
Brett Hazen 2025-05-08 12:57:55 -05:00
parent 844ffae374
commit b6da2c191c
2 changed files with 33 additions and 10 deletions

View file

@ -82,7 +82,9 @@ internal class DPoPJwtBearerEvents
}
else
{
throw new InvalidOperationException("Missing DPoP (proof token) HTTP header");
context.HttpContext.Items["DPoP-Error"] = "invalid_request";
context.Fail("No DPoP header found");
return;
}
var result = await _validator.Validate(new DPoPProofValidationContext

View file

@ -44,7 +44,6 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper)
result.StatusCode.ShouldBe(HttpStatusCode.Unauthorized);
}
[Fact]
[Trait("Category", "Integration")]
public async Task incorrect_token_type_fails()
@ -91,15 +90,8 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper)
Url = "http://localhost/"
});
proof.ShouldNotBeNull();
var anotherProof = await dpopService.CreateProofTokenAsync(new DPoPProofRequest
{
AccessToken = token.AccessToken,
DPoPJsonWebKey = jwk,
Method = "POST",
Url = "http://localhost/"
});
anotherProof.ShouldNotBeNull();
api.HttpClient.DefaultRequestHeaders.Add(OidcConstants.HttpHeaders.DPoP, [proof.ProofToken, proof.ProofToken]);
var result = await api.HttpClient.GetAsync("/");
result.StatusCode.ShouldBe(HttpStatusCode.Unauthorized);
@ -151,6 +143,35 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper)
result.StatusCode.ShouldBe(HttpStatusCode.OK);
}
[Fact]
[Trait("Category", "Integration")]
public async Task access_token_without_proof_token_should_fail()
{
var identityServer = await CreateIdentityServer();
identityServer.Clients.Add(DPoPOnlyClient);
var jwk = CreateJwk();
var api = await CreateDPoPApi();
var app = new AppHost(identityServer, api, "client1", testOutputHelper,
configureUserTokenManagementOptions: opt => opt.DPoPJsonWebKey = jwk);
await app.Initialize();
// Login and get token for api call
await app.LoginAsync("sub");
var response = await app.BrowserClient.GetAsync(app.Url("/user_token"));
var token = await response.Content.ReadFromJsonAsync<UserToken>();
token.ShouldNotBeNull();
token.AccessToken.ShouldNotBeNull();
token.DPoPJsonWebKey.ShouldNotBeNull();
api.HttpClient.SetToken("DPoP", token.AccessToken);
var result = await api.HttpClient.GetAsync("/");
result.StatusCode.ShouldBe(HttpStatusCode.Unauthorized);
var error = result.Headers.GetValues(HeaderNames.WWWAuthenticate).FirstOrDefault();
error.ShouldBe("DPoP error=\"invalid_request\"");
}
[Fact]
[Trait("Category", "Integration")]
public async Task excessively_large_proof_fails()