Skip to content

Commit 1f7fe82

Browse files
Apply V4 style in in-memory host and fix logout issue (#2060)
* in memory host in V4 style * fix issue with logout * introduce testmatrix to BackchannelLogoutEndpointTests * introduce testmatrix to LoginEndpoint tests * introduce testmatrix to UserEndpointTests * introduce testmatrix to LocalEndpointTests * implemented test matrix for yarp based tests * removed empty files * fix playwright tests
1 parent c97e0ec commit 1f7fe82

22 files changed

+747
-652
lines changed

bff/hosts/Hosts.Bff.InMemory/Extensions.cs

Lines changed: 0 additions & 164 deletions
This file was deleted.

bff/hosts/Hosts.Bff.InMemory/Program.cs

Lines changed: 103 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,116 @@
22
// See LICENSE in the project root for license information.
33

44
using Bff;
5+
using Duende.AccessTokenManagement.OpenIdConnect;
6+
using Duende.Bff;
7+
using Duende.Bff.AccessTokenManagement;
8+
using Duende.Bff.Configuration;
9+
using Duende.Bff.Yarp;
10+
using Hosts.ServiceDefaults;
511

612
Console.Title = "BFF";
713

814
var builder = WebApplication.CreateBuilder(args);
915
builder.AddServiceDefaults();
1016

11-
var serviceProviderAccessor = new ServiceProviderAccessor();
17+
var services = builder.Services;
1218

13-
var app = builder
14-
.ConfigureServices(() => serviceProviderAccessor.ServiceProvider ?? throw new InvalidOperationException("Service Provider must be set"))
15-
.ConfigurePipeline();
19+
// Add BFF services to DI - also add server-side session management
20+
services.AddBff()
21+
.WithDefaultOpenIdConnectOptions(options =>
22+
{
23+
var authority = ServiceDiscovery.ResolveService(AppHostServices.IdentityServer);
24+
options.Authority = authority.ToString();
1625

17-
serviceProviderAccessor.ServiceProvider = app.Services;
26+
// confidential client using code flow + PKCE
27+
options.ClientId = "bff";
28+
options.ClientSecret = "secret";
29+
options.ResponseType = "code";
30+
options.ResponseMode = "query";
31+
32+
options.MapInboundClaims = false;
33+
options.GetClaimsFromUserInfoEndpoint = true;
34+
options.SaveTokens = true;
35+
36+
// request scopes + refresh tokens
37+
options.Scope.Clear();
38+
options.Scope.Add("openid");
39+
options.Scope.Add("profile");
40+
options.Scope.Add("api");
41+
options.Scope.Add("scope-for-isolated-api");
42+
options.Scope.Add("offline_access");
43+
44+
options.Resource = "urn:isolated-api";
45+
})
46+
.AddRemoteApis()
47+
.AddServerSideSessions();
48+
49+
// local APIs
50+
services.AddControllers();
51+
52+
services.AddTransient<ImpersonationAccessTokenRetriever>();
53+
54+
services.AddUserAccessTokenHttpClient("api",
55+
configureClient: client => { client.BaseAddress = new Uri("https://localhost:5010/api"); });
56+
57+
58+
var app = builder.Build();
59+
app.UseHttpLogging();
60+
app.UseDeveloperExceptionPage();
61+
62+
app.UseDefaultFiles();
63+
app.UseStaticFiles();
64+
65+
app.UseAuthentication();
66+
app.UseRouting();
67+
68+
// adds antiforgery protection for local APIs
69+
app.UseBff();
70+
71+
// adds authorization for local and remote API endpoints
72+
app.UseAuthorization();
73+
74+
// local APIs
75+
app.MapControllers()
76+
.RequireAuthorization()
77+
.AsBffApiEndpoint();
78+
79+
// login, logout, user, backchannel logout...
80+
app.MapBffManagementEndpoints();
81+
82+
//////////////////////////////////////
83+
// proxy app for cross-site APIs
84+
//////////////////////////////////////
85+
86+
// On this path, we use a client credentials token
87+
app.MapRemoteBffApiEndpoint("/api/client-token", new Uri("https://localhost:5010"))
88+
.WithAccessToken(RequiredTokenType.Client);
89+
90+
// On this path, we use a user token if logged in, and fall back to a client credentials token if not
91+
app.MapRemoteBffApiEndpoint("/api/user-or-client-token", new Uri("https://localhost:5010"))
92+
.WithAccessToken(RequiredTokenType.UserOrClient);
93+
94+
// On this path, we make anonymous requests
95+
app.MapRemoteBffApiEndpoint("/api/anonymous", new Uri("https://localhost:5010"));
96+
97+
// On this path, we use the client token only if the user is logged in
98+
app.MapRemoteBffApiEndpoint("/api/optional-user-token", new Uri("https://localhost:5010"))
99+
.WithAccessToken(RequiredTokenType.UserOrNone);
100+
101+
// On this path, we require the user token
102+
app.MapRemoteBffApiEndpoint("/api/user-token", new Uri("https://localhost:5010"))
103+
.WithAccessToken();
104+
105+
// On this path, we perform token exchange to impersonate a different user
106+
// before making the api request
107+
app.MapRemoteBffApiEndpoint("/api/impersonation", new Uri("https://localhost:5010"))
108+
.WithAccessToken()
109+
.WithAccessTokenRetriever<ImpersonationAccessTokenRetriever>();
110+
111+
// On this path, we obtain an audience constrained token and invoke
112+
// a different api that requires such a token
113+
app.MapRemoteBffApiEndpoint("/api/audience-constrained", new Uri("https://localhost:5012"))
114+
.WithAccessToken()
115+
.WithUserAccessTokenParameter(new BffUserAccessTokenParameters { Resource = Resource.Parse("urn:isolated-api") });
18116

19117
app.Run();

bff/hosts/Hosts.Bff.MultiFrontend/Program.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,14 +184,6 @@
184184

185185
app.MapBffManagementEndpoints();
186186

187-
188-
189-
190-
191-
192-
193-
194-
195187
app.Run();
196188

197189
RouteConfig[] BuildYarpRoutes()

bff/hosts/Hosts.IdentityServer/Config.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ public static class Config
118118
GrantType.ClientCredentials,
119119
OidcConstants.GrantTypes.TokenExchange
120120
},
121-
RedirectUris = { $"{bffMultiFrontendUrl}with-path/bff-signin" },
121+
RedirectUris = { $"{bffMultiFrontendUrl}with-path/signin-oidc" },
122122
FrontChannelLogoutUri = $"{bffMultiFrontendUrl}signout-oidc",
123123
PostLogoutRedirectUris = { $"{bffMultiFrontendUrl}signout-callback-oidc" },
124124

@@ -140,7 +140,7 @@ public static class Config
140140
GrantType.ClientCredentials,
141141
OidcConstants.GrantTypes.TokenExchange
142142
},
143-
RedirectUris = { $"https://app1.localhost:5005/bff-signin" },
143+
RedirectUris = { $"https://app1.localhost:5005/signin-oidc" },
144144
FrontChannelLogoutUri = $"https://app1.localhost:5005/signout-oidc",
145145
PostLogoutRedirectUris = { $"https://app1.localhost:5005/signout-callback-oidc" },
146146

bff/src/Bff/DynamicFrontends/BffAuthenticationSchemes.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ namespace Duende.Bff.DynamicFrontends;
99
public static class BffAuthenticationSchemes
1010
{
1111
public static readonly Scheme BffOpenIdConnect = Scheme.Parse("duende-bff-oidc");
12-
public static readonly Scheme BffDefault = Scheme.Parse("duende-bff-default");
12+
public static readonly Scheme BffCookie = Scheme.Parse("duende-bff-cookie");
1313
}

bff/src/Bff/DynamicFrontends/BffConfigureAuthenticationOptions.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,21 @@ internal class BffConfigureAuthenticationOptions : IPostConfigureOptions<Authent
1010
{
1111
public void PostConfigure(string? name, AuthenticationOptions options)
1212
{
13-
if (options.DefaultScheme == null && options.DefaultAuthenticateScheme == null && options.DefaultAuthenticateScheme == null)
13+
if (options.DefaultScheme == null
14+
&& options.DefaultAuthenticateScheme == null
15+
&& options.DefaultSignOutScheme == null
16+
)
1417
{
15-
options.DefaultScheme = BffAuthenticationSchemes.BffDefault;
18+
options.DefaultScheme = BffAuthenticationSchemes.BffCookie;
1619
options.DefaultChallengeScheme = BffAuthenticationSchemes.BffOpenIdConnect;
20+
options.DefaultSignOutScheme = BffAuthenticationSchemes.BffOpenIdConnect;
21+
22+
// If we don't set this forbid scheme, when calling forbid, it can trigger a stackoverflow exception
23+
// when calling HttpContext.Forbid().
24+
if (options.DefaultForbidScheme == null)
25+
{
26+
options.DefaultForbidScheme = BffAuthenticationSchemes.BffCookie;
27+
}
1728
}
1829
}
1930
}

