diff --git a/test/Duende.Bff.Blazor.UnitTests/Duende.Bff.Blazor.UnitTests.csproj b/test/Duende.Bff.Blazor.UnitTests/Duende.Bff.Blazor.UnitTests.csproj index 9c5b30a2..2c104e3d 100644 --- a/test/Duende.Bff.Blazor.UnitTests/Duende.Bff.Blazor.UnitTests.csproj +++ b/test/Duende.Bff.Blazor.UnitTests/Duende.Bff.Blazor.UnitTests.csproj @@ -12,6 +12,8 @@ + + @@ -20,4 +22,8 @@ + + + + diff --git a/test/Duende.Bff.Blazor.UnitTests/ServerSideTokenStoreTests.cs b/test/Duende.Bff.Blazor.UnitTests/ServerSideTokenStoreTests.cs new file mode 100644 index 00000000..ec82a694 --- /dev/null +++ b/test/Duende.Bff.Blazor.UnitTests/ServerSideTokenStoreTests.cs @@ -0,0 +1,84 @@ +using System.Security.Claims; +using Duende.AccessTokenManagement.OpenIdConnect; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using NSubstitute; +using Shouldly; + +namespace Duende.Bff.Blazor.UnitTests; + +public class ServerSideTokenStoreTests +{ + private ClaimsPrincipal CreatePrincipal(string sub, string sid) + { + return new ClaimsPrincipal(new ClaimsIdentity([ + new Claim("sub", sub), + new Claim("sid", sid) + ], "pwd", "name", "role")); + } + + [Fact] + public async Task Can_add_retrieve_and_remove_tokens() + { + var user = CreatePrincipal("sub", "sid"); + var props = new AuthenticationProperties(); + var expectedToken = new UserToken() + { + AccessToken = "expected-access-token" + }; + + // Create shared dependencies + var sessionStore = new InMemoryUserSessionStore(); + var dataProtection = new EphemeralDataProtectionProvider(); + + // Use the ticket store to save the user's initial session + // Note that we don't yet have tokens in the session + var sessionService = new ServerSideTicketStore(sessionStore, dataProtection, Substitute.For>()); + sessionService.StoreAsync(new AuthenticationTicket( + user, + props, + "test" + )); + + var tokensInProps = MockStoreTokensInAuthProps(); + var sut = new ServerSideTokenStore( + tokensInProps, + sessionStore, + dataProtection, + Substitute.For>()); + + await sut.StoreTokenAsync(user, expectedToken); + var actualToken = await sut.GetTokenAsync(user); + + actualToken.ShouldNotBe(null); + actualToken.AccessToken.ShouldBe(expectedToken.AccessToken); + + await sut.ClearTokenAsync(user); + + var resultAfterClearing = await sut.GetTokenAsync(user); + resultAfterClearing.AccessToken.ShouldBeNull(); + } + + private static StoreTokensInAuthenticationProperties MockStoreTokensInAuthProps() + { + var tokenManagementOptionsMonitor = Substitute.For>(); + var tokenManagementOptions = new UserTokenManagementOptions { UseChallengeSchemeScopedTokens = false }; + tokenManagementOptionsMonitor.CurrentValue.Returns(tokenManagementOptions); + + var cookieOptionsMonitor = Substitute.For>(); + var cookieAuthenticationOptions = new CookieAuthenticationOptions(); + cookieOptionsMonitor.CurrentValue.Returns(cookieAuthenticationOptions); + + var schemeProvider = Substitute.For(); + schemeProvider.GetDefaultSignInSchemeAsync().Returns(new AuthenticationScheme("TestScheme", null, typeof(IAuthenticationHandler))); + + return new StoreTokensInAuthenticationProperties( + tokenManagementOptionsMonitor, + cookieOptionsMonitor, + schemeProvider, + Substitute.For>()); + } +} \ No newline at end of file