From 0afe76f18633fdb1811d9b708fb055b0a1c57bfd Mon Sep 17 00:00:00 2001 From: Damian Hickey Date: Sun, 12 Oct 2025 20:22:42 +0200 Subject: [PATCH 1/9] Migrate all test projects to xUnit v3 and Microsoft Test Platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major Changes: - Upgraded from xunit.core v2 to xunit.v3 (3.1.0) - Replaced Microsoft.NET.Test.Sdk with Microsoft.Testing.Platform.MSBuild (1.8.4) - Updated test projects to use Exe (required for xUnit v3) Package Updates: - Replaced Verify.Xunit with Verify.XunitV3 (31.0.0) - Replaced Meziantou.Extensions.Logging.Xunit with MartinCostello.Logging.XUnit.v3 (0.6.0) - Replaced Serilog.Sinks.XUnit with Serilog.Sinks.XUnit3 (1.1.0) - Removed Xunit.SkippableFact (xUnit v3 has built-in skipping) - Removed Microsoft.SourceLink.GitHub from test projects - Updated Serilog to 4.3.0 (required by Serilog.Sinks.XUnit3) Code Changes: - Updated IAsyncLifetime implementations (Task → ValueTask, Task.CompletedTask → default) - Removed 'using Xunit.Abstractions;' from 37 files - Replaced Skip.If() with Assert.Skip() for conditional test skipping - Replaced [SkippableFact] with [Fact] and [SkippableTheory] with [Theory] - Updated BeforeAfterTestAttribute to IBeforeAfterTestAttribute in xUnit v3 - Fixed TheoryData syntax for xUnit v3 (collection expressions) Playwright Integration: - Removed Retries folder (unused xUnit v2 extensibility code) - Replaced Microsoft.Playwright.Xunit with Microsoft.Playwright - Removed PageTest base class, implemented Playwright directly - Added IAsyncLifetime implementation with manual browser initialization --- Directory.Packages.props | 22 ++-- ...Core.Authentication.JwtBearer.Tests.csproj | 2 +- .../DPoPIntegrationTests.cs | 1 - .../TestFramework/ApiHost.cs | 1 - .../TestFramework/AppHost.cs | 1 - .../TestFramework/GenericHost.cs | 10 +- .../TestFramework/IdentityServerHost.cs | 1 - .../Bff.Blazor.Client.UnitTests.csproj | 2 +- .../Bff.Blazor.UnitTests.csproj | 18 +--- .../Bff.Blazor.UnitTests/BffBlazorTests.cs | 5 +- .../Bff.EntityFramework.Tests.csproj | 3 +- bff/test/Bff.Tests/Bff.Tests.csproj | 2 +- .../Endpoints/DpopRemoteEndpointTests.cs | 1 - .../Bff.Tests/Endpoints/LocalEndpointTests.cs | 1 - .../BackchannelLogoutEndpointTests.cs | 1 - .../Management/LoginEndpointTests.cs | 1 - .../Management/LogoutEndpointTests.cs | 1 - .../Management/ManagementBasePathTests.cs | 1 - .../Endpoints/Management/UserEndpointTests.cs | 1 - .../Endpoints/RemoteEndpointTests.cs | 1 - .../Endpoints/YarpRemoteEndpointTests.cs | 1 - bff/test/Bff.Tests/GenericHostTests.cs | 1 - .../Headers/ApiAndBffUseForwardedHeaders.cs | 1 - .../Headers/ApiUseForwardedHeaders.cs | 1 - bff/test/Bff.Tests/Headers/General.cs | 1 - ...ccessTokenRetriever_Extensibility_tests.cs | 1 - .../SessionManagement/CookieSlidingTests.cs | 1 - .../RevokeRefreshTokenTests.cs | 1 - .../ServerSideTicketStoreTests.cs | 1 - .../Bff.Tests/TestFramework/GenericHost.cs | 2 +- .../TestHosts/BffIntegrationTestBase.cs | 5 +- .../TestHosts/OutputWritingTestBase.cs | 7 +- .../TestHosts/YarpBffIntegrationTestBase.cs | 5 +- .../Hosts.Tests/BffBlazorWebAssemblyTests.cs | 3 +- bff/test/Hosts.Tests/BffTests.cs | 9 +- .../Hosts.Tests/BlazorPerComponentTests.cs | 3 +- bff/test/Hosts.Tests/Hosts.Tests.csproj | 17 ++- bff/test/Hosts.Tests/PlaywrightTestBase.cs | 20 ++-- .../Hosts.Tests/TestInfra/AppHostFixture.cs | 6 +- .../TestInfra/IntegrationTestBase.cs | 3 +- .../IdentityServer.EndToEndTests.csproj | 4 +- .../IdentityServerTests.cs | 1 - .../IdentityServerPlaywrightTestBase.cs | 1 - .../EntityFramework/IntegrationTest.cs | 4 +- .../Storage/Stores/ClientStoreTests.cs | 2 +- .../Hosting/DynamicProvidersTests.cs | 24 ++--- .../TestFramework/GenericHost.cs | 2 +- .../ConfigurationIntegrationTestBase.cs | 4 +- .../ClientConfigurationValidation.cs | 6 +- shared/Xunit.Playwright/AppHostFixture.cs | 6 +- .../Duende.Xunit.Playwright.csproj | 7 +- .../Xunit.Playwright/IntegrationTestBase.cs | 3 +- shared/Xunit.Playwright/PlaywrightTestBase.cs | 58 +++++----- .../Xunit.Playwright/Retries/RetryableFact.cs | 15 --- .../Retries/RetryableTestCase.cs | 61 ----------- .../Retries/RetryableTestDiscoverer.cs | 102 ------------------ .../Xunit.Playwright/WithTestNameAttribute.cs | 22 ++++ src.props | 4 - test.props | 13 +-- 59 files changed, 136 insertions(+), 368 deletions(-) delete mode 100644 shared/Xunit.Playwright/Retries/RetryableFact.cs delete mode 100644 shared/Xunit.Playwright/Retries/RetryableTestCase.cs delete mode 100644 shared/Xunit.Playwright/Retries/RetryableTestDiscoverer.cs create mode 100644 shared/Xunit.Playwright/WithTestNameAttribute.cs 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/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..6f6c1483e 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 @@ -16,7 +16,7 @@ - + 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..16ce9f89b 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoPIntegrationTests.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoPIntegrationTests.cs @@ -16,7 +16,6 @@ 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; 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..d78dae633 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,13 +4,12 @@ using System.Net; using System.Reflection; using System.Security.Claims; -using Meziantou.Extensions.Logging.Xunit; +using MartinCostello.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; @@ -104,7 +103,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 +112,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); 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..669cffc42 100644 --- a/bff/test/Bff.Blazor.UnitTests/BffBlazorTests.cs +++ b/bff/test/Bff.Blazor.UnitTests/BffBlazorTests.cs @@ -6,7 +6,6 @@ using Duende.Bff; using Duende.Bff.Tests.TestHosts; using Duende.IdentityServer.Models; using Duende.IdentityServer.Services; -using Xunit.Abstractions; namespace Bff.Blazor.UnitTests; @@ -70,7 +69,7 @@ public class BffBlazorTests : OutputWritingTestBase response.StatusCode.ShouldBe(HttpStatusCode.OK); } - public override async Task InitializeAsync() + public override async ValueTask InitializeAsync() { await IdentityServerHost.InitializeAsync(); await ApiHost.InitializeAsync(); @@ -78,7 +77,7 @@ public class BffBlazorTests : OutputWritingTestBase await base.InitializeAsync(); } - public override async Task DisposeAsync() + public override async ValueTask DisposeAsync() { await ApiHost.DisposeAsync(); await BffHost.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.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..bfc8091f0 100644 --- a/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs @@ -7,7 +7,6 @@ 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; diff --git a/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs index 9e31b3b3b..59a6f5bdb 100644 --- a/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs @@ -6,7 +6,6 @@ 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; diff --git a/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs index ee2d0f4ab..79ff7710b 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs @@ -4,7 +4,6 @@ using System.Net; using Duende.Bff.Tests.TestHosts; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints.Management; diff --git a/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs index d7858483e..772a892e3 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs @@ -4,7 +4,6 @@ using System.Net; using Duende.Bff.Tests.TestHosts; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints.Management; diff --git a/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs index 53e915d98..495868e5b 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs @@ -4,7 +4,6 @@ using System.Net; using Duende.Bff.Tests.TestHosts; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints.Management; diff --git a/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs b/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs index 978d3eef5..56ac084c0 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs @@ -5,7 +5,6 @@ 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; diff --git a/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs index cc3b1afac..8f74f157c 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs @@ -4,7 +4,6 @@ using System.Net; using System.Security.Claims; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints.Management; diff --git a/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs index dcc54da0a..101777b75 100644 --- a/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs @@ -6,7 +6,6 @@ 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; diff --git a/bff/test/Bff.Tests/Endpoints/YarpRemoteEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/YarpRemoteEndpointTests.cs index d2083f76d..c9ab188d5 100644 --- a/bff/test/Bff.Tests/Endpoints/YarpRemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/YarpRemoteEndpointTests.cs @@ -4,7 +4,6 @@ using System.Net; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Endpoints; diff --git a/bff/test/Bff.Tests/GenericHostTests.cs b/bff/test/Bff.Tests/GenericHostTests.cs index fce77081f..34cfbd39b 100644 --- a/bff/test/Bff.Tests/GenericHostTests.cs +++ b/bff/test/Bff.Tests/GenericHostTests.cs @@ -4,7 +4,6 @@ using System.Net; using Duende.Bff.Tests.TestFramework; using Microsoft.AspNetCore.Builder; -using Xunit.Abstractions; namespace Duende.Bff.Tests; diff --git a/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs b/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs index 00de4fef2..6a0fd2fc7 100644 --- a/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs +++ b/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs @@ -4,7 +4,6 @@ using System.Text.Json; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Headers; diff --git a/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs b/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs index 3f0572751..c003ea57b 100644 --- a/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs +++ b/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs @@ -4,7 +4,6 @@ using System.Text.Json; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Headers; diff --git a/bff/test/Bff.Tests/Headers/General.cs b/bff/test/Bff.Tests/Headers/General.cs index da5f1c6ad..b979d2e7e 100644 --- a/bff/test/Bff.Tests/Headers/General.cs +++ b/bff/test/Bff.Tests/Headers/General.cs @@ -4,7 +4,6 @@ using System.Text.Json; using Duende.Bff.Tests.TestFramework; using Duende.Bff.Tests.TestHosts; -using Xunit.Abstractions; namespace Duende.Bff.Tests.Headers; diff --git a/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs b/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs index 823f9c05f..6351293d1 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; diff --git a/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs b/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs index c9d151574..7451766c5 100644 --- a/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs +++ b/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs @@ -5,7 +5,6 @@ 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; 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..55f623e6b 100644 --- a/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs +++ b/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs @@ -3,7 +3,6 @@ using Duende.Bff.Tests.TestHosts; using Microsoft.Extensions.DependencyInjection; -using Xunit.Abstractions; namespace Duende.Bff.Tests.SessionManagement; 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..3069fcc2a 100644 --- a/bff/test/Bff.Tests/TestHosts/BffIntegrationTestBase.cs +++ b/bff/test/Bff.Tests/TestHosts/BffIntegrationTestBase.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; @@ -52,7 +51,7 @@ public class BffIntegrationTestBase : 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(); @@ -61,7 +60,7 @@ public class BffIntegrationTestBase : OutputWritingTestBase await base.InitializeAsync(); } - public override async Task DisposeAsync() + public override async ValueTask DisposeAsync() { await ApiHost.DisposeAsync(); await BffHost.DisposeAsync(); diff --git a/bff/test/Bff.Tests/TestHosts/OutputWritingTestBase.cs b/bff/test/Bff.Tests/TestHosts/OutputWritingTestBase.cs index 4a7134495..a7c6a1932 100644 --- a/bff/test/Bff.Tests/TestHosts/OutputWritingTestBase.cs +++ b/bff/test/Bff.Tests/TestHosts/OutputWritingTestBase.cs @@ -2,7 +2,6 @@ // See LICENSE in the project root for license information. using System.Text; -using Xunit.Abstractions; namespace Duende.Bff.Tests.TestHosts; @@ -18,9 +17,9 @@ public class OutputWritingTestBase(ITestOutputHelper testOutputHelper) : IAsyncL } } - public virtual Task InitializeAsync() => Task.CompletedTask; + public virtual ValueTask InitializeAsync() => default; - public virtual Task DisposeAsync() + public virtual ValueTask DisposeAsync() { lock (_output) { @@ -28,6 +27,6 @@ public class OutputWritingTestBase(ITestOutputHelper testOutputHelper) : IAsyncL } - 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..49aff2a16 100644 --- a/bff/test/Hosts.Tests/BffTests.cs +++ b/bff/test/Hosts.Tests/BffTests.cs @@ -3,7 +3,6 @@ using Hosts.ServiceDefaults; using Hosts.Tests.TestInfra; -using Xunit.Abstractions; namespace Hosts.Tests; @@ -18,14 +17,14 @@ public class BffTests : IntegrationTestBase _bffClient = new BffClient(CreateHttpClient(AppHostServices.Bff)); } - [SkippableFact] + [Fact] public async Task Can_invoke_home() { var response = await _httpClient.GetAsync("/"); response.StatusCode.ShouldBe(HttpStatusCode.OK); } - [SkippableFact] + [Fact] public async Task Can_initiate_login() { @@ -39,7 +38,7 @@ public class BffTests : IntegrationTestBase claims.Any().ShouldBeTrue(); } - [SkippableTheory] + [Theory] [InlineData("/local/self-contained")] [InlineData("/local/invokes-external-api")] [InlineData("/api/user-token")] @@ -55,7 +54,7 @@ public class BffTests : IntegrationTestBase await _bffClient.InvokeApi(url); } - [SkippableFact] + [Fact] public async Task Can_logout() { await _bffClient.TriggerLogin(); 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..6bf0f94be 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 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. @@ -106,18 +105,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..069ce961c 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; 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/EntityFramework/IntegrationTest.cs b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/IntegrationTest.cs index c250a5077..71ae791c9 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/IntegrationTest.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/IntegrationTest.cs @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. +using System.Linq; using System.Runtime.InteropServices; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; @@ -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/Storage/Stores/ClientStoreTests.cs b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/ClientStoreTests.cs index 1d0a039e7..dbe0d7063 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/ClientStoreTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/ClientStoreTests.cs @@ -167,7 +167,7 @@ public class ClientStoreTests : IntegrationTest @@ -133,9 +133,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 => @@ -403,21 +401,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/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/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..7fa2eabb8 100644 --- a/shared/Xunit.Playwright/PlaywrightTestBase.cs +++ b/shared/Xunit.Playwright/PlaywrightTestBase.cs @@ -3,8 +3,6 @@ using System.Reflection; using Microsoft.Playwright; -using Microsoft.Playwright.Xunit; -using Xunit.Abstractions; using Xunit.Sdk; namespace Duende.Xunit.Playwright; @@ -12,13 +10,20 @@ 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; + + protected IBrowserContext Context { get; private set; } = null!; + protected IPage Page { get; private set; } = null!; public PlaywrightTestBase(ITestOutputHelper output, AppHostFixture fixture) { @@ -35,14 +40,22 @@ 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 } } - public override async Task InitializeAsync() + 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 +66,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 +76,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 +84,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 +101,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 +119,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 - + + From 846082e0f03c69d6fbdbf19f56a5636c49901d54 Mon Sep 17 00:00:00 2001 From: Damian Hickey Date: Sun, 12 Oct 2025 22:28:01 +0200 Subject: [PATCH 2/9] Fix xUnit1051 warnings by adding CancellationToken support to test methods Added CancellationToken support to all test classes to comply with xUnit v3's recommendation for responsive test cancellation. Changes: - Added 'private readonly CancellationToken _ct = TestContext.Current.CancellationToken;' to all async test methods that can forward a cancellation token. - Updated async method calls throughout test projects to pass _ct parameter - Applied to methods accepting CancellationToken: GetAsync, PostAsync, SendAsync, SaveChangesAsync, ToListAsync, FirstOrDefaultAsync, and other async operations - Fixed non-Async methods that accept CancellationToken (ValidateReplay, Add, etc.) This allows tests to be more responsive to cancellation requests and follows xUnit v3 best practices as documented in xUnit1051 analyzer rule. Also fixed a few squiqqles when I came across them. --- .../DPoP/ReplayTests.cs | 11 +- .../DPoPIntegrationTests.cs | 37 +-- .../TestFramework/GenericHost.cs | 108 +++++---- .../Bff.Blazor.UnitTests/BffBlazorTests.cs | 43 ++-- .../UserSessionStoreTests.cs | 223 +++++++++--------- .../Endpoints/DpopRemoteEndpointTests.cs | 9 +- .../Bff.Tests/Endpoints/LocalEndpointTests.cs | 66 +++--- .../BackchannelLogoutEndpointTests.cs | 24 +- .../Management/LoginEndpointTests.cs | 54 +++-- .../Management/LogoutEndpointTests.cs | 32 +-- .../Management/ManagementBasePathTests.cs | 8 +- .../Endpoints/Management/UserEndpointTests.cs | 6 +- .../Endpoints/RemoteEndpointTests.cs | 102 ++++---- .../Endpoints/YarpRemoteEndpointTests.cs | 82 ++++--- bff/test/Bff.Tests/GenericHostTests.cs | 4 +- .../Headers/ApiAndBffUseForwardedHeaders.cs | 14 +- .../Headers/ApiUseForwardedHeaders.cs | 13 +- bff/test/Bff.Tests/Headers/General.cs | 14 +- ...ccessTokenRetriever_Extensibility_tests.cs | 19 +- .../SessionManagement/CookieSlidingTests.cs | 50 ++-- .../ServerSideTicketStoreTests.cs | 17 +- .../TestHosts/BffIntegrationTestBase.cs | 10 +- .../TestHosts/OutputWritingTestBase.cs | 10 +- bff/test/Hosts.Tests/BffTests.cs | 11 +- .../Clients/ClientAssertionClient.cs | 16 +- ...ClientCredentialsAndResourceOwnerClient.cs | 9 +- .../Clients/ClientCredentialsClient.cs | 37 +-- .../CustomTokenRequestValidatorClient.cs | 11 +- .../Clients/CustomTokenResponseClients.cs | 9 +- .../Basic/ClientAuthenticationTests.cs | 12 +- .../Conformance/Basic/CodeFlowTests.cs | 9 +- .../Endpoints/Authorize/AuthorizeTests.cs | 159 +++++++------ .../Endpoints/Authorize/ConsentTests.cs | 21 +- .../Endpoints/Authorize/ResourceTests.cs | 1 + .../CheckSession/CheckSessionTests.cs | 6 +- .../Endpoints/Ciba/CibaTests.cs | 219 ++++++++++------- .../DeviceAuthorizationTests.cs | 1 + .../Discovery/DiscoveryEndpointTests.cs | 1 + ...dpointTests_dpop_signing_algs_supported.cs | 1 + ...en_endpoint_auth_signing_algs_supported.cs | 1 + .../Endpoints/Token/CibaTokenEndpointTests.cs | 164 ++++++++----- .../EntityFramework/IntegrationTest.cs | 1 - .../Services/CorsPolicyServiceTests.cs | 6 +- .../Storage/Stores/ClientStoreTests.cs | 10 +- .../Storage/Stores/DeviceFlowStoreTests.cs | 1 + .../CustomAuthorizeResponseGeneratorTests.cs | 3 +- .../Extensibility/CustomClaimsServiceTests.cs | 3 +- .../CustomProfileServiceTests.cs | 3 +- .../CustomTokenCreationServiceTests.cs | 3 +- .../Hosting/CorsTests.cs | 7 +- .../Endpoints/Results/AuthorizeResultTests.cs | 3 +- .../Results/CheckSessionResultTests.cs | 13 +- 52 files changed, 923 insertions(+), 774 deletions(-) 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 16ce9f89b..9a46e6dc6 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoPIntegrationTests.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoPIntegrationTests.cs @@ -21,7 +21,8 @@ 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())], @@ -38,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); } @@ -51,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); } @@ -71,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(cancellationToken: _ct); token.ShouldNotBeNull(); token.AccessToken.ToString().ShouldNotBeNull(); token.DPoPJsonWebKey.ShouldNotBeNull(); @@ -86,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(); @@ -116,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(); @@ -131,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); } @@ -155,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(); @@ -188,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(); @@ -204,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/GenericHost.cs b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/TestFramework/GenericHost.cs index d78dae633..060423ff7 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,7 +4,6 @@ using System.Net; using System.Reflection; using System.Security.Claims; -using MartinCostello.Logging.XUnit; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.TestHost; @@ -15,31 +14,37 @@ 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("/")) - { - baseAddress = baseAddress.Substring(0, baseAddress.Length - 1); - } + if (baseAddress.EndsWith("/")) baseAddress = baseAddress.Substring(0, baseAddress.Length - 1); _baseAddress = baseAddress; _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 => @@ -48,7 +53,6 @@ public class GenericHost private set => _browserClient = value; } - private HttpClient? _httpClient; public HttpClient HttpClient { get => @@ -57,21 +61,18 @@ public class GenericHost private set => _httpClient = value; } - private readonly ITestOutputHelper _testOutputHelper; - public T Resolve() - where T : notnull => + where T : notnull + { // not calling dispose on scope on purpose - _appServices.GetRequiredService().CreateScope().ServiceProvider + return _appServices.GetRequiredService().CreateScope().ServiceProvider .GetRequiredService(); + } public string Url(string? path = null) { path = path ?? string.Empty; - if (!path.StartsWith("/")) - { - path = "/" + path; - } + if (!path.StartsWith("/")) path = "/" + path; return _baseAddress + path; } @@ -127,17 +128,20 @@ 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() { @@ -145,30 +149,27 @@ public class GenericHost 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) { @@ -176,10 +177,15 @@ 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()); + + public Task IssueSessionCookieAsync(string sub, params Claim[] claims) + { + return IssueSessionCookieAsync(claims.Append(new Claim("sub", sub)).ToArray()); + } } diff --git a/bff/test/Bff.Blazor.UnitTests/BffBlazorTests.cs b/bff/test/Bff.Blazor.UnitTests/BffBlazorTests.cs index 669cffc42..6bd942465 100644 --- a/bff/test/Bff.Blazor.UnitTests/BffBlazorTests.cs +++ b/bff/test/Bff.Blazor.UnitTests/BffBlazorTests.cs @@ -11,18 +11,19 @@ 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()) }, @@ -36,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())); @@ -51,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 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 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/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/Endpoints/DpopRemoteEndpointTests.cs b/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs index bfc8091f0..9fb2bc3b9 100644 --- a/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/DpopRemoteEndpointTests.cs @@ -12,6 +12,8 @@ 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)); @@ -19,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; }); @@ -32,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 59a6f5bdb..9f9e9b384 100644 --- a/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/LocalEndpointTests.cs @@ -11,14 +11,16 @@ 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"); @@ -31,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"); @@ -44,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); } @@ -63,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"); @@ -87,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"); @@ -102,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 @@ -113,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] @@ -138,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] @@ -152,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] @@ -164,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() @@ -183,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 79ff7710b..4ebb030b8 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/BackchannelLogoutEndpointTests.cs @@ -9,12 +9,14 @@ 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() @@ -24,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); } @@ -74,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); } @@ -82,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"); } @@ -99,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); } @@ -107,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 772a892e3..7469cbb0e 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/LoginEndpointTests.cs @@ -9,12 +9,14 @@ 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() @@ -24,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("/"); } @@ -48,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("/"); } @@ -74,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("/"); } @@ -100,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("/"); } @@ -128,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")); } @@ -136,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"); } @@ -153,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 495868e5b..c3324e047 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/LogoutEndpointTests.cs @@ -9,12 +9,14 @@ 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() @@ -24,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); } @@ -43,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(); @@ -56,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")); } @@ -65,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; }); @@ -76,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")); } @@ -84,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")); } @@ -112,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")); @@ -125,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"); } @@ -147,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 56ac084c0..3c41336af 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/ManagementBasePathTests.cs @@ -10,6 +10,8 @@ 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)] @@ -18,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"); }); @@ -30,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 8f74f157c..e51e17fab 100644 --- a/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/Management/UserEndpointTests.cs @@ -9,6 +9,8 @@ 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() { @@ -53,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); } @@ -63,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 101777b75..a4b219a15 100644 --- a/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/RemoteEndpointTests.cs @@ -11,11 +11,14 @@ 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() @@ -23,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"); @@ -36,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"); @@ -61,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] @@ -73,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"); @@ -92,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"); @@ -108,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"); @@ -121,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"); @@ -137,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"); @@ -153,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(); @@ -168,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] @@ -179,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] @@ -189,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"); @@ -201,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"); @@ -214,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"); @@ -229,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"); @@ -242,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"); @@ -260,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] @@ -277,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] @@ -289,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); } @@ -307,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"); @@ -324,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 c9ab188d5..daf8d4bd8 100644 --- a/bff/test/Bff.Tests/Endpoints/YarpRemoteEndpointTests.cs +++ b/bff/test/Bff.Tests/Endpoints/YarpRemoteEndpointTests.cs @@ -9,40 +9,46 @@ 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"); @@ -54,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); @@ -66,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"); @@ -85,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); @@ -103,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); @@ -121,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); @@ -136,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"); @@ -150,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"); @@ -163,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"); @@ -181,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] @@ -191,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 34cfbd39b..c309b2c48 100644 --- a/bff/test/Bff.Tests/GenericHostTests.cs +++ b/bff/test/Bff.Tests/GenericHostTests.cs @@ -9,6 +9,8 @@ namespace Duende.Bff.Tests; public class GenericHostTests(ITestOutputHelper output) { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; + [Fact] public async Task Test1() { @@ -20,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 6a0fd2fc7..55a777108 100644 --- a/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs +++ b/bff/test/Bff.Tests/Headers/ApiAndBffUseForwardedHeaders.cs @@ -9,6 +9,8 @@ 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; @@ -20,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(); @@ -38,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(); @@ -56,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 c003ea57b..c32754068 100644 --- a/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs +++ b/bff/test/Bff.Tests/Headers/ApiUseForwardedHeaders.cs @@ -9,17 +9,20 @@ 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(); @@ -32,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 b979d2e7e..3aa3a405c 100644 --- a/bff/test/Bff.Tests/Headers/General.cs +++ b/bff/test/Bff.Tests/Headers/General.cs @@ -9,15 +9,17 @@ 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); @@ -33,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"); @@ -51,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 6351293d1..4102d6295 100644 --- a/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs +++ b/bff/test/Bff.Tests/IAccessTokenRetriever_Extensibility_tests.cs @@ -14,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 => @@ -54,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); @@ -70,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"); @@ -82,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 7451766c5..5b837fc25 100644 --- a/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs +++ b/bff/test/Bff.Tests/SessionManagement/CookieSlidingTests.cs @@ -11,19 +11,21 @@ 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)); @@ -32,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(); @@ -56,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(); @@ -95,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(); @@ -136,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/ServerSideTicketStoreTests.cs b/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs index 55f623e6b..bb0395813 100644 --- a/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs +++ b/bff/test/Bff.Tests/SessionManagement/ServerSideTicketStoreTests.cs @@ -8,12 +8,14 @@ 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() @@ -21,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/TestHosts/BffIntegrationTestBase.cs b/bff/test/Bff.Tests/TestHosts/BffIntegrationTestBase.cs index 3069fcc2a..e0d9ee544 100644 --- a/bff/test/Bff.Tests/TestHosts/BffIntegrationTestBase.cs +++ b/bff/test/Bff.Tests/TestHosts/BffIntegrationTestBase.cs @@ -12,11 +12,11 @@ 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"); @@ -46,7 +46,6 @@ public class BffIntegrationTestBase : OutputWritingTestBase services.AddSingleton(); }; - } public async Task Login(string sub) => await IdentityServerHost.IssueSessionCookieAsync(new Claim("sub", sub)); @@ -67,6 +66,5 @@ public class BffIntegrationTestBase : OutputWritingTestBase 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 a7c6a1932..4133b091e 100644 --- a/bff/test/Bff.Tests/TestHosts/OutputWritingTestBase.cs +++ b/bff/test/Bff.Tests/TestHosts/OutputWritingTestBase.cs @@ -7,9 +7,11 @@ 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) { @@ -17,16 +19,12 @@ public class OutputWritingTestBase(ITestOutputHelper testOutputHelper) : IAsyncL } } - public virtual ValueTask InitializeAsync() => default; - public virtual ValueTask DisposeAsync() { lock (_output) { testOutputHelper.WriteLine(_output.ToString()); } - - return default; } } diff --git a/bff/test/Hosts.Tests/BffTests.cs b/bff/test/Hosts.Tests/BffTests.cs index 49aff2a16..2f8198c18 100644 --- a/bff/test/Hosts.Tests/BffTests.cs +++ b/bff/test/Hosts.Tests/BffTests.cs @@ -8,6 +8,7 @@ namespace Hosts.Tests; public class BffTests : IntegrationTestBase { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly HttpClient _httpClient; private readonly BffClient _bffClient; @@ -20,7 +21,7 @@ public class BffTests : IntegrationTestBase [Fact] public async Task Can_invoke_home() { - var response = await _httpClient.GetAsync("/"); + var response = await _httpClient.GetAsync("/", _ct); response.StatusCode.ShouldBe(HttpStatusCode.OK); } @@ -28,10 +29,10 @@ public class BffTests : IntegrationTestBase 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(); @@ -50,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); } [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/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..9e6b32509 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" - }); + }, cancellationToken: _ct); var fields = GetFields(response); fields["custom"].GetString().ShouldBe("custom"); @@ -64,7 +65,7 @@ public class CustomTokenRequestValidatorClient UserName = "bob", Password = "bob" - }); + }, cancellationToken: _ct); var fields = GetFields(response); fields["custom"].GetString().ShouldBe("custom"); @@ -83,7 +84,7 @@ public class CustomTokenRequestValidatorClient UserName = "bob", Password = "bob" - }); + }, cancellationToken: _ct); response = await _client.RequestRefreshTokenAsync(new RefreshTokenRequest { @@ -92,7 +93,7 @@ public class CustomTokenRequestValidatorClient ClientSecret = "secret", RefreshToken = response.RefreshToken - }); + }, cancellationToken: _ct); var fields = GetFields(response); fields["custom"].GetString().ShouldBe("custom"); @@ -114,7 +115,7 @@ public class CustomTokenRequestValidatorClient { "scope", "api1" }, { "custom_credential", "custom credential"} } - }); + }, cancellationToken: _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..7a9da1996 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" - }); + }, cancellationToken: _ct); // raw fields var fields = GetFields(response); @@ -109,7 +110,7 @@ public class CustomTokenResponseClients UserName = "bob", Password = "invalid", Scope = "api1" - }); + }, cancellationToken: _ct); // raw fields var fields = GetFields(response); @@ -161,7 +162,7 @@ public class CustomTokenResponseClients { "scope", "api1" }, { "outcome", "succeed"} } - }); + }, cancellationToken: _ct); // raw fields @@ -229,7 +230,7 @@ public class CustomTokenResponseClients { "scope", "api1" }, { "outcome", "fail"} } - }); + }, cancellationToken: _ct); // raw fields 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..aa2671a84 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" - }); + }, cancellationToken: _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" - }); + }, cancellationToken: _ct); tokenResult.IsError.ShouldBeFalse(); tokenResult.HttpErrorReason.ShouldBe("OK"); 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/ResourceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ResourceTests.cs index 79bd474d7..11b86f805 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(); 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..6e7fec0f9 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(); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs index 4b7935de0..d41b00169 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] 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..ac4893ea7 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] 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..f553c09b7 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] 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/EntityFramework/IntegrationTest.cs b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/IntegrationTest.cs index 71ae791c9..b767df0db 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/IntegrationTest.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/IntegrationTest.cs @@ -2,7 +2,6 @@ // See LICENSE in the project root for license information. -using System.Linq; using System.Runtime.InteropServices; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; 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 dbe0d7063..e972a96e9 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; diff --git a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/DeviceFlowStoreTests.cs b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/DeviceFlowStoreTests.cs index 0f386215e..4b5ea7505 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/DeviceFlowStoreTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/DeviceFlowStoreTests.cs @@ -19,6 +19,7 @@ namespace Duende.IdentityServer.IntegrationTests.EntityFramework.Storage.Stores; public class DeviceFlowStoreTests : IntegrationTest { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private readonly IPersistentGrantSerializer serializer = new PersistentGrantSerializer(); public DeviceFlowStoreTests(DatabaseProviderFixture fixture) : base(fixture) diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomAuthorizeResponseGeneratorTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomAuthorizeResponseGeneratorTests.cs index 4667406e7..1046c7c4e 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomAuthorizeResponseGeneratorTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomAuthorizeResponseGeneratorTests.cs @@ -17,6 +17,7 @@ namespace Duende.IdentityServer.IntegrationTests.Extensibility; public class CustomAuthorizeResponseGeneratorTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "CustomAuthorizeResponseGeneratorTests"; private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); @@ -71,7 +72,7 @@ public class CustomAuthorizeResponseGeneratorTests codeChallengeMethod: OidcConstants.CodeChallengeMethods.Sha256, 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.ShouldNotBeNull(); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs index 290e7ba65..b9069531b 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomClaimsServiceTests.cs @@ -18,6 +18,7 @@ namespace Duende.IdentityServer.IntegrationTests.Extensibility; public class CustomClaimsServiceTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "CustomClaimsServiceTests"; private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); @@ -59,7 +60,7 @@ public class CustomClaimsServiceTests Address = IdentityServerPipeline.TokenEndpoint, ClientId = "test", ClientSecret = "secret" - }); + }, cancellationToken: _ct); result.IsError.ShouldBeFalse(); var accessToken = result.AccessToken; diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs index b5c3869c8..3f03d871e 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs @@ -16,6 +16,7 @@ namespace Duende.IdentityServer.IntegrationTests.Extensibility; public class CustomProfileServiceTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "Authorize endpoint"; private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); @@ -63,7 +64,7 @@ public class CustomProfileServiceTests nonce: "nonce"); _mockPipeline.BrowserClient.AllowAutoRedirect = false; - 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://client/callback"); diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs index c4cd24e17..62cacb630 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomTokenCreationServiceTests.cs @@ -17,6 +17,7 @@ namespace Duende.IdentityServer.IntegrationTests.Extensibility; public class CustomTokenCreationServiceTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "CustomTokenCreationServiceTests"; private IdentityServerPipeline _mockPipeline = new IdentityServerPipeline(); @@ -58,7 +59,7 @@ public class CustomTokenCreationServiceTests Address = IdentityServerPipeline.TokenEndpoint, ClientId = "test", ClientSecret = "secret" - }); + }, cancellationToken: _ct); result.IsError.ShouldBeFalse(); var accessToken = result.AccessToken; diff --git a/identity-server/test/IdentityServer.IntegrationTests/Hosting/CorsTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Hosting/CorsTests.cs index f06a93062..48269e6b5 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Hosting/CorsTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Hosting/CorsTests.cs @@ -14,6 +14,7 @@ namespace Duende.IdentityServer.IntegrationTests.Hosting; public class CorsTests { + private readonly CancellationToken _ct = TestContext.Current.CancellationToken; private const string Category = "CORS Integration"; private IdentityServerPipeline _pipeline = new IdentityServerPipeline(); @@ -83,7 +84,7 @@ public class CorsTests _pipeline.BackChannelClient.DefaultRequestHeaders.Add("Access-Control-Request-Method", "GET"); var message = new HttpRequestMessage(HttpMethod.Options, url); - var response = await _pipeline.BackChannelClient.SendAsync(message); + var response = await _pipeline.BackChannelClient.SendAsync(message, _ct); response.StatusCode.ShouldBe(HttpStatusCode.NoContent); response.Headers.Contains("Access-Control-Allow-Origin").ShouldBeTrue(); @@ -103,7 +104,7 @@ public class CorsTests _pipeline.BackChannelClient.DefaultRequestHeaders.Add("Access-Control-Request-Method", "GET"); var message = new HttpRequestMessage(HttpMethod.Options, url); - var response = await _pipeline.BackChannelClient.SendAsync(message); + var response = await _pipeline.BackChannelClient.SendAsync(message, _ct); response.Headers.Contains("Access-Control-Allow-Origin").ShouldBeFalse(); } @@ -123,7 +124,7 @@ public class CorsTests _pipeline.BackChannelClient.DefaultRequestHeaders.Add("Access-Control-Request-Method", "GET"); var message = new HttpRequestMessage(HttpMethod.Options, IdentityServerPipeline.DiscoveryEndpoint); - var response = await _pipeline.BackChannelClient.SendAsync(message); + var response = await _pipeline.BackChannelClient.SendAsync(message, _ct); policy.WasCalled.ShouldBeTrue(); } 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($""); } } From d3b4480c3533ee654605f42a82fbf83c29f3362a Mon Sep 17 00:00:00 2001 From: Damian Hickey <57436+damianh@users.noreply.github.com> Date: Mon, 13 Oct 2025 19:11:20 +0200 Subject: [PATCH 3/9] Fix for xunit 3 playwright --- bff/test/Hosts.Tests/PlaywrightTestBase.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bff/test/Hosts.Tests/PlaywrightTestBase.cs b/bff/test/Hosts.Tests/PlaywrightTestBase.cs index 6bf0f94be..3acb5c181 100644 --- a/bff/test/Hosts.Tests/PlaywrightTestBase.cs +++ b/bff/test/Hosts.Tests/PlaywrightTestBase.cs @@ -35,7 +35,7 @@ public class PlaywrightTestBase : PageTest, IDisposable } } - public async ValueTask InitializeAsync() + public override async ValueTask InitializeAsync() { await base.InitializeAsync(); Context.SetDefaultTimeout(10_000); @@ -58,7 +58,6 @@ public class PlaywrightTestBase : PageTest, IDisposable path = Path.GetFullPath(Path.Combine(path, "../../../")); } - await Context.Tracing.StopAsync(new() { Path = Path.Combine( From b4f1e8048dcc193d7490aa0f820e0484146c8cd6 Mon Sep 17 00:00:00 2001 From: Damian Hickey <57436+damianh@users.noreply.github.com> Date: Mon, 13 Oct 2025 19:41:53 +0200 Subject: [PATCH 4/9] Pass cancellation tokens to all async calls in tests Also some clean up on modifies for some fields (e.g. readonly, consts etc) --- .../DPoPIntegrationTests.cs | 2 +- .../IdentityServerTests.cs | 6 +- .../CustomTokenRequestValidatorClient.cs | 10 +- .../Clients/CustomTokenResponseClients.cs | 8 +- .../Clients/DiscoveryClient.cs | 4 +- .../Clients/ExtensionGrantClient.cs | 32 +-- .../Clients/RefreshTokenClient.cs | 34 +-- .../Clients/ResourceOwnerClient.cs | 16 +- .../Clients/RevocationClient.cs | 12 +- .../Clients/UserInfoClient.cs | 24 +- .../DynamicClientRegistrationTests.cs | 6 +- ...ynamicClientRegistrationValidationTests.cs | 31 +-- .../Conformance/Basic/CodeFlowTests.cs | 4 +- .../Conformance/Basic/RedirectUriTests.cs | 12 +- .../Basic/ResponseTypeResponseModeTests.cs | 10 +- .../Conformance/Pkce/PkceTests.cs | 33 +-- .../Authorize/JwtRequestAuthorizeTests.cs | 63 +++-- .../Authorize/PushedAuthorizationTests.cs | 23 +- .../Endpoints/Authorize/ResourceTests.cs | 48 ++-- .../RestrictAccessTokenViaBrowserTests.cs | 23 +- .../Endpoints/Authorize/SessionIdTests.cs | 6 +- .../DeviceAuthorizationTests.cs | 20 +- .../Discovery/DiscoveryEndpointTests.cs | 52 ++-- ...dpointTests_dpop_signing_algs_supported.cs | 12 +- ...en_endpoint_auth_signing_algs_supported.cs | 14 +- ...uest_object_auth_signing_algs_supported.cs | 12 +- .../Endpoints/EndSession/EndSessionTests.cs | 87 +++---- .../Introspection/IntrospectionTests.cs | 128 +++++---- .../OAuthMetadata/OAuthMetadataTests.cs | 33 +-- .../Endpoints/Revocation/RevocationTests.cs | 54 ++-- .../DPoPPushedAuthorizationEndpointTests.cs | 17 +- .../Endpoints/Token/DPoPTokenEndpointTests.cs | 73 +++--- .../Endpoints/Token/MtlsTokenEndpointTests.cs | 12 +- .../Endpoints/Token/RefreshTokenTests.cs | 17 +- .../Endpoints/Token/ResourceTests.cs | 92 ++++--- .../Endpoints/Token/TokenEndpointTests.cs | 26 +- .../EntityFrameworkBasedLogoutTests.cs | 5 +- .../EntityFramework/IntegrationTest.cs | 5 +- .../Storage/Stores/DeviceFlowStoreTests.cs | 12 +- .../Stores/IdentityProviderStoreTests.cs | 10 +- .../Stores/PersistedGrantStoreTests.cs | 16 +- .../Storage/Stores/ResourceStoreTests.cs | 20 +- .../Storage/TokenCleanup/TokenCleanupTests.cs | 42 +-- .../Extensibility/CustomClaimsServiceTests.cs | 2 +- .../CustomTokenCreationServiceTests.cs | 2 +- .../Hosting/DynamicProvidersTests.cs | 73 +++--- .../Hosting/FederatedSignoutTests.cs | 30 +-- .../Hosting/IdentityServerMiddlewareTests.cs | 5 +- .../Hosting/LicenseTests.cs | 3 +- .../LocalApiAuthenticationTests.cs | 38 +-- .../Hosting/ServerSideSessionTests.cs | 245 +++++++++--------- .../Hosting/SubpathHosting.cs | 7 +- ...ributedDeviceFlowThrottlingServiceTests.cs | 7 +- 53 files changed, 791 insertions(+), 787 deletions(-) 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 9a46e6dc6..779e512d9 100644 --- a/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoPIntegrationTests.cs +++ b/aspnetcore-authentication-jwtbearer/test/AspNetCore.Authentication.JwtBearer.Tests/DPoPIntegrationTests.cs @@ -73,7 +73,7 @@ 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"), _ct); - var token = await response.Content.ReadFromJsonAsync(cancellationToken: _ct); + var token = await response.Content.ReadFromJsonAsync(_ct); token.ShouldNotBeNull(); token.AccessToken.ToString().ShouldNotBeNull(); token.DPoPJsonWebKey.ShouldNotBeNull(); diff --git a/identity-server/test/IdentityServer.EndToEndTests/IdentityServerTests.cs b/identity-server/test/IdentityServer.EndToEndTests/IdentityServerTests.cs index 069ce961c..ff4c34907 100644 --- a/identity-server/test/IdentityServer.EndToEndTests/IdentityServerTests.cs +++ b/identity-server/test/IdentityServer.EndToEndTests/IdentityServerTests.cs @@ -12,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)] @@ -23,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(); @@ -40,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.IntegrationTests/Clients/CustomTokenRequestValidatorClient.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenRequestValidatorClient.cs index 9e6b32509..ceeaf49ab 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenRequestValidatorClient.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenRequestValidatorClient.cs @@ -46,7 +46,7 @@ public class CustomTokenRequestValidatorClient ClientId = "client", ClientSecret = "secret", Scope = "api1" - }, cancellationToken: _ct); + }, _ct); var fields = GetFields(response); fields["custom"].GetString().ShouldBe("custom"); @@ -65,7 +65,7 @@ public class CustomTokenRequestValidatorClient UserName = "bob", Password = "bob" - }, cancellationToken: _ct); + }, _ct); var fields = GetFields(response); fields["custom"].GetString().ShouldBe("custom"); @@ -84,7 +84,7 @@ public class CustomTokenRequestValidatorClient UserName = "bob", Password = "bob" - }, cancellationToken: _ct); + }, _ct); response = await _client.RequestRefreshTokenAsync(new RefreshTokenRequest { @@ -93,7 +93,7 @@ public class CustomTokenRequestValidatorClient ClientSecret = "secret", RefreshToken = response.RefreshToken - }, cancellationToken: _ct); + }, _ct); var fields = GetFields(response); fields["custom"].GetString().ShouldBe("custom"); @@ -115,7 +115,7 @@ public class CustomTokenRequestValidatorClient { "scope", "api1" }, { "custom_credential", "custom credential"} } - }, cancellationToken: _ct); + }, _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 7a9da1996..07f7a28b8 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/CustomTokenResponseClients.cs @@ -47,7 +47,7 @@ public class CustomTokenResponseClients UserName = "bob", Password = "bob", Scope = "api1" - }, cancellationToken: _ct); + }, _ct); // raw fields var fields = GetFields(response); @@ -110,7 +110,7 @@ public class CustomTokenResponseClients UserName = "bob", Password = "invalid", Scope = "api1" - }, cancellationToken: _ct); + }, _ct); // raw fields var fields = GetFields(response); @@ -162,7 +162,7 @@ public class CustomTokenResponseClients { "scope", "api1" }, { "outcome", "succeed"} } - }, cancellationToken: _ct); + }, _ct); // raw fields @@ -230,7 +230,7 @@ public class CustomTokenResponseClients { "scope", "api1" }, { "outcome", "fail"} } - }, cancellationToken: _ct); + }, _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/CodeFlowTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/CodeFlowTests.cs index aa2671a84..ce68782fd 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/CodeFlowTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Conformance/Basic/CodeFlowTests.cs @@ -91,7 +91,7 @@ public class CodeFlowTests Code = code, RedirectUri = "https://code_pipeline.Client/callback?foo=bar&baz=quux" - }, cancellationToken: _ct); + }, _ct); tokenResult.IsError.ShouldBeFalse(); tokenResult.HttpErrorReason.ShouldBe("OK"); @@ -144,7 +144,7 @@ public class CodeFlowTests Code = code, RedirectUri = "https://code_pipeline.Client/callback?foo=bar&baz=quux" - }, cancellationToken: _ct); + }, _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/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 11b86f805..25ac36faf 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ResourceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Authorize/ResourceTests.cs @@ -152,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 @@ -162,7 +162,7 @@ public class ResourceTests ClientSecret = "secret", Code = code, RedirectUri = "https://client1/callback" - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -187,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 @@ -201,7 +201,7 @@ public class ResourceTests { { "resource", " " } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -227,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 @@ -241,7 +241,7 @@ public class ResourceTests { { "resource", " " } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -267,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 @@ -281,7 +281,7 @@ public class ResourceTests { { "resource", "urn:resource1" } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -307,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 @@ -317,7 +317,7 @@ public class ResourceTests ClientSecret = "secret", Code = code, RedirectUri = "https://client1/callback" - }); + }, _ct); tokenResponse = await _mockPipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { @@ -329,7 +329,7 @@ public class ResourceTests { { "resource", "urn:resource1" } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -355,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 @@ -365,7 +365,7 @@ public class ResourceTests ClientSecret = "secret", Code = code, RedirectUri = "https://client1/callback" - }); + }, _ct); tokenResponse = await _mockPipeline.BackChannelClient.RequestRefreshTokenAsync(new RefreshTokenRequest { @@ -373,7 +373,7 @@ public class ResourceTests ClientId = "client1", ClientSecret = "secret", RefreshToken = tokenResponse.RefreshToken, - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -398,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 @@ -412,7 +412,7 @@ public class ResourceTests { { "resource", "urn:resource1" } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -437,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 @@ -451,7 +451,7 @@ public class ResourceTests { // no resource param } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -476,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 @@ -490,7 +490,7 @@ public class ResourceTests { // no resource param } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -508,7 +508,7 @@ public class ResourceTests { { "resource", "urn:resource3" } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -533,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 @@ -547,7 +547,7 @@ public class ResourceTests { { "resource", "urn:resource3" } } - }); + }, _ct); { var claims = ParseAccessTokenClaims(tokenResponse); @@ -572,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/DeviceAuthorization/DeviceAuthorizationTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/DeviceAuthorization/DeviceAuthorizationTests.cs index 6e7fec0f9..4a52c9aff 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/DeviceAuthorization/DeviceAuthorizationTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/DeviceAuthorization/DeviceAuthorizationTests.cs @@ -39,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); @@ -57,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); @@ -72,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); @@ -90,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); @@ -109,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 d41b00169..ac6c8069b 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Endpoints/Discovery/DiscoveryEndpointTests.cs @@ -28,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"); } @@ -44,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"); } @@ -69,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"); @@ -111,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(); @@ -131,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"]; @@ -160,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(); @@ -186,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"); @@ -212,7 +212,7 @@ public class DiscoveryEndpointTests RequireHttps = false, RequireKeySet = false } - }); + }, _ct); result.Issuer.ShouldBe("https://грант.рф"); } @@ -225,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(); @@ -249,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(); @@ -266,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(); } @@ -285,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() { @@ -293,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 @@ -333,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"); } @@ -352,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) { @@ -374,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 ac4893ea7..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 @@ -31,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); @@ -44,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); @@ -72,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 f553c09b7..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 @@ -30,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; @@ -49,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; @@ -78,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(); @@ -103,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/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 b767df0db..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() { diff --git a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/DeviceFlowStoreTests.cs b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/DeviceFlowStoreTests.cs index 4b5ea7505..49981d8ee 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/DeviceFlowStoreTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/DeviceFlowStoreTests.cs @@ -117,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>() 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 } @@ -337,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 @@ -379,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); } @@ -390,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); } 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.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); From 43ec00a0701d3100c21e68b2c809ffc2819b4460 Mon Sep 17 00:00:00 2001 From: Damian Hickey <57436+damianh@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:03:20 +0200 Subject: [PATCH 5/9] Fix lint warnings --- .../TestFramework/GenericHost.cs | 44 +++++++------------ 1 file changed, 15 insertions(+), 29 deletions(-) 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 060423ff7..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 @@ -29,7 +29,10 @@ public class GenericHost public GenericHost(ITestOutputHelper testOutputHelper, string baseAddress = "https://server") { - if (baseAddress.EndsWith("/")) baseAddress = baseAddress.Substring(0, baseAddress.Length - 1); + if (baseAddress.EndsWith("/")) + { + baseAddress = baseAddress.Substring(0, baseAddress.Length - 1); + } _baseAddress = baseAddress; _testOutputHelper = testOutputHelper; @@ -61,18 +64,13 @@ public class GenericHost private set => _httpClient = value; } - public T Resolve() - where T : notnull - { - // not calling dispose on scope on purpose - return _appServices.GetRequiredService().CreateScope().ServiceProvider - .GetRequiredService(); - } - public string Url(string? path = null) { - path = path ?? string.Empty; - if (!path.StartsWith("/")) path = "/" + path; + path ??= string.Empty; + if (!path.StartsWith("/")) + { + path = "/" + path; + } return _baseAddress + path; } @@ -128,8 +126,7 @@ public class GenericHost ConfigureSignout(builder); } - private void ConfigureSignout(WebApplication app) - { + private void ConfigureSignout(WebApplication app) => app.Use(async (ctx, next) => { if (ctx.Request.Path == "/__signout") @@ -141,21 +138,16 @@ public class GenericHost await next(); }); - } - public async Task RevokeSessionCookieAsync() - { - var response = await BrowserClient.GetAsync(Url("__signout")); - response.StatusCode.ShouldBe((HttpStatusCode)204); - } - - private void ConfigureSignin(WebApplication app) - { + 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"); + if (_userToSignIn is not object) + { + throw new Exception("No User Configured for SignIn"); + } var props = _propsToSignIn ?? new AuthenticationProperties(); await ctx.SignInAsync(_userToSignIn, props); @@ -169,7 +161,6 @@ public class GenericHost await next(); }); - } public async Task IssueSessionCookieAsync(params Claim[] claims) { @@ -183,9 +174,4 @@ public class GenericHost _propsToSignIn = props; return IssueSessionCookieAsync(claims); } - - public Task IssueSessionCookieAsync(string sub, params Claim[] claims) - { - return IssueSessionCookieAsync(claims.Append(new Claim("sub", sub)).ToArray()); - } } From bbf40cd2e8fdcc4037d971170b7a5eb3708f13fb Mon Sep 17 00:00:00 2001 From: Damian Hickey <57436+damianh@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:06:12 +0200 Subject: [PATCH 6/9] Address review comment: this should throw. --- .../EntityFramework/Storage/Stores/ClientStoreTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e972a96e9..14f00d5ee 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/ClientStoreTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/EntityFramework/Storage/Stores/ClientStoreTests.cs @@ -169,7 +169,7 @@ public class ClientStoreTests : IntegrationTest Date: Mon, 13 Oct 2025 20:16:48 +0200 Subject: [PATCH 7/9] The analyser missed this one --- .../Results/EndSessionCallbackResultTests.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) 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(""); } From 2654b7be392fe37d0feee22f5c4899f9771a7ff0 Mon Sep 17 00:00:00 2001 From: Damian Hickey <57436+damianh@users.noreply.github.com> Date: Mon, 13 Oct 2025 22:42:05 +0200 Subject: [PATCH 8/9] Fix formatting --- shared/Xunit.Playwright/PlaywrightTestBase.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/shared/Xunit.Playwright/PlaywrightTestBase.cs b/shared/Xunit.Playwright/PlaywrightTestBase.cs index 7fa2eabb8..6657c81b5 100644 --- a/shared/Xunit.Playwright/PlaywrightTestBase.cs +++ b/shared/Xunit.Playwright/PlaywrightTestBase.cs @@ -3,8 +3,6 @@ using System.Reflection; using Microsoft.Playwright; -using Xunit.Sdk; - namespace Duende.Xunit.Playwright; public class Defaults @@ -21,9 +19,6 @@ public class PlaywrightTestBase : IAsyncLifetime, IDisposable where THost private readonly IDisposable _loggingScope; private IPlaywright? _playwright; private IBrowser? _browser; - - protected IBrowserContext Context { get; private set; } = null!; - protected IPage Page { get; private set; } = null!; public PlaywrightTestBase(ITestOutputHelper output, AppHostFixture fixture) { @@ -44,6 +39,9 @@ public class PlaywrightTestBase : IAsyncLifetime, IDisposable where THost #endif } } + protected IBrowserContext Context { get; private set; } = null!; + + protected IPage Page { get; private set; } = null!; public AppHostFixture Fixture { get; } @@ -55,7 +53,7 @@ public class PlaywrightTestBase : IAsyncLifetime, IDisposable where THost _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() { @@ -84,7 +82,7 @@ public class PlaywrightTestBase : IAsyncLifetime, IDisposable where THost $"{WithTestNameAttribute.CurrentClassName}.{WithTestNameAttribute.CurrentTestName}.zip" ) }); - + await Context.CloseAsync(); await _browser!.DisposeAsync(); _playwright!.Dispose(); From e79d9b62e6e6089a2fc2486e056cef5e0f5d54b2 Mon Sep 17 00:00:00 2001 From: Damian Hickey <57436+damianh@users.noreply.github.com> Date: Wed, 15 Oct 2025 13:55:29 +0200 Subject: [PATCH 9/9] Add .NET 10 target --- .../AspNetCore.Authentication.JwtBearer.csproj | 2 +- .../AspNetCore.Authentication.JwtBearer.Tests.csproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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 6f6c1483e..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 @@ - +