bff/src/Bff/DynamicFrontends/BffConfigureCookieOptions.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ public void Configure(string? name, CookieAuthenticationOptions options)
2626
options.TimeProvider = timeProvider;
2727
if (selectedFrontend.TryGet(out var frontEnd))
2828
{
29-
30-
//TODO: EV: check if this is needed
31-
//options.ForwardChallenge = frontEnd.OidcSchemeName;
32-
3329
if (frontEnd.SelectionCriteria.MatchingPath != null)
3430
{
3531
options.Cookie.Name = Constants.Cookies.SecurePrefix + "_" + frontEnd.Name;
@@ -44,12 +40,10 @@ public void Configure(string? name, CookieAuthenticationOptions options)
4440

4541
frontEnd.ConfigureCookieOptions?.Invoke(options);
4642
}
47-
else if (name == BffAuthenticationSchemes.BffDefault.ToString())
43+
else if (name == BffAuthenticationSchemes.BffCookie.ToString())
4844
{
4945
options.Cookie.Name = Constants.Cookies.DefaultCookieName;
5046

51-
// Todo: EV: check if this is needed
52-
//options.ForwardChallenge = ;
5347
ConfigureDefaults(options);
5448
}
5549
}

bff/src/Bff/DynamicFrontends/Internal/BffAuthenticationSchemeProvider.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ public override async Task<IEnumerable<AuthenticationScheme>> GetRequestHandlerS
3838
{
3939
selectedFrontend.TryGet(out var frontend);
4040

41-
if (name == frontend?.CookieSchemeName || name == BffAuthenticationSchemes.BffDefault)
41+
if (name == frontend?.CookieSchemeName || name == BffAuthenticationSchemes.BffCookie)
4242
{
43-
return new BffAuthenticationScheme(frontend?.CookieSchemeName ?? BffAuthenticationSchemes.BffDefault, "Duende Bff Cookie", typeof(CookieAuthenticationHandler));
43+
return new BffAuthenticationScheme(frontend?.CookieSchemeName ?? BffAuthenticationSchemes.BffCookie, "Duende Bff Cookie", typeof(CookieAuthenticationHandler));
4444
}
4545

4646
if (name == frontend?.OidcSchemeName || name == BffAuthenticationSchemes.BffOpenIdConnect)

bff/src/Bff/SessionManagement/Configuration/PostConfigureApplicationCookieTicketStore.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ public void PostConfigure(string? name, CookieAuthenticationOptions options)
2626
{
2727
var isDefaultScheme = name == _scheme;
2828
var isForBffFrontend = selectedFrontend.TryGet(out var frontend) && name == frontend.CookieSchemeName;
29-
if (isDefaultScheme || isForBffFrontend)
29+
var isForImplicitConfig = BffAuthenticationSchemes.BffCookie == name;
30+
if (isDefaultScheme || isForBffFrontend || isForImplicitConfig)
3031
{
3132
options.SessionStore = new TicketStoreShim(httpContextAccessor);
3233
}

0 commit comments

Comments
 (0)