diff --git a/Directory.Packages.props b/Directory.Packages.props index ab4e81320..0ca6e3bd5 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -39,7 +39,6 @@ - @@ -54,7 +53,7 @@ - + @@ -98,10 +97,10 @@ - - - + + + @@ -117,13 +116,13 @@ - + - + @@ -131,10 +130,11 @@ - - - - + + + + + diff --git a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/AspNetCore.Authentication.JwtBearer.csproj b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/AspNetCore.Authentication.JwtBearer.csproj index 312a65744..439ce677a 100644 --- a/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/AspNetCore.Authentication.JwtBearer.csproj +++ b/aspnetcore-authentication-jwtbearer/src/AspNetCore.Authentication.JwtBearer/AspNetCore.Authentication.JwtBearer.csproj @@ -1,6 +1,6 @@ - net8.0;net9.0 + net8.0;net9.0;net10 enable Duende.AspNetCore.Authentication.JwtBearer Duende.AspNetCore.Authentication.JwtBearer diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/AspNetCore.Authentication.JwtBearer.Tests.csproj b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/AspNetCore.Authentication.JwtBearer.Tests.csproj index 7510e9702..2b832076a 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/AspNetCore.Authentication.JwtBearer.Tests.csproj +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/AspNetCore.Authentication.JwtBearer.Tests.csproj @@ -1,7 +1,7 @@  - net8.0;net9.0 + net8.0;net9.0;net10 enable Duende.AspNetCore.Authentication.JwtBearer.Tests Duende.AspNetCore.Authentication.JwtBearer @@ -15,8 +15,8 @@ - - + + diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/ReplayTests.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/ReplayTests.cs index 0c6c3babe..3af241fca 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/ReplayTests.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoP/ReplayTests.cs @@ -7,14 +7,15 @@ namespace Duende.AspNetCore.Authentication.JwtBearer.DPoP; public class ReplayTests : DPoPProofValidatorTestBase { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; [Fact] [Trait("Category", "Unit")] public async Task replays_detected_in_ValidateReplay_fail() { - ReplayCache.Exists(TokenIdHash).Returns(true); + ReplayCache.Exists(TokenIdHash, _ct).Returns(true); Result.TokenIdHash = TokenIdHash; - await ProofValidator.ValidateReplay(Context, Result); + await ProofValidator.ValidateReplay(Context, Result, _ct); Result.ShouldBeInvalidProofWithDescription("Detected DPoP proof token replay."); } @@ -28,7 +29,7 @@ public class ReplayTests : DPoPProofValidatorTestBase [InlineData(true, true, ClockSkew * 2, ClockSkew * 2)] public async Task new_proof_tokens_are_added_to_replay_cache(bool validateIat, bool validateNonce, int clientClockSkew, int serverClockSkew) { - ReplayCache.Exists(TokenIdHash).Returns(false); + ReplayCache.Exists(TokenIdHash, _ct).Returns(false); Options.ValidationMode = (validateIat && validateNonce) ? ExpirationValidationMode.Both : validateIat ? ExpirationValidationMode.IssuedAt : ExpirationValidationMode.Nonce; @@ -38,7 +39,7 @@ public class ReplayTests : DPoPProofValidatorTestBase Result.TokenIdHash = TokenIdHash; - await ProofValidator.ValidateReplay(Context, Result); + await ProofValidator.ValidateReplay(Context, Result, _ct); Result.IsError.ShouldBeFalse(); var skew = validateIat && validateNonce @@ -47,6 +48,6 @@ public class ReplayTests : DPoPProofValidatorTestBase var expectedExpiration = ProofValidator.TestTimeProvider.GetUtcNow() .Add(TimeSpan.FromSeconds(skew * 2)) .Add(TimeSpan.FromSeconds(ValidFor)); - await ReplayCache.Received().Add(TokenIdHash, expectedExpiration); + await ReplayCache.Received().Add(TokenIdHash, expectedExpiration, _ct); } } diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoPIntegrationTests.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoPIntegrationTests.cs index 753d455b9..779e512d9 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoPIntegrationTests.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoPIntegrationTests.cs @@ -16,13 +16,13 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; using Microsoft.Net.Http.Headers; -using Xunit.Abstractions; namespace Duende.AspNetCore.Authentication.JwtBearer; public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper) { - private Client DPoPOnlyClient = new() + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly Client DPoPOnlyClient = new() { ClientId = "client1", ClientSecrets = [new Secret("secret".ToSha256())], @@ -39,7 +39,7 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper) { var api = await CreateDPoPApi(); - var result = await api.HttpClient.GetAsync("/"); + var result = await api.HttpClient.GetAsync("/", _ct); result.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } @@ -52,7 +52,7 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper) var bearerToken = "unimportant opaque value"; api.HttpClient.SetBearerToken(bearerToken); - var result = await api.HttpClient.GetAsync("/"); + var result = await api.HttpClient.GetAsync("/", _ct); result.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } @@ -72,8 +72,8 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper) // Login and get token for api call await app.LoginAsync("sub"); - var response = await app.BrowserClient.GetAsync(app.Url("/user_token")); - var token = await response.Content.ReadFromJsonAsync(); + var response = await app.BrowserClient.GetAsync(app.Url("/user_token"), _ct); + var token = await response.Content.ReadFromJsonAsync(_ct); token.ShouldNotBeNull(); token.AccessToken.ToString().ShouldNotBeNull(); token.DPoPJsonWebKey.ShouldNotBeNull(); @@ -87,11 +87,11 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper) DPoPProofKey = jwk, Method = HttpMethod.Get, Url = new Uri("http://localhost/") - }); + }, _ct); proof.ShouldNotBeNull(); api.HttpClient.DefaultRequestHeaders.Add(OidcConstants.HttpHeaders.DPoP, [proof.Value, proof.Value]); - var result = await api.HttpClient.GetAsync("/"); + var result = await api.HttpClient.GetAsync("/", _ct); result.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); var error = result.Headers.GetValues(HeaderNames.WWWAuthenticate).FirstOrDefault(); @@ -117,8 +117,8 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper) // Login and get token for api call await app.LoginAsync("sub"); - var response = await app.BrowserClient.GetAsync(app.Url("/user_token")); - var token = await response.Content.ReadFromJsonAsync(); + var response = await app.BrowserClient.GetAsync(app.Url("/user_token"), _ct); + var token = await response.Content.ReadFromJsonAsync(_ct); token.ShouldNotBeNull(); token.AccessToken.ToString().ShouldNotBeNull(); token.DPoPJsonWebKey.ShouldNotBeNull(); @@ -132,11 +132,11 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper) DPoPProofKey = jwk, Method = HttpMethod.Get, Url = new Uri("http://localhost/") - }); + }, _ct); proof.ShouldNotBeNull(); api.HttpClient.DefaultRequestHeaders.Add(OidcConstants.HttpHeaders.DPoP, proof.Value); - var result = await api.HttpClient.GetAsync("/"); + var result = await api.HttpClient.GetAsync("/", _ct); result.StatusCode.ShouldBe(HttpStatusCode.OK); } @@ -156,14 +156,14 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper) // Login and get token for api call await app.LoginAsync("sub"); - var response = await app.BrowserClient.GetAsync(app.Url("/user_token")); - var token = await response.Content.ReadFromJsonAsync(); + var response = await app.BrowserClient.GetAsync(app.Url("/user_token"), _ct); + var token = await response.Content.ReadFromJsonAsync(_ct); token.ShouldNotBeNull(); token.AccessToken.ToString().ShouldNotBeNull(); token.DPoPJsonWebKey.ShouldNotBeNull(); api.HttpClient.SetToken("DPoP", token.AccessToken); - var result = await api.HttpClient.GetAsync("/"); + var result = await api.HttpClient.GetAsync("/", _ct); result.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); var error = result.Headers.GetValues(HeaderNames.WWWAuthenticate).FirstOrDefault(); @@ -189,8 +189,8 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper) // Login and get token for api call await app.LoginAsync("sub"); - var response = await app.BrowserClient.GetAsync(app.Url("/user_token")); - var token = await response.Content.ReadFromJsonAsync(); + var response = await app.BrowserClient.GetAsync(app.Url("/user_token"), _ct); + var token = await response.Content.ReadFromJsonAsync(_ct); token.ShouldNotBeNull(); token.AccessToken.ToString().ShouldNotBeNull(); token.DPoPJsonWebKey.ShouldNotBeNull(); @@ -205,11 +205,11 @@ public class DPoPIntegrationTests(ITestOutputHelper testOutputHelper) Method = HttpMethod.Get, Url = new Uri("http://localhost/"), DPoPNonce = DPoPNonce.Parse(new string('x', maxLength + 1)) // <--- Most important part of the test - }); + }, _ct); proof.ShouldNotBeNull(); api.HttpClient.DefaultRequestHeaders.Add(OidcConstants.HttpHeaders.DPoP, proof.Value); - var result = await api.HttpClient.GetAsync("/"); + var result = await api.HttpClient.GetAsync("/", _ct); result.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/ApiHost.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/ApiHost.cs index 85d1eaf93..9c2a02c5b 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/ApiHost.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/ApiHost.cs @@ -4,7 +4,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.AspNetCore.TestFramework; diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/AppHost.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/AppHost.cs index 59291dae1..513ed6823 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/AppHost.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/AppHost.cs @@ -11,7 +11,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using RichardSzalay.MockHttp; -using Xunit.Abstractions; namespace Duende.AspNetCore.TestFramework; diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/GenericHost.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/GenericHost.cs index 52cd9c766..4afe1fab0 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/GenericHost.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/GenericHost.cs @@ -4,18 +4,29 @@ using System.Net; using System.Reflection; using System.Security.Claims; -using Meziantou.Extensions.Logging.Xunit; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Xunit.Abstractions; namespace Duende.AspNetCore.TestFramework; public class GenericHost { + protected readonly string _baseAddress; + + private readonly ITestOutputHelper _testOutputHelper; + private IServiceProvider _appServices = default!; + + private TestBrowserClient? _browserClient; + + private HttpClient? _httpClient; + private AuthenticationProperties? _propsToSignIn; + private TestServer? _server; + + private ClaimsPrincipal? _userToSignIn; + public GenericHost(ITestOutputHelper testOutputHelper, string baseAddress = "https://server") { if (baseAddress.EndsWith("/")) @@ -27,20 +38,16 @@ public class GenericHost _testOutputHelper = testOutputHelper; } - protected readonly string _baseAddress; - private IServiceProvider _appServices = default!; - public Assembly? HostAssembly { get; set; } public bool IsDevelopment { get; set; } - private TestServer? _server; + public TestServer Server { get => _server ?? throw new InvalidOperationException( - $"Attempt to use {nameof(Server)} before it was initialized. Did you forget to call ${Initialize}?"); + $"Attempt to use {nameof(Server)} before it was initialized. Did you forget to call {nameof(Initialize)}"); private set => _server = value; } - private TestBrowserClient? _browserClient; public TestBrowserClient BrowserClient { get => @@ -49,7 +56,6 @@ public class GenericHost private set => _browserClient = value; } - private HttpClient? _httpClient; public HttpClient HttpClient { get => @@ -58,17 +64,9 @@ public class GenericHost private set => _httpClient = value; } - private readonly ITestOutputHelper _testOutputHelper; - - public T Resolve() - where T : notnull => - // not calling dispose on scope on purpose - _appServices.GetRequiredService().CreateScope().ServiceProvider - .GetRequiredService(); - public string Url(string? path = null) { - path = path ?? string.Empty; + path ??= string.Empty; if (!path.StartsWith("/")) { path = "/" + path; @@ -104,7 +102,7 @@ public class GenericHost private void ConfigureServices(IServiceCollection services) { // This adds log messages to the output of our tests when they fail. - // See https://www.meziantou.net/how-to-view-logs-from-ilogger-in-xunitdotnet.htm + // See https://github.com/martincostello/xunit-logging services.AddLogging(options => { // If you need different log output to understand a test failure, configure it here @@ -113,10 +111,7 @@ public class GenericHost options.AddFilter("Duende.IdentityServer.License", LogLevel.Error); options.AddFilter("Duende.IdentityServer.Startup", LogLevel.Error); - options.AddProvider(new XUnitLoggerProvider(_testOutputHelper, new XUnitLoggerOptions - { - IncludeCategory = true, - })); + options.AddXUnit(_testOutputHelper); }); OnConfigureServices(services); @@ -131,48 +126,41 @@ public class GenericHost ConfigureSignout(builder); } - private void ConfigureSignout(WebApplication app) => app.Use(async (ctx, next) => - { - if (ctx.Request.Path == "/__signout") - { - await ctx.SignOutAsync(); - ctx.Response.StatusCode = 204; - return; - } + private void ConfigureSignout(WebApplication app) => + app.Use(async (ctx, next) => + { + if (ctx.Request.Path == "/__signout") + { + await ctx.SignOutAsync(); + ctx.Response.StatusCode = 204; + return; + } - await next(); - }); + await next(); + }); - public async Task RevokeSessionCookieAsync() - { - var response = await BrowserClient.GetAsync(Url("__signout")); - response.StatusCode.ShouldBe((HttpStatusCode)204); - } + private void ConfigureSignin(WebApplication app) => + app.Use(async (ctx, next) => + { + if (ctx.Request.Path == "/__signin") + { + if (_userToSignIn is not object) + { + throw new Exception("No User Configured for SignIn"); + } - private void ConfigureSignin(WebApplication app) => app.Use(async (ctx, next) => - { - if (ctx.Request.Path == "/__signin") - { - if (_userToSignIn is not object) - { - throw new Exception("No User Configured for SignIn"); - } + var props = _propsToSignIn ?? new AuthenticationProperties(); + await ctx.SignInAsync(_userToSignIn, props); - var props = _propsToSignIn ?? new AuthenticationProperties(); - await ctx.SignInAsync(_userToSignIn, props); + _userToSignIn = null; + _propsToSignIn = null; - _userToSignIn = null; - _propsToSignIn = null; + ctx.Response.StatusCode = 204; + return; + } - ctx.Response.StatusCode = 204; - return; - } - - await next(); - }); - - private ClaimsPrincipal? _userToSignIn; - private AuthenticationProperties? _propsToSignIn; + await next(); + }); public async Task IssueSessionCookieAsync(params Claim[] claims) { @@ -180,10 +168,10 @@ public class GenericHost var response = await BrowserClient.GetAsync(Url("__signin")); response.StatusCode.ShouldBe((HttpStatusCode)204); } + public Task IssueSessionCookieAsync(AuthenticationProperties props, params Claim[] claims) { _propsToSignIn = props; return IssueSessionCookieAsync(claims); } - public Task IssueSessionCookieAsync(string sub, params Claim[] claims) => IssueSessionCookieAsync(claims.Append(new Claim("sub", sub)).ToArray()); } diff --git a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/IdentityServerHost.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/IdentityServerHost.cs index 2a00c1d51..06a7578c6 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/IdentityServerHost.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/IdentityServerHost.cs @@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.JsonWebTokens; using Microsoft.IdentityModel.Tokens; -using Xunit.Abstractions; namespace Duende.AspNetCore.TestFramework; diff --git a/bff/test/Bff.Blazor.Client.UnitTests/Bff.Blazor.Client.UnitTests.csproj b/bff/test/Bff.Blazor.Client.UnitTests/Bff.Blazor.Client.UnitTests.csproj index f689b39ae..e3be98335 100644 --- a/bff/test/Bff.Blazor.Client.UnitTests/Bff.Blazor.Client.UnitTests.csproj +++ b/bff/test/Bff.Blazor.Client.UnitTests/Bff.Blazor.Client.UnitTests.csproj @@ -13,7 +13,7 @@ - + diff --git a/bff/test/Bff.Blazor.UnitTests/Bff.Blazor.UnitTests.csproj b/bff/test/Bff.Blazor.UnitTests/Bff.Blazor.UnitTests.csproj index 70ab36c55..7d12ae238 100644 --- a/bff/test/Bff.Blazor.UnitTests/Bff.Blazor.UnitTests.csproj +++ b/bff/test/Bff.Blazor.UnitTests/Bff.Blazor.UnitTests.csproj @@ -3,28 +3,16 @@ enable enable - false true True - - - - - - - - - - - - + @@ -32,4 +20,8 @@ + + + + diff --git a/bff/test/Bff.Blazor.UnitTests/BffBlazorTests.cs b/bff/test/Bff.Blazor.UnitTests/BffBlazorTests.cs index 374808170..6bd942465 100644 --- a/bff/test/Bff.Blazor.UnitTests/BffBlazorTests.cs +++ b/bff/test/Bff.Blazor.UnitTests/BffBlazorTests.cs @@ -6,24 +6,24 @@ using Duende.Bff; using Duende.Bff.Tests.TestHosts; using Duende.IdentityServer.Models; using Duende.IdentityServer.Services; -using Xunit.Abstractions; namespace Bff.Blazor.UnitTests; public class BffBlazorTests : OutputWritingTestBase { - protected readonly IdentityServerHost IdentityServerHost; - protected ApiHost ApiHost; - protected BffBlazorHost BffHost; + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerHost _identityServerHost; + private readonly ApiHost _apiHost; + private readonly BffBlazorHost _bffHost; public BffBlazorTests(ITestOutputHelper testOutputHelper) : base(testOutputHelper) { - IdentityServerHost = new IdentityServerHost(WriteLine); - ApiHost = new ApiHost(WriteLine, IdentityServerHost, "scope1"); + _identityServerHost = new IdentityServerHost(WriteLine); + _apiHost = new ApiHost(WriteLine, _identityServerHost, "scope1"); - BffHost = new BffBlazorHost(WriteLine, IdentityServerHost, ApiHost, "spa"); + _bffHost = new BffBlazorHost(WriteLine, _identityServerHost, _apiHost, "spa"); - IdentityServerHost.Clients.Add(new Client + _identityServerHost.Clients.Add(new Client { ClientId = "spa", ClientSecrets = { new Secret("secret".Sha256()) }, @@ -37,11 +37,11 @@ public class BffBlazorTests : OutputWritingTestBase - IdentityServerHost.OnConfigureServices += services => + _identityServerHost.OnConfigureServices += services => { services.AddTransient(provider => new DefaultBackChannelLogoutHttpClient( - BffHost!.HttpClient, + _bffHost!.HttpClient, provider.GetRequiredService(), provider.GetRequiredService())); @@ -52,38 +52,38 @@ public class BffBlazorTests : OutputWritingTestBase [Fact] public async Task Can_get_home() { - var response = await BffHost.BrowserClient.GetAsync("/"); + var response = await _bffHost.BrowserClient.GetAsync("/", _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); } + [Fact] - public async Task Cannot_get_secure_without_loggin_in() + public async Task Cannot_get_secure_without_logging_in() { - var response = await BffHost.BrowserClient.GetAsync("/secure"); + var response = await _bffHost.BrowserClient.GetAsync("/secure", _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found, "this indicates we are redirecting to the login page"); } [Fact] public async Task Can_get_secure_when_logged_in() { - await BffHost.BffLoginAsync("sub"); - var response = await BffHost.BrowserClient.GetAsync("/secure"); + await _bffHost.BffLoginAsync("sub"); + var response = await _bffHost.BrowserClient.GetAsync("/secure", _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); } - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { - await IdentityServerHost.InitializeAsync(); - await ApiHost.InitializeAsync(); - await BffHost.InitializeAsync(); + await _identityServerHost.InitializeAsync(); + await _apiHost.InitializeAsync(); + await _bffHost.InitializeAsync(); await base.InitializeAsync(); } - public override async Task DisposeAsync() + public override async ValueTask DisposeAsync() { - await ApiHost.DisposeAsync(); - await BffHost.DisposeAsync(); - await IdentityServerHost.DisposeAsync(); + await _apiHost.DisposeAsync(); + await _bffHost.DisposeAsync(); + await _identityServerHost.DisposeAsync(); await base.DisposeAsync(); - } } diff --git a/bff/test/Bff.EntityFramework.Tests/Bff.EntityFramework.Tests.csproj b/bff/test/Bff.EntityFramework.Tests/Bff.EntityFramework.Tests.csproj index 79ed98191..155a1b68a 100644 --- a/bff/test/Bff.EntityFramework.Tests/Bff.EntityFramework.Tests.csproj +++ b/bff/test/Bff.EntityFramework.Tests/Bff.EntityFramework.Tests.csproj @@ -7,8 +7,9 @@ - + + diff --git a/bff/test/Bff.EntityFramework.Tests/UserSessionStoreTests.cs b/bff/test/Bff.EntityFramework.Tests/UserSessionStoreTests.cs index ea7ebbff3..4abf25f3e 100644 --- a/bff/test/Bff.EntityFramework.Tests/UserSessionStoreTests.cs +++ b/bff/test/Bff.EntityFramework.Tests/UserSessionStoreTests.cs @@ -9,6 +9,7 @@ namespace Duende.Bff.EntityFramework.Tests; public class UserSessionStoreTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly IUserSessionStore _subject; private readonly SessionDbContext _database; @@ -37,7 +38,7 @@ public class UserSessionStoreTests Renewed = new DateTime(2021, 4, 2, 10, 13, 34, DateTimeKind.Utc), Expires = new DateTime(2022, 5, 3, 11, 14, 35, DateTimeKind.Utc), Ticket = "ticket" - }); + }, _ct); _database.UserSessions.Count().ShouldBe(1); } @@ -55,9 +56,9 @@ public class UserSessionStoreTests Renewed = new DateTime(2021, 4, 2, 10, 13, 34, DateTimeKind.Utc), Expires = new DateTime(2022, 5, 3, 11, 14, 35, DateTimeKind.Utc), Ticket = "ticket" - }); + }, _ct); - var item = await _subject.GetUserSessionAsync("key123"); + var item = await _subject.GetUserSessionAsync("key123", _ct); item.ShouldNotBeNull(); item.Key.ShouldBe("key123"); @@ -71,7 +72,7 @@ public class UserSessionStoreTests [Fact] public async Task GetUserSessionAsync_for_invalid_key_should_return_null() { - var item = await _subject.GetUserSessionAsync("invalid"); + var item = await _subject.GetUserSessionAsync("invalid", _ct); item.ShouldBeNull(); } @@ -88,7 +89,7 @@ public class UserSessionStoreTests Renewed = new DateTime(2021, 4, 2, 10, 13, 34, DateTimeKind.Utc), Expires = new DateTime(2022, 5, 3, 11, 14, 35, DateTimeKind.Utc), Ticket = "ticket" - }); + }, _ct); { await _subject.UpdateUserSessionAsync("key123", new UserSessionUpdate @@ -99,9 +100,9 @@ public class UserSessionStoreTests Created = new DateTime(2020, 3, 1, 9, 12, 33, DateTimeKind.Utc), Renewed = new DateTime(2024, 1, 3, 5, 7, 9, DateTimeKind.Utc), Expires = new DateTime(2025, 2, 4, 6, 8, 10, DateTimeKind.Utc) - }); + }, _ct); - var item = await _subject.GetUserSessionAsync("key123"); + var item = await _subject.GetUserSessionAsync("key123", _ct); item.ShouldNotBeNull(); item.Key.ShouldBe("key123"); item.SubjectId.ShouldBe("sub"); @@ -120,9 +121,9 @@ public class UserSessionStoreTests Created = new DateTime(2022, 3, 1, 9, 12, 33, DateTimeKind.Utc), Renewed = new DateTime(2024, 1, 3, 5, 7, 9, DateTimeKind.Utc), Expires = new DateTime(2025, 2, 4, 6, 8, 10, DateTimeKind.Utc) - }); + }, _ct); - var item = await _subject.GetUserSessionAsync("key123"); + var item = await _subject.GetUserSessionAsync("key123", _ct); item.ShouldNotBeNull(); item.Key.ShouldBe("key123"); item.SubjectId.ShouldBe("sub2"); @@ -141,9 +142,9 @@ public class UserSessionStoreTests Ticket = "ticket2", Renewed = new DateTime(2024, 1, 3, 5, 7, 9, DateTimeKind.Utc), Expires = new DateTime(2025, 2, 4, 6, 8, 10, DateTimeKind.Utc) - }); + }, _ct); - var item = await _subject.GetUserSessionAsync("key123"); + var item = await _subject.GetUserSessionAsync("key123", _ct); item.ShouldBeNull(); } @@ -157,15 +158,16 @@ public class UserSessionStoreTests SubjectId = "sub", SessionId = "session", Ticket = "ticket", - }); + }, _ct); _database.UserSessions.Count().ShouldBe(1); - await _subject.DeleteUserSessionAsync("key123"); + await _subject.DeleteUserSessionAsync("key123", _ct); _database.UserSessions.Count().ShouldBe(0); } [Fact] - public async Task DeleteUserSessionAsync_for_invalid_key_should_succeed() => await _subject.DeleteUserSessionAsync("invalid"); + public async Task DeleteUserSessionAsync_for_invalid_key_should_succeed() + => await _subject.DeleteUserSessionAsync("invalid", _ct); [Fact] @@ -177,44 +179,44 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); - var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub2" }); + var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub2" }, _ct); items.Count().ShouldBe(3); items.Select(x => x.SubjectId).Distinct().ToArray().ShouldBeEquivalentTo(new[] { "sub2" }); items.Select(x => x.SessionId).ToArray().ShouldBeEquivalentTo(new[] { "sid2_1", "sid2_2", "sid2_3", }); @@ -228,44 +230,44 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); - var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid" }); + var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid" }, _ct); items.Count().ShouldBe(0); } [Fact] @@ -277,44 +279,44 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); - var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SessionId = "sid2_2" }); + var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SessionId = "sid2_2" }, _ct); items.Count().ShouldBe(1); items.Select(x => x.SubjectId).ToArray().ShouldBeEquivalentTo(new[] { "sub2" }); items.Select(x => x.SessionId).ToArray().ShouldBeEquivalentTo(new[] { "sid2_2" }); @@ -328,44 +330,44 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); - var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SessionId = "invalid" }); + var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SessionId = "invalid" }, _ct); items.Count().ShouldBe(0); } [Fact] @@ -377,44 +379,44 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); - var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub2", SessionId = "sid2_2" }); + var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub2", SessionId = "sid2_2" }, _ct); items.Count().ShouldBe(1); items.Select(x => x.SubjectId).ToArray().ShouldBeEquivalentTo(new[] { "sub2" }); items.Select(x => x.SessionId).ToArray().ShouldBeEquivalentTo(new[] { "sid2_2" }); @@ -428,60 +430,60 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); { - var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid", SessionId = "invalid" }); + var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid", SessionId = "invalid" }, _ct); items.Count().ShouldBe(0); } { - var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub1", SessionId = "invalid" }); + var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub1", SessionId = "invalid" }, _ct); items.Count().ShouldBe(0); } { - var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid", SessionId = "sid1_1" }); + var items = await _subject.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid", SessionId = "sid1_1" }, _ct); items.Count().ShouldBe(0); } } [Fact] public async Task GetUserSessionsAsync_for_missing_sub_and_sid_should_throw() { - Func f = () => _subject.GetUserSessionsAsync(new UserSessionsFilter()); + Func f = () => _subject.GetUserSessionsAsync(new UserSessionsFilter(), _ct); await f.ShouldThrowAsync(); } @@ -495,44 +497,44 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); - await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub2" }); + await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub2" }, _ct); _database.UserSessions.Count().ShouldBe(3); _database.UserSessions.Count(x => x.SubjectId == "sub2").ShouldBe(0); } @@ -545,44 +547,44 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); - await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid" }); + await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid" }, _ct); _database.UserSessions.Count().ShouldBe(6); } [Fact] @@ -594,44 +596,47 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); - await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SessionId = "sid2_2" }); + await _subject.DeleteUserSessionsAsync(new UserSessionsFilter + { + SessionId = "sid2_2" + }, _ct); _database.UserSessions.Count().ShouldBe(5); _database.UserSessions.Count(x => x.SessionId == "sid2_2").ShouldBe(0); } @@ -644,44 +649,44 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); - await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SessionId = "invalid" }); + await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SessionId = "invalid" }, _ct); _database.UserSessions.Count().ShouldBe(6); } [Fact] @@ -693,44 +698,44 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); - await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub2", SessionId = "sid2_2" }); + await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub2", SessionId = "sid2_2" }, _ct); _database.UserSessions.Count().ShouldBe(5); _database.UserSessions.Count(x => x.SubjectId == "sub2" && x.SessionId == "sid2_2").ShouldBe(0); } @@ -743,60 +748,60 @@ public class UserSessionStoreTests Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub1", SessionId = "sid1_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_1", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_2", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub2", SessionId = "sid2_3", - }); + }, _ct); await _subject.CreateUserSessionAsync(new UserSession { Key = Guid.NewGuid().ToString(), Ticket = "ticket", SubjectId = "sub3", SessionId = "sid3_1", - }); + }, _ct); { - await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid", SessionId = "invalid" }); + await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid", SessionId = "invalid" }, _ct); _database.UserSessions.Count().ShouldBe(6); } { - await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub1", SessionId = "invalid" }); + await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "sub1", SessionId = "invalid" }, _ct); _database.UserSessions.Count().ShouldBe(6); } { - await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid", SessionId = "sid1_1" }); + await _subject.DeleteUserSessionsAsync(new UserSessionsFilter { SubjectId = "invalid", SessionId = "sid1_1" }, _ct); _database.UserSessions.Count().ShouldBe(6); } } [Fact] public async Task DeleteUserSessionsAsync_for_missing_sub_and_sid_should_throw() { - Func f = () => _subject.DeleteUserSessionsAsync(new UserSessionsFilter()); + Func f = () => _subject.DeleteUserSessionsAsync(new UserSessionsFilter(), _ct); await f.ShouldThrowAsync(); } @@ -820,7 +825,7 @@ public class UserSessionStoreTests SubjectId = "sub", SessionId = "sid", }); - await ctx0.SaveChangesAsync(); + await ctx0.SaveChangesAsync(_ct); using var scope1 = provider.CreateScope(); var ctx1 = scope1.ServiceProvider.GetRequiredService(); @@ -832,14 +837,14 @@ public class UserSessionStoreTests var item2 = ctx2.UserSessions.Single(x => x.Key == key); ctx2.UserSessions.Remove(item2); - await ctx1.SaveChangesAsync(); + await ctx1.SaveChangesAsync(_ct); - Func f1 = async () => await ctx2.SaveChangesAsync(); + Func f1 = async () => await ctx2.SaveChangesAsync(_ct); await f1.ShouldThrowAsync(); try { - await ctx2.SaveChangesAsync(); + await ctx2.SaveChangesAsync(_ct); } catch (DbUpdateConcurrencyException ex) { @@ -851,6 +856,6 @@ public class UserSessionStoreTests } // calling again to not throw - await ctx2.SaveChangesAsync(); + await ctx2.SaveChangesAsync(_ct); } } diff --git a/bff/test/Bff.Tests/Bff.Tests.csproj b/bff/test/Bff.Tests/Bff.Tests.csproj index 410da7cb8..ae3294105 100644 --- a/bff/test/Bff.Tests/Bff.Tests.csproj +++ b/bff/test/Bff.Tests/Bff.Tests.csproj @@ -11,7 +11,7 @@ - + diff --git a/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs index 87d0c340a..9fb2bc3b9 100644 --- a/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs @@ -7,12 +7,13 @@ using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; using Microsoft.Extensions.DependencyInjection; using Microsoft.IdentityModel.Tokens; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints; public class DpopRemoteEndpointTests : BffIntegrationTestBase { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + public DpopRemoteEndpointTests(ITestOutputHelper output) : base(output) { var rsaKey = new RsaSecurityKey(RSA.Create(2048)); @@ -20,9 +21,9 @@ public class DpopRemoteEndpointTests : BffIntegrationTestBase jsonWebKey.Alg = "PS256"; var jwk = JsonSerializer.Serialize(jsonWebKey); - BffHost.OnConfigureServices += svcs => + BffHost.OnConfigureServices += services => { - svcs.PostConfigure(opts => + services.PostConfigure(opts => { opts.DPoPJsonWebKey = jwk; }); @@ -33,8 +34,7 @@ public class DpopRemoteEndpointTests : BffIntegrationTestBase public async Task test_dpop() { ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_client/test") - ); + url: BffHost.Url("/api_client/test"), ct: _ct); apiResult.RequestHeaders["DPoP"].First().ShouldNotBeNullOrEmpty(); apiResult.RequestHeaders["Authorization"].First().StartsWith("DPoP ").ShouldBeTrue(); diff --git a/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs index 9e31b3b3b..9f9e9b384 100644 --- a/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs @@ -6,20 +6,21 @@ using System.Net.Http.Json; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints; public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBase(output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] public async Task calls_to_authorized_local_endpoint_should_succeed() { await BffHost.BffLoginAsync("alice"); ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/local_authz") - ); + url: BffHost.Url("/local_authz"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/local_authz"); @@ -32,8 +33,8 @@ public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa await BffHost.BffLoginAsync("alice"); ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/local_authz_no_csrf") - ); + url: BffHost.Url("/local_authz_no_csrf"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/local_authz_no_csrf"); @@ -45,15 +46,15 @@ public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa { var response = await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/local_authz"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); } [Fact] public async Task calls_to_local_endpoint_should_require_antiforgery_header() { var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/local_anon")); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } @@ -64,16 +65,16 @@ public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa { var response = await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/local_anon_no_csrf"), - expectedStatusCode: HttpStatusCode.OK - ); + expectedStatusCode: HttpStatusCode.OK, + ct: _ct); } [Fact] public async Task calls_to_anon_endpoint_should_allow_anonymous() { ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/local_anon") - ); + url: BffHost.Url("/local_anon"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/local_anon"); @@ -88,8 +89,8 @@ public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/local_authz"), method: HttpMethod.Put, - content: JsonContent.Create(new TestPayload("hello test api")) - ); + content: JsonContent.Create(new TestPayload("hello test api")), + ct: _ct); apiResult.Method.ShouldBe("PUT"); apiResult.Path.ShouldBe("/local_authz"); @@ -103,7 +104,7 @@ public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa { var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/always_fail_authz_non_bff_endpoint")); req.Headers.Add("x-csrf", "1"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location @@ -114,23 +115,21 @@ public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa } [Fact] - public async Task unauthenticated_api_call_should_return_401() - { - var response = await BffHost.BrowserClient.CallBffHostApi( + public async Task unauthenticated_api_call_should_return_401() => + _ = await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/always_fail_authz"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); - } + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); [Fact] public async Task forbidden_api_call_should_return_403() { await BffHost.BffLoginAsync("alice"); - var response = await BffHost.BrowserClient.CallBffHostApi( + _ = await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/always_fail_authz"), - expectedStatusCode: HttpStatusCode.Forbidden - ); + expectedStatusCode: HttpStatusCode.Forbidden, + ct: _ct); } [Fact] @@ -139,10 +138,10 @@ public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa await BffHost.BffLoginAsync("alice"); BffHost.LocalApiResponseStatus = BffHost.ResponseStatus.Challenge; - var response = await BffHost.BrowserClient.CallBffHostApi( + _ = await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/local_authz"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); } [Fact] @@ -153,8 +152,8 @@ public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa var response = await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/local_authz"), - expectedStatusCode: HttpStatusCode.Forbidden - ); + expectedStatusCode: HttpStatusCode.Forbidden, + ct: _ct); } [Fact] @@ -165,16 +164,16 @@ public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa var response = await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/local_anon_no_csrf_no_response_handling"), - expectedStatusCode: HttpStatusCode.Redirect - ); + expectedStatusCode: HttpStatusCode.Redirect, + ct: _ct); } [Fact] public async Task fallback_policy_should_not_fail() { - BffHost.OnConfigureServices += svcs => + BffHost.OnConfigureServices += services => { - svcs.AddAuthorization(opts => + services.AddAuthorization(opts => { opts.FallbackPolicy = new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder() @@ -184,7 +183,7 @@ public class LocalEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa }; await BffHost.InitializeAsync(); - var response = await BffHost.HttpClient.GetAsync(BffHost.Url("/not-found")); + var response = await BffHost.HttpClient.GetAsync(BffHost.Url("/not-found"), _ct); response.StatusCode.ShouldNotBe(HttpStatusCode.InternalServerError); } } diff --git a/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs index ee2d0f4ab..4ebb030b8 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs @@ -4,18 +4,19 @@ using System.Net; using Duende.Bff.Tests.TestHosts; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints.Management; public class BackchannelLogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestBase(output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] public async Task backchannel_logout_should_allow_anonymous() { - BffHost.OnConfigureServices += svcs => + BffHost.OnConfigureServices += services => { - svcs.AddAuthorization(opts => + services.AddAuthorization(opts => { opts.FallbackPolicy = new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder() @@ -25,7 +26,7 @@ public class BackchannelLogoutEndpointTests(ITestOutputHelper output) : BffInteg }; await BffHost.InitializeAsync(); - var response = await BffHost.HttpClient.PostAsync(BffHost.Url("/bff/backchannel"), null); + var response = await BffHost.HttpClient.PostAsync(BffHost.Url("/bff/backchannel"), null, _ct); response.StatusCode.ShouldNotBe(HttpStatusCode.Unauthorized); } @@ -75,7 +76,9 @@ public class BackchannelLogoutEndpointTests(ITestOutputHelper output) : BffInteg { var store = BffHost.Resolve(); - var sessions = await store.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }); + var sessions = await store.GetUserSessionsAsync( + new UserSessionsFilter { SubjectId = "alice" }, + _ct); sessions.Count().ShouldBe(2); } @@ -83,7 +86,9 @@ public class BackchannelLogoutEndpointTests(ITestOutputHelper output) : BffInteg { var store = BffHost.Resolve(); - var sessions = await store.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }); + var sessions = await store.GetUserSessionsAsync( + new UserSessionsFilter { SubjectId = "alice" }, + _ct); var session = sessions.Single(); session.SessionId.ShouldBe("sid1"); } @@ -100,7 +105,9 @@ public class BackchannelLogoutEndpointTests(ITestOutputHelper output) : BffInteg { var store = BffHost.Resolve(); - var sessions = await store.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }); + var sessions = await store.GetUserSessionsAsync( + new UserSessionsFilter { SubjectId = "alice" }, + _ct); sessions.Count().ShouldBe(2); } @@ -108,7 +115,9 @@ public class BackchannelLogoutEndpointTests(ITestOutputHelper output) : BffInteg { var store = BffHost.Resolve(); - var sessions = await store.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }); + var sessions = await store.GetUserSessionsAsync( + new UserSessionsFilter { SubjectId = "alice" }, + _ct); sessions.ShouldBeEmpty(); } } diff --git a/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs index d7858483e..7469cbb0e 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs @@ -4,18 +4,19 @@ using System.Net; using Duende.Bff.Tests.TestHosts; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints.Management; public class LoginEndpointTests(ITestOutputHelper output) : BffIntegrationTestBase(output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] public async Task login_should_allow_anonymous() { - BffHost.OnConfigureServices += svcs => + BffHost.OnConfigureServices += services => { - svcs.AddAuthorization(opts => + services.AddAuthorization(opts => { opts.FallbackPolicy = new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder() @@ -25,23 +26,23 @@ public class LoginEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa }; await BffHost.InitializeAsync(); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/login")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/login"), _ct); response.StatusCode.ShouldNotBe(HttpStatusCode.Unauthorized); } [Fact] public async Task login_endpoint_should_challenge_and_redirect_to_root() { - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/login")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/login"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(IdentityServerHost.Url("/connect/authorize")); await IdentityServerHost.IssueSessionCookieAsync("alice"); - response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(BffHost.Url("/signin-oidc")); - response = await BffHost.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await BffHost.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldBe("/"); } @@ -49,25 +50,25 @@ public class LoginEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa [Fact] public async Task login_endpoint_should_challenge_and_redirect_to_root_with_custom_prefix() { - BffHost.OnConfigureServices += svcs => + BffHost.OnConfigureServices += services => { - svcs.Configure(options => + services.Configure(options => { options.ManagementBasePath = "/custom/bff"; }); }; await BffHost.InitializeAsync(); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/custom/bff/login")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/custom/bff/login"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(IdentityServerHost.Url("/connect/authorize")); await IdentityServerHost.IssueSessionCookieAsync("alice"); - response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(BffHost.Url("/signin-oidc")); - response = await BffHost.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await BffHost.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldBe("/"); } @@ -75,25 +76,25 @@ public class LoginEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa [Fact] public async Task login_endpoint_should_challenge_and_redirect_to_root_with_custom_prefix_trailing_slash() { - BffHost.OnConfigureServices += svcs => + BffHost.OnConfigureServices += services => { - svcs.Configure(options => + services.Configure(options => { options.ManagementBasePath = "/custom/bff/"; }); }; await BffHost.InitializeAsync(); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/custom/bff/login")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/custom/bff/login"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(IdentityServerHost.Url("/connect/authorize")); await IdentityServerHost.IssueSessionCookieAsync("alice"); - response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(BffHost.Url("/signin-oidc")); - response = await BffHost.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await BffHost.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldBe("/"); } @@ -101,25 +102,25 @@ public class LoginEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa [Fact] public async Task login_endpoint_should_challenge_and_redirect_to_root_with_root_prefix() { - BffHost.OnConfigureServices += svcs => + BffHost.OnConfigureServices += services => { - svcs.Configure(options => + services.Configure(options => { options.ManagementBasePath = "/"; }); }; await BffHost.InitializeAsync(); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/login")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/login"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(IdentityServerHost.Url("/connect/authorize")); await IdentityServerHost.IssueSessionCookieAsync("alice"); - response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(BffHost.Url("/signin-oidc")); - response = await BffHost.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await BffHost.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldBe("/"); } @@ -129,7 +130,7 @@ public class LoginEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa { await BffHost.BffLoginAsync("alice"); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/login")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/login"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(IdentityServerHost.Url("/connect/authorize")); } @@ -137,16 +138,16 @@ public class LoginEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa [Fact] public async Task login_endpoint_should_accept_returnUrl() { - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/login") + "?returnUrl=/foo"); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/login") + "?returnUrl=/foo", _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(IdentityServerHost.Url("/connect/authorize")); await IdentityServerHost.IssueSessionCookieAsync("alice"); - response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldStartWith(BffHost.Url("/signin-oidc")); - response = await BffHost.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await BffHost.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location!.ToString().ShouldBe("/foo"); } @@ -154,7 +155,7 @@ public class LoginEndpointTests(ITestOutputHelper output) : BffIntegrationTestBa [Fact] public async Task login_endpoint_should_not_accept_non_local_returnUrl() { - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/login") + "?returnUrl=https://foo"); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/login") + "?returnUrl=https://foo", _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); } } diff --git a/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs index 53e915d98..c3324e047 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs @@ -4,18 +4,19 @@ using System.Net; using Duende.Bff.Tests.TestHosts; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints.Management; public class LogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestBase(output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] public async Task logout_endpoint_should_allow_anonymous() { - BffHost.OnConfigureServices += svcs => + BffHost.OnConfigureServices += services => { - svcs.AddAuthorization(opts => + services.AddAuthorization(opts => { opts.FallbackPolicy = new Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder() @@ -25,7 +26,7 @@ public class LogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestB }; await BffHost.InitializeAsync(); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout"), _ct); response.StatusCode.ShouldNotBe(HttpStatusCode.Unauthorized); } @@ -44,7 +45,7 @@ public class LogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestB { await BffHost.BffLoginAsync("alice", "sid123"); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); (await BffHost.GetIsUserLoggedInAsync()).ShouldBeTrue(); @@ -57,7 +58,7 @@ public class LogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestB BffHost.BffOptions.RequireLogoutSessionId = false; - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); // endsession response.Headers.Location!.ToString().ToLowerInvariant().ShouldStartWith(IdentityServerHost.Url("/connect/endsession")); } @@ -66,9 +67,9 @@ public class LogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestB public async Task logout_endpoint_for_authenticated_user_without_sid_should_succeed() { // workaround for RevokeUserRefreshTokenAsync throwing when no RT in session - BffHost.OnConfigureServices += svcs => + BffHost.OnConfigureServices += services => { - svcs.Configure(options => + services.Configure(options => { options.RevokeRefreshTokenOnLogout = false; }); @@ -77,7 +78,7 @@ public class LogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.IssueSessionCookieAsync("alice"); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); // endsession response.Headers.Location!.ToString().ToLowerInvariant().ShouldStartWith(IdentityServerHost.Url("/connect/endsession")); } @@ -85,7 +86,7 @@ public class LogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestB [Fact] public async Task logout_endpoint_for_anonymous_user_without_sid_should_succeed() { - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout")); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); // endsession response.Headers.Location!.ToString().ToLowerInvariant().ShouldStartWith(IdentityServerHost.Url("/connect/endsession")); } @@ -113,7 +114,7 @@ public class LogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BffLogoutAsync("sid123"); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout") + "?sid=123"); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout") + "?sid=123", _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); // endsession response.Headers.Location!.ToString().ToLowerInvariant().ShouldStartWith(IdentityServerHost.Url("/connect/endsession")); @@ -126,19 +127,19 @@ public class LogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestB { await BffHost.BffLoginAsync("alice", "sid123"); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout") + "?sid=sid123&returnUrl=/foo"); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout") + "?sid=sid123&returnUrl=/foo", _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); // endsession response.Headers.Location!.ToString().ToLowerInvariant().ShouldStartWith(IdentityServerHost.Url("/connect/endsession")); - response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location!.ToString()); + response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location!.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); // logout response.Headers.Location!.ToString().ToLowerInvariant().ShouldStartWith(IdentityServerHost.Url("/account/logout")); - response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location!.ToString()); + response = await IdentityServerHost.BrowserClient.GetAsync(response.Headers.Location!.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); // post logout redirect uri response.Headers.Location!.ToString().ToLowerInvariant().ShouldStartWith(BffHost.Url("/signout-callback-oidc")); - response = await BffHost.BrowserClient.GetAsync(response.Headers.Location!.ToString()); + response = await BffHost.BrowserClient.GetAsync(response.Headers.Location!.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); // root response.Headers.Location!.ToString().ToLowerInvariant().ShouldBe("/foo"); } @@ -148,7 +149,7 @@ public class LogoutEndpointTests(ITestOutputHelper output) : BffIntegrationTestB { await BffHost.BffLoginAsync("alice", "sid123"); - var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout") + "?sid=sid123&returnUrl=https://foo"); + var response = await BffHost.BrowserClient.GetAsync(BffHost.Url("/bff/logout") + "?sid=sid123&returnUrl=https://foo", _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); } } diff --git a/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs b/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs index 978d3eef5..3c41336af 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs @@ -5,12 +5,13 @@ using System.Net; using Duende.Bff.Tests.TestHosts; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints.Management; public class ManagementBasePathTests(ITestOutputHelper output) : BffIntegrationTestBase(output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Theory] [InlineData(Constants.ManagementEndpoints.Login)] [InlineData(Constants.ManagementEndpoints.Logout)] @@ -19,9 +20,9 @@ public class ManagementBasePathTests(ITestOutputHelper output) : BffIntegrationT [InlineData(Constants.ManagementEndpoints.User)] public async Task custom_ManagementBasePath_should_affect_basepath(string path) { - BffHost.OnConfigureServices += svcs => + BffHost.OnConfigureServices += services => { - svcs.Configure(options => + services.Configure(options => { options.ManagementBasePath = new PathString("/{path:regex(^[a-zA-Z\\d-]+$)}/bff"); }); @@ -31,7 +32,7 @@ public class ManagementBasePathTests(ITestOutputHelper output) : BffIntegrationT var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/custom/bff" + path)); req.Headers.Add("x-csrf", "1"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.StatusCode.ShouldNotBe(HttpStatusCode.NotFound); } diff --git a/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs index cc3b1afac..e51e17fab 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs @@ -4,12 +4,13 @@ using System.Net; using System.Security.Claims; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints.Management; public class UserEndpointTests(ITestOutputHelper output) : BffIntegrationTestBase(output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] public async Task user_endpoint_for_authenticated_user_should_return_claims() { @@ -54,7 +55,7 @@ public class UserEndpointTests(ITestOutputHelper output) : BffIntegrationTestBas await BffHost.IssueSessionCookieAsync(new Claim("sub", "alice"), new Claim("foo", "foo1"), new Claim("foo", "foo2")); var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/bff/user")); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } @@ -64,7 +65,7 @@ public class UserEndpointTests(ITestOutputHelper output) : BffIntegrationTestBas { var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/bff/user")); req.Headers.Add("x-csrf", "1"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } diff --git a/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs index dcc54da0a..a4b219a15 100644 --- a/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs @@ -6,17 +6,19 @@ using System.Net.Http.Json; using System.Text.Json; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints; public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestBase(output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] - public async Task unauthenticated_calls_to_remote_endpoint_should_return_401() => await BffHost.BrowserClient.CallBffHostApi( + public async Task unauthenticated_calls_to_remote_endpoint_should_return_401() + => await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/api_user/test"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); [Fact] public async Task calls_to_remote_endpoint_should_forward_user_to_api() @@ -24,8 +26,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BffLoginAsync("alice"); var (response, apiResult) = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_user/test") - ); + url: BffHost.Url("/api_user/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/test"); @@ -37,15 +39,14 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB } [Fact] - public async Task - calls_to_remote_endpoint_with_useraccesstokenparameters_having_stored_named_token_should_forward_user_to_api() + public async Task calls_to_remote_endpoint_with_useraccesstokenparameters_having_stored_named_token_should_forward_user_to_api() { await BffHostWithNamedTokens.BffLoginAsync("alice"); ApiResponse apiResult = await BffHostWithNamedTokens.BrowserClient.CallBffHostApi( url: BffHostWithNamedTokens.Url( - "/api_user_with_useraccesstokenparameters_having_stored_named_token/test") - ); + "/api_user_with_useraccesstokenparameters_having_stored_named_token/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/test"); @@ -62,8 +63,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHostWithNamedTokens.BrowserClient.CallBffHostApi( url: BffHostWithNamedTokens.Url( "/api_user_with_useraccesstokenparameters_having_not_stored_named_token/test"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); } [Fact] @@ -74,8 +75,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/api_user/test"), method: HttpMethod.Put, - content: JsonContent.Create(new TestPayload("hello test api")) - ); + content: JsonContent.Create(new TestPayload("hello test api")), + ct: _ct); apiResult.Method.ShouldBe("PUT"); apiResult.Path.ShouldBe("/test"); @@ -93,8 +94,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/api_user/test"), method: HttpMethod.Post, - content: JsonContent.Create(new TestPayload("hello test api")) - ); + content: JsonContent.Create(new TestPayload("hello test api")), + ct: _ct); apiResult.Method.ShouldBe("POST"); apiResult.Path.ShouldBe("/test"); @@ -109,8 +110,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB { { ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_user_or_anon/test") - ); + url: BffHost.Url("/api_user_or_anon/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/test"); @@ -122,8 +123,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BffLoginAsync("alice"); ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_user_or_anon/test") - ); + url: BffHost.Url("/api_user_or_anon/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/test"); @@ -138,8 +139,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BffLoginAsync("alice"); ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_client/test") - ); + url: BffHost.Url("/api_client/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/test"); @@ -154,8 +155,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/api_with_access_token_retrieval_that_fails"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); // user should be signed out var result = await BffHost.GetIsUserLoggedInAsync(); @@ -169,8 +170,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/api_forbidden"), - expectedStatusCode: HttpStatusCode.Forbidden - ); + expectedStatusCode: HttpStatusCode.Forbidden, + ct: _ct); } [Fact] @@ -180,8 +181,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/api_unauthenticated"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); } [Fact] @@ -190,8 +191,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BffLoginAsync("alice"); ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_with_access_token_retriever") - ); + url: BffHost.Url("/api_with_access_token_retriever"), + ct: _ct); apiResult.Sub.ShouldBe("123"); apiResult.ClientId.ShouldBe("fake-client"); @@ -202,8 +203,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB { { ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_user_or_client/test") - ); + url: BffHost.Url("/api_user_or_client/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/test"); @@ -215,8 +216,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BffLoginAsync("alice"); ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_user_or_client/test") - ); + url: BffHost.Url("/api_user_or_client/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/test"); @@ -230,8 +231,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB { { ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_anon_only/test") - ); + url: BffHost.Url("/api_anon_only/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/test"); @@ -243,8 +244,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BffLoginAsync("alice"); ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_anon_only/test") - ); + url: BffHost.Url("/api_anon_only/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/test"); @@ -261,13 +262,13 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/api_user_or_client/test"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/api_client/test"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); } [Fact] @@ -278,8 +279,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/api_user/test"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); } [Fact] @@ -290,14 +291,14 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BrowserClient.CallBffHostApi( url: BffHost.Url("/api_user/test"), - expectedStatusCode: HttpStatusCode.Forbidden - ); + expectedStatusCode: HttpStatusCode.Forbidden, + ct: _ct); } [Fact] public async Task calls_to_remote_endpoint_should_require_csrf() { var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/api_user_or_client/test")); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } @@ -308,8 +309,8 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB await BffHost.BffLoginAsync("alice"); ApiResponse apiResult = await BffHost.BrowserClient.CallBffHostApi( - url: BffHost.Url("/api_user_no_csrf/test") - ); + url: BffHost.Url("/api_user_no_csrf/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/test"); @@ -325,11 +326,11 @@ public class RemoteEndpointTests(ITestOutputHelper output) : BffIntegrationTestB var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/api_custom_transform/test")); req.Headers.Add("x-csrf", "1"); req.Headers.Add("my-header-to-be-copied-by-yarp", "copied-value"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); response.Content.Headers.ContentType!.MediaType.ShouldBe("application/json"); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var apiResult = JsonSerializer.Deserialize(json).ShouldNotBeNull(); apiResult.RequestHeaders["my-header-to-be-copied-by-yarp"].First().ShouldBe("copied-value"); diff --git a/bff/test/Bff.Tests/Endpoints/YarpRemoteEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/YarpRemoteEndpointTests.cs index d2083f76d..daf8d4bd8 100644 --- a/bff/test/Bff.Tests/Endpoints/YarpRemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/YarpRemoteEndpointTests.cs @@ -4,46 +4,51 @@ using System.Net; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints; public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrationTestBase(output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + + [Fact] - public async Task anonymous_call_with_no_csrf_header_to_no_token_requirement_no_csrf_route_should_succeed() => await YarpBasedBffHost.BrowserClient.CallBffHostApi( + public async Task anonymous_call_with_no_csrf_header_to_no_token_requirement_no_csrf_route_should_succeed() + => await YarpBasedBffHost.BrowserClient.CallBffHostApi( url: YarpBasedBffHost.Url("/api_anon_no_csrf/test"), - expectedStatusCode: HttpStatusCode.OK - ); + expectedStatusCode: HttpStatusCode.OK, + ct: _ct); [Fact] public async Task anonymous_call_with_no_csrf_header_to_csrf_route_should_fail() { var req = new HttpRequestMessage(HttpMethod.Get, YarpBasedBffHost.Url("/api_anon/test")); - var response = await YarpBasedBffHost.BrowserClient.SendAsync(req); + var response = await YarpBasedBffHost.BrowserClient.SendAsync(req, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } [Fact] - public async Task anonymous_call_to_no_token_requirement_route_should_succeed() => await YarpBasedBffHost.BrowserClient.CallBffHostApi( + public async Task anonymous_call_to_no_token_requirement_route_should_succeed() + => await YarpBasedBffHost.BrowserClient.CallBffHostApi( url: YarpBasedBffHost.Url("/api_anon/test"), - expectedStatusCode: HttpStatusCode.OK - ); + expectedStatusCode: HttpStatusCode.OK, + ct: _ct); [Fact] - public async Task anonymous_call_to_user_token_requirement_route_should_fail() => await YarpBasedBffHost.BrowserClient.CallBffHostApi( + public async Task anonymous_call_to_user_token_requirement_route_should_fail() + => await YarpBasedBffHost.BrowserClient.CallBffHostApi( url: YarpBasedBffHost.Url("/api_user/test"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); [Fact] public async Task anonymous_call_to_optional_user_token_route_should_succeed() { ApiResponse apiResult = await YarpBasedBffHost.BrowserClient.CallBffHostApi( - url: YarpBasedBffHost.Url("/api_optional_user/test") - ); + url: YarpBasedBffHost.Url("/api_optional_user/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/api_optional_user/test"); @@ -55,8 +60,8 @@ public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrat public async Task call_to_api_badly_cased_anti_forgery() { var result = await YarpBasedBffHost.BrowserClient.GetAsync( - new Uri(YarpBasedBffHost.Url("/api_badly_cased_anti_forgery/test")) - ); + new Uri(YarpBasedBffHost.Url("/api_badly_cased_anti_forgery/test")), + _ct); result.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); @@ -67,10 +72,9 @@ public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrat { await YarpBasedBffHost.BffLoginAsync("alice"); - ApiResponse apiResult = await YarpBasedBffHost.BrowserClient.CallBffHostApi( - YarpBasedBffHost.Url("/api_badly_cased_optional_token/test") - ); + YarpBasedBffHost.Url("/api_badly_cased_optional_token/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Sub.ShouldBe("alice"); @@ -86,8 +90,8 @@ public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrat await YarpBasedBffHost.BffLoginAsync("alice"); ApiResponse apiResult = await YarpBasedBffHost.BrowserClient.CallBffHostApi( - url: YarpBasedBffHost.Url(route) - ); + url: YarpBasedBffHost.Url(route), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe(route); @@ -104,8 +108,8 @@ public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrat ApiResponse apiResult = await YarpBasedBffHost.BrowserClient.CallBffHostApi( url: YarpBasedBffHost.Url(route), - method: HttpMethod.Put - ); + method: HttpMethod.Put, + ct: _ct); apiResult.Method.ShouldBe("PUT"); apiResult.Path.ShouldBe(route); @@ -122,8 +126,8 @@ public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrat ApiResponse apiResult = await YarpBasedBffHost.BrowserClient.CallBffHostApi( url: YarpBasedBffHost.Url(route), - method: HttpMethod.Post - ); + method: HttpMethod.Post, + ct: _ct); apiResult.Method.ShouldBe("POST"); apiResult.Path.ShouldBe(route); @@ -137,8 +141,8 @@ public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrat await YarpBasedBffHost.BffLoginAsync("alice"); ApiResponse apiResult = await YarpBasedBffHost.BrowserClient.CallBffHostApi( - url: YarpBasedBffHost.Url("/api_client/test") - ); + url: YarpBasedBffHost.Url("/api_client/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/api_client/test"); @@ -151,8 +155,8 @@ public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrat { { ApiResponse apiResult = await YarpBasedBffHost.BrowserClient.CallBffHostApi( - url: YarpBasedBffHost.Url("/api_user_or_client/test") - ); + url: YarpBasedBffHost.Url("/api_user_or_client/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/api_user_or_client/test"); @@ -164,8 +168,8 @@ public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrat await YarpBasedBffHost.BffLoginAsync("alice"); ApiResponse apiResult = await YarpBasedBffHost.BrowserClient.CallBffHostApi( - url: YarpBasedBffHost.Url("/api_user_or_client/test") - ); + url: YarpBasedBffHost.Url("/api_user_or_client/test"), + ct: _ct); apiResult.Method.ShouldBe("GET"); apiResult.Path.ShouldBe("/api_user_or_client/test"); @@ -182,8 +186,8 @@ public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrat var response = await YarpBasedBffHost.BrowserClient.CallBffHostApi( url: YarpBasedBffHost.Url("/api_user/test"), - expectedStatusCode: HttpStatusCode.Unauthorized - ); + expectedStatusCode: HttpStatusCode.Unauthorized, + ct: _ct); } [Fact] @@ -192,18 +196,17 @@ public class YarpRemoteEndpointTests(ITestOutputHelper output) : YarpBffIntegrat await YarpBasedBffHost.BffLoginAsync("alice"); ApiHost.ApiStatusCodeToReturn = 403; - var response = await YarpBasedBffHost.BrowserClient.CallBffHostApi( + _ = await YarpBasedBffHost.BrowserClient.CallBffHostApi( url: YarpBasedBffHost.Url("/api_user/test"), - expectedStatusCode: HttpStatusCode.Forbidden - ); + expectedStatusCode: HttpStatusCode.Forbidden, + ct: _ct); } [Fact] public async Task invalid_configuration_of_routes_should_return_500() - { - var response = await YarpBasedBffHost.BrowserClient.CallBffHostApi( + => + _ = await YarpBasedBffHost.BrowserClient.CallBffHostApi( url: YarpBasedBffHost.Url("/api_invalid/test"), - expectedStatusCode: HttpStatusCode.InternalServerError - ); - } + expectedStatusCode: HttpStatusCode.InternalServerError, + ct: _ct); } diff --git a/bff/test/Bff.Tests/GenericHostTests.cs b/bff/test/Bff.Tests/GenericHostTests.cs index fce77081f..c309b2c48 100644 --- a/bff/test/Bff.Tests/GenericHostTests.cs +++ b/bff/test/Bff.Tests/GenericHostTests.cs @@ -4,12 +4,13 @@ using System.Net; using Duende.Bff.Tests.TestFramework; using Microsoft.AspNetCore.Builder; -using Xunit.Abstractions; namespace Duende.Bff.Tests; public class GenericHostTests(ITestOutputHelper output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] public async Task Test1() { @@ -21,7 +22,7 @@ public class GenericHostTests(ITestOutputHelper output) }); await host.InitializeAsync(); - var response = await host.HttpClient.GetAsync("/test"); + var response = await host.HttpClient.GetAsync("/test", _ct); response.StatusCode.ShouldBe(HttpStatusCode.NoContent); } diff --git a/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs b/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs index 00de4fef2..55a777108 100644 --- a/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs +++ b/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs @@ -4,12 +4,13 @@ using System.Text.Json; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Headers; public class ApiAndBffUseForwardedHeaders : BffIntegrationTestBase { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + public ApiAndBffUseForwardedHeaders(ITestOutputHelper output) : base(output) { BffHost.UseForwardedHeaders = true; @@ -21,10 +22,10 @@ public class ApiAndBffUseForwardedHeaders : BffIntegrationTestBase { var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/api_anon_only/test")); req.Headers.Add("x-csrf", "1"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var apiResult = JsonSerializer.Deserialize(json).ShouldNotBeNull(); var host = apiResult.RequestHeaders["Host"].Single(); @@ -39,10 +40,10 @@ public class ApiAndBffUseForwardedHeaders : BffIntegrationTestBase var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/api_anon_only/test")); req.Headers.Add("x-csrf", "1"); req.Headers.Add("X-Forwarded-Host", "external"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var apiResult = JsonSerializer.Deserialize(json).ShouldNotBeNull(); var host = apiResult.RequestHeaders["Host"].Single(); @@ -57,10 +58,10 @@ public class ApiAndBffUseForwardedHeaders : BffIntegrationTestBase var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/api_anon_only/test")); req.Headers.Add("x-csrf", "1"); req.Headers.Add("X-Forwarded-Host", "external"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var apiResult = JsonSerializer.Deserialize(json).ShouldNotBeNull(); var host = apiResult.RequestHeaders["Host"].Single(); diff --git a/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs b/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs index 3f0572751..c32754068 100644 --- a/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs +++ b/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs @@ -4,23 +4,25 @@ using System.Text.Json; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Headers; public class ApiUseForwardedHeaders : BffIntegrationTestBase { - public ApiUseForwardedHeaders(ITestOutputHelper output) : base(output) => ApiHost.UseForwardedHeaders = true; + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + + public ApiUseForwardedHeaders(ITestOutputHelper output) + : base(output) => ApiHost.UseForwardedHeaders = true; [Fact] public async Task bff_host_name_should_propagate_to_api() { var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/api_anon_only/test")); req.Headers.Add("x-csrf", "1"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var apiResult = JsonSerializer.Deserialize(json).ShouldNotBeNull(); var host = apiResult.RequestHeaders["Host"].Single(); @@ -33,10 +35,10 @@ public class ApiUseForwardedHeaders : BffIntegrationTestBase var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/api_anon_only/test")); req.Headers.Add("x-csrf", "1"); req.Headers.Add("X-Forwarded-Host", "external"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var apiResult = JsonSerializer.Deserialize(json).ShouldNotBeNull(); var host = apiResult.RequestHeaders["Host"].Single(); diff --git a/bff/test/Bff.Tests/Headers/General.cs b/bff/test/Bff.Tests/Headers/General.cs index da5f1c6ad..3aa3a405c 100644 --- a/bff/test/Bff.Tests/Headers/General.cs +++ b/bff/test/Bff.Tests/Headers/General.cs @@ -4,21 +4,22 @@ using System.Text.Json; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Headers; public class General(ITestOutputHelper output) : BffIntegrationTestBase(output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] public async Task local_endpoint_should_receive_standard_headers() { var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/local_anon")); req.Headers.Add("x-csrf", "1"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var apiResult = JsonSerializer.Deserialize(json).ShouldNotBeNull(); apiResult.RequestHeaders.Count.ShouldBe(2); @@ -34,10 +35,10 @@ public class General(ITestOutputHelper output) : BffIntegrationTestBase(output) var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/api_anon_only/test")); req.Headers.Add("x-csrf", "1"); req.Headers.Add("x-custom", "custom"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var apiResult = JsonSerializer.Deserialize(json).ShouldNotBeNull(); apiResult.RequestHeaders["Host"].Single().ShouldBe("api"); @@ -52,10 +53,10 @@ public class General(ITestOutputHelper output) : BffIntegrationTestBase(output) var req = new HttpRequestMessage(HttpMethod.Get, BffHost.Url("/api_anon_only/test")); req.Headers.Add("x-csrf", "1"); req.Headers.Add("x-custom", "custom"); - var response = await BffHost.BrowserClient.SendAsync(req); + var response = await BffHost.BrowserClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var apiResult = JsonSerializer.Deserialize(json).ShouldNotBeNull(); apiResult.RequestHeaders["X-Forwarded-Host"].Single().ShouldBe("app"); diff --git a/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs b/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs index 823f9c05f..4102d6295 100644 --- a/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs +++ b/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Abstractions; -using Xunit.Abstractions; namespace Duende.Bff.Tests; @@ -15,14 +14,15 @@ namespace Duende.Bff.Tests; /// public class IAccessTokenRetriever_Extensibility_tests : BffIntegrationTestBase { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; - private ContextCapturingAccessTokenRetriever _customAccessTokenReceiver { get; } = new(NullLogger.Instance); + private ContextCapturingAccessTokenRetriever CustomAccessTokenReceiver { get; } = new(NullLogger.Instance); public IAccessTokenRetriever_Extensibility_tests(ITestOutputHelper output) : base(output) { BffHost.OnConfigureServices += services => { - services.AddSingleton(_customAccessTokenReceiver); + services.AddSingleton(CustomAccessTokenReceiver); }; BffHost.OnConfigure += app => @@ -55,9 +55,9 @@ public class IAccessTokenRetriever_Extensibility_tests : BffIntegrationTestBase { await BffHost.BffLoginAsync("alice"); - await BffHost.BrowserClient.CallBffHostApi(BffHost.Url("/custom")); + await BffHost.BrowserClient.CallBffHostApi(BffHost.Url("/custom"), ct: _ct); - var usedContext = _customAccessTokenReceiver.UsedContext.ShouldNotBeNull(); + var usedContext = CustomAccessTokenReceiver.UsedContext.ShouldNotBeNull(); usedContext.Metadata.RequiredTokenType.ShouldBe(TokenType.User); @@ -71,9 +71,9 @@ public class IAccessTokenRetriever_Extensibility_tests : BffIntegrationTestBase { await BffHost.BffLoginAsync("alice"); - await BffHost.BrowserClient.CallBffHostApi(BffHost.Url("/subPath/custom_within_subpath")); + await BffHost.BrowserClient.CallBffHostApi(BffHost.Url("/subPath/custom_within_subpath"), ct: _ct); - var usedContext = _customAccessTokenReceiver.UsedContext.ShouldNotBeNull(); + var usedContext = CustomAccessTokenReceiver.UsedContext.ShouldNotBeNull(); usedContext.ApiAddress.ShouldBe(new Uri(ApiHost.Url("/some/path"))); usedContext.LocalPath.ToString().ShouldBe("/custom_within_subpath"); @@ -83,12 +83,10 @@ public class IAccessTokenRetriever_Extensibility_tests : BffIntegrationTestBase /// /// Captures the context in which the access token retriever is called, so we can assert on it /// - private class ContextCapturingAccessTokenRetriever : DefaultAccessTokenRetriever + private class ContextCapturingAccessTokenRetriever(ILogger logger) + : DefaultAccessTokenRetriever(logger) { public AccessTokenRetrievalContext? UsedContext { get; private set; } - public ContextCapturingAccessTokenRetriever(ILogger logger) : base(logger) - { - } public override Task GetAccessToken(AccessTokenRetrievalContext context) { diff --git a/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs b/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs index c9d151574..5b837fc25 100644 --- a/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs +++ b/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs @@ -5,26 +5,27 @@ using Duende.Bff.Tests.TestHosts; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Time.Testing; -using Xunit.Abstractions; namespace Duende.Bff.Tests.SessionManagement; public class CookieSlidingTests : BffIntegrationTestBase { - readonly InMemoryUserSessionStore _sessionStore = new(); - readonly FakeTimeProvider _clock = new(DateTime.UtcNow); + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly InMemoryUserSessionStore _sessionStore = new(); + private readonly FakeTimeProvider _clock = new(DateTime.UtcNow); - public CookieSlidingTests(ITestOutputHelper output) : base(output) => BffHost.OnConfigureServices += services => - { - services.AddSingleton(_sessionStore); - services.Configure("cookie", options => - { - options.SlidingExpiration = true; - options.ExpireTimeSpan = TimeSpan.FromMinutes(10); - }); - services.AddSingleton(_clock); - }; + public CookieSlidingTests(ITestOutputHelper output) : base(output) + => BffHost.OnConfigureServices += services => + { + services.AddSingleton(_sessionStore); + services.Configure("cookie", options => + { + options.SlidingExpiration = true; + options.ExpireTimeSpan = TimeSpan.FromMinutes(10); + }); + services.AddSingleton(_clock); + }; private void SetClock(TimeSpan t) => _clock.SetUtcNow(_clock.GetUtcNow().Add(t)); @@ -33,19 +34,19 @@ public class CookieSlidingTests : BffIntegrationTestBase { await BffHost.BffLoginAsync("alice"); - var sessions = await _sessionStore.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }); + var sessions = await _sessionStore.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }, _ct); sessions.Count().ShouldBe(1); var session = sessions.Single(); var ticketStore = BffHost.Resolve(); - var firstTicket = await ticketStore.RetrieveAsync(session.Key); + var firstTicket = await ticketStore.RetrieveAsync(session.Key, _ct); firstTicket.ShouldNotBeNull(); SetClock(TimeSpan.FromMinutes(8)); (await BffHost.GetIsUserLoggedInAsync()).ShouldBeTrue(); - var secondTicket = await ticketStore.RetrieveAsync(session.Key); + var secondTicket = await ticketStore.RetrieveAsync(session.Key, _ct); secondTicket.ShouldNotBeNull(); (secondTicket.Properties.IssuedUtc > firstTicket.Properties.IssuedUtc).ShouldBeTrue(); @@ -57,19 +58,19 @@ public class CookieSlidingTests : BffIntegrationTestBase { await BffHost.BffLoginAsync("alice"); - var sessions = await _sessionStore.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }); + var sessions = await _sessionStore.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }, _ct); sessions.Count().ShouldBe(1); var session = sessions.Single(); var ticketStore = BffHost.Resolve(); - var firstTicket = await ticketStore.RetrieveAsync(session.Key); + var firstTicket = await ticketStore.RetrieveAsync(session.Key, _ct); firstTicket.ShouldNotBeNull(); SetClock(TimeSpan.FromMinutes(8)); (await BffHost.GetIsUserLoggedInAsync("slide=false")).ShouldBeTrue(); - var secondTicket = await ticketStore.RetrieveAsync(session.Key); + var secondTicket = await ticketStore.RetrieveAsync(session.Key, _ct); secondTicket.ShouldNotBeNull(); (secondTicket.Properties.IssuedUtc == firstTicket.Properties.IssuedUtc).ShouldBeTrue(); @@ -96,20 +97,20 @@ public class CookieSlidingTests : BffIntegrationTestBase await BffHost.BffLoginAsync("alice"); - var sessions = await _sessionStore.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }); + var sessions = await _sessionStore.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }, _ct); sessions.Count().ShouldBe(1); var session = sessions.Single(); var ticketStore = BffHost.Resolve(); - var firstTicket = await ticketStore.RetrieveAsync(session.Key); + var firstTicket = await ticketStore.RetrieveAsync(session.Key, _ct); firstTicket.ShouldNotBeNull(); shouldRenew = true; SetClock(TimeSpan.FromSeconds(1)); (await BffHost.GetIsUserLoggedInAsync()).ShouldBeTrue(); - var secondTicket = await ticketStore.RetrieveAsync(session.Key); + var secondTicket = await ticketStore.RetrieveAsync(session.Key, _ct); secondTicket.ShouldNotBeNull(); (secondTicket.Properties.IssuedUtc > firstTicket.Properties.IssuedUtc).ShouldBeTrue(); @@ -137,20 +138,20 @@ public class CookieSlidingTests : BffIntegrationTestBase await BffHost.BffLoginAsync("alice"); - var sessions = await _sessionStore.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }); + var sessions = await _sessionStore.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" }, _ct); sessions.Count().ShouldBe(1); var session = sessions.Single(); var ticketStore = BffHost.Resolve(); - var firstTicket = await ticketStore.RetrieveAsync(session.Key); + var firstTicket = await ticketStore.RetrieveAsync(session.Key, _ct); firstTicket.ShouldNotBeNull(); shouldRenew = true; SetClock(TimeSpan.FromSeconds(1)); (await BffHost.GetIsUserLoggedInAsync("slide=false")).ShouldBeTrue(); - var secondTicket = await ticketStore.RetrieveAsync(session.Key); + var secondTicket = await ticketStore.RetrieveAsync(session.Key, _ct); secondTicket.ShouldNotBeNull(); (secondTicket.Properties.IssuedUtc == firstTicket.Properties.IssuedUtc).ShouldBeTrue(); diff --git a/bff/test/Bff.Tests/SessionManagement/RevokeRefreshTokenTests.cs b/bff/test/Bff.Tests/SessionManagement/RevokeRefreshTokenTests.cs index 2a15d9703..9e2dd28bc 100644 --- a/bff/test/Bff.Tests/SessionManagement/RevokeRefreshTokenTests.cs +++ b/bff/test/Bff.Tests/SessionManagement/RevokeRefreshTokenTests.cs @@ -4,7 +4,6 @@ using Duende.Bff.Tests.TestHosts; using Duende.IdentityServer.Stores; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.SessionManagement; diff --git a/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs b/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs index 019884a79..bb0395813 100644 --- a/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs +++ b/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs @@ -3,18 +3,19 @@ using Duende.Bff.Tests.TestHosts; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.SessionManagement; public class ServerSideTicketStoreTests : BffIntegrationTestBase { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; readonly InMemoryUserSessionStore _sessionStore = new(); - public ServerSideTicketStoreTests(ITestOutputHelper output) : base(output) => BffHost.OnConfigureServices += services => - { - services.AddSingleton(_sessionStore); - }; + public ServerSideTicketStoreTests(ITestOutputHelper output) : base(output) + => BffHost.OnConfigureServices += services => + { + services.AddSingleton(_sessionStore); + }; [Fact] public async Task StoreAsync_should_remove_conflicting_entries_prior_to_creating_new_entry() @@ -22,10 +23,13 @@ public class ServerSideTicketStoreTests : BffIntegrationTestBase await BffHost.BffLoginAsync("alice"); BffHost.BrowserClient.RemoveCookie("bff"); - (await _sessionStore.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" })).Count().ShouldBe(1); + var userSessionsFilter = new UserSessionsFilter { SubjectId = "alice" }; + var result = await _sessionStore.GetUserSessionsAsync(userSessionsFilter, _ct); + result.Count.ShouldBe(1); await BffHost.BffOidcLoginAsync(); - (await _sessionStore.GetUserSessionsAsync(new UserSessionsFilter { SubjectId = "alice" })).Count().ShouldBe(1); + result = await _sessionStore.GetUserSessionsAsync(userSessionsFilter, _ct); + result.Count.ShouldBe(1); } } diff --git a/bff/test/Bff.Tests/TestFramework/GenericHost.cs b/bff/test/Bff.Tests/TestFramework/GenericHost.cs index f605405b0..9f0bc70ca 100644 --- a/bff/test/Bff.Tests/TestFramework/GenericHost.cs +++ b/bff/test/Bff.Tests/TestFramework/GenericHost.cs @@ -46,7 +46,7 @@ public class GenericHost(WriteTestOutput writeOutput, string baseAddress = "http return _baseAddress + path; } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { var hostBuilder = new HostBuilder() .ConfigureWebHost(builder => diff --git a/bff/test/Bff.Tests/TestHosts/BffIntegrationTestBase.cs b/bff/test/Bff.Tests/TestHosts/BffIntegrationTestBase.cs index e8d908da8..e0d9ee544 100644 --- a/bff/test/Bff.Tests/TestHosts/BffIntegrationTestBase.cs +++ b/bff/test/Bff.Tests/TestHosts/BffIntegrationTestBase.cs @@ -6,18 +6,17 @@ using Duende.IdentityServer.Models; using Duende.IdentityServer.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Xunit.Abstractions; namespace Duende.Bff.Tests.TestHosts; public class BffIntegrationTestBase : OutputWritingTestBase { protected readonly IdentityServerHost IdentityServerHost; - protected ApiHost ApiHost; - protected BffHost BffHost; - protected BffHostUsingResourceNamedTokens BffHostWithNamedTokens; + protected readonly ApiHost ApiHost; + protected readonly BffHost BffHost; + protected readonly BffHostUsingResourceNamedTokens BffHostWithNamedTokens; - public BffIntegrationTestBase(ITestOutputHelper output) : base(output) + protected BffIntegrationTestBase(ITestOutputHelper output) : base(output) { IdentityServerHost = new IdentityServerHost(WriteLine); ApiHost = new ApiHost(WriteLine, IdentityServerHost, "scope1"); @@ -47,12 +46,11 @@ public class BffIntegrationTestBase : OutputWritingTestBase services.AddSingleton(); }; - } public async Task Login(string sub) => await IdentityServerHost.IssueSessionCookieAsync(new Claim("sub", sub)); - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { await IdentityServerHost.InitializeAsync(); await ApiHost.InitializeAsync(); @@ -61,13 +59,12 @@ public class BffIntegrationTestBase : OutputWritingTestBase await base.InitializeAsync(); } - public override async Task DisposeAsync() + public override async ValueTask DisposeAsync() { await ApiHost.DisposeAsync(); await BffHost.DisposeAsync(); await BffHostWithNamedTokens.DisposeAsync(); await IdentityServerHost.DisposeAsync(); await base.DisposeAsync(); - } } diff --git a/bff/test/Bff.Tests/TestHosts/OutputWritingTestBase.cs b/bff/test/Bff.Tests/TestHosts/OutputWritingTestBase.cs index 4a7134495..4133b091e 100644 --- a/bff/test/Bff.Tests/TestHosts/OutputWritingTestBase.cs +++ b/bff/test/Bff.Tests/TestHosts/OutputWritingTestBase.cs @@ -2,15 +2,16 @@ // See LICENSE in the project root for license information. using System.Text; -using Xunit.Abstractions; namespace Duende.Bff.Tests.TestHosts; public class OutputWritingTestBase(ITestOutputHelper testOutputHelper) : IAsyncLifetime { - private readonly StringBuilder _output = new StringBuilder(); + private readonly StringBuilder _output = new(); - public void WriteLine(string message) + public virtual ValueTask InitializeAsync() => default; + + protected void WriteLine(string message) { lock (_output) { @@ -18,16 +19,12 @@ public class OutputWritingTestBase(ITestOutputHelper testOutputHelper) : IAsyncL } } - public virtual Task InitializeAsync() => Task.CompletedTask; - - public virtual Task DisposeAsync() + public virtual ValueTask DisposeAsync() { lock (_output) { testOutputHelper.WriteLine(_output.ToString()); } - - - return Task.CompletedTask; + return default; } } diff --git a/bff/test/Bff.Tests/TestHosts/YarpBffIntegrationTestBase.cs b/bff/test/Bff.Tests/TestHosts/YarpBffIntegrationTestBase.cs index 5a8ffa664..bc736c6bf 100644 --- a/bff/test/Bff.Tests/TestHosts/YarpBffIntegrationTestBase.cs +++ b/bff/test/Bff.Tests/TestHosts/YarpBffIntegrationTestBase.cs @@ -6,7 +6,6 @@ using Duende.IdentityServer.Models; using Duende.IdentityServer.Services; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Xunit.Abstractions; namespace Duende.Bff.Tests.TestHosts; @@ -51,7 +50,7 @@ public class YarpBffIntegrationTestBase : OutputWritingTestBase public async Task Login(string sub) => await _identityServerHost.IssueSessionCookieAsync(new Claim("sub", sub)); - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { await _identityServerHost.InitializeAsync(); await ApiHost.InitializeAsync(); @@ -60,7 +59,7 @@ public class YarpBffIntegrationTestBase : OutputWritingTestBase await base.InitializeAsync(); } - public override async Task DisposeAsync() + public override async ValueTask DisposeAsync() { await _identityServerHost.DisposeAsync(); await ApiHost.DisposeAsync(); diff --git a/bff/test/Hosts.Tests/BffBlazorWebAssemblyTests.cs b/bff/test/Hosts.Tests/BffBlazorWebAssemblyTests.cs index 728e0bcde..2b35ce75d 100644 --- a/bff/test/Hosts.Tests/BffBlazorWebAssemblyTests.cs +++ b/bff/test/Hosts.Tests/BffBlazorWebAssemblyTests.cs @@ -4,7 +4,6 @@ using Hosts.ServiceDefaults; using Hosts.Tests.PageModels; using Hosts.Tests.TestInfra; -using Xunit.Abstractions; namespace Hosts.Tests; @@ -20,7 +19,7 @@ public class BffBlazorWebAssemblyTests(ITestOutputHelper output, AppHostFixture }; } - [SkippableFact] + [Fact] public async Task Can_login_and_load_local_api() { await Warmup(); diff --git a/bff/test/Hosts.Tests/BffTests.cs b/bff/test/Hosts.Tests/BffTests.cs index fb8e79c6f..2f8198c18 100644 --- a/bff/test/Hosts.Tests/BffTests.cs +++ b/bff/test/Hosts.Tests/BffTests.cs @@ -3,12 +3,12 @@ using Hosts.ServiceDefaults; using Hosts.Tests.TestInfra; -using Xunit.Abstractions; namespace Hosts.Tests; public class BffTests : IntegrationTestBase { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly HttpClient _httpClient; private readonly BffClient _bffClient; @@ -18,28 +18,28 @@ public class BffTests : IntegrationTestBase _bffClient = new BffClient(CreateHttpClient(AppHostServices.Bff)); } - [SkippableFact] + [Fact] public async Task Can_invoke_home() { - var response = await _httpClient.GetAsync("/"); + var response = await _httpClient.GetAsync("/", _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); } - [SkippableFact] + [Fact] public async Task Can_initiate_login() { - var response = await _httpClient.GetAsync("/"); + var response = await _httpClient.GetAsync("/", _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); - await _bffClient.TriggerLogin(); + await _bffClient.TriggerLogin(ct: _ct); // Verify that there are user claims var claims = await _bffClient.GetUserClaims(); claims.Any().ShouldBeTrue(); } - [SkippableTheory] + [Theory] [InlineData("/local/self-contained")] [InlineData("/local/invokes-external-api")] [InlineData("/api/user-token")] @@ -51,14 +51,14 @@ public class BffTests : IntegrationTestBase [InlineData("/api/audience-constrained")] public async Task Once_authenticated_can_call_proxied_urls(string url) { - await _bffClient.TriggerLogin(); + await _bffClient.TriggerLogin(ct: _ct); await _bffClient.InvokeApi(url); } - [SkippableFact] + [Fact] public async Task Can_logout() { - await _bffClient.TriggerLogin(); + await _bffClient.TriggerLogin(ct: _ct); await _bffClient.TriggerLogout(); await _bffClient.InvokeApi(url: "/local/self-contained", expectedResponse: HttpStatusCode.Unauthorized); diff --git a/bff/test/Hosts.Tests/BlazorPerComponentTests.cs b/bff/test/Hosts.Tests/BlazorPerComponentTests.cs index 2ce60b061..cfa2f8611 100644 --- a/bff/test/Hosts.Tests/BlazorPerComponentTests.cs +++ b/bff/test/Hosts.Tests/BlazorPerComponentTests.cs @@ -4,7 +4,6 @@ using Hosts.ServiceDefaults; using Hosts.Tests.PageModels; using Hosts.Tests.TestInfra; -using Xunit.Abstractions; namespace Hosts.Tests; @@ -21,7 +20,7 @@ public class BlazorPerComponentTests(ITestOutputHelper output, AppHostFixture fi }; } - [SkippableFact] + [Fact] public async Task Can_load_blazor_webassembly_app() { await Warmup(); diff --git a/bff/test/Hosts.Tests/Hosts.Tests.csproj b/bff/test/Hosts.Tests/Hosts.Tests.csproj index c21f38cb0..2273d4860 100644 --- a/bff/test/Hosts.Tests/Hosts.Tests.csproj +++ b/bff/test/Hosts.Tests/Hosts.Tests.csproj @@ -13,30 +13,25 @@ - + - + - - - - + - - - - - + + + diff --git a/bff/test/Hosts.Tests/PlaywrightTestBase.cs b/bff/test/Hosts.Tests/PlaywrightTestBase.cs index 939512f76..3acb5c181 100644 --- a/bff/test/Hosts.Tests/PlaywrightTestBase.cs +++ b/bff/test/Hosts.Tests/PlaywrightTestBase.cs @@ -4,9 +4,8 @@ using System.Reflection; using Hosts.Tests.TestInfra; using Microsoft.Playwright; -using Microsoft.Playwright.Xunit; -using Xunit.Abstractions; -using Xunit.Sdk; +using Microsoft.Playwright.Xunit.v3; +using Xunit.v3; namespace Hosts.Tests; @@ -31,12 +30,12 @@ public class PlaywrightTestBase : PageTest, IDisposable #if DEBUG_NCRUNCH // Running in NCrunch. NCrunch cannot build the aspire project, so it needs // to be started manually. - Skip.If(true, "When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); + Assert.Skip("When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); #endif } } - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { await base.InitializeAsync(); Context.SetDefaultTimeout(10_000); @@ -49,7 +48,7 @@ public class PlaywrightTestBase : PageTest, IDisposable }); } - public override async Task DisposeAsync() + public override async ValueTask DisposeAsync() { var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Environment.CurrentDirectory; // if path ends with /bin/{build configuration}/{dotnetversion}, then strip that from the path. @@ -59,7 +58,6 @@ public class PlaywrightTestBase : PageTest, IDisposable path = Path.GetFullPath(Path.Combine(path, "../../../")); } - await Context.Tracing.StopAsync(new() { Path = Path.Combine( @@ -106,18 +104,17 @@ public class PlaywrightTestBase : PageTest, IDisposable public HttpClient CreateHttpClient(string clientName) => Fixture.CreateHttpClient(clientName); } -public class WithTestNameAttribute : BeforeAfterTestAttribute +public class WithTestNameAttribute : Attribute, IBeforeAfterTestAttribute { public static string CurrentTestName = string.Empty; public static string CurrentClassName = string.Empty; - public override void Before(MethodInfo methodInfo) + public void Before(MethodInfo methodInfo, IXunitTest _) { CurrentTestName = methodInfo.Name; CurrentClassName = methodInfo.DeclaringType!.Name; } - public override void After(MethodInfo methodInfo) - { - } + public void After(MethodInfo methodInfo, IXunitTest _) + { } } diff --git a/bff/test/Hosts.Tests/TestInfra/AppHostFixture.cs b/bff/test/Hosts.Tests/TestInfra/AppHostFixture.cs index 701d26262..2ebc4e593 100644 --- a/bff/test/Hosts.Tests/TestInfra/AppHostFixture.cs +++ b/bff/test/Hosts.Tests/TestInfra/AppHostFixture.cs @@ -51,7 +51,7 @@ public class AppHostFixture : IAsyncLifetime public bool UsingAlreadyRunningInstance { get; private set; } public string StartupLogs => _startupLogs.ToString() ?? string.Empty; - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { using var startupLogWriter = ConnectLogger(s => _startupLogs.Write(s)); @@ -130,7 +130,7 @@ public class AppHostFixture : IAsyncLifetime } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { if (_app != null) { @@ -272,7 +272,7 @@ public class AppHostFixture : IAsyncLifetime return _app.GetEndpoint(clientName); #else - Skip.If(true, "When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); + Assert.Skip("When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); return null!; #endif } diff --git a/bff/test/Hosts.Tests/TestInfra/IntegrationTestBase.cs b/bff/test/Hosts.Tests/TestInfra/IntegrationTestBase.cs index c0c0cfbe1..bc1857044 100644 --- a/bff/test/Hosts.Tests/TestInfra/IntegrationTestBase.cs +++ b/bff/test/Hosts.Tests/TestInfra/IntegrationTestBase.cs @@ -1,7 +1,6 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. -using Xunit.Abstractions; namespace Hosts.Tests.TestInfra; @@ -24,7 +23,7 @@ public class IntegrationTestBase : IDisposable #if DEBUG_NCRUNCH // Running in NCrunch. NCrunch cannot build the aspire project, so it needs // to be started manually. - Skip.If(true, "When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); + Assert.Skip("When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); #endif } } diff --git a/identity-server/test/IdentityServer.EndToEndTests/IdentityServer.EndToEndTests.csproj b/identity-server/test/IdentityServer.EndToEndTests/IdentityServer.EndToEndTests.csproj index 33d7e410a..2c592fec7 100644 --- a/identity-server/test/IdentityServer.EndToEndTests/IdentityServer.EndToEndTests.csproj +++ b/identity-server/test/IdentityServer.EndToEndTests/IdentityServer.EndToEndTests.csproj @@ -12,11 +12,9 @@ - + - - diff --git a/identity-server/test/IdentityServer.EndToEndTests/IdentityServerTests.cs b/identity-server/test/IdentityServer.EndToEndTests/IdentityServerTests.cs index 786de6519..ff4c34907 100644 --- a/identity-server/test/IdentityServer.EndToEndTests/IdentityServerTests.cs +++ b/identity-server/test/IdentityServer.EndToEndTests/IdentityServerTests.cs @@ -5,7 +5,6 @@ using Duende.IdentityServer.EndToEndTests.TestInfra; using Duende.Xunit.Playwright; using Projects; using ServiceDefaults; -using Xunit.Abstractions; namespace Duende.IdentityServer.EndToEndTests; @@ -13,6 +12,8 @@ namespace Duende.IdentityServer.EndToEndTests; public class IdentityServerTests(ITestOutputHelper output, IdentityServerHostTestFixture fixture) : PlaywrightTestBase(output, fixture) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Theory] [InlineData(AppHostServices.MvcAutomaticTokenManagement)] [InlineData(AppHostServices.MvcCode)] @@ -24,7 +25,7 @@ public class IdentityServerTests(ITestOutputHelper output, IdentityServerHostTes public async Task clients_can_login_use_tokens_and_logout(string clientName) { await Page.GotoAsync(Fixture.GetUrlTo(clientName).ToString()); - await Page.Login(); + await Page.Login(ct: _ct); await Page.CallApi(); await Page.RenewTokens(); await Page.CallApi(); @@ -41,7 +42,7 @@ public class IdentityServerTests(ITestOutputHelper output, IdentityServerHostTes public async Task templates_can_serve_discovery(string templateName) { var client = CreateHttpClient(templateName); - var response = await client.GetAsync(".well-known/openid-configuration"); + var response = await client.GetAsync(".well-known/openid-configuration", _ct); response.IsSuccessStatusCode.ShouldBeTrue(); } } diff --git a/identity-server/test/IdentityServer.EndToEndTests/TestInfra/IdentityServerPlaywrightTestBase.cs b/identity-server/test/IdentityServer.EndToEndTests/TestInfra/IdentityServerPlaywrightTestBase.cs index 1139da7f9..07f4902a4 100644 --- a/identity-server/test/IdentityServer.EndToEndTests/TestInfra/IdentityServerPlaywrightTestBase.cs +++ b/identity-server/test/IdentityServer.EndToEndTests/TestInfra/IdentityServerPlaywrightTestBase.cs @@ -3,7 +3,6 @@ using Duende.Xunit.Playwright; using Projects; -using Xunit.Abstractions; namespace Duende.IdentityServer.EndToEndTests.TestInfra; diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs index 56de3fba3..058d7f852 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientAssertionClient.cs @@ -1,7 +1,6 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. - using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using System.Text; @@ -19,6 +18,7 @@ namespace Duende.IdentityServer.IntegrationTests.Clients; public class ClientAssertionClient { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string TokenEndpoint = "https://idsvr4/connect/token"; private const string ClientId = "certificate_base64_valid"; @@ -74,7 +74,7 @@ public class ClientAssertionClient }, Scope = "api1" - }); + }, _ct); AssertValidToken(response); } @@ -97,7 +97,7 @@ public class ClientAssertionClient }, Scope = "api1" - }); + }, _ct); AssertValidToken(response); } @@ -120,7 +120,7 @@ public class ClientAssertionClient }, Scope = "api1" - }); + }, _ct); AssertValidToken(response); @@ -138,7 +138,7 @@ public class ClientAssertionClient }, Scope = "api1" - }); + }, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe("invalid_client"); @@ -160,7 +160,7 @@ public class ClientAssertionClient }, Scope = "api1" - }); + }, _ct); response.IsError.ShouldBe(true); response.Error.ShouldBe(OidcConstants.TokenErrors.InvalidClient); @@ -186,7 +186,7 @@ public class ClientAssertionClient }, Scope = "api1" - }); + }, _ct); response.IsError.ShouldBe(true); response.Error.ShouldBe(OidcConstants.TokenErrors.InvalidClient); @@ -195,7 +195,7 @@ public class ClientAssertionClient private async Task GetToken(FormUrlEncodedContent body) { - var response = await _client.PostAsync(TokenEndpoint, body); + var response = await _client.PostAsync(TokenEndpoint, body, _ct); return await ProtocolResponse.FromHttpResponseAsync(response); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsAndResourceOwnerClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsAndResourceOwnerClient.cs index 694166b1c..2ea7584fd 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsAndResourceOwnerClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsAndResourceOwnerClient.cs @@ -12,6 +12,7 @@ namespace Duende.IdentityServer.IntegrationTests.Clients; public class ClientCredentialsandResourceOwnerClient { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string TokenEndpoint = "https://server/connect/token"; private readonly HttpClient _client; @@ -39,7 +40,7 @@ public class ClientCredentialsandResourceOwnerClient ClientId = "client.and.ro", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); response.IsError.ShouldBe(false); } @@ -53,7 +54,7 @@ public class ClientCredentialsandResourceOwnerClient ClientId = "client.and.ro", ClientSecret = "secret", Scope = "openid api1" - }); + }, _ct); response.IsError.ShouldBe(true); } @@ -70,7 +71,7 @@ public class ClientCredentialsandResourceOwnerClient UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBe(false); } @@ -87,7 +88,7 @@ public class ClientCredentialsandResourceOwnerClient UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBe(false); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs index a913cbecb..e58d03d33 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ClientCredentialsClient.cs @@ -16,6 +16,7 @@ namespace Duende.IdentityServer.IntegrationTests.Clients; public class ClientCredentialsClient { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string TokenEndpoint = "https://server/connect/token"; private readonly HttpClient _client; @@ -43,7 +44,7 @@ public class ClientCredentialsClient ClientId = "client", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Http); @@ -60,7 +61,7 @@ public class ClientCredentialsClient ClientId = "client", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); response.IsError.ShouldBe(false); response.ExpiresIn.ShouldBe(3600); @@ -90,7 +91,7 @@ public class ClientCredentialsClient ClientId = "client", ClientSecret = "secret", Scope = "api1 other_api" - }); + }, _ct); response.IsError.ShouldBe(false); response.ExpiresIn.ShouldBe(3600); @@ -124,7 +125,7 @@ public class ClientCredentialsClient ClientId = "client.cnf", ClientSecret = "foo", Scope = "api1" - }); + }, _ct); response.IsError.ShouldBe(false); response.ExpiresIn.ShouldBe(3600); @@ -157,7 +158,7 @@ public class ClientCredentialsClient ClientId = "client", ClientSecret = "secret", Scope = "api1 api2" - }); + }, _ct); response.IsError.ShouldBe(false); response.ExpiresIn.ShouldBe(3600); @@ -188,7 +189,7 @@ public class ClientCredentialsClient Address = TokenEndpoint, ClientId = "client", ClientSecret = "secret" - }); + }, _ct); response.IsError.ShouldBe(false); response.ExpiresIn.ShouldBe(3600); @@ -224,7 +225,7 @@ public class ClientCredentialsClient Address = TokenEndpoint, ClientId = "client.no_default_scopes", ClientSecret = "secret" - }); + }, _ct); response.IsError.ShouldBe(true); response.ExpiresIn.ShouldBe(0); @@ -245,7 +246,7 @@ public class ClientCredentialsClient Scope = "api1", ClientCredentialStyle = ClientCredentialStyle.PostBody - }); + }, _ct); response.IsError.ShouldBe(false); response.ExpiresIn.ShouldBe(3600); @@ -272,7 +273,7 @@ public class ClientCredentialsClient Address = TokenEndpoint, ClientId = "client.no_secret", Scope = "api1" - }); + }, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe("invalid_client"); @@ -287,7 +288,7 @@ public class ClientCredentialsClient ClientId = "client", ClientSecret = "invalid", Scope = "api1" - }); + }, _ct); response.IsError.ShouldBe(true); response.Error.ShouldBe("invalid_client"); @@ -302,7 +303,7 @@ public class ClientCredentialsClient ClientId = "invalid", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -318,7 +319,7 @@ public class ClientCredentialsClient Address = TokenEndpoint, ClientId = "implicit", Scope = "api1" - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -335,7 +336,7 @@ public class ClientCredentialsClient ClientId = "implicit_and_client_creds", ClientSecret = "invalid", Scope = "api1" - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -353,7 +354,7 @@ public class ClientCredentialsClient ClientId = "client", ClientSecret = "secret", Scope = "unknown" - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -370,7 +371,7 @@ public class ClientCredentialsClient ClientId = "client.identityscopes", ClientSecret = "secret", Scope = "openid api1" - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -387,7 +388,7 @@ public class ClientCredentialsClient ClientId = "client", ClientSecret = "secret", Scope = "api1 offline_access" - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -404,7 +405,7 @@ public class ClientCredentialsClient ClientId = "client", ClientSecret = "secret", Scope = "api3" - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -421,7 +422,7 @@ public class ClientCredentialsClient ClientId = "client", ClientSecret = "secret", Scope = "api1 api3" - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenRequestValidatorClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenRequestValidatorClient.cs index 44a75f22d..ceeaf49ab 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenRequestValidatorClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenRequestValidatorClient.cs @@ -14,6 +14,7 @@ namespace Duende.IdentityServer.IntegrationTests.Clients; public class CustomTokenRequestValidatorClient { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string TokenEndpoint = "https://server/connect/token"; private readonly HttpClient _client; @@ -45,7 +46,7 @@ public class CustomTokenRequestValidatorClient ClientId = "client", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); var fields = GetFields(response); fields["custom"].GetString().ShouldBe("custom"); @@ -64,7 +65,7 @@ public class CustomTokenRequestValidatorClient UserName = "bob", Password = "bob" - }); + }, _ct); var fields = GetFields(response); fields["custom"].GetString().ShouldBe("custom"); @@ -83,7 +84,7 @@ public class CustomTokenRequestValidatorClient UserName = "bob", Password = "bob" - }); + }, _ct); response = await _client.RequestRefreshTokenAsync(new RefreshTokenRequest { @@ -92,7 +93,7 @@ public class CustomTokenRequestValidatorClient ClientSecret = "secret", RefreshToken = response.RefreshToken - }); + }, _ct); var fields = GetFields(response); fields["custom"].GetString().ShouldBe("custom"); @@ -114,7 +115,7 @@ public class CustomTokenRequestValidatorClient { "scope", "api1" }, { "custom_credential", "custom credential"} } - }); + }, _ct); var fields = GetFields(response); fields["custom"].GetString().ShouldBe("custom"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs index 83801d7a6..07f7a28b8 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs @@ -16,6 +16,7 @@ namespace Duende.IdentityServer.IntegrationTests.Clients; public class CustomTokenResponseClients { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string TokenEndpoint = "https://server/connect/token"; private readonly HttpClient _client; @@ -46,7 +47,7 @@ public class CustomTokenResponseClients UserName = "bob", Password = "bob", Scope = "api1" - }); + }, _ct); // raw fields var fields = GetFields(response); @@ -109,7 +110,7 @@ public class CustomTokenResponseClients UserName = "bob", Password = "invalid", Scope = "api1" - }); + }, _ct); // raw fields var fields = GetFields(response); @@ -161,7 +162,7 @@ public class CustomTokenResponseClients { "scope", "api1" }, { "outcome", "succeed"} } - }); + }, _ct); // raw fields @@ -229,7 +230,7 @@ public class CustomTokenResponseClients { "scope", "api1" }, { "outcome", "fail"} } - }); + }, _ct); // raw fields diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/DiscoveryClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/DiscoveryClient.cs index d354f6e17..6d7960c71 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/DiscoveryClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/DiscoveryClient.cs @@ -13,7 +13,7 @@ namespace Duende.IdentityServer.IntegrationTests.Clients; public class DiscoveryClientTests { private const string DiscoveryEndpoint = "https://server/.well-known/openid-configuration"; - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly HttpClient _client; public DiscoveryClientTests() @@ -40,7 +40,7 @@ public class DiscoveryClientTests { ValidateIssuerName = false } - }); + }, _ct); // endpoints doc.TokenEndpoint.ShouldBe("https://server/connect/token"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs index 0c6b2ff1b..14b10c593 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ExtensionGrantClient.cs @@ -18,7 +18,7 @@ namespace Duende.IdentityServer.IntegrationTests.Clients; public class ExtensionGrantClient { private const string TokenEndpoint = "https://server/connect/token"; - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly HttpClient _client; public ExtensionGrantClient() @@ -51,7 +51,7 @@ public class ExtensionGrantClient { "custom_credential", "custom credential"}, { "scope", "api1" } } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -96,7 +96,7 @@ public class ExtensionGrantClient { "extra_claim", "extra_value" }, { "scope", "api1" } } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -148,7 +148,7 @@ public class ExtensionGrantClient { "extra_claim", "extra_value" }, { "scope", "api1 offline_access" } } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -165,7 +165,7 @@ public class ExtensionGrantClient ClientSecret = "secret", RefreshToken = response.RefreshToken - }); + }, _ct); refreshResponse.IsError.ShouldBeFalse(); refreshResponse.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -215,7 +215,7 @@ public class ExtensionGrantClient { "custom_credential", "custom credential"}, { "scope", "api1" } } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -250,7 +250,7 @@ public class ExtensionGrantClient { { "custom_credential", "custom credential"} } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -296,7 +296,7 @@ public class ExtensionGrantClient { { "scope", "api1" } } - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -320,7 +320,7 @@ public class ExtensionGrantClient { "custom_credential", "custom credential"}, { "scope", "api1" } } - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -344,7 +344,7 @@ public class ExtensionGrantClient { "custom_credential", "custom credential"}, { "scope", "api1" } } - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -370,7 +370,7 @@ public class ExtensionGrantClient { "lifetime", "5000"}, { "sub", "818727"} } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -421,7 +421,7 @@ public class ExtensionGrantClient { "type", "jwt"}, { "sub", "818727"} } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -452,7 +452,7 @@ public class ExtensionGrantClient { "impersonated_client", "impersonated_client_id"}, { "sub", "818727"} } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -485,7 +485,7 @@ public class ExtensionGrantClient { "type", "reference"}, { "sub", "818727"} } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -515,7 +515,7 @@ public class ExtensionGrantClient { "claim", "extra_claim"}, { "sub", "818727"} } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); @@ -561,7 +561,7 @@ public class ExtensionGrantClient { "claim", "extra_claim"}, } - }); + }, _ct); response.IsError.ShouldBeFalse(); response.HttpStatusCode.ShouldBe(HttpStatusCode.OK); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/RefreshTokenClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/RefreshTokenClient.cs index cee617f09..46e5dc3e3 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/RefreshTokenClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/RefreshTokenClient.cs @@ -14,7 +14,7 @@ public class RefreshTokenClient { private const string TokenEndpoint = "https://server/connect/token"; private const string RevocationEndpoint = "https://server/connect/revocation"; - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly HttpClient _client; public RefreshTokenClient() @@ -43,7 +43,7 @@ public class RefreshTokenClient Scope = "api1 offline_access", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -58,7 +58,7 @@ public class RefreshTokenClient ClientSecret = "secret", RefreshToken = response.RefreshToken - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -79,7 +79,7 @@ public class RefreshTokenClient Scope = "openid api1 offline_access", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -94,7 +94,7 @@ public class RefreshTokenClient ClientSecret = "secret", RefreshToken = response.RefreshToken - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -115,7 +115,7 @@ public class RefreshTokenClient Scope = "openid api1 offline_access", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -132,7 +132,7 @@ public class RefreshTokenClient ClientSecret = "secret", RefreshToken = response.RefreshToken - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -157,7 +157,7 @@ public class RefreshTokenClient Scope = "openid api1 offline_access", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -174,7 +174,7 @@ public class RefreshTokenClient ClientSecret = "secret", RefreshToken = response.RefreshToken - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -200,7 +200,7 @@ public class RefreshTokenClient Scope = "openid api1 offline_access", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -218,7 +218,7 @@ public class RefreshTokenClient ClientSecret = "secret", RefreshToken = response.RefreshToken - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -234,7 +234,7 @@ public class RefreshTokenClient ClientSecret = "secret", RefreshToken = rt1 - }); + }, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe("invalid_grant"); @@ -253,7 +253,7 @@ public class RefreshTokenClient Scope = "openid api1 offline_access", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -271,7 +271,7 @@ public class RefreshTokenClient ClientSecret = "secret", RefreshToken = rt1 - }); + }, _ct); response.IsError.ShouldBeFalse(); } @@ -289,7 +289,7 @@ public class RefreshTokenClient Scope = "openid api1 offline_access", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); response.ExpiresIn.ShouldBe(3600); @@ -309,7 +309,7 @@ public class RefreshTokenClient Token = rt1, TokenTypeHint = "refresh_token" - }); + }, _ct); revocationResponse.IsError.ShouldBe(false); @@ -321,7 +321,7 @@ public class RefreshTokenClient ClientSecret = "secret", RefreshToken = rt1 - }); + }, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe("invalid_grant"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs index ef492f51d..f4ff29884 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/ResourceOwnerClient.cs @@ -17,7 +17,7 @@ namespace Duende.IdentityServer.IntegrationTests.Clients; public class ResourceOwnerClient { private const string TokenEndpoint = "https://server/connect/token"; - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly HttpClient _client; public ResourceOwnerClient() @@ -46,7 +46,7 @@ public class ResourceOwnerClient Scope = "api1", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBe(false); response.ExpiresIn.ShouldBe(3600); @@ -85,7 +85,7 @@ public class ResourceOwnerClient UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBe(false); response.ExpiresIn.ShouldBe(3600); @@ -132,7 +132,7 @@ public class ResourceOwnerClient Scope = "openid email api1", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBe(false); response.ExpiresIn.ShouldBe(3600); @@ -174,7 +174,7 @@ public class ResourceOwnerClient Scope = "openid email api1 offline_access", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBe(false); response.ExpiresIn.ShouldBe(3600); @@ -217,7 +217,7 @@ public class ResourceOwnerClient Scope = "api1", UserName = "unknown", Password = "bob" - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); @@ -236,7 +236,7 @@ public class ResourceOwnerClient Scope = "api1", UserName = "bob_no_password" - }); + }, _ct); response.IsError.ShouldBe(false); } @@ -255,7 +255,7 @@ public class ResourceOwnerClient Scope = "api1", UserName = "bob", Password = password - }); + }, _ct); response.IsError.ShouldBe(true); response.ErrorType.ShouldBe(ResponseErrorType.Protocol); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/RevocationClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/RevocationClient.cs index 45ca63835..6d380740e 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/RevocationClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/RevocationClient.cs @@ -15,7 +15,7 @@ public class RevocationClient private const string TokenEndpoint = "https://server/connect/token"; private const string RevocationEndpoint = "https://server/connect/revocation"; private const string IntrospectionEndpoint = "https://server/connect/introspect"; - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly HttpClient _client; public RevocationClient() @@ -35,7 +35,7 @@ public class RevocationClient [Fact] public async Task Revoking_reference_token_should_invalidate_token() { - // request acccess token + // request access token var response = await _client.RequestPasswordTokenAsync(new PasswordTokenRequest { Address = TokenEndpoint, @@ -45,7 +45,7 @@ public class RevocationClient Scope = "api1", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); @@ -57,7 +57,7 @@ public class RevocationClient ClientSecret = "secret", Token = response.AccessToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBe(true); @@ -69,7 +69,7 @@ public class RevocationClient ClientSecret = "secret", Token = response.AccessToken - }); + }, _ct); // introspect - should be inactive introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest @@ -79,7 +79,7 @@ public class RevocationClient ClientSecret = "secret", Token = response.AccessToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBe(false); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs index 76875c33e..5a268db7f 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/UserInfoClient.cs @@ -19,7 +19,7 @@ public class UserInfoEndpointClient { private const string TokenEndpoint = "https://server/connect/token"; private const string UserInfoEndpoint = "https://server/connect/userinfo"; - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly HttpClient _client; public UserInfoEndpointClient() @@ -48,7 +48,7 @@ public class UserInfoEndpointClient Scope = "openid email api1", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); @@ -56,7 +56,7 @@ public class UserInfoEndpointClient { Address = UserInfoEndpoint, Token = response.AccessToken - }); + }, _ct); userInfo.IsError.ShouldBeFalse(); userInfo.Claims.Count().ShouldBe(3); @@ -78,7 +78,7 @@ public class UserInfoEndpointClient Scope = "openid address", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); @@ -86,7 +86,7 @@ public class UserInfoEndpointClient { Address = UserInfoEndpoint, Token = response.AccessToken - }); + }, _ct); userInfo.IsError.ShouldBeFalse(); userInfo.Claims.First().Value.ShouldBe("{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }"); @@ -104,7 +104,7 @@ public class UserInfoEndpointClient Scope = "api1", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); @@ -112,7 +112,7 @@ public class UserInfoEndpointClient { Address = UserInfoEndpoint, Token = response.AccessToken - }); + }, _ct); userInfo.IsError.ShouldBeTrue(); userInfo.HttpStatusCode.ShouldBe(HttpStatusCode.Forbidden); @@ -130,7 +130,7 @@ public class UserInfoEndpointClient Scope = "email api1", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); @@ -138,7 +138,7 @@ public class UserInfoEndpointClient { Address = UserInfoEndpoint, Token = response.AccessToken - }); + }, _ct); userInfo.IsError.ShouldBeTrue(); userInfo.HttpStatusCode.ShouldBe(HttpStatusCode.Forbidden); @@ -151,7 +151,7 @@ public class UserInfoEndpointClient { Address = UserInfoEndpoint, Token = "invalid" - }); + }, _ct); userInfo.IsError.ShouldBeTrue(); userInfo.HttpStatusCode.ShouldBe(HttpStatusCode.Unauthorized); @@ -169,7 +169,7 @@ public class UserInfoEndpointClient Scope = "openid email api1 api4.with.roles roles", UserName = "bob", Password = "bob" - }); + }, _ct); response.IsError.ShouldBeFalse(); @@ -192,7 +192,7 @@ public class UserInfoEndpointClient { Address = UserInfoEndpoint, Token = response.AccessToken - }); + }, _ct); roles = userInfo.Json?.TryGetStringArray("role").ToList(); roles.Count.ShouldBe(2); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Configuration/DynamicClientRegistrationTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Configuration/DynamicClientRegistrationTests.cs index 4d4679f3a..0569ac617 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Configuration/DynamicClientRegistrationTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Configuration/DynamicClientRegistrationTests.cs @@ -11,6 +11,8 @@ namespace Duende.IdentityServer.IntegrationTests.Configuration; public class DynamicClientRegistrationTests : ConfigurationIntegrationTestBase { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] public async Task valid_request_creates_new_client() { @@ -25,9 +27,9 @@ public class DynamicClientRegistrationTests : ConfigurationIntegrationTestBase DefaultMaxAge = 10000, Scope = "api1 openid profile" }; - var httpResponse = await ConfigurationHost.HttpClient!.PostAsJsonAsync("/connect/dcr", request); + var httpResponse = await ConfigurationHost.HttpClient!.PostAsJsonAsync("/connect/dcr", request, _ct); - var response = await httpResponse.Content.ReadFromJsonAsync(); + var response = await httpResponse.Content.ReadFromJsonAsync(_ct); response.ShouldNotBeNull(); var newClient = await IdentityServerHost.GetClientAsync(response!.ClientId); // Not null already asserted newClient.ShouldNotBeNull(); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Configuration/DynamicClientRegistrationValidationTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Configuration/DynamicClientRegistrationValidationTests.cs index 14a1dc0aa..22ffb471c 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Configuration/DynamicClientRegistrationValidationTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Configuration/DynamicClientRegistrationValidationTests.cs @@ -12,10 +12,12 @@ namespace Duende.IdentityServer.IntegrationTests.Configuration; public class DynamicClientRegistrationValidationTests : ConfigurationIntegrationTestBase { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] public async Task http_get_method_should_fail() { - var response = await ConfigurationHost.HttpClient!.GetAsync("/connect/dcr"); + var response = await ConfigurationHost.HttpClient!.GetAsync("/connect/dcr", _ct); response.StatusCode.ShouldBe(HttpStatusCode.MethodNotAllowed); } @@ -26,7 +28,7 @@ public class DynamicClientRegistrationValidationTests : ConfigurationIntegration { "redirect_uris", "https://example.com/callback" }, { "grant_types", "authorization_code" } }); - var response = await ConfigurationHost.HttpClient!.PostAsync("/connect/dcr", content); + var response = await ConfigurationHost.HttpClient!.PostAsync("/connect/dcr", content, _ct); response.StatusCode.ShouldBe(HttpStatusCode.UnsupportedMediaType); } @@ -36,10 +38,10 @@ public class DynamicClientRegistrationValidationTests : ConfigurationIntegration var response = await ConfigurationHost.HttpClient!.PostAsJsonAsync("/connect/dcr", new { redirect_uris = new[] { "https://example.com/callback" } - }); + }, _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var error = await response.Content.ReadFromJsonAsync(); + var error = await response.Content.ReadFromJsonAsync(_ct); error?.Error.ShouldBe("invalid_client_metadata"); } @@ -50,10 +52,10 @@ public class DynamicClientRegistrationValidationTests : ConfigurationIntegration { redirect_uris = new[] { "https://example.com/callback" }, grant_types = new[] { "password" } - }); + }, _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var error = await response.Content.ReadFromJsonAsync(); + var error = await response.Content.ReadFromJsonAsync(_ct); error?.Error.ShouldBe("invalid_client_metadata"); } @@ -64,10 +66,10 @@ public class DynamicClientRegistrationValidationTests : ConfigurationIntegration { redirect_uris = new[] { "https://example.com/callback" }, grant_types = new[] { "client_credentials" } - }); + }, _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var error = await response.Content.ReadFromJsonAsync(); + var error = await response.Content.ReadFromJsonAsync(_ct); error?.Error.ShouldBe("invalid_redirect_uri"); } @@ -77,10 +79,10 @@ public class DynamicClientRegistrationValidationTests : ConfigurationIntegration var response = await ConfigurationHost.HttpClient!.PostAsJsonAsync("/connect/dcr", new { grant_types = new[] { "authorization_code", "client_credentials" } - }); + }, _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var error = await response.Content.ReadFromJsonAsync(); + var error = await response.Content.ReadFromJsonAsync(_ct); error?.Error.ShouldBe("invalid_redirect_uri"); } @@ -90,10 +92,10 @@ public class DynamicClientRegistrationValidationTests : ConfigurationIntegration var response = await ConfigurationHost.HttpClient!.PostAsJsonAsync("/connect/dcr", new { grant_types = new[] { "client_credentials", "refresh_token" } - }); + }, _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var error = await response.Content.ReadFromJsonAsync(); + var error = await response.Content.ReadFromJsonAsync(_ct); error?.Error.ShouldBe("invalid_client_metadata"); } @@ -106,11 +108,10 @@ public class DynamicClientRegistrationValidationTests : ConfigurationIntegration GrantTypes = { "client_credentials" }, Jwks = new KeySet(Array.Empty()), JwksUri = new Uri("https://example.com") - } - ); + }, _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var error = await response.Content.ReadFromJsonAsync(); + var error = await response.Content.ReadFromJsonAsync(_ct); error?.Error.ShouldBe("invalid_client_metadata"); } } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/ClientAuthenticationTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/ClientAuthenticationTests.cs index 299c1c622..8644a11c6 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/ClientAuthenticationTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/ClientAuthenticationTests.cs @@ -13,8 +13,8 @@ namespace Duende.IdentityServer.IntegrationTests.Conformance.Basic; public class ClientAuthenticationTests { private const string Category = "Conformance.Basic.ClientAuthenticationTests"; - - private IdentityServerPipeline _pipeline = new IdentityServerPipeline(); + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _pipeline = new IdentityServerPipeline(); public ClientAuthenticationTests() { @@ -70,7 +70,7 @@ public class ClientAuthenticationTests scope: "openid", redirectUri: "https://code_pipeline.Client/callback?foo=bar&baz=quux", nonce: nonce); - var response = await _pipeline.BrowserClient.GetAsync(url); + var response = await _pipeline.BrowserClient.GetAsync(url, _ct); var authorization = _pipeline.ParseAuthorizationResponseUrl(response.Headers.Location.ToString()); authorization.Code.ShouldNotBeNull(); @@ -88,7 +88,7 @@ public class ClientAuthenticationTests Code = code, RedirectUri = "https://code_pipeline.Client/callback?foo=bar&baz=quux" - }); + }, _ct); tokenResult.IsError.ShouldBeFalse(); tokenResult.HttpErrorReason.ShouldBe("OK"); @@ -116,7 +116,7 @@ public class ClientAuthenticationTests scope: "openid", redirectUri: "https://code_pipeline.Client/callback?foo=bar&baz=quux", nonce: nonce); - var response = await _pipeline.BrowserClient.GetAsync(url); + var response = await _pipeline.BrowserClient.GetAsync(url, _ct); var authorization = _pipeline.ParseAuthorizationResponseUrl(response.Headers.Location.ToString()); authorization.Code.ShouldNotBeNull(); @@ -135,7 +135,7 @@ public class ClientAuthenticationTests Code = code, RedirectUri = "https://code_pipeline.Client/callback?foo=bar&baz=quux" - }); + }, _ct); tokenResult.IsError.ShouldBeFalse(); tokenResult.HttpErrorReason.ShouldBe("OK"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/CodeFlowTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/CodeFlowTests.cs index 502dc6750..ce68782fd 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/CodeFlowTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/CodeFlowTests.cs @@ -14,6 +14,7 @@ namespace Duende.IdentityServer.IntegrationTests.Conformance.Basic; public class CodeFlowTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Conformance.Basic.CodeFlowTests"; private IdentityServerPipeline _pipeline = new IdentityServerPipeline(); @@ -72,7 +73,7 @@ public class CodeFlowTests scope: "openid", redirectUri: "https://code_pipeline.Client/callback?foo=bar&baz=quux", nonce: nonce); - var response = await _pipeline.BrowserClient.GetAsync(url); + var response = await _pipeline.BrowserClient.GetAsync(url, _ct); var authorization = _pipeline.ParseAuthorizationResponseUrl(response.Headers.Location.ToString()); authorization.Code.ShouldNotBeNull(); @@ -90,7 +91,7 @@ public class CodeFlowTests Code = code, RedirectUri = "https://code_pipeline.Client/callback?foo=bar&baz=quux" - }); + }, _ct); tokenResult.IsError.ShouldBeFalse(); tokenResult.HttpErrorReason.ShouldBe("OK"); @@ -125,7 +126,7 @@ public class CodeFlowTests redirectUri: "https://code_pipeline.Client/callback?foo=bar&baz=quux", state: "state", nonce: nonce); - var response = await _pipeline.BrowserClient.GetAsync(url); + var response = await _pipeline.BrowserClient.GetAsync(url, _ct); var authorization = _pipeline.ParseAuthorizationResponseUrl(response.Headers.Location.ToString()); authorization.Code.ShouldNotBeNull(); @@ -143,7 +144,7 @@ public class CodeFlowTests Code = code, RedirectUri = "https://code_pipeline.Client/callback?foo=bar&baz=quux" - }); + }, _ct); tokenResult.IsError.ShouldBeFalse(); tokenResult.HttpErrorReason.ShouldBe("OK"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/RedirectUriTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/RedirectUriTests.cs index 6fb233f2e..2fa42a9f1 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/RedirectUriTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/RedirectUriTests.cs @@ -13,8 +13,8 @@ namespace Duende.IdentityServer.IntegrationTests.Conformance.Basic; public class RedirectUriTests { private const string Category = "Conformance.Basic.RedirectUriTests"; - - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); public RedirectUriTests() { @@ -72,7 +72,7 @@ public class RedirectUriTests redirectUri: "https://bad", state: state, nonce: nonce); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request"); @@ -95,7 +95,7 @@ public class RedirectUriTests redirectUri: null, state: state, nonce: nonce); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request"); @@ -118,7 +118,7 @@ public class RedirectUriTests redirectUri: "https://code_client/callback?foo=bar&baz=quux", state: state, nonce: nonce); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://code_client/callback?"); @@ -146,7 +146,7 @@ public class RedirectUriTests redirectUri: "https://code_client/callback?baz=quux&foo=bar", state: state, nonce: nonce); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/ResponseTypeResponseModeTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/ResponseTypeResponseModeTests.cs index 5dbcd7e26..df5113138 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/ResponseTypeResponseModeTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/ResponseTypeResponseModeTests.cs @@ -15,8 +15,8 @@ namespace Duende.IdentityServer.IntegrationTests.Conformance.Basic; public class ResponseTypeResponseModeTests { private const string Category = "Conformance.Basic.ResponseTypeResponseModeTests"; - - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); public ResponseTypeResponseModeTests() { @@ -63,7 +63,7 @@ public class ResponseTypeResponseModeTests { await _mockPipeline.LoginAsync("bob"); - var metadata = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.DiscoveryEndpoint); + var metadata = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.DiscoveryEndpoint, _ct); metadata.StatusCode.ShouldBe(HttpStatusCode.OK); var state = Guid.NewGuid().ToString(); @@ -76,7 +76,7 @@ public class ResponseTypeResponseModeTests redirectUri: "https://code_client/callback", state: state, nonce: nonce); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found); var authorization = new AuthorizeResponse(response.Headers.Location.ToString()); @@ -109,7 +109,7 @@ public class ResponseTypeResponseModeTests var url = request.Create(values); _mockPipeline.BrowserClient.AllowAutoRedirect = true; - var _ = await _mockPipeline.BrowserClient.GetAsync(url); + var _ = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs index 5cd7fddbe..ccd0eb802 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Pkce/PkceTests.cs @@ -15,22 +15,19 @@ namespace Duende.IdentityServer.IntegrationTests.Conformance.Pkce; public class PkceTests { private const string Category = "PKCE"; - - private IdentityServerPipeline _pipeline = new IdentityServerPipeline(); - - private Client client; - private const string client_id = "code_client"; private const string client_id_optional = "code_client_optional"; private const string client_id_plain = "code_plain_client"; private const string client_id_pkce = "codewithproofkey_client"; private const string client_id_pkce_plain = "codewithproofkey_plain_client"; + private const string client_secret = "secret"; + private const string code_verifier = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + private const string redirect_uri = "https://code_client/callback"; + private const string response_type = "code"; - - private string redirect_uri = "https://code_client/callback"; - private string code_verifier = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; - private string client_secret = "secret"; - private string response_type = "code"; + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private Client client; + private readonly IdentityServerPipeline _pipeline = new IdentityServerPipeline(); public PkceTests() { @@ -208,7 +205,7 @@ public class PkceTests Code = code, RedirectUri = redirect_uri, CodeVerifier = code_verifier - }); + }, _ct); tokenResponse.IsError.ShouldBeFalse(); tokenResponse.TokenType.ShouldBe("Bearer"); @@ -248,7 +245,7 @@ public class PkceTests Code = code, RedirectUri = redirect_uri, CodeVerifier = code_verifier - }); + }, _ct); tokenResponse.IsError.ShouldBeFalse(); tokenResponse.TokenType.ShouldBe("Bearer"); @@ -301,7 +298,7 @@ public class PkceTests Code = code, RedirectUri = redirect_uri, CodeVerifier = code_verifier - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); } @@ -317,7 +314,6 @@ public class PkceTests await _pipeline.LoginAsync("bob"); var nonce = Guid.NewGuid().ToString(); - var code_challenge = code_verifier; var authorizeResponse = await _pipeline.RequestAuthorizationEndpointAsync(clientId, response_type, IdentityServerConstants.StandardScopes.OpenId, @@ -340,7 +336,6 @@ public class PkceTests await _pipeline.LoginAsync("bob"); var nonce = Guid.NewGuid().ToString(); - var code_challenge = code_verifier; var authorizeResponse = await _pipeline.RequestAuthorizationEndpointAsync(clientId, response_type, IdentityServerConstants.StandardScopes.OpenId, @@ -407,7 +402,7 @@ public class PkceTests Code = code, RedirectUri = redirect_uri, - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe(OidcConstants.TokenErrors.InvalidGrant); @@ -444,7 +439,7 @@ public class PkceTests Code = code, RedirectUri = redirect_uri, CodeVerifier = "a" - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe(OidcConstants.TokenErrors.InvalidGrant); @@ -481,7 +476,7 @@ public class PkceTests Code = code, RedirectUri = redirect_uri, CodeVerifier = new string('a', _pipeline.Options.InputLengthRestrictions.CodeVerifierMaxLength + 1) - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe(OidcConstants.TokenErrors.InvalidGrant); @@ -518,7 +513,7 @@ public class PkceTests Code = code, RedirectUri = redirect_uri, CodeVerifier = "mismatched_code_verifier" - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe(OidcConstants.TokenErrors.InvalidGrant); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/AuthorizeTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/AuthorizeTests.cs index 466eb37a7..6ef530f25 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/AuthorizeTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/AuthorizeTests.cs @@ -22,15 +22,14 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Authorize; public class AuthorizeTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Authorize endpoint"; - - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); - - private Client _client1; + private readonly IdentityServerPipeline _mockPipeline = new(); + private readonly Client _client1; public AuthorizeTests() { - _mockPipeline.Clients.AddRange(new Client[] { + _mockPipeline.Clients.AddRange([ _client1 = new Client { ClientId = "client1", @@ -72,9 +71,9 @@ public class AuthorizeTests RequirePkce = false, AllowedScopes = new List { "openid", "profile", "api1", "api2" }, RedirectUris = new List { "https://client4/callback" }, - }, + } - }); + ]); _mockPipeline.Users.Add(new TestUser { @@ -82,8 +81,8 @@ public class AuthorizeTests Username = "bob", Claims = new Claim[] { - new Claim("name", "Bob Loblaw"), - new Claim("email", "bob@loblaw.com"), + new("name", "Bob Loblaw"), + new("email", "bob@loblaw.com"), new Claim("role", "Attorney") } }); @@ -134,7 +133,7 @@ public class AuthorizeTests [Trait("Category", Category)] public async Task get_request_should_not_return_404() { - var response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.AuthorizeEndpoint); + var response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.AuthorizeEndpoint, _ct); response.StatusCode.ShouldNotBe(HttpStatusCode.NotFound); } @@ -143,7 +142,7 @@ public class AuthorizeTests [Trait("Category", Category)] public async Task post_request_without_form_should_return_415() { - var response = await _mockPipeline.BrowserClient.PostAsync(IdentityServerPipeline.AuthorizeEndpoint, new StringContent("foo")); + var response = await _mockPipeline.BrowserClient.PostAsync(IdentityServerPipeline.AuthorizeEndpoint, new StringContent("foo"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.UnsupportedMediaType); } @@ -154,7 +153,7 @@ public class AuthorizeTests { var response = await _mockPipeline.BrowserClient.PostAsync(IdentityServerPipeline.AuthorizeEndpoint, new FormUrlEncodedContent( - new Dictionary { })); + new Dictionary { }), _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); } @@ -163,7 +162,7 @@ public class AuthorizeTests [Trait("Category", Category)] public async Task get_request_should_not_return_500() { - var response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.AuthorizeEndpoint); + var response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.AuthorizeEndpoint, _ct); ((int)response.StatusCode).ShouldBeLessThan(500); } @@ -179,7 +178,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); } @@ -215,7 +214,7 @@ public class AuthorizeTests ui_locales = "ui_locale_value", custom_foo = "foo_value" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url + "&foo=foo1&foo=foo2"); + var response = await _mockPipeline.BrowserClient.GetAsync(url + "&foo=foo1&foo=foo2", _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); _mockPipeline.LoginRequest.Client.ClientId.ShouldBe("client1"); @@ -243,7 +242,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client1/callback"); @@ -269,7 +268,7 @@ public class AuthorizeTests redirectUri: "https://client4/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client4/callback"); @@ -299,7 +298,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client1/callback"); @@ -330,7 +329,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client1/callback"); @@ -373,7 +372,7 @@ public class AuthorizeTests redirectUri: "https://client2/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client2/callback"); @@ -398,7 +397,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce", acrValues: "idp:google"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); _mockPipeline.LoginRequest.IdP.ShouldBe("google"); @@ -416,7 +415,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce", acrValues: "idp:facebook"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); _mockPipeline.LoginRequest.IdP.ShouldBeNull(); @@ -435,7 +434,7 @@ public class AuthorizeTests redirectUri: "https://client3/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); _mockPipeline.LoginRequest.IdP.ShouldBeNull(); @@ -456,7 +455,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce", acrValues: "idp:idp2"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); _mockPipeline.LoginRequest.IdP.ShouldBe("idp2"); @@ -479,7 +478,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce", acrValues: "tenant:t2"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); _mockPipeline.LoginRequest.Tenant.ShouldBe("t2"); @@ -501,7 +500,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce", acrValues: "tenant:t2"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeFalse(); } @@ -519,7 +518,7 @@ public class AuthorizeTests redirectUri: "https://invalid", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.ClientId.ShouldBeNull(); @@ -538,7 +537,7 @@ public class AuthorizeTests redirectUri: "https://invalid", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.ClientId.ShouldBe("client1"); @@ -557,7 +556,7 @@ public class AuthorizeTests redirectUri: "https://invalid", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -577,7 +576,7 @@ public class AuthorizeTests redirectUri: "https://invalid", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.RedirectUri.ShouldBeNull(); @@ -597,7 +596,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.UnauthorizedClient); @@ -616,7 +615,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.RedirectUri.ShouldBeNull(); @@ -636,7 +635,7 @@ public class AuthorizeTests //redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.UnauthorizedClient); @@ -656,7 +655,7 @@ public class AuthorizeTests //redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.RedirectUri.ShouldBeNull(); @@ -676,7 +675,7 @@ public class AuthorizeTests redirectUri: "invalid-uri", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.UnauthorizedClient); @@ -698,7 +697,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.UnauthorizedClient); @@ -719,7 +718,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.RedirectUri.ShouldBeNull(); @@ -741,7 +740,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.UnauthorizedClient); @@ -763,7 +762,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.RedirectUri.ShouldBeNull(); @@ -783,7 +782,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.UnsupportedResponseType); @@ -802,7 +801,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.RedirectUri.ShouldBeNull(); @@ -823,7 +822,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -844,7 +843,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.RedirectUri.ShouldBeNull(); @@ -865,7 +864,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.UnsupportedResponseType); @@ -886,7 +885,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.RedirectUri.ShouldBeNull(); @@ -906,7 +905,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -926,7 +925,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.RedirectUri.ShouldBeNull(); @@ -947,7 +946,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.RedirectUri.ShouldBeNull(); @@ -967,7 +966,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -989,7 +988,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -1012,7 +1011,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidScope); @@ -1035,7 +1034,7 @@ public class AuthorizeTests state: "123_state" //nonce: "123_nonce" ); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -1057,7 +1056,7 @@ public class AuthorizeTests redirectUri: "https://client1/callback", state: "123_state", nonce: new string('x', 500)); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -1080,7 +1079,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce", extra: new { ui_locales = new string('x', 500) }); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -1103,7 +1102,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce", extra: new { max_age = "invalid" }); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -1126,7 +1125,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce", extra: new { max_age = "-10" }); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -1149,7 +1148,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce", loginHint: new string('x', 500)); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -1172,7 +1171,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce", acrValues: new string('x', 500)); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -1200,7 +1199,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce"); - Func a = () => _mockPipeline.BrowserClient.GetAsync(url); + Func a = () => _mockPipeline.BrowserClient.GetAsync(url, _ct); await a.ShouldThrowAsync(); } @@ -1219,7 +1218,7 @@ public class AuthorizeTests nonce: "123_nonce", acrValues: new string('x', 500), extra: new { ui_locales = "fr-FR" }); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.UiLocales.ShouldBe("fr-FR"); @@ -1240,7 +1239,7 @@ public class AuthorizeTests nonce: "123_nonce", acrValues: new string('x', 500), extra: new { display = "popup" }); - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.DisplayMode.ShouldBe("popup"); @@ -1259,7 +1258,7 @@ public class AuthorizeTests nonce: "123_nonce"); url = url.Replace(IdentityServerPipeline.BaseUrl, "https://грант.рф"); - var result = await _mockPipeline.BackChannelClient.GetAsync(url); + var result = await _mockPipeline.BackChannelClient.GetAsync(url, _ct); result.Headers.Location.Authority.ShouldBe("xn--80af5akm.xn--p1ai"); } @@ -1276,7 +1275,7 @@ public class AuthorizeTests state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); } @@ -1295,7 +1294,7 @@ public class AuthorizeTests nonce: "123_nonce", extra: new { prompt = "login" } ); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); _mockPipeline.LoginRequest.PromptModes.ShouldContain("login"); @@ -1316,7 +1315,7 @@ public class AuthorizeTests nonce: "123_nonce", extra: new { max_age = "0" } ); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); } @@ -1337,11 +1336,11 @@ public class AuthorizeTests extra: new { prompt = "login" } ); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); // this simulates the login page returning to the returnUrl which is the authorize callback page _mockPipeline.BrowserClient.AllowAutoRedirect = false; - response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.BaseUrl + _mockPipeline.LoginReturnUrl); + response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.BaseUrl + _mockPipeline.LoginReturnUrl, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client1/callback"); response.Headers.Location.ToString().ShouldContain("id_token="); @@ -1363,11 +1362,11 @@ public class AuthorizeTests extra: new { max_age = "0" } ); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); // this simulates the login page returning to the returnUrl which is the authorize callback page _mockPipeline.BrowserClient.AllowAutoRedirect = false; - response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.BaseUrl + _mockPipeline.LoginReturnUrl); + response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.BaseUrl + _mockPipeline.LoginReturnUrl, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client1/callback"); response.Headers.Location.ToString().ShouldContain("id_token="); @@ -1386,7 +1385,7 @@ public class AuthorizeTests nonce: "123_nonce", extra: new { prompt = "unknown" } ); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); } @@ -1404,7 +1403,7 @@ public class AuthorizeTests nonce: "123_nonce", extra: new { prompt = "create" } ); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); } @@ -1433,7 +1432,7 @@ public class AuthorizeTests nonce: "123_nonce", extra: new { prompt = "create" } ); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.CreateAccountWasCalled.ShouldBeTrue(); _mockPipeline.CreateAccountRequest.PromptModes.ShouldContain("create"); @@ -1463,7 +1462,7 @@ public class AuthorizeTests nonce: "123_nonce", extra: new { prompt = "create login" } ); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); } @@ -1512,7 +1511,7 @@ public class AuthorizeTests ui_locales = "ui_locale_value", custom_foo = "foo_value" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url + "&foo=bar"); + var response = await _mockPipeline.BrowserClient.GetAsync(url + "&foo=bar", _ct); _mockPipeline.CustomWasCalled.ShouldBeTrue(); @@ -1546,7 +1545,7 @@ public class AuthorizeTests _mockPipeline.BrowserClient.AllowAutoRedirect = false; - Func a = () => _mockPipeline.BrowserClient.GetAsync(url); + Func a = () => _mockPipeline.BrowserClient.GetAsync(url, _ct); await a.ShouldThrowAsync(); } @@ -1577,7 +1576,7 @@ public class AuthorizeTests _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.Headers.Location.GetLeftPart(UriPartial.Path).ShouldBe("https://server/custom"); mockAuthzInteractionService.Request.PromptModes.ShouldContain("custom-prompt"); mockAuthzInteractionService.Request.PromptModes.Count().ShouldBe(1); @@ -1599,7 +1598,7 @@ public class AuthorizeTests ui_locales = "nb-NO" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); @@ -1626,7 +1625,7 @@ public class AuthorizeTests ui_locales = "nb-NO" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ConsentWasCalled.ShouldBeTrue(); @@ -1663,7 +1662,7 @@ public class AuthorizeTests ui_locales = "nb-NO" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.CreateAccountWasCalled.ShouldBeTrue(); @@ -1687,7 +1686,7 @@ public class AuthorizeTests ui_locales = "nb-NO" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ConsentTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ConsentTests.cs index 0bfa618b7..abf802b4f 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ConsentTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ConsentTests.cs @@ -19,6 +19,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Authorize; public class ConsentTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Authorize and consent tests"; private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); @@ -110,7 +111,7 @@ public class ConsentTests state: "123_state", nonce: "123_nonce" ); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ConsentWasCalled.ShouldBeTrue(); } @@ -149,7 +150,7 @@ public class ConsentTests custom_foo = "foo_value" } ); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ConsentRequest.ShouldNotBeNull(); _mockPipeline.ConsentRequest.Client.ClientId.ShouldBe("client2"); @@ -193,7 +194,7 @@ public class ConsentTests redirectUri: "https://client2/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client2/callback"); @@ -225,12 +226,12 @@ public class ConsentTests redirectUri: "https://client2/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://server/consent"); - response = await _mockPipeline.BrowserClient.GetAsync(response.Headers.Location.ToString()); + response = await _mockPipeline.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("/connect/authorize/callback"); @@ -238,7 +239,7 @@ public class ConsentTests var modifiedAuthorizeCallback = "https://server" + response.Headers.Location; modifiedAuthorizeCallback = modifiedAuthorizeCallback.Replace("api2", "api1%20api2"); - response = await _mockPipeline.BrowserClient.GetAsync(modifiedAuthorizeCallback); + response = await _mockPipeline.BrowserClient.GetAsync(modifiedAuthorizeCallback, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://server/consent"); } @@ -262,7 +263,7 @@ public class ConsentTests redirectUri: "https://client2/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client2/callback"); @@ -304,7 +305,7 @@ public class ConsentTests redirectUri: "https://client2/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client2/callback"); @@ -347,7 +348,7 @@ public class ConsentTests redirectUri: "https://client2/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://client2/callback"); @@ -407,7 +408,7 @@ public class ConsentTests nonce: "123_nonce" ); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); // The existing legacy consent should apply - user isn't show consent screen response.StatusCode.ShouldBe(HttpStatusCode.Redirect); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/JwtRequestAuthorizeTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/JwtRequestAuthorizeTests.cs index 82dcd7ffe..fff10d29e 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/JwtRequestAuthorizeTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/JwtRequestAuthorizeTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. - using System.IdentityModel.Tokens.Jwt; using System.Net; using System.Net.Http.Headers; @@ -24,7 +23,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Authorize; public class JwtRequestAuthorizeTests { private const string Category = "Authorize endpoint with JWT requests"; - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); private readonly Client _client; @@ -209,7 +208,7 @@ public class JwtRequestAuthorizeTests nonce: "123nonce", redirectUri: "https://client/callback"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request"); _mockPipeline.ErrorMessage.ErrorDescription.ShouldBe("Client must use request object, but no request or request_uri parameter present"); @@ -245,7 +244,7 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); _mockPipeline.LoginRequest.Client.ClientId.ShouldBe(_client.ClientId); @@ -293,7 +292,7 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); _mockPipeline.LoginRequest.Client.ClientId.ShouldBe(_client.ClientId); @@ -340,7 +339,7 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); _mockPipeline.LoginRequest.Client.ClientId.ShouldBe(_client.ClientId); @@ -393,7 +392,7 @@ public class JwtRequestAuthorizeTests var url = _mockPipeline.CreateAuthorizeUrl( clientId: _client.ClientId, requestUri: parResponse.RootElement.GetProperty("request_uri").GetString()); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); _mockPipeline.LoginRequest.Client.ClientId.ShouldBe(_client.ClientId); @@ -452,7 +451,7 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); _mockPipeline.LoginRequest.Client.ClientId.ShouldBe(_client.ClientId); @@ -505,7 +504,7 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); _mockPipeline.LoginRequest.Client.ClientId.ShouldBe(_client.ClientId); @@ -554,7 +553,7 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request_object"); _mockPipeline.LoginRequest.ShouldBeNull(); @@ -597,7 +596,7 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); @@ -646,7 +645,7 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request"); _mockPipeline.ErrorMessage.ErrorDescription.ShouldBe("Invalid client_id"); @@ -681,7 +680,7 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request_object"); _mockPipeline.ErrorMessage.ErrorDescription.ShouldBe("Invalid JWT request"); @@ -718,7 +717,7 @@ public class JwtRequestAuthorizeTests request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request_object"); _mockPipeline.ErrorMessage.ErrorDescription.ShouldBe("Invalid JWT request"); @@ -755,7 +754,7 @@ public class JwtRequestAuthorizeTests request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request_object"); _mockPipeline.ErrorMessage.ErrorDescription.ShouldBe("Invalid JWT request"); @@ -792,7 +791,7 @@ public class JwtRequestAuthorizeTests request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request_object"); _mockPipeline.ErrorMessage.ErrorDescription.ShouldBe("Invalid JWT request"); @@ -829,7 +828,7 @@ public class JwtRequestAuthorizeTests request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request_object"); _mockPipeline.ErrorMessage.ErrorDescription.ShouldBe("Invalid JWT request"); @@ -865,7 +864,7 @@ public class JwtRequestAuthorizeTests request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request"); _mockPipeline.ErrorMessage.ErrorDescription.ShouldBe("Invalid JWT request"); @@ -902,7 +901,7 @@ public class JwtRequestAuthorizeTests request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request"); _mockPipeline.ErrorMessage.ErrorDescription.ShouldBe("Invalid JWT request"); @@ -939,7 +938,7 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - _ = await _mockPipeline.BrowserClient.GetAsync(url); + _ = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request_object"); _mockPipeline.ErrorMessage.ErrorDescription.ShouldBe("Invalid JWT request"); @@ -984,7 +983,7 @@ public class JwtRequestAuthorizeTests { request_uri = "http://client_jwt" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.JwtRequestMessageHandler.InvokeWasCalled.ShouldBeFalse(); @@ -1030,7 +1029,7 @@ public class JwtRequestAuthorizeTests { request_uri = "http://client_jwt" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); _mockPipeline.LoginRequest.Client.ClientId.ShouldBe(_client.ClientId); @@ -1099,7 +1098,7 @@ public class JwtRequestAuthorizeTests { request_uri = "http://client_jwt" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); _mockPipeline.LoginRequest.Client.ClientId.ShouldBe(_client.ClientId); @@ -1160,7 +1159,7 @@ public class JwtRequestAuthorizeTests { request_uri = "http://client_jwt" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginRequest.ShouldNotBeNull(); _mockPipeline.LoginRequest.Client.ClientId.ShouldBe(_client.ClientId); @@ -1215,7 +1214,7 @@ public class JwtRequestAuthorizeTests { request_uri = "http://client_jwt" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_request_uri"); _mockPipeline.LoginRequest.ShouldBeNull(); @@ -1237,7 +1236,7 @@ public class JwtRequestAuthorizeTests { request_uri = "http://client_jwt" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.LoginRequest.ShouldBeNull(); @@ -1260,7 +1259,7 @@ public class JwtRequestAuthorizeTests { request_uri = "http://client_jwt" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.LoginRequest.ShouldBeNull(); @@ -1281,7 +1280,7 @@ public class JwtRequestAuthorizeTests { request_uri = "http://" + new string('x', 512) }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.LoginRequest.ShouldBeNull(); @@ -1322,7 +1321,7 @@ public class JwtRequestAuthorizeTests request = requestJwt, request_uri = "http://client_jwt" }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.LoginRequest.ShouldBeNull(); @@ -1368,11 +1367,11 @@ public class JwtRequestAuthorizeTests { request = requestJwt }); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); // this simulates the login page returning to the returnUrl which is the authorize callback page _mockPipeline.BrowserClient.AllowAutoRedirect = false; - response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.BaseUrl + _mockPipeline.LoginReturnUrl); + response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.BaseUrl + _mockPipeline.LoginReturnUrl, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found); response.Headers.Location!.ToString().ShouldSatisfyAllConditions( @@ -1428,7 +1427,7 @@ public class JwtRequestAuthorizeTests }; _mockPipeline.BrowserClient.StopRedirectingAfter = 2; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/PushedAuthorizationTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/PushedAuthorizationTests.cs index 30348e370..3a8431898 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/PushedAuthorizationTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/PushedAuthorizationTests.cs @@ -18,9 +18,10 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Authorize; public class PushedAuthorizationTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly IdentityServerPipeline _mockPipeline = new(); private Client _client; - private string clientSecret = Guid.NewGuid().ToString(); + private readonly string clientSecret = Guid.NewGuid().ToString(); private Client _client2; private WilsonJsonWebKey _privateKey; @@ -58,7 +59,7 @@ public class PushedAuthorizationTests var authorizeUrl = _mockPipeline.CreateAuthorizeUrl( clientId: "client1", requestUri: parJson.RootElement.GetProperty("request_uri").GetString()); - var response = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl); + var response = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found); response.Headers.Location!.AbsoluteUri.ShouldMatch($"{expectedCallback}.*"); @@ -89,7 +90,7 @@ public class PushedAuthorizationTests var authorizeUrl = _mockPipeline.CreateAuthorizeUrl( clientId: "client2", requestUri: parJson.RootElement.GetProperty("request_uri").GetString()); - var response = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl); + var response = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found); response.Headers.Location!.AbsoluteUri.ShouldMatch($"{expectedCallback}.*"); @@ -141,7 +142,7 @@ public class PushedAuthorizationTests redirectUri: "https://client1/callback", nonce: "123_nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); // We expect to be redirected to the error page, as this is an interactive // call to authorize @@ -163,7 +164,7 @@ public class PushedAuthorizationTests redirectUri: "https://client1/callback", nonce: "123_nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); // We expect to be redirected to the error page, as this is an interactive // call to authorize @@ -191,7 +192,7 @@ public class PushedAuthorizationTests // call to authorize. We don't want to follow redirects. Instead we'll just // check for a 302 to the error page _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var authorizeResponse = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl); + var authorizeResponse = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl, _ct); authorizeResponse.StatusCode.ShouldBe(HttpStatusCode.Found); authorizeResponse.Headers.Location!.ToString().ShouldMatch(".*/error.*"); @@ -213,8 +214,8 @@ public class PushedAuthorizationTests requestUri: parJson.RootElement.GetProperty("request_uri").GetString()); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var firstAuthorizeResponse = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl); - var secondAuthorizeResponse = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl); + var firstAuthorizeResponse = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl, _ct); + var secondAuthorizeResponse = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl, _ct); secondAuthorizeResponse.StatusCode.ShouldBe(HttpStatusCode.Found); secondAuthorizeResponse.Headers.Location!.ToString().ShouldMatch(".*/error.*"); @@ -268,7 +269,7 @@ public class PushedAuthorizationTests var authorizeUrl = _mockPipeline.CreateAuthorizeUrl( clientId: "client1", requestUri: parJson.RootElement.GetProperty("request_uri").GetString()); - var authorizeResponse = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl); + var authorizeResponse = await _mockPipeline.BrowserClient.GetAsync(authorizeUrl, _ct); // Verify that authorize redirects to login authorizeResponse.StatusCode.ShouldBe(HttpStatusCode.Found); @@ -277,14 +278,14 @@ public class PushedAuthorizationTests authorizeResponse.Headers.Location.ToString().ToLower().ShouldMatch($"{expectedLocation.ToLower()}*"); // Verify that the UI prompts the user at this point - var uiResponse = await _mockPipeline.BrowserClient.GetAsync(authorizeResponse.Headers.Location); + var uiResponse = await _mockPipeline.BrowserClient.GetAsync(authorizeResponse.Headers.Location, _ct); uiResponse.StatusCode.ShouldBe(HttpStatusCode.OK); // Now login and return to the return url we were given var returnPath = isPromptCreate ? _mockPipeline.CreateAccountReturnUrl : _mockPipeline.LoginReturnUrl; var returnUrl = new Uri(new Uri(IdentityServerPipeline.BaseUrl), returnPath); await _mockPipeline.LoginAsync("bob"); - var authorizeCallbackResponse = await _mockPipeline.BrowserClient.GetAsync(returnUrl); + var authorizeCallbackResponse = await _mockPipeline.BrowserClient.GetAsync(returnUrl, _ct); // The authorize callback should continue back to the application (the prompt parameter is processed so we don't go back to the UI) authorizeCallbackResponse.StatusCode.ShouldBe(HttpStatusCode.Found); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ResourceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ResourceTests.cs index 79bd474d7..25ac36faf 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ResourceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ResourceTests.cs @@ -14,6 +14,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Authorize; public class ResourceTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Authorize endpoint"; private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); @@ -151,7 +152,7 @@ public class ResourceTests url += "&resource=urn:resource1"; url += "&resource=urn:resource3"; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var code = GetCode(response); var tokenResponse = await _mockPipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest @@ -161,7 +162,7 @@ public class ResourceTests ClientSecret = "secret", Code = code, RedirectUri = "https://client1/callback" - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -186,7 +187,7 @@ public class ResourceTests url += "&resource= "; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var code = GetCode(response); var tokenResponse = await _mockPipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest @@ -200,7 +201,7 @@ public class ResourceTests { { "resource", " " } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -226,7 +227,7 @@ public class ResourceTests url += "&resource=urn:resource1"; url += "&resource=urn:resource3"; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var code = GetCode(response); var tokenResponse = await _mockPipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest @@ -240,7 +241,7 @@ public class ResourceTests { { "resource", " " } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -266,7 +267,7 @@ public class ResourceTests url += "&resource=urn:resource1"; url += "&resource=urn:resource3"; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var code = GetCode(response); var tokenResponse = await _mockPipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest @@ -280,7 +281,7 @@ public class ResourceTests { { "resource", "urn:resource1" } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -306,7 +307,7 @@ public class ResourceTests url += "&resource=urn:resource1"; url += "&resource=urn:resource3"; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var code = GetCode(response); var tokenResponse = await _mockPipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest @@ -316,7 +317,7 @@ public class ResourceTests ClientSecret = "secret", Code = code, RedirectUri = "https://client1/callback" - }); + }, _ct); tokenResponse = await _mockPipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { @@ -328,7 +329,7 @@ public class ResourceTests { { "resource", "urn:resource1" } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -354,7 +355,7 @@ public class ResourceTests url += "&resource=urn:resource1"; url += "&resource=urn:resource3"; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var code = GetCode(response); var tokenResponse = await _mockPipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest @@ -364,7 +365,7 @@ public class ResourceTests ClientSecret = "secret", Code = code, RedirectUri = "https://client1/callback" - }); + }, _ct); tokenResponse = await _mockPipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { @@ -372,7 +373,7 @@ public class ResourceTests ClientId = "client1", ClientSecret = "secret", RefreshToken = tokenResponse.RefreshToken, - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -397,7 +398,7 @@ public class ResourceTests url += "&resource=urn:resource1"; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var code = GetCode(response); var tokenResponse = await _mockPipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest @@ -411,7 +412,7 @@ public class ResourceTests { { "resource", "urn:resource1" } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -436,7 +437,7 @@ public class ResourceTests url += "&resource=urn:resource1"; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var code = GetCode(response); var tokenResponse = await _mockPipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest @@ -450,7 +451,7 @@ public class ResourceTests { // no resource param } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -475,7 +476,7 @@ public class ResourceTests url += "&resource=urn:resource3"; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var code = GetCode(response); var tokenResponse = await _mockPipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest @@ -489,7 +490,7 @@ public class ResourceTests { // no resource param } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -507,7 +508,7 @@ public class ResourceTests { { "resource", "urn:resource3" } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -532,7 +533,7 @@ public class ResourceTests url += "&resource=urn:resource3"; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var code = GetCode(response); var tokenResponse = await _mockPipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest @@ -546,7 +547,7 @@ public class ResourceTests { { "resource", "urn:resource3" } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -571,7 +572,7 @@ public class ResourceTests url += "&resource=urn:resource1"; url += "&resource=urn:resource3"; - await _mockPipeline.BrowserClient.GetAsync(url); + await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); _mockPipeline.ErrorMessage.Error.ShouldBe("invalid_target"); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/RestrictAccessTokenViaBrowserTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/RestrictAccessTokenViaBrowserTests.cs index 22657a810..4b1c3ade1 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/RestrictAccessTokenViaBrowserTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/RestrictAccessTokenViaBrowserTests.cs @@ -13,10 +13,9 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Authorize; public class RestrictAccessTokenViaBrowserTests { private const string Category = "RestrictAccessTokenViaBrowserTests"; - - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); - - private ClaimsPrincipal _user = new IdentityServerUser("bob").CreatePrincipal(); + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); + private readonly ClaimsPrincipal _user = new IdentityServerUser("bob").CreatePrincipal(); public RestrictAccessTokenViaBrowserTests() { @@ -92,7 +91,7 @@ public class RestrictAccessTokenViaBrowserTests "id_token", "openid", "https://client1/callback", "state", "nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found); response.Headers.Location.AbsoluteUri.ShouldStartWith("https://client1/callback"); @@ -111,7 +110,7 @@ public class RestrictAccessTokenViaBrowserTests "id_token token", "openid", "https://client1/callback", "state", "nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found); response.Headers.Location.AbsoluteUri.ShouldStartWith("https://client1/callback"); @@ -130,7 +129,7 @@ public class RestrictAccessTokenViaBrowserTests "id_token", "openid", "https://client2/callback", "state", "nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found); response.Headers.Location.AbsoluteUri.ShouldStartWith("https://client2/callback"); @@ -149,7 +148,7 @@ public class RestrictAccessTokenViaBrowserTests "id_token token", "openid", "https://client2/callback", "state", "nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = true; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); } @@ -163,7 +162,7 @@ public class RestrictAccessTokenViaBrowserTests "code id_token", "openid", "https://client3/callback", "state", "nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found); response.Headers.Location.AbsoluteUri.ShouldStartWith("https://client3/callback"); @@ -183,7 +182,7 @@ public class RestrictAccessTokenViaBrowserTests "code id_token token", "openid", "https://client3/callback", "state", "nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found); response.Headers.Location.AbsoluteUri.ShouldStartWith("https://client3/callback"); @@ -204,7 +203,7 @@ public class RestrictAccessTokenViaBrowserTests "code id_token", "openid", "https://client4/callback", "state", "nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Found); response.Headers.Location.AbsoluteUri.ShouldStartWith("https://client4/callback"); @@ -224,7 +223,7 @@ public class RestrictAccessTokenViaBrowserTests "code id_token token", "openid", "https://client4/callback", "state", "nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = true; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.ErrorWasCalled.ShouldBeTrue(); } } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/SessionIdTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/SessionIdTests.cs index 115415438..7e4e332ac 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/SessionIdTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/SessionIdTests.cs @@ -12,8 +12,8 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Authorize; public class SessionIdTests { private const string Category = "SessionIdTests"; - - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); public SessionIdTests() { @@ -84,7 +84,7 @@ public class SessionIdTests _mockPipeline.RemoveSessionCookie(); - await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.DiscoveryEndpoint); + await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.DiscoveryEndpoint, _ct); var sid2 = _mockPipeline.GetSessionCookie().Value; sid2.ShouldBe(sid1); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/CheckSession/CheckSessionTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/CheckSession/CheckSessionTests.cs index 7d851901e..8184530bf 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/CheckSession/CheckSessionTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/CheckSession/CheckSessionTests.cs @@ -9,17 +9,17 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.CheckSession; public class CheckSessionTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); private const string Category = "Check session endpoint"; - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); - public CheckSessionTests() => _mockPipeline.Initialize(); [Fact] [Trait("Category", Category)] public async Task get_request_should_not_return_404() { - var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.CheckSessionEndpoint); + var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.CheckSessionEndpoint, _ct); response.StatusCode.ShouldNotBe(HttpStatusCode.NotFound); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Ciba/CibaTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Ciba/CibaTests.cs index 557909451..cb6914ec2 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Ciba/CibaTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Ciba/CibaTests.cs @@ -19,6 +19,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Ciba; public class CibaTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Backchannel Authentication (CIBA) endpoint"; private IdentityServerPipeline _mockPipeline = new(); @@ -158,7 +159,7 @@ public class CibaTests [Trait("Category", Category)] public async Task get_request_should_return_error() { - var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.BackchannelAuthenticationEndpoint); + var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.BackchannelAuthenticationEndpoint, _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); } @@ -169,7 +170,8 @@ public class CibaTests { var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new StringContent("invalid")); + new StringContent("invalid"), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); } @@ -193,7 +195,8 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -233,7 +236,8 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); // The custom validator was invoked with the request parameters and mapped the custom input var validatedRequest = _mockCustomBackchannelAuthenticationValidator.Context.ValidationResult.ValidatedRequest; @@ -272,11 +276,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); // Custom request properties are not included automatically in the response to the client response.StatusCode.ShouldBe(HttpStatusCode.OK); - var responseContent = await response.Content.ReadAsStringAsync(); + var responseContent = await response.Content.ReadAsStringAsync(_ct); var json = JsonSerializer.Deserialize>(responseContent); json.ShouldNotBeNull(); json.ShouldNotContainKey("complex"); @@ -306,11 +311,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("auth_req_id").ShouldBeTrue(); @@ -341,11 +347,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("auth_req_id").ShouldBeTrue(); @@ -373,11 +380,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -407,11 +415,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -441,11 +450,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -474,11 +484,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -509,11 +520,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -544,11 +556,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -581,11 +594,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -619,11 +633,11 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -654,11 +668,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -689,11 +704,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -724,7 +740,8 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); } @@ -749,7 +766,8 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -780,11 +798,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -811,11 +830,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -846,11 +866,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(code); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -875,11 +896,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -906,11 +928,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -934,11 +957,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -964,11 +988,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -993,11 +1018,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1023,11 +1049,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1053,11 +1080,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1083,11 +1111,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1118,11 +1147,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1148,11 +1178,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1180,11 +1211,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1212,7 +1244,8 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); } @@ -1236,11 +1269,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1268,7 +1302,8 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -1295,11 +1330,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1321,11 +1357,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1347,11 +1384,11 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1376,11 +1413,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1405,11 +1443,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1434,11 +1473,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1463,11 +1503,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1492,11 +1533,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1529,7 +1571,8 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -1556,7 +1599,8 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -1583,11 +1627,12 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -1612,15 +1657,15 @@ public class CibaTests var response = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(body)); + new FormUrlEncodedContent(body), + _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); values["error"].ToString().ShouldBe("invalid_binding_message"); } - } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/DeviceAuthorization/DeviceAuthorizationTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/DeviceAuthorization/DeviceAuthorizationTests.cs index 18326d9d2..4a52c9aff 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/DeviceAuthorization/DeviceAuthorizationTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/DeviceAuthorization/DeviceAuthorizationTests.cs @@ -13,6 +13,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.DeviceAuthorization; public class DeviceAuthorizationTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Device authorization endpoint"; private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); @@ -38,10 +39,10 @@ public class DeviceAuthorizationTests [Trait("Category", Category)] public async Task get_should_return_InvalidRequest() { - var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.DeviceAuthorization); + var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.DeviceAuthorization, _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var resultDto = ParseJsonBody(await response.Content.ReadAsStreamAsync()); + var resultDto = ParseJsonBody(await response.Content.ReadAsStreamAsync(_ct)); resultDto.ShouldNotBeNull(); resultDto.error.ShouldBe(OidcConstants.TokenErrors.InvalidRequest); @@ -56,11 +57,11 @@ public class DeviceAuthorizationTests {"client_id", Guid.NewGuid().ToString()} }; var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.DeviceAuthorization, - new StringContent(@"{""client_id"": ""client1""}", Encoding.UTF8, "application/json")); + new StringContent(@"{""client_id"": ""client1""}", Encoding.UTF8, "application/json"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var resultDto = ParseJsonBody(await response.Content.ReadAsStreamAsync()); + var resultDto = ParseJsonBody(await response.Content.ReadAsStreamAsync(_ct)); resultDto.ShouldNotBeNull(); resultDto.error.ShouldBe(OidcConstants.TokenErrors.InvalidRequest); @@ -71,11 +72,11 @@ public class DeviceAuthorizationTests public async Task empty_request_should_return_InvalidRequest() { var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.DeviceAuthorization, - new FormUrlEncodedContent(new Dictionary())); + new FormUrlEncodedContent(new Dictionary()), _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var resultDto = ParseJsonBody(await response.Content.ReadAsStreamAsync()); + var resultDto = ParseJsonBody(await response.Content.ReadAsStreamAsync(_ct)); resultDto.ShouldNotBeNull(); resultDto.error.ShouldBe(OidcConstants.TokenErrors.InvalidRequest); @@ -89,11 +90,11 @@ public class DeviceAuthorizationTests { {"client_id", "client1"} }; - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.DeviceAuthorization, new FormUrlEncodedContent(form)); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.DeviceAuthorization, new FormUrlEncodedContent(form), _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var resultDto = ParseJsonBody(await response.Content.ReadAsStreamAsync()); + var resultDto = ParseJsonBody(await response.Content.ReadAsStreamAsync(_ct)); resultDto.ShouldNotBeNull(); resultDto.error.ShouldBe(OidcConstants.TokenErrors.InvalidClient); @@ -108,12 +109,12 @@ public class DeviceAuthorizationTests {"client_id", "client1"}, {"client_secret", "secret" } }; - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.DeviceAuthorization, new FormUrlEncodedContent(form)); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.DeviceAuthorization, new FormUrlEncodedContent(form), _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); response.Content.Headers.ContentType.MediaType.ShouldBe("application/json"); - var resultDto = ParseJsonBody(await response.Content.ReadAsStreamAsync()); + var resultDto = ParseJsonBody(await response.Content.ReadAsStreamAsync(_ct)); resultDto.ShouldNotBeNull(); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs index 4b7935de0..ac6c8069b 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs @@ -18,6 +18,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; public class DiscoveryEndpointTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Discovery endpoint"; [Fact] @@ -27,9 +28,9 @@ public class DiscoveryEndpointTests var pipeline = new IdentityServerPipeline(); pipeline.Initialize("/ROOT"); - var result = await pipeline.BackChannelClient.GetAsync("HTTPS://SERVER/ROOT/.WELL-KNOWN/OPENID-CONFIGURATION"); + var result = await pipeline.BackChannelClient.GetAsync("HTTPS://SERVER/ROOT/.WELL-KNOWN/OPENID-CONFIGURATION", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data["issuer"].GetString().ShouldBe("https://server/root"); } @@ -43,9 +44,9 @@ public class DiscoveryEndpointTests pipeline.Options.LowerCaseIssuerUri = false; - var result = await pipeline.BackChannelClient.GetAsync("HTTPS://SERVER/ROOT/.WELL-KNOWN/OPENID-CONFIGURATION"); + var result = await pipeline.BackChannelClient.GetAsync("HTTPS://SERVER/ROOT/.WELL-KNOWN/OPENID-CONFIGURATION", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data["issuer"].GetString().ShouldBe("https://server/ROOT"); } @@ -68,7 +69,7 @@ public class DiscoveryEndpointTests }; pipeline.Initialize(); - var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration", _ct); var algorithmsSupported = result.TryGetStringArray("id_token_signing_alg_values_supported"); @@ -110,9 +111,9 @@ public class DiscoveryEndpointTests pipeline.Initialize("/ROOT"); - var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration/jwks"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration/jwks", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); var keys = data["keys"].EnumerateArray().ToList(); @@ -130,9 +131,9 @@ public class DiscoveryEndpointTests var pipeline = new IdentityServerPipeline(); pipeline.Initialize("/ROOT"); - var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration/jwks"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration/jwks", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); var keys = data["keys"]; @@ -159,9 +160,9 @@ public class DiscoveryEndpointTests }; pipeline.Initialize("/ROOT"); - var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration/jwks"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration/jwks", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var jwks = new JsonWebKeySet(json); var parsedKeys = jwks.GetSigningKeys(); @@ -185,9 +186,9 @@ public class DiscoveryEndpointTests }; pipeline.Initialize("/ROOT"); - var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration/jwks"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration/jwks", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var jwks = new JsonWebKeySet(json); jwks.Keys.ShouldContain(x => x.KeyId == ecdsaKey.KeyId && x.Alg == "ES256"); @@ -211,7 +212,7 @@ public class DiscoveryEndpointTests RequireHttps = false, RequireKeySet = false } - }); + }, _ct); result.Issuer.ShouldBe("https://грант.рф"); } @@ -224,9 +225,9 @@ public class DiscoveryEndpointTests var pipeline = new IdentityServerPipeline(); pipeline.Initialize(); - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/openid-configuration", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); var prompts = data["prompt_values_supported"].EnumerateArray() .Select(x => x.GetString()).ToList(); @@ -248,9 +249,9 @@ public class DiscoveryEndpointTests pipeline.Initialize(); - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/openid-configuration", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); var prompts = data["prompt_values_supported"].EnumerateArray() .Select(x => x.GetString()).ToList(); @@ -265,9 +266,9 @@ public class DiscoveryEndpointTests pipeline.Initialize(); pipeline.Options.Endpoints.EnableAuthorizeEndpoint = false; - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/openid-configuration", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data.ContainsKey("prompt_values_supported").ShouldBeFalse(); } @@ -284,7 +285,7 @@ public class DiscoveryEndpointTests pipeline.Options.Preview.DiscoveryDocumentCacheDuration = TimeSpan.FromSeconds(1); // cache - _ = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration"); + _ = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration", _ct); // add new entry pipeline.Options.Discovery.CustomEntries = new() { @@ -292,9 +293,9 @@ public class DiscoveryEndpointTests }; // get cached document - var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/root/.well-known/openid-configuration", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); // we got a result back @@ -332,7 +333,7 @@ public class DiscoveryEndpointTests pipeline.Options.Preview.EnableDiscoveryDocumentCache = enableCache; pipeline.Options.Discovery.CustomEntries.Add("foo", "bar"); - var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration", _ct); result.TryGetString("foo").ShouldBe("bar"); } @@ -351,7 +352,7 @@ public class DiscoveryEndpointTests pipeline.Initialize(); pipeline.Options.Preview.EnableDiscoveryDocumentCache = enableCache; - var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration", _ct); if (enableCache) { @@ -373,7 +374,7 @@ public class DiscoveryEndpointTests pipeline.Options.MutualTls.Enabled = true; - var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration", _ct); result.MtlsEndpointAliases.PushedAuthorizationRequestEndpoint.ShouldNotBeNull(); } } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_dpop_signing_algs_supported.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_dpop_signing_algs_supported.cs index 50c79d457..ba0a573a6 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_dpop_signing_algs_supported.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_dpop_signing_algs_supported.cs @@ -12,6 +12,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; public class DiscoveryEndpointTests_dpop_signing_alg_values_supported { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Discovery endpoint - dpop_signing_alg_values_supported"; [Fact] @@ -30,7 +31,7 @@ public class DiscoveryEndpointTests_dpop_signing_alg_values_supported var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( - "https://server/.well-known/openid-configuration"); + "https://server/.well-known/openid-configuration", _ct); var supportedAlgorithmsFromResponse = result.TryGetStringArray(OidcConstants.Discovery.DPoPSigningAlgorithmsSupported); @@ -43,9 +44,9 @@ public class DiscoveryEndpointTests_dpop_signing_alg_values_supported var pipeline = new IdentityServerPipeline(); pipeline.Initialize(); - var result = - await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( - "https://server/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( + "https://server/.well-known/openid-configuration", + _ct); var algorithmsSupported = result.TryGetStringArray("dpop_signing_alg_values_supported"); algorithmsSupported.Count().ShouldBe(9); @@ -71,8 +72,8 @@ public class DiscoveryEndpointTests_dpop_signing_alg_values_supported pipeline.Options.DPoP.SupportedDPoPSigningAlgorithms = algorithms; var result = await pipeline.BackChannelClient - .GetAsync("https://server/.well-known/openid-configuration"); - var json = await result.Content.ReadAsStringAsync(); + .GetAsync("https://server/.well-known/openid-configuration", _ct); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data.ShouldNotContainKey(OidcConstants.Discovery.DPoPSigningAlgorithmsSupported); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_signing_algs_supported.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_signing_algs_supported.cs index d844bd205..2b47ff0c2 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_signing_algs_supported.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests_token_endpoint_auth_signing_algs_supported.cs @@ -12,6 +12,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_supported { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Discovery endpoint - token_endpoint_auth_signing_alg_values_supported"; [Fact] @@ -29,7 +30,7 @@ public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_suppo ]; var disco = await pipeline.BackChannelClient - .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration", _ct); disco.IsError.ShouldBeFalse(); var algorithmsSupported = disco.TokenEndpointAuthenticationSigningAlgorithmsSupported; @@ -48,9 +49,9 @@ public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_suppo svcs.AddIdentityServerBuilder().AddJwtBearerClientAuthentication(); pipeline.Initialize(); - var result = - await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( - "https://server/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( + "https://server/.well-known/openid-configuration", + _ct); result.IsError.ShouldBeFalse(); var algorithmsSupported = result.TokenEndpointAuthenticationSigningAlgorithmsSupported; @@ -77,7 +78,7 @@ public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_suppo pipeline.Options.SupportedClientAssertionSigningAlgorithms = [SecurityAlgorithms.RsaSha256]; var disco = await pipeline.BackChannelClient - .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration"); + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration", _ct); // Verify assumptions disco.IsError.ShouldBeFalse(); @@ -102,8 +103,8 @@ public class DiscoveryEndpointTests_token_endpoint_auth_signing_alg_values_suppo pipeline.Options.SupportedClientAssertionSigningAlgorithms = algorithms; var result = await pipeline.BackChannelClient - .GetAsync("https://server/.well-known/openid-configuration"); - var json = await result.Content.ReadAsStringAsync(); + .GetAsync("https://server/.well-known/openid-configuration", _ct); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data.ShouldNotContainKey(OidcConstants.Discovery.TokenEndpointAuthSigningAlgorithmsSupported); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_request_object_auth_signing_algs_supported.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_request_object_auth_signing_algs_supported.cs index 8d44552b7..471bf5d6b 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_request_object_auth_signing_algs_supported.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpoint_request_object_auth_signing_algs_supported.cs @@ -10,6 +10,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Discovery; public class DiscoveryEndpoint_request_object_auth_signing_algs_supported_Tests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Discovery endpoint - request_object_signing_algs_supported"; [Fact] @@ -25,9 +26,8 @@ public class DiscoveryEndpoint_request_object_auth_signing_algs_supported_Tests SecurityAlgorithms.EcdsaSha256 ]; - var result = - await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( - "https://server/.well-known/openid-configuration"); + var result = await pipeline.BackChannelClient + .GetDiscoveryDocumentAsync("https://server/.well-known/openid-configuration", _ct); var algorithmsSupported = result.TryGetStringArray("request_object_signing_alg_values_supported"); algorithmsSupported.Count().ShouldBe(2); @@ -46,8 +46,8 @@ public class DiscoveryEndpoint_request_object_auth_signing_algs_supported_Tests pipeline.Options.SupportedRequestObjectSigningAlgorithms = algorithms; var result = await pipeline.BackChannelClient - .GetAsync("https://server/.well-known/openid-configuration"); - var json = await result.Content.ReadAsStringAsync(); + .GetAsync("https://server/.well-known/openid-configuration", _ct); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data.ShouldNotContainKey("request_object_signing_alg_values_supported"); @@ -62,7 +62,7 @@ public class DiscoveryEndpoint_request_object_auth_signing_algs_supported_Tests var result = await pipeline.BackChannelClient.GetDiscoveryDocumentAsync( - "https://server/.well-known/openid-configuration"); + "https://server/.well-known/openid-configuration", _ct); var algorithmsSupported = result.TryGetStringArray("request_object_signing_alg_values_supported"); algorithmsSupported.ShouldBe([ diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs index 25ea0df75..639a7da6c 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/EndSession/EndSessionTests.cs @@ -22,7 +22,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.EndSession; public class EndSessionTests { private const string Category = "End session endpoint"; - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); private Client _wsfedClient; @@ -116,7 +116,7 @@ public class EndSessionTests [Trait("Category", Category)] public async Task get_request_should_not_return_404() { - var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); response.StatusCode.ShouldNotBe(HttpStatusCode.NotFound); } @@ -125,7 +125,7 @@ public class EndSessionTests [Trait("Category", Category)] public async Task signout_request_should_redirect_to_logout_page() { - var response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + var response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); _mockPipeline.LogoutWasCalled.ShouldBeTrue(); } @@ -148,13 +148,12 @@ public class EndSessionTests nonce: "123_nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var authorization = new Duende.IdentityModel.Client.AuthorizeResponse(response.Headers.Location.ToString()); var id_token = authorization.IdentityToken; - response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint + - "?id_token_hint=" + id_token + - "&post_logout_redirect_uri=https://client1/signout-callback"); + response = await _mockPipeline.BrowserClient + .GetAsync(IdentityServerPipeline.EndSessionEndpoint + "?id_token_hint=" + id_token + "&post_logout_redirect_uri=https://client1/signout-callback", _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://server/logout?id="); @@ -179,7 +178,7 @@ public class EndSessionTests var response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint + "?id_token_hint=" + id_token + "&post_logout_redirect_uri=https://client2/signout-callback2" + - "&ui_locales=fr-FR fr-CA"); + "&ui_locales=fr-FR fr-CA", _ct); _mockPipeline.LogoutWasCalled.ShouldBeTrue(); _mockPipeline.LogoutRequest.ShouldNotBeNull(); @@ -212,7 +211,7 @@ public class EndSessionTests var response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint + "?id_token_hint=" + id_token + "&post_logout_redirect_uri=https://client2/signout-callback2" + - "&ui_locales=" + new string('x', 101)); + "&ui_locales=" + new string('x', 101), _ct); _mockPipeline.LogoutWasCalled.ShouldBeTrue(); _mockPipeline.LogoutRequest.ShouldNotBeNull(); @@ -240,7 +239,7 @@ public class EndSessionTests var response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint + "?id_token_hint=" + id_token + "&post_logout_redirect_uri=https://client2/signout-callback2" + - "&ui_locales=nb-NO"); + "&ui_locales=nb-NO", _ct); _mockPipeline.LogoutWasCalled.ShouldBeTrue(); var cookie = _mockPipeline.BrowserClient.GetCookie("http://server", CookieRequestCultureProvider.DefaultCookieName); @@ -268,7 +267,7 @@ public class EndSessionTests var response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint + "?id_token_hint=" + id_token + - "&post_logout_redirect_uri=https://client2/signout-callback2"); + "&post_logout_redirect_uri=https://client2/signout-callback2", _ct); _mockPipeline.LogoutWasCalled.ShouldBeTrue(); _mockPipeline.LogoutRequest.ShouldNotBeNull(); @@ -292,7 +291,7 @@ public class EndSessionTests nonce: "123_nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var authorization = new Duende.IdentityModel.Client.AuthorizeResponse(response.Headers.Location.ToString()); var id_token = authorization.IdentityToken; @@ -302,7 +301,7 @@ public class EndSessionTests values.Add(new KeyValuePair("id_token_hint", id_token)); values.Add(new KeyValuePair("post_logout_redirect_uri", "https://client1/signout-callback")); var content = new FormUrlEncodedContent(values); - response = await _mockPipeline.BrowserClient.PostAsync(IdentityServerPipeline.EndSessionEndpoint, content); + response = await _mockPipeline.BrowserClient.PostAsync(IdentityServerPipeline.EndSessionEndpoint, content, _ct); _mockPipeline.LogoutWasCalled.ShouldBeTrue(); _mockPipeline.LogoutRequest.ShouldNotBeNull(); @@ -319,7 +318,7 @@ public class EndSessionTests [Trait("Category", Category)] public async Task signout_callback_without_params_should_return_400() { - var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.EndSessionCallbackEndpoint); + var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.EndSessionCallbackEndpoint, _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); } @@ -339,7 +338,7 @@ public class EndSessionTests nonce: "123_nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var authorization = new Duende.IdentityModel.Client.AuthorizeResponse(response.Headers.Location.ToString()); var id_token = authorization.IdentityToken; @@ -347,11 +346,11 @@ public class EndSessionTests _mockPipeline.BrowserClient.AllowAutoRedirect = true; response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint + "?id_token_hint=" + id_token + - "&post_logout_redirect_uri=https://client1/signout-callback-not-valid"); + "&post_logout_redirect_uri=https://client1/signout-callback-not-valid", _ct); var signoutFrameUrl = _mockPipeline.LogoutRequest.SignOutIFrameUrl; - response = await _mockPipeline.BrowserClient.GetAsync(signoutFrameUrl); + response = await _mockPipeline.BrowserClient.GetAsync(signoutFrameUrl, _ct); _mockPipeline.LogoutRequest.ClientId.ShouldNotBeNull(); _mockPipeline.LogoutRequest.PostLogoutRedirectUri.ShouldBeNull(); @@ -372,7 +371,7 @@ public class EndSessionTests nonce: "123_nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var authorization = new Duende.IdentityModel.Client.AuthorizeResponse(response.Headers.Location.ToString()); var id_token = authorization.IdentityToken; @@ -382,7 +381,7 @@ public class EndSessionTests _mockPipeline.BrowserClient.AllowAutoRedirect = true; response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint + "?id_token_hint=" + id_token + - "&post_logout_redirect_uri=https://client1/signout-callback"); + "&post_logout_redirect_uri=https://client1/signout-callback", _ct); _mockPipeline.LogoutRequest.ClientId.ShouldBeNull(); _mockPipeline.LogoutRequest.PostLogoutRedirectUri.ShouldBeNull(); @@ -403,14 +402,14 @@ public class EndSessionTests nonce: "123_nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.BrowserClient.AllowAutoRedirect = true; - response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); var signoutFrameUrl = _mockPipeline.LogoutRequest.SignOutIFrameUrl; - response = await _mockPipeline.BrowserClient.GetAsync(signoutFrameUrl); + response = await _mockPipeline.BrowserClient.GetAsync(signoutFrameUrl, _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); response.Content.Headers.ContentType.MediaType.ShouldBe("text/html"); } @@ -430,7 +429,7 @@ public class EndSessionTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var url2 = _mockPipeline.CreateAuthorizeUrl( clientId: "client2", @@ -439,15 +438,15 @@ public class EndSessionTests redirectUri: "https://client2/callback", state: "123_state", nonce: "123_nonce"); - var response2 = await _mockPipeline.BrowserClient.GetAsync(url2); + var response2 = await _mockPipeline.BrowserClient.GetAsync(url2, _ct); _mockPipeline.BrowserClient.AllowAutoRedirect = true; - response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); var signoutFrameUrl = _mockPipeline.LogoutRequest.SignOutIFrameUrl; - response = await _mockPipeline.BrowserClient.GetAsync(signoutFrameUrl); - var html = await response.Content.ReadAsStringAsync(); + response = await _mockPipeline.BrowserClient.GetAsync(signoutFrameUrl, _ct); + var html = await response.Content.ReadAsStringAsync(_ct); html.ShouldContain(HtmlEncoder.Default.Encode("https://client1/signout?sid=" + sid + "&iss=" + UrlEncoder.Default.Encode("https://server"))); html.ShouldContain(HtmlEncoder.Default.Encode("https://client2/signout?sid=" + sid + "&iss=" + UrlEncoder.Default.Encode("https://server"))); } @@ -467,10 +466,10 @@ public class EndSessionTests redirectUri: "https://client4/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.BrowserClient.AllowAutoRedirect = true; - response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); var signoutFrameUrl = _mockPipeline.LogoutRequest.SignOutIFrameUrl; @@ -478,8 +477,8 @@ public class EndSessionTests // at signout to use ws-fed so we can test the iframe params _wsfedClient.ProtocolType = IdentityServerConstants.ProtocolTypes.WsFederation; - response = await _mockPipeline.BrowserClient.GetAsync(signoutFrameUrl); - var html = await response.Content.ReadAsStringAsync(); + response = await _mockPipeline.BrowserClient.GetAsync(signoutFrameUrl, _ct); + var html = await response.Content.ReadAsStringAsync(_ct); html.ShouldContain("https://client4/signout?wa=wsignoutcleanup1.0"); } @@ -497,13 +496,13 @@ public class EndSessionTests redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var authorization = new Duende.IdentityModel.Client.AuthorizeResponse(response.Headers.Location.ToString()); var id_token = authorization.IdentityToken; _mockPipeline.BrowserClient.AllowAutoRedirect = true; response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint + - "?id_token_hint=" + id_token); + "?id_token_hint=" + id_token, _ct); _mockPipeline.LogoutRequest.PostLogoutRedirectUri.ShouldBeNull(); } @@ -522,13 +521,13 @@ public class EndSessionTests redirectUri: "https://client2/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); var authorization = new Duende.IdentityModel.Client.AuthorizeResponse(response.Headers.Location.ToString()); var id_token = authorization.IdentityToken; _mockPipeline.BrowserClient.AllowAutoRedirect = true; response = await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint + - "?id_token_hint=" + id_token); + "?id_token_hint=" + id_token, _ct); _mockPipeline.LogoutRequest.PostLogoutRedirectUri.ShouldBeNull(); } @@ -548,7 +547,7 @@ public class EndSessionTests nonce: "123_nonce"); response.ShouldNotBeNull(); - await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); _mockPipeline.LogoutWasCalled.ShouldBeTrue(); _mockPipeline.LogoutRequest.SignOutIFrameUrl.ShouldNotBeNull(); @@ -560,7 +559,7 @@ public class EndSessionTests { await _mockPipeline.LoginAsync("bob"); - await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); _mockPipeline.LogoutWasCalled.ShouldBeTrue(); _mockPipeline.LogoutRequest.SignOutIFrameUrl.ShouldBeNull(); @@ -609,7 +608,7 @@ public class EndSessionTests nonce: "123_nonce"); response.ShouldNotBeNull(); - await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); _mockPipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeTrue(); } @@ -647,7 +646,7 @@ public class EndSessionTests nonce: "123_nonce"); response.ShouldNotBeNull(); - await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); _mockPipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeTrue(); } @@ -687,7 +686,7 @@ public class EndSessionTests nonce: "123_nonce"); response.ShouldNotBeNull(); - await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); _mockPipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeTrue(); } @@ -709,7 +708,7 @@ public class EndSessionTests nonce: "123_nonce"); response.ShouldNotBeNull(); - await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); _mockPipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeTrue(); } @@ -734,7 +733,7 @@ public class EndSessionTests nonce: "123_nonce"); response.ShouldNotBeNull(); - await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); _mockPipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeTrue(); } @@ -759,7 +758,7 @@ public class EndSessionTests nonce: "123_nonce"); response.ShouldNotBeNull(); - await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); _mockPipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeTrue(); } @@ -782,7 +781,7 @@ public class EndSessionTests nonce: "123_nonce"); response.ShouldNotBeNull(); - await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint); + await _mockPipeline.BrowserClient.GetAsync(IdentityServerPipeline.EndSessionEndpoint, _ct); _mockPipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeTrue(); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Introspection/IntrospectionTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Introspection/IntrospectionTests.cs index 86d304fa7..82333d8cf 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Introspection/IntrospectionTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Introspection/IntrospectionTests.cs @@ -24,7 +24,7 @@ public class IntrospectionTests private const string IntrospectionEndpoint = "https://server/connect/introspect"; private const string TokenEndpoint = "https://server/connect/token"; private const string RevocationEndpoint = "https://server/connect/revocation"; - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly HttpClient _client; private readonly HttpMessageHandler _handler; @@ -49,7 +49,7 @@ public class IntrospectionTests { var form = new Dictionary(); - var response = await _client.PostAsync(IntrospectionEndpoint, new FormUrlEncodedContent(form)); + var response = await _client.PostAsync(IntrospectionEndpoint, new FormUrlEncodedContent(form), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } @@ -61,7 +61,7 @@ public class IntrospectionTests var form = new Dictionary(); _client.SetBasicAuthentication("unknown", "invalid"); - var response = await _client.PostAsync(IntrospectionEndpoint, new FormUrlEncodedContent(form)); + var response = await _client.PostAsync(IntrospectionEndpoint, new FormUrlEncodedContent(form), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } @@ -73,7 +73,7 @@ public class IntrospectionTests var form = new Dictionary(); _client.SetBasicAuthentication("api1", "invalid"); - var response = await _client.PostAsync(IntrospectionEndpoint, new FormUrlEncodedContent(form)); + var response = await _client.PostAsync(IntrospectionEndpoint, new FormUrlEncodedContent(form), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } @@ -85,7 +85,7 @@ public class IntrospectionTests var form = new Dictionary(); _client.SetBasicAuthentication("api1", "secret"); - var response = await _client.PostAsync(IntrospectionEndpoint, new FormUrlEncodedContent(form)); + var response = await _client.PostAsync(IntrospectionEndpoint, new FormUrlEncodedContent(form), _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); } @@ -101,7 +101,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = "invalid" - }); + }, _ct); introspectionResponse.IsActive.ShouldBe(false); introspectionResponse.IsError.ShouldBe(false); @@ -117,7 +117,7 @@ public class IntrospectionTests ClientId = "client1", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); var data = new { @@ -129,7 +129,7 @@ public class IntrospectionTests var client = new HttpClient(_handler); var response = await client.PostAsync(IntrospectionEndpoint, - new StringContent(json, Encoding.UTF8, "application/json")); + new StringContent(json, Encoding.UTF8, "application/json"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.UnsupportedMediaType); } @@ -143,7 +143,7 @@ public class IntrospectionTests ClientId = "client1", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -153,7 +153,7 @@ public class IntrospectionTests Token = tokenResponse.AccessToken, TokenTypeHint = "invalid" - }); + }, _ct); introspectionResponse.IsActive.ShouldBe(true); introspectionResponse.IsError.ShouldBe(false); @@ -176,9 +176,7 @@ public class IntrospectionTests [InlineData("api1", "bogus")] public async Task Access_tokens_can_be_introspected_with_any_hint(string introspectedBy, string hint) { - TokenResponse tokenResponse; - - tokenResponse = await _client.RequestPasswordTokenAsync(new PasswordTokenRequest + var tokenResponse = await _client.RequestPasswordTokenAsync(new PasswordTokenRequest { Address = TokenEndpoint, ClientId = "ro.client", @@ -186,7 +184,7 @@ public class IntrospectionTests UserName = "bob", Password = "bob", Scope = "api1 offline_access" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -196,7 +194,7 @@ public class IntrospectionTests Token = tokenResponse.AccessToken, TokenTypeHint = hint - }); + }, _ct); introspectionResponse.IsActive.ShouldBe(true); introspectionResponse.IsError.ShouldBe(false); @@ -223,9 +221,7 @@ public class IntrospectionTests public async Task Refresh_tokens_can_be_introspected_by_their_client_with_any_hint(string introspectedBy, string hint, bool isActive) { - TokenResponse tokenResponse; - - tokenResponse = await _client.RequestPasswordTokenAsync(new PasswordTokenRequest + var tokenResponse = await _client.RequestPasswordTokenAsync(new PasswordTokenRequest { Address = TokenEndpoint, ClientId = "ro.client", @@ -233,7 +229,7 @@ public class IntrospectionTests UserName = "bob", Password = "bob", Scope = "api1 offline_access" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -243,7 +239,7 @@ public class IntrospectionTests Token = tokenResponse.RefreshToken, TokenTypeHint = hint - }); + }, _ct); if (isActive) { @@ -274,7 +270,7 @@ public class IntrospectionTests ClientId = "client1", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -283,7 +279,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBe(true); introspectionResponse.IsError.ShouldBe(false); @@ -306,7 +302,7 @@ public class IntrospectionTests ClientId = "client1", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -315,7 +311,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); var values = GetFields(introspectionResponse); @@ -344,7 +340,7 @@ public class IntrospectionTests Password = "bob", Scope = "api1", - }); + }, _ct); tokenResponse.IsError.ShouldBeFalse(); @@ -355,7 +351,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); var values = GetFields(introspectionResponse); @@ -382,7 +378,7 @@ public class IntrospectionTests ClientSecret = "secret", Scope = "api2 api3-a api3-b", - }); + }, _ct); tokenResponse.IsError.ShouldBeFalse(); @@ -393,7 +389,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); var values = GetFields(introspectionResponse); @@ -427,7 +423,7 @@ public class IntrospectionTests ClientSecret = "secret", Scope = "api3-a api3-b", - }); + }, _ct); tokenResponse.IsError.ShouldBeFalse(); @@ -438,7 +434,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); var values = GetFields(introspectionResponse); @@ -465,7 +461,7 @@ public class IntrospectionTests ClientSecret = "secret", Scope = "api1 api2 api3-a", - }); + }, _ct); tokenResponse.IsError.ShouldBeFalse(); @@ -476,7 +472,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBeTrue(); introspectionResponse.IsError.ShouldBeFalse(); @@ -500,7 +496,7 @@ public class IntrospectionTests ClientSecret = "secret", Scope = "api1 api2", - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -509,7 +505,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBe(true); introspectionResponse.IsError.ShouldBe(false); @@ -533,7 +529,7 @@ public class IntrospectionTests ClientSecret = "secret", Scope = "api1", - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -542,7 +538,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBe(false); introspectionResponse.IsError.ShouldBe(false); @@ -558,7 +554,7 @@ public class IntrospectionTests ClientId = "client1", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -567,7 +563,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBeTrue(); introspectionResponse.IsError.ShouldBeFalse(); @@ -586,7 +582,7 @@ public class IntrospectionTests UserName = "bob", Password = "bob", Scope = "api1 offline_access" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -595,7 +591,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.RefreshToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBeTrue(); introspectionResponse.IsError.ShouldBeFalse(); @@ -617,7 +613,7 @@ public class IntrospectionTests UserName = "bob", Password = "bob", Scope = "api1 offline_access" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -626,7 +622,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.RefreshToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBeFalse(); introspectionResponse.IsError.ShouldBeFalse(); @@ -644,7 +640,7 @@ public class IntrospectionTests UserName = "bob", Password = "bob", Scope = "api1 offline_access" - }); + }, _ct); var revocationResponse = await _client.RevokeTokenAsync(new TokenRevocationRequest { @@ -653,7 +649,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.RefreshToken - }); + }, _ct); revocationResponse.IsError.ShouldBeFalse(); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest @@ -663,7 +659,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.RefreshToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBeFalse(); introspectionResponse.IsError.ShouldBeFalse(); @@ -679,7 +675,7 @@ public class IntrospectionTests ClientId = "client1", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -688,7 +684,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBeFalse(); introspectionResponse.IsError.ShouldBeFalse(); @@ -706,7 +702,7 @@ public class IntrospectionTests UserName = "bob", Password = "bob", Scope = "api1 offline_access" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -715,7 +711,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.RefreshToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBeFalse(); introspectionResponse.IsError.ShouldBeFalse(); @@ -733,7 +729,7 @@ public class IntrospectionTests UserName = "bob", Password = "bob", Scope = "api1 offline_access" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -744,7 +740,7 @@ public class IntrospectionTests Token = tokenResponse.AccessToken, TokenTypeHint = Constants.TokenTypeHints.AccessToken, ResponseFormat = ResponseFormat.Jwt - }); + }, _ct); introspectionResponse.HttpResponse.Content.Headers.ContentType.MediaType.ShouldBe($"application/{JwtClaimTypes.JwtTypes.IntrospectionJwtResponse}"); } @@ -761,7 +757,7 @@ public class IntrospectionTests UserName = "bob", Password = "bob", Scope = "api1 offline_access" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -772,7 +768,7 @@ public class IntrospectionTests Token = tokenResponse.AccessToken, TokenTypeHint = Constants.TokenTypeHints.AccessToken, ResponseFormat = ResponseFormat.Jwt - }); + }, _ct); var handler = new JwtSecurityTokenHandler(); var jwt = handler.ReadJwtToken(introspectionResponse.Raw); @@ -804,7 +800,7 @@ public class IntrospectionTests UserName = "bob", Password = "bob", Scope = "api1 offline_access" - }); + }, _ct); var revocationResponse = await _client.RevokeTokenAsync(new TokenRevocationRequest { @@ -813,7 +809,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.RefreshToken - }); + }, _ct); revocationResponse.IsError.ShouldBeFalse(); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest @@ -825,7 +821,7 @@ public class IntrospectionTests Token = tokenResponse.AccessToken, TokenTypeHint = Constants.TokenTypeHints.AccessToken, ResponseFormat = ResponseFormat.Jwt - }); + }, _ct); var handler = new JwtSecurityTokenHandler(); var jwt = handler.ReadJwtToken(introspectionResponse.Raw); @@ -850,7 +846,7 @@ public class IntrospectionTests Token = "invalid", ResponseFormat = ResponseFormat.Jwt - }); + }, _ct); var handler = new JwtSecurityTokenHandler(); var jwt = handler.ReadJwtToken(introspectionResponse.Raw); @@ -876,7 +872,7 @@ public class IntrospectionTests Scope = "api1 offline_access roles address", UserName = "bob", Password = "bob" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -887,7 +883,7 @@ public class IntrospectionTests Token = tokenResponse.AccessToken, TokenTypeHint = Constants.TokenTypeHints.AccessToken, ResponseFormat = ResponseFormat.Jwt - }); + }, _ct); introspectionResponse.Json.ShouldNotBeNull(); var addressClaim = introspectionResponse.Json.Value.TryGetString("address"); @@ -907,7 +903,7 @@ public class IntrospectionTests Scope = "api1 offline_access roles", UserName = "bob", Password = "bob" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -918,7 +914,7 @@ public class IntrospectionTests Token = tokenResponse.AccessToken, TokenTypeHint = Constants.TokenTypeHints.AccessToken, ResponseFormat = ResponseFormat.Jwt - }); + }, _ct); introspectionResponse.Json.ShouldNotBeNull(); var rolesClaim = introspectionResponse.Json.Value.TryGetStringArray("role").ToList(); @@ -939,7 +935,7 @@ public class IntrospectionTests ClientId = "client1", ClientSecret = "secret", Scope = "api1" - }); + }, _ct); var introspectionResponse = await _client.IntrospectTokenAsync(new TokenIntrospectionRequest { @@ -948,7 +944,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = tokenResponse.AccessToken - }); + }, _ct); introspectionResponse.IsActive.ShouldBe(true); introspectionResponse.IsError.ShouldBe(false); @@ -971,7 +967,7 @@ public class IntrospectionTests ClientSecret = "secret", Token = "invalid" - }); + }, _ct); introspectionResponse.IsActive.ShouldBe(false); introspectionResponse.IsError.ShouldBe(false); @@ -993,8 +989,8 @@ public class IntrospectionTests { "client_secret", "secret" }, { "token", "" } }); - var rawIntrospectionResponse = await _client.PostAsync(IntrospectionEndpoint, requestContent); - var introspectionResponse = await rawIntrospectionResponse.Content.ReadFromJsonAsync(); + var rawIntrospectionResponse = await _client.PostAsync(IntrospectionEndpoint, requestContent, _ct); + var introspectionResponse = await rawIntrospectionResponse.Content.ReadFromJsonAsync(_ct); introspectionResponse.IsActive.ShouldBe(false); introspectionResponse.IsError.ShouldBe(false); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/OAuthMetadata/OAuthMetadataTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/OAuthMetadata/OAuthMetadataTests.cs index 9c6ec8c14..e2909c9e4 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/OAuthMetadata/OAuthMetadataTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/OAuthMetadata/OAuthMetadataTests.cs @@ -13,6 +13,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.OAuthMetadata; public class OAuthMetadataTests { private const string Category = "OAuth Metadata endpoint"; + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; [Fact] [Trait("Category", Category)] @@ -21,7 +22,7 @@ public class OAuthMetadataTests var pipeline = new IdentityServerPipeline(); pipeline.Initialize(); - var result = await pipeline.BackChannelClient.PostAsync("https://server/.well-known/oauth-authorization-server", null); + var result = await pipeline.BackChannelClient.PostAsync("https://server/.well-known/oauth-authorization-server", null, _ct); result.StatusCode.ShouldBe(HttpStatusCode.MethodNotAllowed); } @@ -33,9 +34,9 @@ public class OAuthMetadataTests var pipeline = new IdentityServerPipeline(); pipeline.Initialize(); - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data["issuer"].GetString().ShouldBe("https://server"); } @@ -49,9 +50,9 @@ public class OAuthMetadataTests pipeline.Initialize(); pipeline.Options.IssuerUri = "https://server/identity"; - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/identity"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/identity", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data["issuer"].GetString().ShouldBe("https://server/identity"); } @@ -65,9 +66,9 @@ public class OAuthMetadataTests pipeline.Initialize(); pipeline.Options.IssuerUri = "https://server/identity"; - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/identity?query=string"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/identity?query=string", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data["issuer"].GetString().ShouldBe("https://server/identity"); } @@ -81,9 +82,9 @@ public class OAuthMetadataTests pipeline.Initialize(); pipeline.Options.IssuerUri = "https://server/identity"; - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/identity#fragment"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/identity#fragment", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data["issuer"].GetString().ShouldBe("https://server/identity"); } @@ -96,9 +97,9 @@ public class OAuthMetadataTests pipeline.Initialize(); pipeline.Options.IssuerUri = "https://server/explicit"; - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/explicit"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/explicit", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data["issuer"].GetString().ShouldBe("https://server/explicit"); } @@ -111,7 +112,7 @@ public class OAuthMetadataTests pipeline.Initialize(); pipeline.Options.IssuerUri = "https://example.com/explicit"; - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server", _ct); result.StatusCode.ShouldBe(HttpStatusCode.NotFound); } @@ -123,7 +124,7 @@ public class OAuthMetadataTests var pipeline = new IdentityServerPipeline(); pipeline.Initialize("/identity"); - var result = await pipeline.BackChannelClient.GetAsync("https://server/identity/.well-known/oauth-authorization-server"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/identity/.well-known/oauth-authorization-server", _ct); result.StatusCode.ShouldBe(HttpStatusCode.NotFound); } @@ -137,7 +138,7 @@ public class OAuthMetadataTests pipeline.Initialize(); pipeline.Options.IssuerUri = "https://server/identity"; - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/wrong"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/wrong", _ct); result.StatusCode.ShouldBe(HttpStatusCode.NotFound); } @@ -151,9 +152,9 @@ public class OAuthMetadataTests pipeline.Initialize(); pipeline.Options.IssuerUri = "https://server/identity"; - var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/identity"); + var result = await pipeline.BackChannelClient.GetAsync("https://server/.well-known/oauth-authorization-server/identity", _ct); - var json = await result.Content.ReadAsStringAsync(); + var json = await result.Content.ReadAsStringAsync(_ct); var data = JsonSerializer.Deserialize>(json); data["issuer"].GetString().ShouldBe("https://server/identity"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Revocation/RevocationTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Revocation/RevocationTests.cs index 6f6eb6a41..c7c2a0e30 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Revocation/RevocationTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Revocation/RevocationTests.cs @@ -14,15 +14,13 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Revocation; public class RevocationTests { private const string Category = "RevocationTests endpoint"; - - private string client_id = "client"; - private string client_secret = "secret"; - private string redirect_uri = "https://client/callback"; - - private string scope_name = "api"; - private string scope_secret = "api_secret"; - - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); + private const string client_id = "client"; + private const string client_secret = "secret"; + private const string redirect_uri = "https://client/callback"; + private const string scope_name = "api"; + private const string scope_secret = "api_secret"; + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); public RevocationTests() { @@ -197,7 +195,7 @@ public class RevocationTests [Trait("Category", Category)] public async Task Get_request_should_return_405() { - var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.RevocationEndpoint); + var response = await _mockPipeline.BackChannelClient.GetAsync(IdentityServerPipeline.RevocationEndpoint, _ct); response.StatusCode.ShouldBe(HttpStatusCode.MethodNotAllowed); } @@ -206,7 +204,7 @@ public class RevocationTests [Trait("Category", Category)] public async Task Post_without_form_urlencoded_should_return_415() { - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, null); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, null, _ct); response.StatusCode.ShouldBe(HttpStatusCode.UnsupportedMediaType); } @@ -225,7 +223,7 @@ public class RevocationTests ClientSecret = client_secret, Token = tokens.AccessToken - }); + }, _ct); result.IsError.ShouldBeFalse(); (await IsAccessTokenValidAsync(tokens)).ShouldBeFalse(); @@ -245,7 +243,7 @@ public class RevocationTests ClientSecret = client_secret, Token = tokens.AccessToken - }); + }, _ct); result.IsError.ShouldBeFalse(); (await IsAccessTokenValidAsync(tokens)).ShouldBeTrue(); @@ -265,7 +263,7 @@ public class RevocationTests ClientSecret = client_secret, Token = tokens.RefreshToken - }); + }, _ct); result.IsError.ShouldBeFalse(); @@ -286,7 +284,7 @@ public class RevocationTests ClientSecret = client_secret, Token = tokens.RefreshToken - }); + }, _ct); result.IsError.ShouldBeFalse(); @@ -311,7 +309,7 @@ public class RevocationTests ClientSecret = client_secret, Token = tokens1.RefreshToken - }); + }, _ct); result.IsError.ShouldBeFalse(); @@ -333,7 +331,7 @@ public class RevocationTests ClientSecret = client_secret, Token = tokens.AccessToken - }); + }, _ct); result.IsError.ShouldBeFalse(); @@ -346,7 +344,7 @@ public class RevocationTests ClientSecret = client_secret, Token = tokens.AccessToken - }); + }, _ct); result.IsError.ShouldBeFalse(); } @@ -365,7 +363,7 @@ public class RevocationTests ClientSecret = client_secret, Token = tokens.RefreshToken - }); + }, _ct); result.IsError.ShouldBeFalse(); @@ -378,7 +376,7 @@ public class RevocationTests ClientSecret = client_secret, Token = tokens.RefreshToken - }); + }, _ct); result.IsError.ShouldBeFalse(); } @@ -397,7 +395,7 @@ public class RevocationTests ClientSecret = client_secret, Token = tokens.AccessToken - }); + }, _ct); result.IsError.ShouldBeTrue(); result.Error.ShouldBe("invalid_client"); @@ -417,7 +415,7 @@ public class RevocationTests ClientSecret = "not_valid", Token = tokens.AccessToken - }); + }, _ct); result.IsError.ShouldBeTrue(); result.Error.ShouldBe("invalid_client"); @@ -433,7 +431,7 @@ public class RevocationTests { "client_secret", client_secret } }; - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data)); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data), _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); var result = await ProtocolResponse.FromHttpResponseAsync(response); @@ -456,7 +454,7 @@ public class RevocationTests { "token_type_hint", "not_valid" } }; - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data)); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data), _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); var result = await ProtocolResponse.FromHttpResponseAsync(response); @@ -478,7 +476,7 @@ public class RevocationTests { "token", tokens.AccessToken } }; - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data)); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data), _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); (await IsAccessTokenValidAsync(tokens)).ShouldBeFalse(); @@ -498,7 +496,7 @@ public class RevocationTests { "token", tokens.RefreshToken } }; - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data)); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data), _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); (await UseRefreshTokenAsync(tokens)).ShouldBeFalse(); @@ -518,7 +516,7 @@ public class RevocationTests (await IsAccessTokenValidAsync(token)).ShouldBeTrue(); - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data)); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data), _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); (await IsAccessTokenValidAsync(token)).ShouldBeFalse(); } @@ -537,7 +535,7 @@ public class RevocationTests (await IsAccessTokenValidAsync(token)).ShouldBeTrue(); - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data)); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.RevocationEndpoint, new FormUrlEncodedContent(data), _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); (await IsAccessTokenValidAsync(token)).ShouldBeTrue(); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/CibaTokenEndpointTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/CibaTokenEndpointTests.cs index 20e61b7a4..e06156e91 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/CibaTokenEndpointTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/CibaTokenEndpointTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. - using System.Net; using System.Security.Claims; using System.Text.Json; @@ -16,13 +15,14 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Token; public class CibaTokenEndpointTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "CIBA Token endpoint"; - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); private MockCibaUserValidator _mockCibaUserValidator = new MockCibaUserValidator(); private MockCibaUserNotificationService _mockCibaUserNotificationService = new MockCibaUserNotificationService(); - private TestUser _user; + private readonly TestUser _user; private Client _cibaClient; public CibaTokenEndpointTests() @@ -138,7 +138,8 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -158,7 +159,8 @@ public class CibaTokenEndpointTests // token request - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var body = await cibaResponse.Content.ReadAsStringAsync(_ct); + var values = JsonSerializer.Deserialize>(body); var requestId = values["auth_req_id"].ToString(); var tokenBody = new Dictionary @@ -171,7 +173,8 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.OK); } @@ -196,13 +199,14 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); // token request - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync(_ct)); var requestId = values["auth_req_id"].ToString(); var tokenBody = new Dictionary @@ -215,11 +219,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -245,7 +250,8 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -265,7 +271,7 @@ public class CibaTokenEndpointTests // token request - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync(_ct)); var requestId = values["auth_req_id"].ToString(); var tokenBody = new Dictionary @@ -278,11 +284,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -308,7 +315,8 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -328,7 +336,8 @@ public class CibaTokenEndpointTests // token request - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var body = await cibaResponse.Content.ReadAsStringAsync(_ct); + var values = JsonSerializer.Deserialize>(body); var requestId = values["auth_req_id"].ToString(); var tokenBody = new Dictionary @@ -341,11 +350,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -371,7 +381,8 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -391,7 +402,8 @@ public class CibaTokenEndpointTests // token request - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var body = await cibaResponse.Content.ReadAsStringAsync(_ct); + var values = JsonSerializer.Deserialize>(body); var requestId = values["auth_req_id"].ToString(); var tokenBody = new Dictionary @@ -404,11 +416,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -434,10 +447,10 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); - // user auth/consent var cibaService = _mockPipeline.Resolve(); var request = await cibaService.GetLoginRequestByInternalIdAsync(_mockCibaUserNotificationService.LoginRequest.InternalId); @@ -456,7 +469,7 @@ public class CibaTokenEndpointTests // token request _user.IsActive = false; - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync(_ct)); var requestId = values["auth_req_id"].ToString(); var tokenBody = new Dictionary @@ -469,11 +482,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -503,7 +517,8 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); @@ -525,7 +540,8 @@ public class CibaTokenEndpointTests // token request clock.UtcNow = DateTimeOffset.UtcNow.AddHours(1); - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var body = await cibaResponse.Content.ReadAsStringAsync(_ct); + var values = JsonSerializer.Deserialize>(body); var requestId = values["auth_req_id"].ToString(); var tokenBody = new Dictionary @@ -538,11 +554,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -572,12 +589,13 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); // token request - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync(_ct)); var requestId = values["auth_req_id"].ToString(); { @@ -591,11 +609,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -612,11 +631,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -647,12 +667,14 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); // token request - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var body = await cibaResponse.Content.ReadAsStringAsync(_ct); + var values = JsonSerializer.Deserialize>(body); var requestId = values["auth_req_id"].ToString(); { @@ -666,11 +688,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -687,11 +710,11 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -711,11 +734,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -732,11 +756,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -769,12 +794,13 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); // token request - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync(_ct)); var requestId = values["auth_req_id"].ToString(); { @@ -788,11 +814,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -809,11 +836,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -833,11 +861,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -857,11 +886,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -878,11 +908,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -915,12 +946,13 @@ public class CibaTokenEndpointTests var cibaResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.BackchannelAuthenticationEndpoint, - new FormUrlEncodedContent(cibaBody)); + new FormUrlEncodedContent(cibaBody), + _ct); cibaResponse.StatusCode.ShouldBe(HttpStatusCode.OK); // token request - var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync()); + var values = JsonSerializer.Deserialize>(await cibaResponse.Content.ReadAsStringAsync(_ct)); var requestId = values["auth_req_id"].ToString(); { @@ -934,11 +966,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); @@ -958,11 +991,12 @@ public class CibaTokenEndpointTests var tokenResponse = await _mockPipeline.BackChannelClient.PostAsync( IdentityServerPipeline.TokenEndpoint, - new FormUrlEncodedContent(tokenBody)); + new FormUrlEncodedContent(tokenBody), + _ct); tokenResponse.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await tokenResponse.Content.ReadAsStringAsync(); + var json = await tokenResponse.Content.ReadAsStringAsync(_ct); values = JsonSerializer.Deserialize>(json); values.ContainsKey("error").ShouldBeTrue(); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/DPoPPushedAuthorizationEndpointTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/DPoPPushedAuthorizationEndpointTests.cs index 5d3322f0e..4de2ee506 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/DPoPPushedAuthorizationEndpointTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/DPoPPushedAuthorizationEndpointTests.cs @@ -17,7 +17,8 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Token; /// public class DPoPPushedAuthorizationEndpointTests : DPoPEndpointTestBase { - protected const string Category = "DPoP PAR endpoint"; + private const string Category = "DPoP PAR endpoint"; + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private PushedAuthorizationRequest CreatePushedAuthorizationRequest( string proofToken = null, bool omitDPoPProof = false, string dpopKeyThumprint = null @@ -47,7 +48,7 @@ public class DPoPPushedAuthorizationEndpointTests : DPoPEndpointTestBase { Payload.Add("foo", new string('x', 3000)); var request = CreatePushedAuthorizationRequest(); - var response = await Pipeline.BackChannelClient.PushAuthorizationAsync(request); + var response = await Pipeline.BackChannelClient.PushAuthorizationAsync(request, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe("invalid_dpop_proof"); } @@ -61,12 +62,12 @@ public class DPoPPushedAuthorizationEndpointTests : DPoPEndpointTestBase // Initial request succeeds var firstRequest = CreatePushedAuthorizationRequest(dpopToken); - var firstResponse = await Pipeline.BackChannelClient.PushAuthorizationAsync(firstRequest); + var firstResponse = await Pipeline.BackChannelClient.PushAuthorizationAsync(firstRequest, _ct); firstResponse.IsError.ShouldBeFalse(); // Second request fails var secondRequest = CreatePushedAuthorizationRequest(dpopToken); - var secondResponse = await Pipeline.BackChannelClient.PushAuthorizationAsync(secondRequest); + var secondResponse = await Pipeline.BackChannelClient.PushAuthorizationAsync(secondRequest, _ct); secondResponse.IsError.ShouldBeTrue(); secondResponse.Error.ShouldBe("invalid_dpop_proof"); } @@ -76,7 +77,7 @@ public class DPoPPushedAuthorizationEndpointTests : DPoPEndpointTestBase public async Task invalid_dpop_request_should_fail() { var request = CreatePushedAuthorizationRequest(proofToken: "malformed"); - var response = await Pipeline.BackChannelClient.PushAuthorizationAsync(request); + var response = await Pipeline.BackChannelClient.PushAuthorizationAsync(request, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe("invalid_dpop_proof"); } @@ -89,7 +90,7 @@ public class DPoPPushedAuthorizationEndpointTests : DPoPEndpointTestBase request.Headers.Add("DPoP", dpopToken); request.Headers.Add("DPoP", dpopToken); - var response = await Pipeline.BackChannelClient.PushAuthorizationAsync(request); + var response = await Pipeline.BackChannelClient.PushAuthorizationAsync(request, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -103,7 +104,7 @@ public class DPoPPushedAuthorizationEndpointTests : DPoPEndpointTestBase oldThumbprint.ShouldNotBe(JKT); var request = CreatePushedAuthorizationRequest(dpopKeyThumprint: oldThumbprint); - var response = await Pipeline.BackChannelClient.PushAuthorizationAsync(request); + var response = await Pipeline.BackChannelClient.PushAuthorizationAsync(request, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe(OidcConstants.AuthorizeErrors.InvalidRequest); @@ -144,7 +145,7 @@ public class DPoPPushedAuthorizationEndpointTests : DPoPEndpointTestBase tokenClient.DefaultRequestHeaders.Add("DPoP", proofToken); var request = CreatePushedAuthorizationRequest(proofToken); - var response = await tokenClient.PushAuthorizationAsync(request); + var response = await tokenClient.PushAuthorizationAsync(request, _ct); response.IsError.ShouldBeFalse(); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/DPoPTokenEndpointTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/DPoPTokenEndpointTests.cs index af5578ba5..e61e36ffa 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/DPoPTokenEndpointTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/DPoPTokenEndpointTests.cs @@ -18,6 +18,7 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Token; public class DPoPTokenEndpointTests : DPoPEndpointTestBase { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; protected const string Category = "DPoP Token endpoint"; private ClientCredentialsTokenRequest CreateClientCredentialsTokenRequest( @@ -61,7 +62,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase { var request = CreateClientCredentialsTokenRequest(); - var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request); + var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request, _ct); response.IsError.ShouldBeFalse(); response.TokenType.ShouldBe("DPoP"); @@ -78,7 +79,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase Payload.Add("key_ops", new string[] { "sign", "verify" }); var request = CreateClientCredentialsTokenRequest(); - var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request); + var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request, _ct); response.IsError.ShouldBeFalse(); response.TokenType.ShouldBe("DPoP"); @@ -93,7 +94,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase Payload.Add("foo", new string('x', 3000)); var request = CreateClientCredentialsTokenRequest(); - var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request); + var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request, _ct); response.IsError.ShouldBeTrue(); } @@ -107,7 +108,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase // Initial request succeeds var firstRequest = CreateClientCredentialsTokenRequest(dpopToken); - var firstResponse = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(firstRequest); + var firstResponse = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(firstRequest, _ct); firstResponse.IsError.ShouldBeFalse(); firstResponse.TokenType.ShouldBe("DPoP"); var jkt = GetJKTFromAccessToken(firstResponse); @@ -116,7 +117,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase // Second request fails var secondRequest = CreateClientCredentialsTokenRequest(dpopToken); secondRequest.Headers.Add("DPoP", dpopToken); - var secondResponse = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(secondRequest); + var secondResponse = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(secondRequest, _ct); secondResponse.IsError.ShouldBeTrue(); } @@ -126,7 +127,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase { var request = CreateClientCredentialsTokenRequest(proofToken: "malformed"); - var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request); + var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe("invalid_dpop_proof"); @@ -139,7 +140,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase ConfidentialClient.RequireDPoP = true; var request = CreateClientCredentialsTokenRequest(omitDPoPProof: true); - var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request); + var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe("invalid_request"); @@ -154,7 +155,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase request.Headers.Add("DPoP", dpopToken); request.Headers.Add("DPoP", dpopToken); - var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request); + var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request, _ct); response.IsError.ShouldBeTrue(); response.Error.ShouldBe("invalid_request"); @@ -166,11 +167,11 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase public async Task valid_dpop_request_should_return_bound_refresh_token(ParMode parMode) { var codeRequest = await CreateAuthCodeTokenRequestAsync(parMode: parMode); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.ShouldHaveDPoPThumbprint(JKT); var rtRequest = CreateRefreshTokenRequest(codeResponse); - var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest); + var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest, _ct); rtResponse.ShouldHaveDPoPThumbprint(JKT); } @@ -180,11 +181,11 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase public async Task confidential_client_dpop_proof_should_be_required_on_renewal(ParMode parMode) { var codeRequest = await CreateAuthCodeTokenRequestAsync(parMode: parMode); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.ShouldHaveDPoPThumbprint(JKT); var rtRequest = CreateRefreshTokenRequest(codeResponse, omitDPoPProof: true); - var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest); + var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest, _ct); rtResponse.IsError.ShouldBeTrue(); rtResponse.Error.ShouldBe("invalid_request"); } @@ -195,11 +196,11 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase public async Task public_client_dpop_proof_should_be_required_on_renewal(ParMode parMode) { var codeRequest = await CreateAuthCodeTokenRequestAsync(clientId: "client2", parMode: parMode); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.ShouldHaveDPoPThumbprint(JKT); var rtRequest = CreateRefreshTokenRequest(codeResponse, clientId: "client2", omitDPoPProof: true); - var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest); + var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest, _ct); rtResponse.IsError.ShouldBeTrue(); rtResponse.Error.ShouldBe("invalid_request"); } @@ -212,13 +213,13 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase { // Initial code flow doesn't use dpop var codeRequest = await CreateAuthCodeTokenRequestAsync(omitDPoPProofAtTokenEndpoint: true, parMode: parMode); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.IsError.ShouldBeFalse(); // Subsequent refresh token request tries to use dpop var rtRequest = CreateRefreshTokenRequest(codeResponse, omitDPoPProof: false); - var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest); + var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest, _ct); rtResponse.IsError.ShouldBeTrue(); } @@ -228,13 +229,13 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase public async Task confidential_client_should_be_able_to_use_different_dpop_key_for_refresh_token_request(ParMode parMode) { var codeRequest = await CreateAuthCodeTokenRequestAsync(parMode: parMode); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.ShouldHaveDPoPThumbprint(JKT); CreateNewRSAKey(); var rtRequest = CreateRefreshTokenRequest(codeResponse); - var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest); + var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest, _ct); rtResponse.ShouldHaveDPoPThumbprint(JKT); } @@ -244,13 +245,13 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase public async Task public_client_should_not_be_able_to_use_different_dpop_key_for_refresh_token_request(ParMode parMode) { var codeRequest = await CreateAuthCodeTokenRequestAsync(clientId: "client2", parMode: parMode); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.ShouldHaveDPoPThumbprint(JKT); CreateNewRSAKey(); var rtRequest = CreateRefreshTokenRequest(codeResponse, clientId: "client2"); - var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest); + var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest, _ct); rtResponse.IsError.ShouldBeTrue(); rtResponse.Error.ShouldBe("invalid_dpop_proof"); } @@ -261,15 +262,15 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase public async Task public_client_using_same_dpop_key_for_refresh_token_request_should_succeed(ParMode parMode) { var codeRequest = await CreateAuthCodeTokenRequestAsync(clientId: "client2", parMode: parMode); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.ShouldHaveDPoPThumbprint(JKT); var firstRefreshRequest = CreateRefreshTokenRequest(codeResponse, clientId: "client2"); - var firstRefreshResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(firstRefreshRequest); + var firstRefreshResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(firstRefreshRequest, _ct); firstRefreshResponse.ShouldHaveDPoPThumbprint(JKT); var secondRefreshRequest = CreateRefreshTokenRequest(codeResponse, clientId: "client2"); - var secondRefreshResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(secondRefreshRequest); + var secondRefreshResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(secondRefreshRequest, _ct); secondRefreshResponse.ShouldHaveDPoPThumbprint(JKT); } @@ -282,11 +283,11 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase ConfidentialClient.RequireDPoP = true; var codeRequest = await CreateAuthCodeTokenRequestAsync(parMode: parMode); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.ShouldHaveDPoPThumbprint(JKT); var rtRequest = CreateRefreshTokenRequest(codeResponse, omitDPoPProof: true); - var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest); + var rtResponse = await Pipeline.BackChannelClient.RequestRefreshTokenAsync(rtRequest, _ct); rtResponse.IsError.ShouldBeTrue(); rtResponse.Error.ShouldBe("invalid_request"); } @@ -299,7 +300,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase { ConfidentialClient.AccessTokenType = accessTokenType; var codeRequest = await CreateAuthCodeTokenRequestAsync(); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); var introspectionRequest = new TokenIntrospectionRequest { @@ -308,7 +309,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase ClientSecret = "secret", Token = codeResponse.AccessToken, }; - var introspectionResponse = await Pipeline.BackChannelClient.IntrospectTokenAsync(introspectionRequest); + var introspectionResponse = await Pipeline.BackChannelClient.IntrospectTokenAsync(introspectionRequest, _ct); introspectionResponse.IsError.ShouldBeFalse(); GetJKTFromCnfClaim(introspectionResponse.Claims).ShouldBe(JKT); } @@ -319,7 +320,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase { var codeRequest = await CreateAuthCodeTokenRequestAsync(dpopJkt: JKT); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.ShouldHaveDPoPThumbprint(JKT); } @@ -337,7 +338,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase { dpop_jkt = new string('x', 101) }); - await Pipeline.BrowserClient.GetAsync(url); + await Pipeline.BrowserClient.GetAsync(url, _ct); Pipeline.ErrorWasCalled.ShouldBeTrue(); } @@ -356,7 +357,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase JKT.ShouldNotBe(oldJkt); var codeRequest = await CreateAuthCodeTokenRequestAsync(parMode: parMode, dpopJkt: oldJkt, dpopProof: oldProof); - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.IsError.ShouldBeTrue(); codeResponse.Error.ShouldBe("invalid_dpop_proof"); } @@ -386,7 +387,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase { return; } - var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest); + var codeResponse = await Pipeline.BackChannelClient.RequestAuthorizationCodeTokenAsync(codeRequest, _ct); codeResponse.IsError.ShouldBeTrue(); codeResponse.Error.ShouldBe(OidcConstants.TokenErrors.UseDPoPNonce); codeResponse.DPoPNonce.ShouldBe(expectedNonce); @@ -428,10 +429,10 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase }; var form = new FormUrlEncodedContent(formParams); - var response = await tokenClient.PostAsync(IdentityServerPipeline.TokenMtlsEndpoint, form); + var response = await tokenClient.PostAsync(IdentityServerPipeline.TokenMtlsEndpoint, form, _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); json.ShouldContain("access_token"); json.ShouldContain("\"token_type\":\"DPoP\""); } @@ -485,7 +486,7 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase var proofToken = CreateDPoPProofToken(alg); var request = CreateClientCredentialsTokenRequest(proofToken); - var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request); + var response = await Pipeline.BackChannelClient.RequestClientCredentialsTokenAsync(request, _ct); response.IsError.ShouldBeFalse(); response.TokenType.ShouldBe("DPoP"); @@ -533,11 +534,11 @@ public class DPoPTokenEndpointTests : DPoPEndpointTestBase var form = new FormUrlEncodedContent(formParams); tokenClient.DefaultRequestHeaders.Add("DPoP", CreateDPoPProofToken(htu: IdentityServerPipeline.TokenMtlsEndpoint)); - var response = await tokenClient.PostAsync(IdentityServerPipeline.TokenMtlsEndpoint, form); + var response = await tokenClient.PostAsync(IdentityServerPipeline.TokenMtlsEndpoint, form, _ct); response.StatusCode.ShouldBe(System.Net.HttpStatusCode.OK); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); json.ShouldContain("access_token"); json.ShouldContain("\"token_type\":\"DPoP\""); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/MtlsTokenEndpointTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/MtlsTokenEndpointTests.cs index 708faf54c..d9b853d6f 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/MtlsTokenEndpointTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/MtlsTokenEndpointTests.cs @@ -10,8 +10,8 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Token; public class MtlsTokenEndpointTests { private const string Category = "mTLS Token endpoint"; - - private IdentityServerPipeline _pipeline = new IdentityServerPipeline(); + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _pipeline = new IdentityServerPipeline(); [Fact] [Trait("Category", Category)] @@ -57,12 +57,12 @@ public class MtlsTokenEndpointTests }; var form = new FormUrlEncodedContent(formParams); - var response = await tokenClient.PostAsync(IdentityServerPipeline.TokenMtlsEndpoint, form); + var response = await tokenClient.PostAsync(IdentityServerPipeline.TokenMtlsEndpoint, form, _ct); // Assert response.StatusCode.ShouldBe(System.Net.HttpStatusCode.OK); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); json.ShouldContain("access_token"); json.ShouldContain("\"token_type\":\"Bearer\""); } @@ -99,12 +99,12 @@ public class MtlsTokenEndpointTests }; var form = new FormUrlEncodedContent(formParams); - var response = await tokenClient.PostAsync(IdentityServerPipeline.TokenEndpoint, form); + var response = await tokenClient.PostAsync(IdentityServerPipeline.TokenEndpoint, form, _ct); // Assert response.StatusCode.ShouldBe(System.Net.HttpStatusCode.OK); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); json.ShouldContain("access_token"); json.ShouldContain("\"token_type\":\"Bearer\""); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs index 940f18fe8..7131ec3eb 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/RefreshTokenTests.cs @@ -15,12 +15,11 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Token; public class RefreshTokenTests { private const string Category = "Refresh Token Tests"; - + private const string client_id = "client"; + private const string client_secret = "secret"; + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly Client _client; - private string client_id = "client"; - private string client_secret = "secret"; - - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); public RefreshTokenTests() { @@ -91,7 +90,7 @@ public class RefreshTokenTests Code = code, RedirectUri = "https://client/callback" - }); + }, _ct); tokenResult1.IsError.ShouldBeFalse(); tokenResult1.AccessToken.ShouldNotBeNull(); @@ -109,7 +108,7 @@ public class RefreshTokenTests ClientCredentialStyle = ClientCredentialStyle.PostBody, RefreshToken = tokenResult1.RefreshToken - }); + }, _ct); tokenResult2.IsError.ShouldBeFalse(); tokenResult2.AccessToken.ShouldNotBeNull(); @@ -149,7 +148,7 @@ public class RefreshTokenTests Code = code, RedirectUri = "https://client/callback" - }); + }, _ct); tokenResult1.IsError.ShouldBeFalse(); tokenResult1.AccessToken.ShouldNotBeNull(); @@ -167,7 +166,7 @@ public class RefreshTokenTests ClientCredentialStyle = ClientCredentialStyle.PostBody, RefreshToken = tokenResult1.RefreshToken - }); + }, _ct); tokenResult2.IsError.ShouldBeFalse(); tokenResult2.AccessToken.ShouldNotBeNull(); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/ResourceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/ResourceTests.cs index 339fd04d2..6f4331a69 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/ResourceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/ResourceTests.cs @@ -14,13 +14,13 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Token; public class ResourceTests { private const string Category = "Token endpoint"; + private const string client_id = "client"; + private const string client_secret = "secret"; + private const string username = "bob"; + private const string password = "password"; - private string client_id = "client"; - private string client_secret = "secret"; - private string username = "bob"; - private string password = "password"; - - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); public ResourceTests() { @@ -33,7 +33,6 @@ public class ResourceTests AllowOfflineAccess = true, }); - _mockPipeline.Users.Add(new TestUser { SubjectId = "bob", @@ -87,12 +86,13 @@ public class ResourceTests Address = IdentityServerPipeline.TokenEndpoint, ClientId = client_id, ClientSecret = client_secret, - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1", "urn:api2"]); claims.Where(x => x.Type == "scope").Select(x => x.Value).ShouldBe(["scope1", "scope2", "scope3", "scope4"]); } + [Fact] [Trait("Category", Category)] public async Task client_credentials_with_resource_without_scope_should_succeed() @@ -107,7 +107,7 @@ public class ResourceTests { { "resource", "urn:api1" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1"]); @@ -123,7 +123,7 @@ public class ResourceTests { { "resource", "urn:api2" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api2"]); @@ -139,13 +139,14 @@ public class ResourceTests { { "resource", "urn:api3" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api3"]); claims.Where(x => x.Type == "scope").Select(x => x.Value).ShouldBe(["scope1", "scope3"]); } } + [Fact] [Trait("Category", Category)] public async Task client_credentials_without_resource_with_scope_should_succeed() @@ -156,12 +157,13 @@ public class ResourceTests ClientId = client_id, ClientSecret = client_secret, Scope = "scope1", - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1"]); claims.Where(x => x.Type == "scope").Select(x => x.Value).ShouldBe(["scope1"]); } + [Fact] [Trait("Category", Category)] public async Task client_credentials_with_resource_with_scope_should_succeed() @@ -177,7 +179,7 @@ public class ResourceTests { { "resource", "urn:api1" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1"]); @@ -194,13 +196,14 @@ public class ResourceTests { { "resource", "urn:api3" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api3"]); claims.Where(x => x.Type == "scope").Select(x => x.Value).ShouldBe(["scope1"]); } } + [Fact] [Trait("Category", Category)] public async Task client_credentials_with_invalid_resource_and_scope_should_fail() @@ -216,7 +219,7 @@ public class ResourceTests { { "resource", "urn:api2" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } @@ -231,7 +234,7 @@ public class ResourceTests { { "resource", "urn:api3" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } @@ -246,7 +249,7 @@ public class ResourceTests { { "resource", "urn:api4" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } @@ -260,14 +263,13 @@ public class ResourceTests { { "resource", "urn:api4" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } } - [Fact] [Trait("Category", Category)] public async Task client_credentials_with_empty_resource_should_be_treated_as_if_no_resource_and_succeed() @@ -281,7 +283,7 @@ public class ResourceTests { { "resource", " " } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1", "urn:api2"]); @@ -299,12 +301,13 @@ public class ResourceTests ClientSecret = client_secret, UserName = username, Password = password, - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1", "urn:api2"]); claims.Where(x => x.Type == "scope").Select(x => x.Value).ShouldBe(["scope1", "scope2", "scope3", "scope4", "offline_access"]); } + [Fact] [Trait("Category", Category)] public async Task refresh_token_requested_with_resource_without_scope_should_succeed() @@ -321,7 +324,7 @@ public class ResourceTests { { "resource", "urn:api1" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1"]); @@ -340,7 +343,7 @@ public class ResourceTests { { "resource", "urn:api2" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api2"]); @@ -359,13 +362,14 @@ public class ResourceTests { { "resource", "urn:api3" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api3"]); claims.Where(x => x.Type == "scope").Select(x => x.Value).ShouldBe(["scope1", "scope3", "offline_access"]); } } + [Fact] [Trait("Category", Category)] public async Task refresh_token_requested_without_resource_with_scope_should_succeed() @@ -378,12 +382,13 @@ public class ResourceTests UserName = username, Password = password, Scope = "scope1 offline_access" - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1"]); claims.Where(x => x.Type == "scope").Select(x => x.Value).ShouldBe(["scope1", "offline_access"]); } + [Fact] [Trait("Category", Category)] public async Task refresh_token_requested_with_resource_with_scope_should_succeed() @@ -401,7 +406,7 @@ public class ResourceTests { { "resource", "urn:api1" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1"]); @@ -420,13 +425,14 @@ public class ResourceTests { { "resource", "urn:api3" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api3"]); claims.Where(x => x.Type == "scope").Select(x => x.Value).ShouldBe(["scope1", "offline_access"]); } } + [Fact] [Trait("Category", Category)] public async Task refresh_token_requested_with_invalid_resource_and_scope_should_fail() @@ -444,7 +450,7 @@ public class ResourceTests { { "resource", "urn:api2" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } @@ -461,7 +467,7 @@ public class ResourceTests { { "resource", "urn:api3" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } @@ -478,7 +484,7 @@ public class ResourceTests { { "resource", "urn:api4" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } @@ -495,14 +501,13 @@ public class ResourceTests { { "resource", "urn:api4" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } } - [Fact] [Trait("Category", Category)] public async Task refresh_token_exchange_with_resource_should_succeed() @@ -515,7 +520,7 @@ public class ResourceTests UserName = username, Password = password, Scope = "scope1 scope2 scope3 scope4 offline_access", - }); + }, _ct); { tokenResponse = await _mockPipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest @@ -524,7 +529,7 @@ public class ResourceTests ClientId = client_id, ClientSecret = client_secret, RefreshToken = tokenResponse.RefreshToken, - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1", "urn:api2"]); @@ -541,7 +546,7 @@ public class ResourceTests { { "resource", "urn:api1" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api1"]); @@ -558,7 +563,7 @@ public class ResourceTests { { "resource", "urn:api2" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(["urn:api2"]); @@ -575,13 +580,14 @@ public class ResourceTests { { "resource", "urn:api3" } } - }); + }, _ct); var claims = ParseAccessTokenClaims(tokenResponse); claims.Where(x => x.Type == "aud").Select(x => x.Value).ShouldBe(new[] { "urn:api3" }); claims.Where(x => x.Type == "scope").Select(x => x.Value).ShouldBe(new[] { "scope1", "scope3", "offline_access" }); } } + [Fact] [Trait("Category", Category)] public async Task refresh_token_exchange_with_invalid_resource_should_fail() @@ -595,7 +601,7 @@ public class ResourceTests UserName = username, Password = password, Scope = "scope1 scope2 scope3 scope4 offline_access", - }); + }, _ct); tokenResponse = await _mockPipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, @@ -606,7 +612,7 @@ public class ResourceTests { { "resource", "urn:api4" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } @@ -621,7 +627,7 @@ public class ResourceTests UserName = username, Password = password, Scope = "scope2 offline_access", - }); + }, _ct); tokenResponse = await _mockPipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, @@ -632,7 +638,7 @@ public class ResourceTests { { "resource", "urn:api1" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } @@ -646,7 +652,7 @@ public class ResourceTests UserName = username, Password = password, Scope = "scope4 offline_access", - }); + }, _ct); tokenResponse = await _mockPipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, @@ -657,7 +663,7 @@ public class ResourceTests { { "resource", "urn:api1" } } - }); + }, _ct); tokenResponse.IsError.ShouldBeTrue(); tokenResponse.Error.ShouldBe("invalid_target"); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/TokenEndpointTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/TokenEndpointTests.cs index 57b28065f..216e3a0e6 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/TokenEndpointTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Token/TokenEndpointTests.cs @@ -15,14 +15,12 @@ namespace Duende.IdentityServer.IntegrationTests.Endpoints.Token; public class TokenEndpointTests { private const string Category = "Token endpoint"; - - private string client_id = "client"; - private string client_secret = "secret"; - - private string scope_name = "api"; - private string scope_secret = "api_secret"; - - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); + private const string client_id = "client"; + private const string client_secret = "secret"; + private const string scope_name = "api"; + private const string scope_secret = "api_secret"; + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); public TokenEndpointTests() { @@ -84,10 +82,10 @@ public class TokenEndpointTests }; var form = new FormUrlEncodedContent(data); _mockPipeline.BackChannelClient.DefaultRequestHeaders.Add("Referer", "http://127.0.0.1:33086/appservice/appservice?t=1564165664142?load"); - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.TokenEndpoint, form); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.TokenEndpoint, form, _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var result = JsonSerializer.Deserialize>(json); result.ContainsKey("error").ShouldBeFalse(); } @@ -107,10 +105,10 @@ public class TokenEndpointTests }; var form = new FormUrlEncodedContent(data); _mockPipeline.BackChannelClient.DefaultRequestHeaders.Add("Referer", "http://127.0.0.1:33086/appservice/appservice?t=1564165664142?load"); - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.TokenEndpoint, form); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.TokenEndpoint, form, _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var result = JsonSerializer.Deserialize>(json); result.ContainsKey("error").ShouldBeFalse(); } @@ -122,10 +120,10 @@ public class TokenEndpointTests var text = $"grant_type=client_credentials&client_id={client_id}&client_secret={client_secret}&scope=%00"; var content = new StringContent(text, Encoding.UTF8, "application/x-www-form-urlencoded"); - var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.TokenEndpoint, content); + var response = await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.TokenEndpoint, content, _ct); response.StatusCode.ShouldBe(HttpStatusCode.BadRequest); - var json = await response.Content.ReadAsStringAsync(); + var json = await response.Content.ReadAsStringAsync(_ct); var result = JsonSerializer.Deserialize>(json); var error = result["error"].GetString(); error.ShouldBe("invalid_request"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/EntityFrameworkBasedLogoutTests.cs b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/EntityFrameworkBasedLogoutTests.cs index 59bc1285c..1999c763b 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/EntityFrameworkBasedLogoutTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/EntityFrameworkBasedLogoutTests.cs @@ -20,6 +20,7 @@ namespace Duende.IdentityServer.IntegrationTests.EntityFramework; public class EntityFrameworkBasedLogoutTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly IdentityServerPipeline _mockPipeline = new(); private static readonly ICollection _clients = @@ -74,7 +75,7 @@ public class EntityFrameworkBasedLogoutTests var options = DatabaseProviderBuilder.BuildSqlite("NotUsed", new OperationalStoreOptions(), TimeSpan.FromMilliseconds(1)); await using var context = new PersistedGrantDbContext(options); - await context.Database.EnsureCreatedAsync(); + await context.Database.EnsureCreatedAsync(_ct); _mockPipeline.OnPostConfigureServices += services => { @@ -98,7 +99,7 @@ public class EntityFrameworkBasedLogoutTests ClientId = client.ClientId, Code = authzResponse.Code, RedirectUri = client.RedirectUris.First() - }); + }, _ct); } //Clear cache to simulate needing to load from db when creating logout notifications to send diff --git a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/IntegrationTest.cs b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/IntegrationTest.cs index c250a5077..1e0a8ed53 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/IntegrationTest.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/IntegrationTest.cs @@ -15,12 +15,13 @@ namespace Duende.IdentityServer.IntegrationTests.EntityFramework; /// The type of the database context. /// The type of the store option. /// -public class IntegrationTest : IClassFixture> +public abstract class IntegrationTest : IClassFixture> where TDbContext : DbContext where TStoreOption : class { public static readonly TheoryData> TestDatabaseProviders; - protected static TStoreOption StoreOptions = Activator.CreateInstance(); + + protected static readonly TStoreOption StoreOptions = Activator.CreateInstance(); static IntegrationTest() { @@ -50,5 +51,6 @@ public class IntegrationTest : IClassFixture fixture) => fixture.Options = TestDatabaseProviders.ToList>(); + protected IntegrationTest(DatabaseProviderFixture fixture) + => fixture.Options = TestDatabaseProviders.Select(row => row.Data).ToList(); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Services/CorsPolicyServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Services/CorsPolicyServiceTests.cs index fe34b208a..0c33b3478 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Services/CorsPolicyServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Services/CorsPolicyServiceTests.cs @@ -15,6 +15,8 @@ namespace Duende.IdentityServer.IntegrationTests.EntityFramework.Services; public class CorsPolicyServiceTests : IntegrationTest { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + public CorsPolicyServiceTests(DatabaseProviderFixture fixture) : base(fixture) { foreach (var options in TestDatabaseProviders) @@ -43,7 +45,7 @@ public class CorsPolicyServiceTests : IntegrationTest { "https://www.identityserver.com", testCorsOrigin } }.ToEntity()); - await context.SaveChangesAsync(); + await context.SaveChangesAsync(_ct); } bool result; @@ -67,7 +69,7 @@ public class CorsPolicyServiceTests : IntegrationTest { "https://www.identityserver.com" } }.ToEntity()); - await context.SaveChangesAsync(); + await context.SaveChangesAsync(_ct); } bool result; diff --git a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/ClientStoreTests.cs b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/ClientStoreTests.cs index 1d0a039e7..14f00d5ee 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/ClientStoreTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/ClientStoreTests.cs @@ -16,6 +16,8 @@ namespace Duende.IdentityServer.IntegrationTests.EntityFramework.Storage.Stores; public class ClientStoreTests : IntegrationTest { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + public ClientStoreTests(DatabaseProviderFixture fixture) : base(fixture) { foreach (var options in TestDatabaseProviders) @@ -46,7 +48,7 @@ public class ClientStoreTests : IntegrationTest store.FindClientByIdAsync(testClient.ClientId)); - if (await Task.WhenAny(task, Task.Delay(timeout)) == task) + if (await Task.WhenAny(task, Task.Delay(timeout, _ct)) == task) { #pragma warning disable xUnit1031 // Do not use blocking task operations in test method, suppressed because the task must have completed to enter this block var client = task.Result; @@ -167,7 +169,7 @@ public class ClientStoreTests : IntegrationTest { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly IPersistentGrantSerializer serializer = new PersistentGrantSerializer(); public DeviceFlowStoreTests(DatabaseProviderFixture fixture) : base(fixture) @@ -116,7 +117,7 @@ public class DeviceFlowStoreTests : IntegrationTest { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + public IdentityProviderStoreTests(DatabaseProviderFixture fixture) : base(fixture) { foreach (var options in TestDatabaseProviders) @@ -24,8 +26,6 @@ public class IdentityProviderStoreTests : IntegrationTest options) { @@ -37,7 +37,7 @@ public class IdentityProviderStoreTests : IntegrationTest { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + public PersistedGrantStoreTests(DatabaseProviderFixture fixture) : base(fixture) { foreach (var options in TestDatabaseProviders) @@ -63,7 +65,7 @@ public class PersistedGrantStoreTests : IntegrationTest foundPersistedGrants; @@ -114,7 +116,7 @@ public class PersistedGrantStoreTests : IntegrationTest { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + public ScopeStoreTests(DatabaseProviderFixture fixture) : base(fixture) { foreach (var options in TestDatabaseProviders) @@ -69,7 +71,7 @@ public class ScopeStoreTests : IntegrationTest resources; @@ -164,7 +166,7 @@ public class ScopeStoreTests : IntegrationTest resources; @@ -187,7 +189,7 @@ public class ScopeStoreTests : IntegrationTest resources; @@ -218,7 +220,7 @@ public class ScopeStoreTests : IntegrationTest resources; @@ -244,7 +246,7 @@ public class ScopeStoreTests : IntegrationTest resources; @@ -275,7 +277,7 @@ public class ScopeStoreTests : IntegrationTest resources; @@ -322,7 +324,7 @@ public class ScopeStoreTests : IntegrationTest { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + public TokenCleanupTests(DatabaseProviderFixture fixture) : base(fixture) { foreach (var options in TestDatabaseProviders) @@ -54,10 +56,10 @@ public class TokenCleanupTests : IntegrationTest { svcs.AddSingleton(mockNotifications); - }).CleanupGrantsAsync(); + }).CleanupGrantsAsync(_ct); // The right number of batches executed mockNotifications.PersistedGrantNotifications.Count.ShouldBe(expectedPageCount); @@ -328,7 +330,7 @@ public class TokenCleanupTests : IntegrationTest { svcs.AddSingleton(mockNotifications); - }).CleanupGrantsAsync(); + }).CleanupGrantsAsync(_ct); // Each batch created an extra grant, so we do an extra batch to clean up // the extras @@ -414,10 +416,10 @@ public class TokenCleanupTests : IntegrationTest @@ -133,9 +134,7 @@ public class DynamicProvidersTests await ctx.SignInAsync(new IdentityServerUser("2").CreatePrincipal()); }); }; - _idp2.InitializeAsync().Wait(); - - + _idp2.InitializeAsync().AsTask().Wait(); _host = new GenericHost("https://server"); _host.OnConfigureServices += services => @@ -230,7 +229,7 @@ public class DynamicProvidersTests { await _host.InitializeAsync(); - var response = await _host.HttpClient.GetAsync(_host.Url("/challenge?scheme=idp1")); + var response = await _host.HttpClient.GetAsync(_host.Url("/challenge?scheme=idp1"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://idp1/connect/authorize"); @@ -241,7 +240,7 @@ public class DynamicProvidersTests { await _host.InitializeAsync(); - var response = await _host.HttpClient.GetAsync(_host.Url("/logout?scheme=idp1")); + var response = await _host.HttpClient.GetAsync(_host.Url("/logout?scheme=idp1"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://idp1/connect/endsession"); @@ -252,7 +251,7 @@ public class DynamicProvidersTests { await _host.InitializeAsync(); - var response = await _host.HttpClient.GetAsync(_host.Url("/challenge?scheme=idp2")); + var response = await _host.HttpClient.GetAsync(_host.Url("/challenge?scheme=idp2"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Headers.Location.ToString().ShouldStartWith("https://idp2/connect/authorize"); @@ -269,20 +268,20 @@ public class DynamicProvidersTests _configureIdentityServerOptions = testScenario.ConfigureOptions; await _host.InitializeAsync(); - var response = await _host.BrowserClient.GetAsync(_host.Url("/challenge?scheme=idp1")); + var response = await _host.BrowserClient.GetAsync(_host.Url("/challenge?scheme=idp1"), _ct); var authzUrl = response.Headers.Location.ToString(); - await _idp1.BrowserClient.GetAsync(_idp1.Url("/signin")); - response = await _idp1.BrowserClient.GetAsync(authzUrl); + await _idp1.BrowserClient.GetAsync(_idp1.Url("/signin"), _ct); + response = await _idp1.BrowserClient.GetAsync(authzUrl, _ct); var redirectUri = response.Headers.Location.ToString(); redirectUri.ShouldStartWith("https://server/federation/idp1/signin"); - response = await _host.BrowserClient.GetAsync(redirectUri); + response = await _host.BrowserClient.GetAsync(redirectUri, _ct); response.Headers.Location.ToString().ShouldStartWith("/callback"); - response = await _host.BrowserClient.GetAsync(_host.Url("/callback")); + response = await _host.BrowserClient.GetAsync(_host.Url("/callback"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var body = await response.Content.ReadAsStringAsync(); + var body = await response.Content.ReadAsStringAsync(_ct); body.ShouldBe("1"); // sub } @@ -291,18 +290,18 @@ public class DynamicProvidersTests { await _host.InitializeAsync(); - var response = await _host.BrowserClient.GetAsync(_host.Url("/challenge?scheme=idp2")); + var response = await _host.BrowserClient.GetAsync(_host.Url("/challenge?scheme=idp2"), _ct); var authzUrl = response.Headers.Location.ToString(); - await _idp2.BrowserClient.GetAsync(_idp2.Url("/signin")); - response = await _idp2.BrowserClient.GetAsync(authzUrl); + await _idp2.BrowserClient.GetAsync(_idp2.Url("/signin"), _ct); + response = await _idp2.BrowserClient.GetAsync(authzUrl, _ct); var redirectUri = response.Headers.Location.ToString(); redirectUri.ShouldStartWith("https://server/signin-oidc"); - response = await _host.BrowserClient.GetAsync(redirectUri); - response = await _host.BrowserClient.GetAsync(_host.Url(response.Headers.Location.ToString())); // ~/callback + response = await _host.BrowserClient.GetAsync(redirectUri, _ct); + response = await _host.BrowserClient.GetAsync(_host.Url(response.Headers.Location.ToString()), _ct); // ~/callback response.StatusCode.ShouldBe(HttpStatusCode.OK); - var body = await response.Content.ReadAsStringAsync(); + var body = await response.Content.ReadAsStringAsync(_ct); body.ShouldBe("2"); // sub } @@ -313,22 +312,22 @@ public class DynamicProvidersTests _configureIdentityServerOptions = testScenario.ConfigureOptions; await _host.InitializeAsync(); - var response = await _host.BrowserClient.GetAsync(_host.Url("/challenge?scheme=idp1")); + var response = await _host.BrowserClient.GetAsync(_host.Url("/challenge?scheme=idp1"), _ct); var authzUrl = response.Headers.Location.ToString(); - await _idp1.BrowserClient.GetAsync(_idp1.Url("/signin")); - response = await _idp1.BrowserClient.GetAsync(authzUrl); + await _idp1.BrowserClient.GetAsync(_idp1.Url("/signin"), _ct); + response = await _idp1.BrowserClient.GetAsync(authzUrl, _ct); var redirectUri = response.Headers.Location.ToString(); redirectUri.ShouldStartWith("https://server/federation/idp1/signin"); var cache = _host.Resolve>() as DefaultCache; await cache.RemoveAsync("test"); - response = await _host.BrowserClient.GetAsync(redirectUri); + response = await _host.BrowserClient.GetAsync(redirectUri, _ct); - response = await _host.BrowserClient.GetAsync(_host.Url(response.Headers.Location.ToString())); + response = await _host.BrowserClient.GetAsync(_host.Url(response.Headers.Location.ToString()), _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); - var body = await response.Content.ReadAsStringAsync(); + var body = await response.Content.ReadAsStringAsync(_ct); body.ShouldBe("1"); // sub } @@ -339,37 +338,37 @@ public class DynamicProvidersTests _configureIdentityServerOptions = testScenario.ConfigureOptions; await _host.InitializeAsync(); - var response = await _host.BrowserClient.GetAsync(_host.Url("/challenge?scheme=idp1")); + var response = await _host.BrowserClient.GetAsync(_host.Url("/challenge?scheme=idp1"), _ct); var authzUrl = response.Headers.Location.ToString(); - await _idp1.BrowserClient.GetAsync(_idp1.Url("/signin")); - response = await _idp1.BrowserClient.GetAsync(authzUrl); // ~idp1/connect/authorize + await _idp1.BrowserClient.GetAsync(_idp1.Url("/signin"), _ct); + response = await _idp1.BrowserClient.GetAsync(authzUrl, _ct); // ~idp1/connect/authorize var redirectUri = response.Headers.Location.ToString(); - response = await _host.BrowserClient.GetAsync(redirectUri); // federation/idp1/signin - response = await _host.BrowserClient.GetAsync(_host.Url("/callback")); // signs the user in + response = await _host.BrowserClient.GetAsync(redirectUri, _ct); // federation/idp1/signin + response = await _host.BrowserClient.GetAsync(_host.Url("/callback"), _ct); // signs the user in - response = await _host.BrowserClient.GetAsync(_host.Url("/user")); + response = await _host.BrowserClient.GetAsync(_host.Url("/user"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); - response = await _host.BrowserClient.GetAsync(_host.Url("/logout?scheme=idp1")); + response = await _host.BrowserClient.GetAsync(_host.Url("/logout?scheme=idp1"), _ct); var endSessionUrl = response.Headers.Location.ToString(); - response = await _idp1.BrowserClient.GetAsync(endSessionUrl); - response = await _idp1.BrowserClient.GetAsync(response.Headers.Location.ToString()); // ~/idp1/account/logout + response = await _idp1.BrowserClient.GetAsync(endSessionUrl, _ct); + response = await _idp1.BrowserClient.GetAsync(response.Headers.Location.ToString(), _ct); // ~/idp1/account/logout - var page = await _idp1.BrowserClient.GetAsync(Idp1FrontChannelLogoutUri); + var page = await _idp1.BrowserClient.GetAsync(Idp1FrontChannelLogoutUri, _ct); var iframeUrl = await _idp1.BrowserClient.ReadElementAttributeAsync("iframe", "src"); - response = await _host.BrowserClient.GetAsync(_host.Url("/user")); + response = await _host.BrowserClient.GetAsync(_host.Url("/user"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); iframeUrl.ShouldStartWith(_host.Url("/federation/idp1/signout")); - response = await _host.BrowserClient.GetAsync(iframeUrl); // ~/federation/idp1/signout + response = await _host.BrowserClient.GetAsync(iframeUrl, _ct); // ~/federation/idp1/signout response.IsSuccessStatusCode.ShouldBeTrue(); - response = await _host.BrowserClient.GetAsync(_host.Url("/user")); + response = await _host.BrowserClient.GetAsync(_host.Url("/user"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } #endif @@ -381,7 +380,7 @@ public class DynamicProvidersTests _configureIdentityServerOptions = testScenario.ConfigureOptions; await _host.InitializeAsync(); - var response = await _host.HttpClient.GetAsync(_host.Url("/federation/idp1")); + var response = await _host.HttpClient.GetAsync(_host.Url("/federation/idp1"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.NotFound); } @@ -392,7 +391,7 @@ public class DynamicProvidersTests _configureIdentityServerOptions = testScenario.ConfigureOptions; await _host.InitializeAsync(); - var response = await _host.HttpClient.GetAsync(_host.Url("/federation")); + var response = await _host.HttpClient.GetAsync(_host.Url("/federation"), _ct); response.StatusCode.ShouldBe(HttpStatusCode.NotFound); } @@ -403,21 +402,15 @@ public class DynamicProvidersTests public override string ToString() => Name; } - private class DynamicProviderConfigurationData : TheoryData + private sealed class DynamicProviderConfigurationData : TheoryData { public DynamicProviderConfigurationData() { - Add(new("Default PathPrefix", _ => { })); - Add(new("PathPrefix Callback", - options => options.DynamicProviders.PathMatchingCallback = ctx => - { - if (ctx.Request.Path.StartsWithSegments("/federation/idp1", StringComparison.InvariantCulture)) - { - return Task.FromResult("idp1"); - } - - return Task.FromResult((string)null); - })); + Add(new DynamicProviderTestScenario("Default PathPrefix", _ => { })); + Add(new DynamicProviderTestScenario("PathPrefix Callback", + options => options.DynamicProviders.PathMatchingCallback = ctx => ctx.Request.Path.StartsWithSegments("/federation/idp1", StringComparison.InvariantCulture) + ? Task.FromResult("idp1") + : Task.FromResult((string)null))); } } } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Hosting/FederatedSignoutTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Hosting/FederatedSignoutTests.cs index e14e20f48..517e9462c 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Hosting/FederatedSignoutTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Hosting/FederatedSignoutTests.cs @@ -15,9 +15,9 @@ namespace Duende.IdentityServer.IntegrationTests.Hosting; public class FederatedSignoutTests { private const string Category = "Federated Signout"; - - private IdentityServerPipeline _pipeline = new IdentityServerPipeline(); - private ClaimsPrincipal _user; + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _pipeline = new IdentityServerPipeline(); + private readonly ClaimsPrincipal _user; public FederatedSignoutTests() { @@ -72,11 +72,11 @@ public class FederatedSignoutTests state: "123_state", nonce: "123_nonce"); - var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.FederatedSignOutUrl + "?sid=123"); + var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.FederatedSignOutUrl + "?sid=123", _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); response.Content.Headers.ContentType.MediaType.ShouldBe("text/html"); - var html = await response.Content.ReadAsStringAsync(); + var html = await response.Content.ReadAsStringAsync(_ct); html.ShouldContain("https://server/connect/endsession/callback?endSessionId="); } @@ -93,11 +93,11 @@ public class FederatedSignoutTests state: "123_state", nonce: "123_nonce"); - var response = await _pipeline.BrowserClient.PostAsync(IdentityServerPipeline.FederatedSignOutUrl, new FormUrlEncodedContent(new Dictionary { { "sid", "123" } })); + var response = await _pipeline.BrowserClient.PostAsync(IdentityServerPipeline.FederatedSignOutUrl, new FormUrlEncodedContent(new Dictionary { { "sid", "123" } }), _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); response.Content.Headers.ContentType.MediaType.ShouldBe("text/html"); - var html = await response.Content.ReadAsStringAsync(); + var html = await response.Content.ReadAsStringAsync(_ct); html.ShouldContain("https://server/connect/endsession/callback?endSessionId="); } @@ -106,22 +106,22 @@ public class FederatedSignoutTests { await _pipeline.LoginAsync(_user); - var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.FederatedSignOutUrl + "?sid=123"); + var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.FederatedSignOutUrl + "?sid=123", _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); response.Content.Headers.ContentType.ShouldBeNull(); - var html = await response.Content.ReadAsStringAsync(); + var html = await response.Content.ReadAsStringAsync(_ct); html.ShouldBe(string.Empty); } [Fact] public async Task no_authenticated_user_should_not_render_page_with_iframe() { - var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.FederatedSignOutUrl + "?sid=123"); + var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.FederatedSignOutUrl + "?sid=123", _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); response.Content.Headers.ContentType.ShouldBeNull(); - var html = await response.Content.ReadAsStringAsync(); + var html = await response.Content.ReadAsStringAsync(_ct); html.ShouldBe(string.Empty); } @@ -143,11 +143,11 @@ public class FederatedSignoutTests state: "123_state", nonce: "123_nonce"); - var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.FederatedSignOutUrl + "?sid=123"); + var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.FederatedSignOutUrl + "?sid=123", _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); response.Content.Headers.ContentType.ShouldBeNull(); - var html = await response.Content.ReadAsStringAsync(); + var html = await response.Content.ReadAsStringAsync(_ct); html.ShouldBe(string.Empty); } @@ -172,11 +172,11 @@ public class FederatedSignoutTests nonce: "123_nonce"); _pipeline.BrowserClient.AllowAutoRedirect = false; - var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.FederatedSignOutUrl + "?sid=123"); + var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.FederatedSignOutUrl + "?sid=123", _ct); response.StatusCode.ShouldBe(HttpStatusCode.Redirect); response.Content.Headers.ContentType.ShouldBeNull(); - var html = await response.Content.ReadAsStringAsync(); + var html = await response.Content.ReadAsStringAsync(_ct); html.ShouldBe(string.Empty); } } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Hosting/IdentityServerMiddlewareTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Hosting/IdentityServerMiddlewareTests.cs index 673b02cdb..e622a7f78 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Hosting/IdentityServerMiddlewareTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Hosting/IdentityServerMiddlewareTests.cs @@ -20,6 +20,7 @@ public class FailRouter : IEndpointRouter public class IdentityServerMiddlewareTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private IdentityServerPipeline _pipeline = new IdentityServerPipeline(); public static readonly TheoryData ExceptionFilteringTestCases = new TheoryData { @@ -91,7 +92,7 @@ public class IdentityServerMiddlewareTests pipeline.OnPreConfigure += builder => builder.Use(next => context => testActivityMiddleware.Handle(context, next)); pipeline.Initialize(); - await pipeline.BackChannelClient.GetAsync($"https://server{path}"); + await pipeline.BackChannelClient.GetAsync($"https://server{path}", _ct); if (displayNameShouldBeSet) { @@ -113,7 +114,7 @@ public class IdentityServerMiddlewareTests var clientCert = TestCert.Load(); pipeline.SetClientCertificate(clientCert); - await pipeline.MtlsBackChannelClient.GetAsync(IdentityServerPipeline.TokenMtlsEndpoint); + await pipeline.MtlsBackChannelClient.GetAsync(IdentityServerPipeline.TokenMtlsEndpoint, _ct); var path = IdentityServerPipeline.TokenMtlsEndpoint.Substring(14); // trim off "https://server" testActivityMiddleware.CapturedActivity.DisplayName.ShouldBe($"GET {path}"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Hosting/LicenseTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Hosting/LicenseTests.cs index 9d5af7916..1e997cf83 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Hosting/LicenseTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Hosting/LicenseTests.cs @@ -10,6 +10,7 @@ namespace Duende.IdentityServer.IntegrationTests.Hosting; public class LicenseTests : IDisposable { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private string client_id = "client"; private string client_secret = "secret"; private string scope_name = "api"; @@ -68,7 +69,7 @@ public class LicenseTests : IDisposable for (var i = 0; i < threshold + 1; i++) { - await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.TokenEndpoint, form); + await _mockPipeline.BackChannelClient.PostAsync(IdentityServerPipeline.TokenEndpoint, form, _ct); } _mockPipeline.MockLogger.LogMessages.ShouldContain( diff --git a/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs index 5ee8c133f..8e9ecb21a 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Hosting/LocalApiAuthentication/LocalApiAuthenticationTests.cs @@ -24,15 +24,15 @@ namespace Duende.IdentityServer.IntegrationTests.Hosting.LocalApiAuthentication; public class LocalApiAuthenticationTests { private const string Category = "Local API Integration"; - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private IdentityServerPipeline _pipeline = new IdentityServerPipeline(); - private static string _jwk; private Client _client; public LocalApiTokenMode Mode { get; set; } public bool ApiWasCalled { get; set; } + public ClaimsPrincipal ApiPrincipal { get; set; } static LocalApiAuthenticationTests() => _jwk = GenerateJwk(); @@ -240,7 +240,7 @@ public class LocalApiAuthenticationTests var at = await GetAccessTokenAsync(); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", at); - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); ApiWasCalled.ShouldBeTrue(); @@ -257,7 +257,7 @@ public class LocalApiAuthenticationTests var at = await GetAccessTokenAsync(); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", at); - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); ApiWasCalled.ShouldBeTrue(); @@ -273,7 +273,7 @@ public class LocalApiAuthenticationTests req.Headers.Authorization = new AuthenticationHeaderValue("DPoP", at); req.Headers.Add("DPoP", CreateProofToken("GET", "https://server/api", at)); - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeTrue(); ApiWasCalled.ShouldBeTrue(); @@ -310,7 +310,7 @@ public class LocalApiAuthenticationTests accessTokenJkt.ShouldNotBe(newJkt); } - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } @@ -339,7 +339,7 @@ public class LocalApiAuthenticationTests ClientSecret = "secret", Token = at }; - var introspectionResponse = await _pipeline.BackChannelClient.IntrospectTokenAsync(introspectionRequest); + var introspectionResponse = await _pipeline.BackChannelClient.IntrospectTokenAsync(introspectionRequest, _ct); introspectionResponse.IsError.ShouldBeFalse(); var cnf = introspectionResponse.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.Confirmation); @@ -350,7 +350,7 @@ public class LocalApiAuthenticationTests accessTokenJkt.ShouldNotBe(newJkt); } - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.StatusCode.ShouldBe(HttpStatusCode.Unauthorized); } @@ -365,7 +365,7 @@ public class LocalApiAuthenticationTests req.Headers.Add("DPoP", CreateProofToken("GET", "https://server/api", at)); _client.DPoPValidationMode = DPoPTokenExpirationValidationMode.Nonce; - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeFalse(); response.Headers.Contains("DPoP-Nonce").ShouldBeTrue(); @@ -381,14 +381,14 @@ public class LocalApiAuthenticationTests req.Headers.Add("DPoP", CreateProofToken("GET", "https://server/api", at)); _client.DPoPValidationMode = DPoPTokenExpirationValidationMode.Nonce; - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); var nonce = response.Headers.GetValues("DPoP-Nonce").FirstOrDefault(); var req2 = new HttpRequestMessage(HttpMethod.Get, "https://server/api"); req2.Headers.Authorization = new AuthenticationHeaderValue("DPoP", at); req2.Headers.Add("DPoP", CreateProofToken("GET", "https://server/api", at, nonce)); - var response2 = await _pipeline.BackChannelClient.SendAsync(req2); + var response2 = await _pipeline.BackChannelClient.SendAsync(req2, _ct); response2.IsSuccessStatusCode.ShouldBeTrue(); } @@ -402,7 +402,7 @@ public class LocalApiAuthenticationTests req.Headers.Authorization = new AuthenticationHeaderValue("DPoP", at); req.Headers.Add("DPoP", CreateProofToken("GET", "https://server/api", at)); - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeFalse(); response.Headers.WwwAuthenticate.Select(x => x.Scheme).ShouldBe(["Bearer"]); @@ -418,7 +418,7 @@ public class LocalApiAuthenticationTests var at = await GetAccessTokenAsync(); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", at); - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeFalse(); response.Headers.WwwAuthenticate.Select(x => x.Scheme).ShouldBe(["DPoP"]); @@ -430,7 +430,7 @@ public class LocalApiAuthenticationTests { var req = new HttpRequestMessage(HttpMethod.Get, "https://server/api"); - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeFalse(); response.Headers.WwwAuthenticate.Select(x => x.Scheme).ShouldBe(["Bearer", "DPoP"]); @@ -442,7 +442,7 @@ public class LocalApiAuthenticationTests var req = new HttpRequestMessage(HttpMethod.Get, "https://server/api"); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", ""); - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeFalse(); } @@ -454,7 +454,7 @@ public class LocalApiAuthenticationTests var at = await GetAccessTokenAsync(); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", at.Substring(at.Length / 2)); - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeFalse(); } @@ -470,7 +470,7 @@ public class LocalApiAuthenticationTests _client.Enabled = false; - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeFalse(); } @@ -483,7 +483,7 @@ public class LocalApiAuthenticationTests var at = await GetAccessTokenAsync(true); req.Headers.Authorization = new AuthenticationHeaderValue("DPoP", at); - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeFalse(); } @@ -495,7 +495,7 @@ public class LocalApiAuthenticationTests var at = await GetAccessTokenAsync(true); req.Headers.Authorization = new AuthenticationHeaderValue("Bearer", at); - var response = await _pipeline.BackChannelClient.SendAsync(req); + var response = await _pipeline.BackChannelClient.SendAsync(req, _ct); response.IsSuccessStatusCode.ShouldBeFalse(); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/Hosting/ServerSideSessionTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Hosting/ServerSideSessionTests.cs index 6dadc19fd..bbfa3ad01 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Hosting/ServerSideSessionTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Hosting/ServerSideSessionTests.cs @@ -24,15 +24,15 @@ public class ServerSideSessionTests { private const string Category = "Server Side Sessions"; - private IdentityServerPipeline _pipeline = new IdentityServerPipeline(); - private IServerSideSessionStore _sessionStore; - private IServerSideTicketStore _ticketService; - private ISessionManagementService _sessionMgmt; - private IPersistedGrantStore _grantStore; + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _pipeline = new IdentityServerPipeline(); + private readonly IServerSideSessionStore _sessionStore; + private readonly IServerSideTicketStore _ticketService; + private readonly ISessionManagementService _sessionMgmt; + private readonly IPersistedGrantStore _grantStore; private IRefreshTokenStore _refreshTokenStore; - private IDataProtector _protector; - - private MockServerUrls _urls = new MockServerUrls(); + private readonly IDataProtector _protector; + private readonly MockServerUrls _urls = new MockServerUrls(); public class MockServerUrls : IServerUrls { @@ -127,7 +127,7 @@ public class ServerSideSessionTests private async Task IsLoggedIn() { - var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.BaseUrl + "/user"); + var response = await _pipeline.BrowserClient.GetAsync(IdentityServerPipeline.BaseUrl + "/user", _ct); return response.StatusCode == System.Net.HttpStatusCode.OK; } @@ -135,9 +135,9 @@ public class ServerSideSessionTests [Trait("Category", Category)] public async Task login_should_create_server_side_session() { - (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" })).ShouldBeEmpty(); + (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct)).ShouldBeEmpty(); await _pipeline.LoginAsync("bob"); - (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" })).ShouldNotBeEmpty(); + (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct)).ShouldNotBeEmpty(); (await IsLoggedIn()).ShouldBeTrue(); } @@ -150,7 +150,7 @@ public class ServerSideSessionTests ShouldRenewCookie = true; (await IsLoggedIn()).ShouldBeTrue(); - (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" })).ShouldNotBeEmpty(); + (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct)).ShouldNotBeEmpty(); } [Fact] @@ -159,8 +159,8 @@ public class ServerSideSessionTests { await _pipeline.LoginAsync("bob"); - await _sessionStore.DeleteSessionsAsync(new SessionFilter { SubjectId = "bob" }); - (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" })).ShouldBeEmpty(); + await _sessionStore.DeleteSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct); + (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct)).ShouldBeEmpty(); (await IsLoggedIn()).ShouldBeFalse(); } @@ -172,7 +172,7 @@ public class ServerSideSessionTests await _pipeline.LoginAsync("bob"); await _pipeline.LogoutAsync(); - (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" })).ShouldBeEmpty(); + (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct)).ShouldBeEmpty(); (await IsLoggedIn()).ShouldBeFalse(); } @@ -183,13 +183,13 @@ public class ServerSideSessionTests { await _pipeline.LoginAsync("bob"); - var sessions = await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }); - var session = await _sessionStore.GetSessionAsync(sessions.Single().Key); + var sessions = await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct); + var session = await _sessionStore.GetSessionAsync(sessions.Single().Key, _ct); session.Ticket = "invalid"; - await _sessionStore.UpdateSessionAsync(session); + await _sessionStore.UpdateSessionAsync(session, _ct); (await IsLoggedIn()).ShouldBeFalse(); - (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" })).ShouldBeEmpty(); + (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct)).ShouldBeEmpty(); } [Fact] @@ -198,12 +198,12 @@ public class ServerSideSessionTests { await _pipeline.LoginAsync("bob"); - var key = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" })).Single().Key; + var key = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct)).Single().Key; await _pipeline.LoginAsync("bob"); (await IsLoggedIn()).ShouldBeTrue(); - var sessions = await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }); + var sessions = await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct); sessions.First().Key.ShouldBe(key); } @@ -213,13 +213,13 @@ public class ServerSideSessionTests { await _pipeline.LoginAsync("bob"); - var bob_session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" })).Single(); + var bob_session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "bob" }, _ct)).Single(); - await Task.Delay(1000); + await Task.Delay(1000, _ct); await _pipeline.LoginAsync("alice"); (await IsLoggedIn()).ShouldBeTrue(); - var alice_session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single(); + var alice_session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single(); alice_session.Key.ShouldBe(bob_session.Key); (alice_session.Created > bob_session.Created).ShouldBeTrue(); @@ -237,8 +237,8 @@ public class ServerSideSessionTests await _pipeline.LoginAsync("alice"); _pipeline.RemoveLoginCookie(); - var tickets = await _ticketService.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }); - var sessions = await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }); + var tickets = await _ticketService.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct); + var sessions = await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct); tickets.Select(x => x.SessionId).ShouldBe(sessions.Select(x => x.SessionId)); } @@ -254,9 +254,9 @@ public class ServerSideSessionTests await _pipeline.LoginAsync("bob"); _pipeline.RemoveLoginCookie(); - var tickets = await _ticketService.QuerySessionsAsync(new SessionQuery { SubjectId = "alice" }); + var tickets = await _ticketService.QuerySessionsAsync(new SessionQuery { SubjectId = "alice" }, _ct); tickets.TotalCount.ShouldBe(2); - var sessions = await _sessionStore.QuerySessionsAsync(new SessionQuery { SubjectId = "alice" }); + var sessions = await _sessionStore.QuerySessionsAsync(new SessionQuery { SubjectId = "alice" }, _ct); sessions.TotalCount.ShouldBe(2); tickets.ResultsToken.ShouldBe(sessions.ResultsToken); @@ -280,8 +280,8 @@ public class ServerSideSessionTests await _pipeline.LoginAsync("alice"); _pipeline.RemoveLoginCookie(); - var sessions = await _sessionMgmt.QuerySessionsAsync(new SessionQuery { SubjectId = "alice" }); - var tickets = await _ticketService.QuerySessionsAsync(new SessionQuery { SubjectId = "alice" }); + var sessions = await _sessionMgmt.QuerySessionsAsync(new SessionQuery { SubjectId = "alice" }, _ct); + var tickets = await _ticketService.QuerySessionsAsync(new SessionQuery { SubjectId = "alice" }, _ct); tickets.ResultsToken.ShouldBe(sessions.ResultsToken); tickets.HasPrevResults.ShouldBe(sessions.HasPrevResults); @@ -306,7 +306,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); (await _grantStore.GetAllAsync(new PersistedGrantFilter { SubjectId = "alice" })).ShouldNotBeEmpty(); @@ -317,7 +317,7 @@ public class ServerSideSessionTests RevokeConsents = false, RevokeTokens = true, SendBackchannelLogoutNotification = false - }); + }, _ct); (await _grantStore.GetAllAsync(new PersistedGrantFilter { SubjectId = "alice" })).ShouldBeEmpty(); } @@ -335,7 +335,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); (await _grantStore.GetAllAsync(new PersistedGrantFilter { SubjectId = "alice" })).ShouldNotBeEmpty(); @@ -347,7 +347,7 @@ public class ServerSideSessionTests RevokeTokens = true, SendBackchannelLogoutNotification = false, ClientIds = new[] { "foo" } - }); + }, _ct); (await _grantStore.GetAllAsync(new PersistedGrantFilter { SubjectId = "alice" })).ShouldNotBeEmpty(); } @@ -365,7 +365,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); _pipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeFalse(); @@ -376,7 +376,7 @@ public class ServerSideSessionTests RevokeConsents = false, RevokeTokens = false, SendBackchannelLogoutNotification = true - }); + }, _ct); _pipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeTrue(); } @@ -395,7 +395,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); _pipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeFalse(); @@ -407,7 +407,7 @@ public class ServerSideSessionTests RevokeTokens = false, SendBackchannelLogoutNotification = true, ClientIds = new List { "foo" } - }); + }, _ct); _pipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeFalse(); } @@ -425,11 +425,11 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); _pipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeFalse(); - (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).ShouldNotBeEmpty(); + (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).ShouldNotBeEmpty(); await _sessionMgmt.RemoveSessionsAsync(new RemoveSessionsContext { @@ -438,9 +438,9 @@ public class ServerSideSessionTests RevokeConsents = false, RevokeTokens = false, SendBackchannelLogoutNotification = false - }); + }, _ct); - (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).ShouldBeEmpty(); + (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).ShouldBeEmpty(); } [Fact] @@ -458,11 +458,11 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); _pipeline.BackChannelMessageHandler.OnInvoke = async msg => { - var form = await msg.Content.ReadAsStringAsync(); + var form = await msg.Content.ReadAsStringAsync(_ct); var jwt = form.Substring("login_token=".Length + 1); var handler = new JsonWebTokenHandler(); var token = handler.ReadJsonWebToken(jwt); @@ -471,11 +471,11 @@ public class ServerSideSessionTests }; _pipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeFalse(); - var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single(); + var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single(); session.Expires = System.DateTime.UtcNow.AddMinutes(-1); - await _sessionStore.UpdateSessionAsync(session); + await _sessionStore.UpdateSessionAsync(session, _ct); - await Task.Delay(1000); + await Task.Delay(1000, _ct); _pipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeTrue(); } @@ -497,11 +497,11 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); _pipeline.BackChannelMessageHandler.OnInvoke = async msg => { - var form = await msg.Content.ReadAsStringAsync(); + var form = await msg.Content.ReadAsStringAsync(_ct); var jwt = form.Substring("login_token=".Length + 1); var handler = new JsonWebTokenHandler(); var token = handler.ReadJsonWebToken(jwt); @@ -510,9 +510,9 @@ public class ServerSideSessionTests }; _pipeline.BackChannelMessageHandler.InvokeWasCalled.ShouldBeFalse(); - var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single(); + var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single(); session.Expires = System.DateTime.UtcNow.AddMinutes(-1); - await _sessionStore.UpdateSessionAsync(session); + await _sessionStore.UpdateSessionAsync(session, _ct); await _pipeline.RequestAuthorizationEndpointAsync("client", "code", "openid api offline_access", "https://client/callback"); @@ -532,15 +532,15 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); (await _grantStore.GetAllAsync(new PersistedGrantFilter { SubjectId = "alice" })).ShouldNotBeEmpty(); - var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single(); + var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single(); session.Expires = System.DateTime.UtcNow.AddMinutes(-1); - await _sessionStore.UpdateSessionAsync(session); + await _sessionStore.UpdateSessionAsync(session, _ct); - await Task.Delay(1000); + await Task.Delay(1000, _ct); (await _grantStore.GetAllAsync(new PersistedGrantFilter { SubjectId = "alice" })).ShouldBeEmpty(); } @@ -558,7 +558,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); (await _grantStore.GetAllAsync(new PersistedGrantFilter { SubjectId = "alice" })).ShouldNotBeEmpty(); @@ -580,23 +580,23 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); - var ticket1 = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket1 = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); var expiration1 = ticket1.GetExpiration(); var issued1 = ticket1.GetIssued(); - await Task.Delay(1000); + await Task.Delay(1000, _ct); await _pipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, ClientId = "client", RefreshToken = tokenResponse.RefreshToken - }); + }, _ct); - var ticket2 = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket2 = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); var expiration2 = ticket2.GetExpiration(); var issued2 = ticket2.GetIssued(); @@ -620,16 +620,16 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); await _pipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, ClientId = "client", RefreshToken = tokenResponse.RefreshToken - }); + }, _ct); - var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); ticket.Properties.Items.ShouldNotContainKey(IdentityServerConstants.ForceCookieRenewalFlag); } @@ -650,16 +650,16 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); await _pipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, ClientId = "client", RefreshToken = tokenResponse.RefreshToken - }); + }, _ct); - var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); ticket.Properties.Items.ShouldNotContainKey(IdentityServerConstants.ForceCookieRenewalFlag); } @@ -679,16 +679,16 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); await _pipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, ClientId = "client", RefreshToken = tokenResponse.RefreshToken - }); + }, _ct); - var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); ticket.Properties.Items.ShouldNotContainKey(IdentityServerConstants.ForceCookieRenewalFlag); } @@ -708,16 +708,16 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); await _pipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, ClientId = "client", RefreshToken = tokenResponse.RefreshToken - }); + }, _ct); - var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); ticket.Properties.Items.ShouldContainKey(IdentityServerConstants.ForceCookieRenewalFlag); } @@ -735,21 +735,25 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); - var expiration1 = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single().Expires.Value; - - await _pipeline.BackChannelClient.GetUserInfoAsync(new UserInfoRequest + var dateTime = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single().Expires; + if (dateTime != null) { - Address = IdentityServerPipeline.UserInfoEndpoint, - ClientId = "client", - ClientCredentialStyle = ClientCredentialStyle.PostBody, - Token = tokenResponse.AccessToken - }); + var expiration1 = dateTime.Value; - var expiration2 = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single().Expires.Value; + await _pipeline.BackChannelClient.GetUserInfoAsync(new UserInfoRequest + { + Address = IdentityServerPipeline.UserInfoEndpoint, + ClientId = "client", + ClientCredentialStyle = ClientCredentialStyle.PostBody, + Token = tokenResponse.AccessToken + }, _ct); - expiration2.ShouldBeGreaterThan(expiration1); + var expiration2 = dateTime.Value; + + expiration2.ShouldBeGreaterThan(expiration1); + } } [Fact] @@ -767,7 +771,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); await _pipeline.BackChannelClient.GetUserInfoAsync(new UserInfoRequest { @@ -775,9 +779,9 @@ public class ServerSideSessionTests ClientId = "client", ClientCredentialStyle = ClientCredentialStyle.PostBody, Token = tokenResponse.AccessToken - }); + }, _ct); - var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); ticket.Properties.Items.ShouldNotContainKey(IdentityServerConstants.ForceCookieRenewalFlag); } @@ -798,7 +802,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); await _pipeline.BackChannelClient.GetUserInfoAsync(new UserInfoRequest { @@ -806,9 +810,9 @@ public class ServerSideSessionTests ClientId = "client", ClientCredentialStyle = ClientCredentialStyle.PostBody, Token = tokenResponse.AccessToken - }); + }, _ct); - var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); ticket.Properties.Items.ShouldNotContainKey(IdentityServerConstants.ForceCookieRenewalFlag); } @@ -828,7 +832,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); await _pipeline.BackChannelClient.GetUserInfoAsync(new UserInfoRequest { @@ -836,9 +840,9 @@ public class ServerSideSessionTests ClientId = "client", ClientCredentialStyle = ClientCredentialStyle.PostBody, Token = tokenResponse.AccessToken - }); + }, _ct); - var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); ticket.Properties.Items.ShouldNotContainKey(IdentityServerConstants.ForceCookieRenewalFlag); } @@ -858,7 +862,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); await _pipeline.BackChannelClient.GetUserInfoAsync(new UserInfoRequest { @@ -866,9 +870,9 @@ public class ServerSideSessionTests ClientId = "client", ClientCredentialStyle = ClientCredentialStyle.PostBody, Token = tokenResponse.AccessToken - }); + }, _ct); - var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); ticket.Properties.Items.ShouldContainKey(IdentityServerConstants.ForceCookieRenewalFlag); } @@ -888,8 +892,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); - + }, _ct); { var refreshResponse = await _pipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest @@ -897,50 +900,47 @@ public class ServerSideSessionTests Address = IdentityServerPipeline.TokenEndpoint, ClientId = "client", RefreshToken = tokenResponse.RefreshToken - }); + }, _ct); refreshResponse.IsError.ShouldBeFalse(); } - { - var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single(); + var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single(); session.Expires = null; - await _sessionStore.UpdateSessionAsync(session); + await _sessionStore.UpdateSessionAsync(session, _ct); var refreshResponse = await _pipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, ClientId = "client", RefreshToken = tokenResponse.RefreshToken - }); + }, _ct); refreshResponse.IsError.ShouldBeFalse(); } - { - var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single(); + var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single(); session.Expires = DateTime.UtcNow.AddMinutes(-1); - await _sessionStore.UpdateSessionAsync(session); + await _sessionStore.UpdateSessionAsync(session, _ct); var refreshResponse = await _pipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, ClientId = "client", RefreshToken = tokenResponse.RefreshToken - }); + }, _ct); refreshResponse.IsError.ShouldBeTrue(); } - { - await _sessionStore.DeleteSessionsAsync(new SessionFilter { SubjectId = "alice" }); + await _sessionStore.DeleteSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct); var refreshResponse = await _pipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { Address = IdentityServerPipeline.TokenEndpoint, ClientId = "client", RefreshToken = tokenResponse.RefreshToken - }); + }, _ct); refreshResponse.IsError.ShouldBeTrue(); } } @@ -960,7 +960,7 @@ public class ServerSideSessionTests ClientId = "client", Code = authzResponse.Code, RedirectUri = "https://client/callback" - }); + }, _ct); { @@ -970,15 +970,15 @@ public class ServerSideSessionTests ClientId = "client", ClientCredentialStyle = ClientCredentialStyle.PostBody, Token = tokenResponse.AccessToken - }); + }, _ct); response.IsError.ShouldBeFalse(); } { - var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single(); + var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single(); session.Expires = null; - await _sessionStore.UpdateSessionAsync(session); + await _sessionStore.UpdateSessionAsync(session, _ct); var response = await _pipeline.BackChannelClient.GetUserInfoAsync(new UserInfoRequest { @@ -986,15 +986,14 @@ public class ServerSideSessionTests ClientId = "client", ClientCredentialStyle = ClientCredentialStyle.PostBody, Token = tokenResponse.AccessToken - }); + }, _ct); response.IsError.ShouldBeFalse(); } - { - var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single(); + var session = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single(); session.Expires = DateTime.UtcNow.AddMinutes(-1); - await _sessionStore.UpdateSessionAsync(session); + await _sessionStore.UpdateSessionAsync(session, _ct); var response = await _pipeline.BackChannelClient.GetUserInfoAsync(new UserInfoRequest { @@ -1002,13 +1001,12 @@ public class ServerSideSessionTests ClientId = "client", ClientCredentialStyle = ClientCredentialStyle.PostBody, Token = tokenResponse.AccessToken - }); + }, _ct); response.IsError.ShouldBeTrue(); } - { - await _sessionStore.DeleteSessionsAsync(new SessionFilter { SubjectId = "alice" }); + await _sessionStore.DeleteSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct); var response = await _pipeline.BackChannelClient.GetUserInfoAsync(new UserInfoRequest { @@ -1016,12 +1014,11 @@ public class ServerSideSessionTests ClientId = "client", ClientCredentialStyle = ClientCredentialStyle.PostBody, Token = tokenResponse.AccessToken - }); + }, _ct); response.IsError.ShouldBeTrue(); } } - [Fact] public async Task claim_issuers_should_be_persisted() { @@ -1034,7 +1031,7 @@ public class ServerSideSessionTests await _pipeline.LoginAsync(user); - var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" })).Single() + var ticket = (await _sessionStore.GetSessionsAsync(new SessionFilter { SubjectId = "alice" }, _ct)).Single() .Deserialize(_protector, null); var claims = ticket.Principal.Claims; claims.ShouldContain(c => c.Issuer == "Custom Issuer" && c.Type == "Test"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Hosting/SubpathHosting.cs b/identity-server/test/IdentityServer.IntegrationTests/Hosting/SubpathHosting.cs index 06521301d..23d01e1af 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Hosting/SubpathHosting.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Hosting/SubpathHosting.cs @@ -13,9 +13,8 @@ namespace Duende.IdentityServer.IntegrationTests.Hosting; public class SubpathHosting { private const string Category = "Subpath endpoint"; - - private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); - + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); private Client _client1; public SubpathHosting() @@ -64,7 +63,7 @@ public class SubpathHosting redirectUri: "https://client1/callback", state: "123_state", nonce: "123_nonce"); - var response = await _mockPipeline.BrowserClient.GetAsync(url); + var response = await _mockPipeline.BrowserClient.GetAsync(url, _ct); _mockPipeline.LoginWasCalled.ShouldBeTrue(); } diff --git a/identity-server/test/IdentityServer.IntegrationTests/TestFramework/GenericHost.cs b/identity-server/test/IdentityServer.IntegrationTests/TestFramework/GenericHost.cs index 7806adf25..072f35ed3 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/TestFramework/GenericHost.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/TestFramework/GenericHost.cs @@ -52,7 +52,7 @@ public class GenericHost return _baseAddress + path; } - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { var builder = WebApplication.CreateBuilder(new WebApplicationOptions { diff --git a/identity-server/test/IdentityServer.IntegrationTests/TestHosts/ConfigurationIntegrationTestBase.cs b/identity-server/test/IdentityServer.IntegrationTests/TestHosts/ConfigurationIntegrationTestBase.cs index ea7d4a987..a9b8850ae 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/TestHosts/ConfigurationIntegrationTestBase.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/TestHosts/ConfigurationIntegrationTestBase.cs @@ -15,9 +15,9 @@ public class ConfigurationIntegrationTestBase { var dbRoot = new InMemoryDatabaseRoot(); IdentityServerHost = new IdentityServerHost(dbRoot); - IdentityServerHost.InitializeAsync().Wait(); + IdentityServerHost.InitializeAsync().AsTask().Wait(); ConfigurationHost = new ConfigurationHost(dbRoot); - ConfigurationHost.InitializeAsync().Wait(); + ConfigurationHost.InitializeAsync().AsTask().Wait(); } } diff --git a/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/AuthorizeResultTests.cs b/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/AuthorizeResultTests.cs index 3573dec02..dc83e36e9 100644 --- a/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/AuthorizeResultTests.cs +++ b/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/AuthorizeResultTests.cs @@ -20,6 +20,7 @@ namespace UnitTests.Endpoints.Results; public class AuthorizeResultTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private AuthorizeHttpWriter _subject; private AuthorizeResponse _response = new AuthorizeResponse(); @@ -220,7 +221,7 @@ public class AuthorizeResultTests _context.Response.Headers["X-Content-Security-Policy"].First().ShouldContain($"script-src '{IdentityServerConstants.ContentSecurityPolicyHashes.AuthorizeScript}'"); _context.Response.Body.Seek(0, SeekOrigin.Begin); using var rdr = new StreamReader(_context.Response.Body); - var html = await rdr.ReadToEndAsync(); + var html = await rdr.ReadToEndAsync(_ct); html.ShouldContain(""); html.ShouldContain("
"); html.ShouldContain(""); diff --git a/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/CheckSessionResultTests.cs b/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/CheckSessionResultTests.cs index 0d17795b6..b47ece591 100644 --- a/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/CheckSessionResultTests.cs +++ b/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/CheckSessionResultTests.cs @@ -12,11 +12,10 @@ namespace UnitTests.Endpoints.Results; public class CheckSessionResultTests { - private CheckSessionHttpWriter _subject; - - private IdentityServerOptions _options = new IdentityServerOptions(); - - private DefaultHttpContext _context = new DefaultHttpContext(); + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly CheckSessionHttpWriter _subject; + private readonly IdentityServerOptions _options = new IdentityServerOptions(); + private readonly DefaultHttpContext _context = new DefaultHttpContext(); public CheckSessionResultTests() { @@ -42,7 +41,7 @@ public class CheckSessionResultTests _context.Response.Headers["X-Content-Security-Policy"].First().ShouldContain($"script-src '{IdentityServerConstants.ContentSecurityPolicyHashes.CheckSessionScript}'"); _context.Response.Body.Seek(0, SeekOrigin.Begin); using var rdr = new StreamReader(_context.Response.Body); - var html = await rdr.ReadToEndAsync(); + var html = await rdr.ReadToEndAsync(_ct); html.ShouldContain(""); } @@ -77,7 +76,7 @@ public class CheckSessionResultTests await _subject.WriteHttpResponse(new CheckSessionResult(), _context); _context.Response.Body.Seek(0, SeekOrigin.Begin); using var rdr = new StreamReader(_context.Response.Body); - var html = await rdr.ReadToEndAsync(); + var html = await rdr.ReadToEndAsync(_ct); html.ShouldContain($""); } } diff --git a/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/EndSessionCallbackResultTests.cs b/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/EndSessionCallbackResultTests.cs index 74eb6204f..cc5d9d3b5 100644 --- a/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/EndSessionCallbackResultTests.cs +++ b/identity-server/test/IdentityServer.UnitTests/Endpoints/Results/EndSessionCallbackResultTests.cs @@ -13,12 +13,11 @@ namespace UnitTests.Endpoints.Results; public class EndSessionCallbackResultTests { - private EndSessionCallbackHttpWriter _subject; - - private EndSessionCallbackValidationResult _result = new EndSessionCallbackValidationResult(); - private IdentityServerOptions _options = TestIdentityServerOptions.Create(); - - private DefaultHttpContext _context = new DefaultHttpContext(); + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + private readonly EndSessionCallbackHttpWriter _subject; + private readonly EndSessionCallbackValidationResult _result = new EndSessionCallbackValidationResult(); + private readonly IdentityServerOptions _options = TestIdentityServerOptions.Create(); + private readonly DefaultHttpContext _context = new DefaultHttpContext(); public EndSessionCallbackResultTests() { @@ -59,7 +58,7 @@ public class EndSessionCallbackResultTests _context.Response.Headers["X-Content-Security-Policy"].First().ShouldContain("frame-src http://foo.com http://bar.com"); _context.Response.Body.Seek(0, SeekOrigin.Begin); using var rdr = new StreamReader(_context.Response.Body); - var html = await rdr.ReadToEndAsync(); + var html = await rdr.ReadToEndAsync(_ct); html.ShouldContain(""); html.ShouldContain(""); } diff --git a/identity-server/test/IdentityServer.UnitTests/Services/Default/DistributedDeviceFlowThrottlingServiceTests.cs b/identity-server/test/IdentityServer.UnitTests/Services/Default/DistributedDeviceFlowThrottlingServiceTests.cs index bd9796795..bd317606b 100644 --- a/identity-server/test/IdentityServer.UnitTests/Services/Default/DistributedDeviceFlowThrottlingServiceTests.cs +++ b/identity-server/test/IdentityServer.UnitTests/Services/Default/DistributedDeviceFlowThrottlingServiceTests.cs @@ -14,16 +14,15 @@ namespace UnitTests.Services.Default; public class DistributedDeviceFlowThrottlingServiceTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private TestCache cache = new TestCache(); private InMemoryClientStore _store; - private readonly IdentityServerOptions options = new IdentityServerOptions { DeviceFlow = new DeviceFlowOptions { Interval = 5 } }; private readonly DeviceCode deviceCode = new DeviceCode { Lifetime = 300, CreationTime = DateTime.UtcNow }; - private const string CacheKey = "devicecode_"; private readonly DateTime testDate = new DateTime(2018, 09, 01, 8, 0, 0, DateTimeKind.Utc); @@ -48,7 +47,7 @@ public class DistributedDeviceFlowThrottlingServiceTests var handle = Guid.NewGuid().ToString(); var service = new DistributedDeviceFlowThrottlingService(cache, _store, new StubClock { UtcNowFunc = () => testDate }, options); - await cache.SetAsync(CacheKey + handle, Encoding.UTF8.GetBytes(testDate.AddSeconds(-1).ToString("O"))); + await cache.SetAsync(CacheKey + handle, Encoding.UTF8.GetBytes(testDate.AddSeconds(-1).ToString("O")), token: _ct); var result = await service.ShouldSlowDown(handle, deviceCode); @@ -64,7 +63,7 @@ public class DistributedDeviceFlowThrottlingServiceTests var service = new DistributedDeviceFlowThrottlingService(cache, _store, new StubClock { UtcNowFunc = () => testDate }, options); - await cache.SetAsync($"devicecode_{handle}", Encoding.UTF8.GetBytes(testDate.AddSeconds(-deviceCode.Lifetime - 1).ToString("O"))); + await cache.SetAsync($"devicecode_{handle}", Encoding.UTF8.GetBytes(testDate.AddSeconds(-deviceCode.Lifetime - 1).ToString("O")), _ct); var result = await service.ShouldSlowDown(handle, deviceCode); diff --git a/identity-server/test/IdentityServer.UnitTests/Validation/ClientConfigurationValidation.cs b/identity-server/test/IdentityServer.UnitTests/Validation/ClientConfigurationValidation.cs index 968108833..db62bbcee 100644 --- a/identity-server/test/IdentityServer.UnitTests/Validation/ClientConfigurationValidation.cs +++ b/identity-server/test/IdentityServer.UnitTests/Validation/ClientConfigurationValidation.cs @@ -514,13 +514,13 @@ public class ClientConfigurationValidation context.ErrorMessage.ShouldBe(expectedError); } - public static TheoryData> GrantTypesWithClientCredentialsTestData => - [ + public static TheoryData> GrantTypesWithClientCredentialsTestData => new() + { GrantTypes.ImplicitAndClientCredentials, GrantTypes.CodeAndClientCredentials, GrantTypes.HybridAndClientCredentials, GrantTypes.ClientCredentials, GrantTypes.ResourceOwnerPasswordAndClientCredentials - ]; + }; } diff --git a/shared/Xunit.Playwright/AppHostFixture.cs b/shared/Xunit.Playwright/AppHostFixture.cs index 8e0b3e0cb..890262393 100644 --- a/shared/Xunit.Playwright/AppHostFixture.cs +++ b/shared/Xunit.Playwright/AppHostFixture.cs @@ -24,7 +24,7 @@ public class AppHostFixture(IAppHostServiceRoutes routes) : IAsyncLifetim public bool UsingAlreadyRunningInstance { get; private set; } public string StartupLogs => _startupLogs.ToString() ?? string.Empty; - public async Task InitializeAsync() + public async ValueTask InitializeAsync() { using var startupLogWriter = ConnectLogger(s => _startupLogs.Write(s)); @@ -103,7 +103,7 @@ public class AppHostFixture(IAppHostServiceRoutes routes) : IAsyncLifetim } - public async Task DisposeAsync() + public async ValueTask DisposeAsync() { if (_app != null) { @@ -237,7 +237,7 @@ public class AppHostFixture(IAppHostServiceRoutes routes) : IAsyncLifetim return _app.GetEndpoint(hostName); #else - Skip.If(true, "When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); + Assert.Skip("When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); return null!; #endif } diff --git a/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj b/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj index fe2a6dc09..b8efccbcf 100644 --- a/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj +++ b/shared/Xunit.Playwright/Duende.Xunit.Playwright.csproj @@ -18,13 +18,12 @@ - + - - + - + diff --git a/shared/Xunit.Playwright/IntegrationTestBase.cs b/shared/Xunit.Playwright/IntegrationTestBase.cs index 37d9a35db..b6cd258cd 100644 --- a/shared/Xunit.Playwright/IntegrationTestBase.cs +++ b/shared/Xunit.Playwright/IntegrationTestBase.cs @@ -1,7 +1,6 @@ // Copyright (c) Duende Software. All rights reserved. // See LICENSE in the project root for license information. -using Xunit.Abstractions; namespace Duende.Xunit.Playwright; @@ -23,7 +22,7 @@ public class IntegrationTestBase : IDisposable where THost : class #if DEBUG_NCRUNCH // Running in NCrunch. NCrunch cannot build the aspire project, so it needs // to be started manually. - Skip.If(true, "When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); + Assert.Skip("When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); #endif } } diff --git a/shared/Xunit.Playwright/PlaywrightTestBase.cs b/shared/Xunit.Playwright/PlaywrightTestBase.cs index be3d3b562..6657c81b5 100644 --- a/shared/Xunit.Playwright/PlaywrightTestBase.cs +++ b/shared/Xunit.Playwright/PlaywrightTestBase.cs @@ -3,22 +3,22 @@ using System.Reflection; using Microsoft.Playwright; -using Microsoft.Playwright.Xunit; -using Xunit.Abstractions; -using Xunit.Sdk; - namespace Duende.Xunit.Playwright; public class Defaults { public static readonly PageGotoOptions PageGotoOptions = new PageGotoOptions() - { WaitUntil = WaitUntilState.NetworkIdle }; + { + WaitUntil = WaitUntilState.NetworkIdle + }; } [WithTestName] -public class PlaywrightTestBase : PageTest, IDisposable where THost : class +public class PlaywrightTestBase : IAsyncLifetime, IDisposable where THost : class { private readonly IDisposable _loggingScope; + private IPlaywright? _playwright; + private IBrowser? _browser; public PlaywrightTestBase(ITestOutputHelper output, AppHostFixture fixture) { @@ -35,14 +35,25 @@ public class PlaywrightTestBase : PageTest, IDisposable where THost : cla #if DEBUG_NCRUNCH // Running in NCrunch. NCrunch cannot build the aspire project, so it needs // to be started manually. - Skip.If(true, "When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); + Assert.Skip("When running the Host.Tests using NCrunch, you must start the Hosts.AppHost project manually. IE: dotnet run -p bff/samples/Hosts.AppHost. Or start without debugging from the UI. "); #endif } } + protected IBrowserContext Context { get; private set; } = null!; - public override async Task InitializeAsync() + protected IPage Page { get; private set; } = null!; + + public AppHostFixture Fixture { get; } + + public ITestOutputHelper Output { get; } + + public virtual async ValueTask InitializeAsync() { - await base.InitializeAsync(); + _playwright = await Microsoft.Playwright.Playwright.CreateAsync(); + _browser = await _playwright.Chromium.LaunchAsync(new() { Headless = true }); + Context = await _browser.NewContextAsync(ContextOptions()); + Page = await Context.NewPageAsync(); + Context.SetDefaultTimeout(10_000); await Context.Tracing.StartAsync(new() { @@ -53,7 +64,7 @@ public class PlaywrightTestBase : PageTest, IDisposable where THost : cla }); } - public override async Task DisposeAsync() + public virtual async ValueTask DisposeAsync() { var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? Environment.CurrentDirectory; // if path ends with /bin/{build configuration}/{dotnetversion}, then strip that from the path. @@ -63,7 +74,6 @@ public class PlaywrightTestBase : PageTest, IDisposable where THost : cla path = Path.GetFullPath(Path.Combine(path, "../../../")); } - await Context.Tracing.StopAsync(new() { Path = Path.Combine( @@ -72,10 +82,13 @@ public class PlaywrightTestBase : PageTest, IDisposable where THost : cla $"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}.zip" ) }); - await base.DisposeAsync(); + + await Context.CloseAsync(); + await _browser!.DisposeAsync(); + _playwright!.Dispose(); } - public override BrowserNewContextOptions ContextOptions() => new() + public virtual BrowserNewContextOptions ContextOptions() => new() { Locale = "en-US", ColorScheme = ColorScheme.Light, @@ -86,11 +99,6 @@ public class PlaywrightTestBase : PageTest, IDisposable where THost : cla IgnoreHTTPSErrors = true, }; - - public AppHostFixture Fixture { get; } - - public ITestOutputHelper Output { get; } - public void Dispose() { if (!Fixture.UsingAlreadyRunningInstance) @@ -109,19 +117,3 @@ public class PlaywrightTestBase : PageTest, IDisposable where THost : cla public HttpClient CreateHttpClient(string clientName) => Fixture.CreateHttpClient(clientName); } - -public class WithTestNameAttribute : BeforeAfterTestAttribute -{ - public static string CurrentTestName = string.Empty; - public static string CurrentClassName = string.Empty; - - public override void Before(MethodInfo methodInfo) - { - CurrentTestName = methodInfo.Name; - CurrentClassName = methodInfo.DeclaringType!.Name; - } - - public override void After(MethodInfo methodInfo) - { - } -} diff --git a/shared/Xunit.Playwright/Retries/RetryableFact.cs b/shared/Xunit.Playwright/Retries/RetryableFact.cs deleted file mode 100644 index 912043db9..000000000 --- a/shared/Xunit.Playwright/Retries/RetryableFact.cs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Xunit.Sdk; - -namespace Duende.Xunit.Playwright.Retries; - -[XunitTestCaseDiscoverer( - typeName: "Duende.Hosts.Tests.TestInfra.Retries.RetryableTestDiscoverer", - assemblyName: "Duende.Hosts.Tests" -)] -public class RetryableFact : FactAttribute -{ - public int MaxRetries { get; set; } = 5; -} diff --git a/shared/Xunit.Playwright/Retries/RetryableTestCase.cs b/shared/Xunit.Playwright/Retries/RetryableTestCase.cs deleted file mode 100644 index ecac29181..000000000 --- a/shared/Xunit.Playwright/Retries/RetryableTestCase.cs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Duende.Xunit.Playwright.Retries; - -public class RetryableTestCase( - IMessageSink sink, - TestMethodDisplay display, - TestMethodDisplayOptions methodDisplayOptions, - ITestMethod method -) : XunitTestCase(sink, - display, - methodDisplayOptions, - method, - testMethodArguments: null) -{ - public override async Task RunAsync( - IMessageSink diagnosticMessageSink, - IMessageBus messageBus, - object[] constructorArguments, - ExceptionAggregator aggregator, - CancellationTokenSource cts) - { - var retryCount = 0; - var maxRetries = Method.GetCustomAttributes(typeof(RetryableFact)).FirstOrDefault()?.GetNamedArgument(nameof(RetryableFact.MaxRetries)) ?? 5; - - while (true) - { - retryCount++; - - var exceptionCapturingBus = new ExceptionCapturingMessageBus(messageBus); - var summary = await base.RunAsync( - diagnosticMessageSink, - exceptionCapturingBus, - constructorArguments, - aggregator, - cts); - - summary.Failed -= exceptionCapturingBus.SkippedCount; - summary.Skipped += exceptionCapturingBus.SkippedCount; - - if (aggregator.HasExceptions || summary.Failed == 0 || retryCount >= maxRetries) - { - exceptionCapturingBus.Flush(); - return summary; - } - - diagnosticMessageSink.OnMessage(new DiagnosticMessage( - "Execution of retriable test '{0}' failed. Attempt {1} of {2}", - DisplayName, - retryCount, - maxRetries - )); - } - } - - -} diff --git a/shared/Xunit.Playwright/Retries/RetryableTestDiscoverer.cs b/shared/Xunit.Playwright/Retries/RetryableTestDiscoverer.cs deleted file mode 100644 index d460ecaae..000000000 --- a/shared/Xunit.Playwright/Retries/RetryableTestDiscoverer.cs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright (c) Duende Software. All rights reserved. -// See LICENSE in the project root for license information. - -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace Duende.Xunit.Playwright.Retries; - -public class RetryableTestDiscoverer(IMessageSink messageSink) : IXunitTestCaseDiscoverer -{ - public IEnumerable Discover( - ITestFrameworkDiscoveryOptions discoveryOptions, - ITestMethod testMethod, - IAttributeInfo factAttribute) - { - yield return new RetryableTestCase( - messageSink, - discoveryOptions.MethodDisplayOrDefault(), - discoveryOptions.MethodDisplayOptionsOrDefault(), - testMethod - ); - } -} - -public class ExceptionCapturingMessageBus(IMessageBus inner) : IMessageBus -{ - private readonly object _syncRoot = new(); - private readonly Queue _failedMessages = new(); - private bool _disposed = false; - - public bool ExceptionHasOccurred { get; private set; } - public int SkippedCount { get; private set; } - - public bool QueueMessage(IMessageSinkMessage message) - { - if (_disposed) - { - throw new ObjectDisposedException(nameof(ExceptionCapturingMessageBus)); - } - - var skipTest = false; - - if (message is ITestFailed failed) - { - // We ignore 'skip' exceptions - if (failed.ExceptionTypes.Contains("XUnit.SkipException", StringComparer.InvariantCultureIgnoreCase)) - { - skipTest = true; - } - else - { - ExceptionHasOccurred = true; - } - - if (skipTest) - { - SkippedCount++; - return inner.QueueMessage(new TestSkipped(failed.Test, "Skipped")); - } - } - - lock (_syncRoot) - { - _failedMessages.Enqueue(message); - } - - - - return true; - } - - public void Flush() - { - lock (_syncRoot) - { - while (_failedMessages.Any()) - { - inner.QueueMessage(_failedMessages.Dequeue()); - } - } - } - - public void Dispose() - { - if (_disposed) - { - return; - } - - lock (_syncRoot) - { - if (_disposed) - { - return; - } - - _disposed = true; - } - - Flush(); - } -} diff --git a/shared/Xunit.Playwright/WithTestNameAttribute.cs b/shared/Xunit.Playwright/WithTestNameAttribute.cs new file mode 100644 index 000000000..73d3c483d --- /dev/null +++ b/shared/Xunit.Playwright/WithTestNameAttribute.cs @@ -0,0 +1,22 @@ +// Copyright (c) Duende Software. All rights reserved. +// See LICENSE in the project root for license information. + +using System.Reflection; +using Xunit.v3; + +namespace Duende.Xunit.Playwright; + +public class WithTestNameAttribute : Attribute, IBeforeAfterTestAttribute +{ + public static string CurrentTestName = string.Empty; + public static string CurrentClassName = string.Empty; + + public void Before(MethodInfo methodInfo, IXunitTest _) + { + CurrentTestName = methodInfo.Name; + CurrentClassName = methodInfo.DeclaringType!.Name; + } + + public void After(MethodInfo methodInfo, IXunitTest _) + { } +} diff --git a/src.props b/src.props index 010b4b20f..81ab951e6 100644 --- a/src.props +++ b/src.props @@ -62,10 +62,6 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/test.props b/test.props index 61a33ca95..a6856335d 100644 --- a/test.props +++ b/test.props @@ -6,6 +6,7 @@ full false true + Exe true true @@ -25,17 +26,9 @@ - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + +