diff --git a/Directory.Packages.props b/Directory.Packages.props index d911c69d3..d5c161ffd 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -40,7 +40,7 @@ that supports the target frameworks our products target (8, 9, 10) --> - + @@ -136,4 +136,4 @@ that supports the target frameworks our products target (8, 9, 10) --> - + \ No newline at end of file diff --git a/bff/bff.slnf b/bff/bff.slnf index 1b9761854..dda74c9af 100644 --- a/bff/bff.slnf +++ b/bff/bff.slnf @@ -2,8 +2,6 @@ "solution": { "path": "..\\products.slnx", "projects": [ - "bff\\performance\\Bff.Benchmarks\\Bff.Benchmarks.csproj", - "bff\\performance\\Bff.Performance\\Bff.Performance.csproj", ".github\\workflow-gen\\workflow-gen.csproj", "bff\\hosts\\Blazor\\PerComponent\\Hosts.Bff.Blazor.PerComponent.Client\\Hosts.Bff.Blazor.PerComponent.Client.csproj", "bff\\hosts\\Blazor\\PerComponent\\Hosts.Bff.Blazor.PerComponent\\Hosts.Bff.Blazor.PerComponent.csproj", @@ -13,8 +11,8 @@ "bff\\hosts\\Hosts.Bff.DPoP\\Hosts.Bff.DPoP.csproj", "bff\\hosts\\Hosts.Bff.EF\\Hosts.Bff.EF.csproj", "bff\\hosts\\Hosts.Bff.InMemory\\Hosts.Bff.InMemory.csproj", - "bff\\hosts\\Hosts.Bff.Performance\\Hosts.Bff.Performance.csproj", "bff\\hosts\\Hosts.Bff.MultiFrontend\\Hosts.Bff.MultiFrontend.csproj", + "bff\\hosts\\Hosts.Bff.Performance\\Hosts.Bff.Performance.csproj", "bff\\hosts\\Hosts.IdentityServer\\Hosts.IdentityServer.csproj", "bff\\hosts\\Hosts.ServiceDefaults\\Hosts.ServiceDefaults.csproj", "bff\\hosts\\RemoteApis\\Hosts.RemoteApi.DPoP\\Hosts.RemoteApi.DPoP.csproj", @@ -22,6 +20,7 @@ "bff\\hosts\\RemoteApis\\Hosts.RemoteApi\\Hosts.RemoteApi.csproj", "bff\\migrations\\UserSessionDb\\UserSessionDb.csproj", "bff\\performance\\Bff.Benchmarks\\Bff.Benchmarks.csproj", + "bff\\performance\\Bff.Performance\\Bff.Performance.csproj", "bff\\src\\Bff.Blazor.Client\\Bff.Blazor.Client.csproj", "bff\\src\\Bff.Blazor\\Bff.Blazor.csproj", "bff\\src\\Bff.EntityFramework\\Bff.EntityFramework.csproj", @@ -33,8 +32,8 @@ "bff\\templates\\src\\BffRemoteApi\\BffRemoteApi.csproj", "bff\\test\\Bff.Tests\\Bff.Tests.csproj", "bff\\test\\Hosts.Tests\\Hosts.Tests.csproj", - "shared\\Xunit.Playwright\\Duende.Xunit.Playwright.csproj", - "shared\\ShouldlyExtensions\\ShouldlyExtensions.csproj" + "shared\\ShouldlyExtensions\\ShouldlyExtensions.csproj", + "shared\\Xunit.Playwright\\Duende.Xunit.Playwright.csproj" ] } -} +} \ No newline at end of file diff --git a/bff/src/Bff/HttpContextExtensions.cs b/bff/src/Bff/HttpContextExtensions.cs index 7be3a4da8..f2254abac 100644 --- a/bff/src/Bff/HttpContextExtensions.cs +++ b/bff/src/Bff/HttpContextExtensions.cs @@ -95,7 +95,7 @@ internal static class HttpContextExtensions return new DPoPTokenResult() { - AccessToken = AccessToken.Parse(userToken.ToString()), + AccessToken = AccessToken.Parse(userToken.AccessToken.ToString()), DPoPJsonWebKey = DPoPProofKey.Parse(userToken.DPoPJsonWebKey!.ToString()!) }; } @@ -156,7 +156,7 @@ internal static class HttpContextExtensions return new DPoPTokenResult() { - AccessToken = AccessToken.Parse(clientToken.ToString()), + AccessToken = AccessToken.Parse(clientToken.AccessToken.ToString()), DPoPJsonWebKey = DPoPProofKey.Parse(clientToken.DPoPJsonWebKey!.ToString()!) }; diff --git a/bff/test/Bff.Tests/Bff.Tests.csproj b/bff/test/Bff.Tests/Bff.Tests.csproj index c3374d6b3..a88f859af 100644 --- a/bff/test/Bff.Tests/Bff.Tests.csproj +++ b/bff/test/Bff.Tests/Bff.Tests.csproj @@ -7,6 +7,7 @@ + diff --git a/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/DPoPRemoteEndpointTests.cs similarity index 51% rename from bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs rename to bff/test/Bff.Tests/Endpoints/DPoPRemoteEndpointTests.cs index bb51785d2..58d8f4fcb 100644 --- a/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/DPoPRemoteEndpointTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. +using Duende.AspNetCore.Authentication.JwtBearer.DPoP; using Duende.Bff.AccessTokenManagement; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestInfra; @@ -9,7 +10,7 @@ using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints; -public class DpopRemoteEndpointTests(ITestOutputHelper output) : BffTestBase(output), IAsyncLifetime +public class DPoPRemoteEndpointTests(ITestOutputHelper output) : BffTestBase(output) { public override async Task InitializeAsync() { @@ -18,11 +19,7 @@ public class DpopRemoteEndpointTests(ITestOutputHelper output) : BffTestBase(out idSrvClient.RequireDPoP = true; Bff.OnConfigureBff += bff => bff.AddRemoteApis(); - Bff.OnConfigureApp += app => - { - app.MapRemoteBffApiEndpoint(The.Path, Api.Url()) - .WithAccessToken(RequiredTokenType.Client); - }; + await base.InitializeAsync(); Bff.BffOptions.DPoPJsonWebKey = The.DPoPJsonWebKey; @@ -34,17 +31,55 @@ public class DpopRemoteEndpointTests(ITestOutputHelper output) : BffTestBase(out } [Fact] - public async Task Can_login_with_dpop_enabled() => await Bff.BrowserClient.Login() - .CheckHttpStatusCode(); - - [Fact] - public async Task When_calling_api_endpoint_with_dpop_enabled_then_dpop_headers_are_sent() + public async Task Can_call_dpop_protected_api_with_user_token() { + Api.OnConfigureServices += services => + { + services.ConfigureDPoPTokensForScheme("token"); + }; + + Bff.OnConfigureApp += app => + { + app.MapRemoteBffApiEndpoint(The.Path, Api.Url()) + .WithAccessToken(RequiredTokenType.User); + }; + + await InitializeAsync(); + + await Bff.BrowserClient.Login() + .CheckHttpStatusCode(); + ApiCallDetails callToApi = await Bff.BrowserClient.CallBffHostApi( url: Bff.Url(The.PathAndSubPath) ); callToApi.RequestHeaders["DPoP"].First().ShouldNotBeNullOrEmpty(); callToApi.RequestHeaders["Authorization"].First().StartsWith("DPoP ").ShouldBeTrue(); + callToApi.Sub.ShouldNotBeNullOrEmpty(); + } + + [Fact] + public async Task Can_call_dpop_protected_api_with_client_token() + { + Api.OnConfigureServices += services => + { + services.ConfigureDPoPTokensForScheme("token"); + }; + + Bff.OnConfigureApp += app => + { + app.MapRemoteBffApiEndpoint(The.Path, Api.Url()) + .WithAccessToken(RequiredTokenType.Client); + }; + + await InitializeAsync(); + + ApiCallDetails callToApi = await Bff.BrowserClient.CallBffHostApi( + url: Bff.Url(The.PathAndSubPath) + ); + + callToApi.RequestHeaders["DPoP"].First().ShouldNotBeNullOrEmpty(); + callToApi.RequestHeaders["Authorization"].First().StartsWith("DPoP ").ShouldBeTrue(); + callToApi.ClientId.ShouldNotBeNullOrEmpty(); } }