diff --git a/src/Bifrost.Web/Features/Heimdall/HeimdallTokenVerifier.cs b/src/Bifrost.Web/Features/Heimdall/HeimdallTokenVerifier.cs index 38f71f1..8e82ed4 100644 --- a/src/Bifrost.Web/Features/Heimdall/HeimdallTokenVerifier.cs +++ b/src/Bifrost.Web/Features/Heimdall/HeimdallTokenVerifier.cs @@ -193,11 +193,6 @@ public sealed class HeimdallTokenVerifier( await _fetchGate.WaitAsync(cancellationToken); try { - if (TryFreshKey(kid, out cached)) - { - return cached; - } - var now = timeProvider.GetUtcNow(); if (now - _attemptedAt >= KeyRefreshInterval) { diff --git a/tests/Bifrost.Web.Tests/HeimdallCompletionTests.cs b/tests/Bifrost.Web.Tests/HeimdallCompletionTests.cs index 2aef4a7..1f2da00 100644 --- a/tests/Bifrost.Web.Tests/HeimdallCompletionTests.cs +++ b/tests/Bifrost.Web.Tests/HeimdallCompletionTests.cs @@ -643,6 +643,32 @@ public sealed class HeimdallCompletionTests Assert.Null(host.Heimdall.StartSecrets[0]); } + [Theory] + [InlineData("https://localhost", "https://localhost/auth/heimdall/complete?attempt=")] + [InlineData("https://localhost/", "https://localhost/auth/heimdall/complete?attempt=")] + [InlineData("https://localhost/sub", "https://localhost/sub/auth/heimdall/complete?attempt=")] + [InlineData("https://localhost/sub/", "https://localhost/sub/auth/heimdall/complete?attempt=")] + public async Task The_return_target_Heimdall_gets_is_under_the_public_base_url(string publicBaseUrl, string prefix) + { + using var host = new HeimdallHost(publicBaseUrl: publicBaseUrl); + var attempt = await host.StartAsync(); + + Assert.Equal(prefix + attempt.Nonce, attempt.ReturnTo); + Assert.True((await Genuine(host, attempt, HeimdallShapes.NewAccountId())).SignedIn); + } + + [Fact] + public async Task A_member_start_with_no_allowed_discord_roles_is_refused_before_Heimdall_is_called() + { + using var host = new HeimdallHost(discordRoles: false); + + var member = await host.StartAsync(member: true); + + Assert.Equal(ErrorRedirect, member.Response.Headers.Location!.OriginalString); + Assert.Empty(host.Heimdall.StartBodies); + Assert.NotNull((await host.StartAsync()).Cookie); + } + [Fact] public async Task Every_completion_refusal_looks_the_same() { @@ -674,6 +700,9 @@ public sealed class HeimdallCompletionTests "Heimdall did not grant Bifrost member access.") }; + var illFormed = await host.CompleteAsync(new string('A', 42) + "!", "code", "x"); + results.Add(("ill-formed nonce", illFormed, "Heimdall completion has no attempt for this browser.")); + using var client = host.NewClient(); using var json = await client.PostAsync( "/auth/heimdall/complete", @@ -694,6 +723,7 @@ public sealed class HeimdallCompletionTests } Assert.Null(await host.Account(accountId)); + Assert.False(illFormed.Response.Headers.Contains("Set-Cookie")); foreach (var url in new[] { "/auth/heimdall/bogus", "/auth/heimdall/twitch?access=member" }) { diff --git a/tests/Bifrost.Web.Tests/Support/HeimdallTestKit.cs b/tests/Bifrost.Web.Tests/Support/HeimdallTestKit.cs index 94861cb..c4992a7 100644 --- a/tests/Bifrost.Web.Tests/Support/HeimdallTestKit.cs +++ b/tests/Bifrost.Web.Tests/Support/HeimdallTestKit.cs @@ -348,6 +348,8 @@ public sealed class HeimdallHost : TestWebApplicationFactory private readonly string _appSecret; private readonly string _baseUrl; + private readonly string _publicBaseUrl; + private readonly bool _discordRoles; public TestClock Clock { get; } = new(); @@ -357,10 +359,16 @@ public sealed class HeimdallHost : TestWebApplicationFactory public HeimdallKey Key { get; } = HeimdallKey.Generate(); - public HeimdallHost(string appSecret = AppSecret, string baseUrl = HeimdallShapes.Issuer) + public HeimdallHost( + string appSecret = AppSecret, + string baseUrl = HeimdallShapes.Issuer, + string publicBaseUrl = "https://localhost", + bool discordRoles = true) { _appSecret = appSecret; _baseUrl = baseUrl; + _publicBaseUrl = publicBaseUrl; + _discordRoles = discordRoles; Heimdall.Published.Add(Key); Heimdall.RequiredAppSecret = AppSecret; } @@ -378,8 +386,12 @@ public sealed class HeimdallHost : TestWebApplicationFactory ["Heimdall:BaseUrl"] = _baseUrl, ["Heimdall:AppSecret"] = _appSecret, ["Heimdall:DiscordGuildId"] = "guild-1", - ["Heimdall:DiscordAllowedRoleIds:0"] = "role-1" + ["Host:PublicBaseUrl"] = _publicBaseUrl }); + if (_discordRoles) + { + configuration.AddInMemoryCollection(new Dictionary { ["Heimdall:DiscordAllowedRoleIds:0"] = "role-1" }); + } }); builder.ConfigureLogging(logging => logging.AddProvider(Logs)); builder.ConfigureServices(services =>