Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Commit cca5e5f

Browse files
committed
Handle ordering edge cases in auth state changes
1 parent 85257fb commit cca5e5f

File tree

2 files changed

+29
-3
lines changed

2 files changed

+29
-3
lines changed

Diff for: src/Duende.Bff.Blazor/BffBuilderExtensions.cs

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Duende Software. All rights reserved.
22
// See LICENSE in the project root for license information.
33

4+
using Duende.AccessTokenManagement.OpenIdConnect;
45
using Microsoft.AspNetCore.Builder;
56
using Microsoft.AspNetCore.Components.Authorization;
67
using Microsoft.Extensions.DependencyInjection;
@@ -13,6 +14,11 @@ public static BffBuilder AddBlazorServer(this BffBuilder builder)
1314
{
1415
builder.Services.AddOpenIdConnectAccessTokenManagement()
1516
.AddBlazorServerAccessTokenManagement<ServerSideTokenStore>();
17+
18+
var removeThis = builder.Services.First(d => d.ImplementationType == typeof(ServerSideTokenStore));
19+
builder.Services.Remove(removeThis);
20+
builder.Services.AddScoped<IUserTokenStore, ServerSideTokenStore>();
21+
1622
builder.Services.AddScoped<AuthenticationStateProvider, BffServerAuthenticationStateProvider>();
1723
builder.Services.AddScoped<CaptureManagementClaimsCookieEvents>();
1824

Diff for: src/Duende.Bff.Blazor/ServerSideTokenStore.cs

+23-3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Security.Claims;
55
using Duende.AccessTokenManagement.OpenIdConnect;
66
using Microsoft.AspNetCore.Authentication;
7+
using Microsoft.AspNetCore.Components.Authorization;
78
using Microsoft.AspNetCore.DataProtection;
89
using Microsoft.Extensions.Logging;
910

@@ -16,22 +17,33 @@ public class ServerSideTokenStore(
1617
IStoreTokensInAuthenticationProperties tokensInAuthProperties,
1718
IUserSessionStore sessionStore,
1819
IDataProtectionProvider dataProtectionProvider,
19-
ILogger<ServerSideTokenStore> logger) : IUserTokenStore
20+
ILogger<ServerSideTokenStore> logger,
21+
AuthenticationStateProvider authenticationStateProvider) : IUserTokenStore
2022
{
2123
private readonly IDataProtector protector =
2224
dataProtectionProvider.CreateProtector(ServerSideTicketStore.DataProtectorPurpose);
2325

26+
private readonly IHostEnvironmentAuthenticationStateProvider _authenticationStateProvider = authenticationStateProvider as IHostEnvironmentAuthenticationStateProvider
27+
?? throw new ArgumentException("AuthenticationStateProvider must implement IHostEnvironmentAuthenticationStateProvider");
28+
2429
public async Task<UserToken> GetTokenAsync(ClaimsPrincipal user, UserTokenRequestParameters? parameters = null)
2530
{
2631
logger.LogDebug("Retrieving token for user {user}", user.Identity?.Name);
2732
var session = await GetSession(user);
33+
if (session == null)
34+
{
35+
var anonymous = new ClaimsPrincipal(new ClaimsIdentity());
36+
var loggedOutTask = Task.FromResult(new AuthenticationState(user: anonymous));
37+
_authenticationStateProvider.SetAuthenticationState(loggedOutTask);
38+
return new UserToken();
39+
}
2840
var ticket = session.Deserialize(protector, logger) ??
2941
throw new InvalidOperationException("Failed to deserialize authentication ticket from session");
3042

3143
return tokensInAuthProperties.GetUserToken(ticket.Properties, parameters);
3244
}
3345

34-
private async Task<UserSession> GetSession(ClaimsPrincipal user)
46+
private async Task<UserSession?> GetSession(ClaimsPrincipal user)
3547
{
3648
var sub = user.FindFirst("sub")?.Value ?? throw new InvalidOperationException("no sub claim");
3749
var sid = user.FindFirst("sid")?.Value ?? throw new InvalidOperationException("no sid claim");
@@ -44,7 +56,10 @@ private async Task<UserSession> GetSession(ClaimsPrincipal user)
4456
SessionId = sid
4557
});
4658

47-
if (sessions.Count == 0) throw new InvalidOperationException("No ticket found");
59+
if (sessions.Count == 0)
60+
{
61+
return null;
62+
}
4863
if (sessions.Count > 1) throw new InvalidOperationException("Multiple tickets found");
4964

5065
return sessions.First();
@@ -67,6 +82,11 @@ public async Task ClearTokenAsync(ClaimsPrincipal user, UserTokenRequestParamete
6782
protected async Task UpdateTicket(ClaimsPrincipal user, Action<AuthenticationTicket> updateAction)
6883
{
6984
var session = await GetSession(user);
85+
if (session == null)
86+
{
87+
logger.LogDebug("Failed to find a session to update, bailing out");
88+
return;
89+
}
7090
var ticket = session.Deserialize(protector, logger) ??
7191
throw new InvalidOperationException("Failed to deserialize authentication ticket from session");
7292

0 commit comments

Comments
 (0)