From c832d2c3242540bc94b63ab94b6ffa1bdc0c705c Mon Sep 17 00:00:00 2001 From: NachoEscrig Date: Thu, 11 Jun 2026 09:31:22 +0100 Subject: [PATCH 1/2] Upgrade to duende v8 --- .../AccountControllerUnitTests.cs | 19 ++++----- .../AccountServiceUnitTests.cs | 5 ++- .../AdminUIIntegration.Tests.csproj | 4 +- .../ExternalProvidersServiceTests.cs | 25 ++++++------ .../Controllers/AccountController.cs | 40 +++++++++++-------- .../Controllers/ConsentController.cs | 7 +++- .../Controllers/GrantsController.cs | 12 ++++-- .../Controllers/HomeController.cs | 4 +- .../Controllers/WebhookController.cs | 4 +- .../Demo/DemoCorsPolicy.cs | 3 +- .../Demo/DemoRedirectUriValidator.cs | 3 +- ...s.IdentityServer.AdminUiIntegration.csproj | 32 +++++++-------- .../Services/AccountService.cs | 25 ++++++------ .../Services/ConsentService.cs | 19 ++++----- .../Services/CustomEventSink.cs | 3 +- .../Services/ExternalProviderService.cs | 13 +++--- .../Services/IAccountService.cs | 9 +++-- .../Services/IExternalProviderService.cs | 5 ++- 18 files changed, 127 insertions(+), 105 deletions(-) diff --git a/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AccountControllerUnitTests.cs b/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AccountControllerUnitTests.cs index 26017b5..4fba446 100644 --- a/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AccountControllerUnitTests.cs +++ b/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AccountControllerUnitTests.cs @@ -1,4 +1,5 @@ -using System.Threading.Tasks; +using System.Threading; +using System.Threading.Tasks; using Duende.IdentityServer.Models; using IdentityExpress.Identity; using Duende.IdentityServer.Services; @@ -20,9 +21,6 @@ public class AccountControllerUnitTests { private readonly Mock> mockUserManager; private readonly Mock mockInteraction; - private readonly Mock mockClientStore; - private readonly Mock mockAccessor; - private readonly Mock mockSchemeProvider; private readonly Mock mockEvents; private readonly Mock mockAccountService; private readonly Mock mockUrlHelper; @@ -34,11 +32,8 @@ public class AccountControllerUnitTests public AccountControllerUnitTests() { mockInteraction = new Mock(); - mockClientStore = new Mock(); - mockAccessor = new Mock(); var userStoreMock = new Mock>(); mockUserManager = new Mock>(userStoreMock.Object, null, null, null, null, null, null, null, null); - mockSchemeProvider = new Mock(); mockEvents = new Mock(); mockAccountService = new Mock(); mockUrlHelper = new Mock(); @@ -83,14 +78,14 @@ public async Task Login_WhenNotExternal_ShouldCallBuildLoginViewModelAsync() Username = "LoginHunt", }; - mockAccountService.Setup(x => x.BuildLoginViewModelAsync(It.IsAny())) + mockAccountService.Setup(x => x.BuildLoginViewModelAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(testLoginViewModel); var sut = CreateSut(); var actual = await sut.Login(testReturnUrl); - mockAccountService.Verify(x => x.BuildLoginViewModelAsync(testReturnUrl)); + mockAccountService.Verify(x => x.BuildLoginViewModelAsync(testReturnUrl, CancellationToken.None)); var viewResult = Assert.IsType(actual); Assert.Equal(viewResult.Model, testLoginViewModel); @@ -132,7 +127,7 @@ public async Task Login_WhenModelPassedIn_WithButtonNotLogin_AndNullAuthContext_ ReturnUrl = "https://some.return.com", }; - mockInteraction.Setup(x => x.GetAuthorizationContextAsync(It.IsAny())) + mockInteraction.Setup(x => x.GetAuthorizationContextAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(() => null); var sut = CreateSut(); @@ -155,13 +150,13 @@ public async Task Login_WhenModelPassedIn_WithButtonNotLogin_AndAuthContextRetur var authRequest = new AuthorizationRequest(); - mockInteraction.Setup(x => x.GetAuthorizationContextAsync(It.IsAny())) + mockInteraction.Setup(x => x.GetAuthorizationContextAsync(It.IsAny(), It.IsAny())) .ReturnsAsync(() => authRequest); var sut = CreateSut(); var actual = await sut.Login(testLoginModel, "cancel"); - mockInteraction.Verify(x => x.DenyAuthorizationAsync(authRequest, AuthorizationError.AccessDenied, null)); + mockInteraction.Verify(x => x.DenyAuthorizationAsync(authRequest, InteractionError.AccessDenied, CancellationToken.None, null)); var viewResult = Assert.IsType(actual); Assert.Equal(testLoginModel.ReturnUrl, viewResult.Url); diff --git a/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AccountServiceUnitTests.cs b/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AccountServiceUnitTests.cs index dbe012b..cad300f 100644 --- a/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AccountServiceUnitTests.cs +++ b/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AccountServiceUnitTests.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Security.Claims; +using System.Threading; using System.Threading.Tasks; using IdentityModel; using Duende.IdentityServer.Models; @@ -82,13 +83,13 @@ public async Task BuildLoggedOutViewModelAsync_WhenSuccessfulLogout_ShowCorrectL }; LogoutRequest logoutRequest = new LogoutRequest(iFrameUrl, logoutMessge); - mockInteraction.Setup(x => x.GetLogoutContextAsync(logoutId)) + mockInteraction.Setup(x => x.GetLogoutContextAsync(logoutId, It.IsAny())) .ReturnsAsync(logoutRequest).Verifiable(); mockAccessor.SetupGet(x => x.HttpContext.User).Returns(user).Verifiable(); //act - var result = await CreateSut().BuildLoggedOutViewModelAsync(logoutId); + var result = await CreateSut().BuildLoggedOutViewModelAsync(logoutId, CancellationToken.None); //assert Assert.True(result.AutomaticRedirectAfterSignOut); diff --git a/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AdminUIIntegration.Tests.csproj b/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AdminUIIntegration.Tests.csproj index e1e701f..258b22a 100644 --- a/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AdminUIIntegration.Tests.csproj +++ b/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/AdminUIIntegration.Tests.csproj @@ -8,8 +8,8 @@ - - + + diff --git a/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/ExternalProvidersServiceTests.cs b/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/ExternalProvidersServiceTests.cs index 55ae103..30445a8 100644 --- a/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/ExternalProvidersServiceTests.cs +++ b/Rsk.Samples.IdentityServer.AdminUIIntegration.Tests/ExternalProvidersServiceTests.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer.Models; using Duende.IdentityServer.Stores; @@ -8,7 +9,7 @@ using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.Extensions.Configuration; using Moq; -using Rsk.AspNetCore.Authentication.Saml2p; +// using Rsk.AspNetCore.Authentication.Saml2p; using Rsk.Samples.IdentityServer.AdminUiIntegration.Models; using Rsk.Samples.IdentityServer.AdminUiIntegration.Services; using Xunit; @@ -25,7 +26,7 @@ public class ExternalProvidersServiceTests { new AuthenticationScheme("Cookies", null, typeof(CookieAuthenticationHandler)), new AuthenticationScheme("rsk-oidc-scheme", "RSK OIDC Scheme", typeof(OpenIdConnectHandler)), - new AuthenticationScheme("rsk-saml-scheme", "RSK SAML Scheme", typeof(Saml2pAuthenticationHandler)), + // new AuthenticationScheme("rsk-saml-scheme", "RSK SAML Scheme", typeof(Saml2pAuthenticationHandler)), }; private readonly List fakeDuendeSchemes = new List @@ -40,7 +41,7 @@ public ExternalProvidersServiceTests() authenticationSchemeProviderMock.Setup(x => x.GetAllSchemesAsync()) .ReturnsAsync(fakeAuthSchemesIncRsk); - identityProviderStoreMock.Setup(x => x.GetAllSchemeNamesAsync()) + identityProviderStoreMock.Setup(x => x.GetAllSchemeNamesAsync(It.IsAny())) .ReturnsAsync(fakeDuendeSchemes); } @@ -64,7 +65,7 @@ [Fact] public async Task GetAll_WhenDisabled_ShouldBeEmpty() var sut = CreateSut(); - var actual = await sut.GetAll(); + var actual = await sut.GetAll(CancellationToken.None); actual.Should().BeEmpty(); } @@ -75,7 +76,7 @@ [Fact] public async Task GetAll_WhenDuende_ShouldOnlyReturnDuendeEnabledDynamicP var sut = CreateSut(); - var actual = await sut.GetAll(); + var actual = await sut.GetAll(CancellationToken.None); var expected = new List { @@ -92,7 +93,7 @@ [Fact] public async Task GetAll_WhenRsk_ShouldOnlyReturnRskDynamicProviders() var sut = CreateSut(); - var actual = await sut.GetAll(); + var actual = await sut.GetAll(CancellationToken.None); var expected = new List { @@ -110,11 +111,11 @@ public async Task GetScheme_WhenDisabled_ShouldNotReturnAnything() var sut = CreateSut(); - var actualDuende = await sut.GetScheme("duende-oidc-scheme"); + var actualDuende = await sut.GetScheme("duende-oidc-scheme", CancellationToken.None); actualDuende.Should().BeNull(); - var actualRsk = await sut.GetScheme("rsk-oidc-scheme"); + var actualRsk = await sut.GetScheme("rsk-oidc-scheme", CancellationToken.None); actualRsk.Should().BeNull(); } @@ -126,13 +127,13 @@ public async Task GetScheme_WhenDuende_ShouldNotReturnDuendeExternalProvider() var sut = CreateSut(); - var actualDuende = await sut.GetScheme("duende-oidc-scheme"); + var actualDuende = await sut.GetScheme("duende-oidc-scheme", CancellationToken.None); actualDuende.Should().NotBeNull(); actualDuende.AuthenticationScheme.Should().Be("duende-oidc-scheme"); actualDuende.DisplayName.Should().Be("Duende OIDC Scheme"); - var actualRsk = await sut.GetScheme("rsk-saml-scheme"); + var actualRsk = await sut.GetScheme("rsk-saml-scheme", CancellationToken.None); actualRsk.Should().BeNull(); } @@ -144,11 +145,11 @@ public async Task GetScheme_WhenRsk_ShouldNotReturnRskExternalProvider() var sut = CreateSut(); - var actualDuende = await sut.GetScheme("duende-oidc-scheme"); + var actualDuende = await sut.GetScheme("duende-oidc-scheme", CancellationToken.None); actualDuende.Should().BeNull(); - var actualRsk = await sut.GetScheme("rsk-saml-scheme"); + var actualRsk = await sut.GetScheme("rsk-saml-scheme", CancellationToken.None); actualRsk.Should().NotBeNull(); actualRsk.AuthenticationScheme.Should().Be("rsk-saml-scheme"); diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/AccountController.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/AccountController.cs index e3d5d3c..eaa39aa 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/AccountController.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/AccountController.cs @@ -1,11 +1,10 @@ // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. - - using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer; using Duende.IdentityServer.Events; @@ -66,9 +65,11 @@ public async Task Login(string returnUrl) { bool externalLogin = Request.Cookies["Identity.External"] != null; + CancellationToken cancellationToken = HttpContext.RequestAborted; + // build a model so we know what to show on the login page // if were told we a linking an external login then then we build a model - var vm = !externalLogin ? await accountService.BuildLoginViewModelAsync(returnUrl) + var vm = !externalLogin ? await accountService.BuildLoginViewModelAsync(returnUrl, cancellationToken) : accountService.BuildLinkLoginViewModel(returnUrl); if (!externalLogin && vm.IsExternalLoginOnly) @@ -87,6 +88,8 @@ public async Task Login(string returnUrl) [ValidateAntiForgeryToken] public async Task Login(LoginInputModel model, string button) { + CancellationToken cancellationToken = HttpContext.RequestAborted; + if (button != "login") { if (Request.Cookies["Identity.External"] != null) @@ -95,13 +98,13 @@ public async Task Login(LoginInputModel model, string button) } // the user clicked the "cancel" button - var context = await interaction.GetAuthorizationContextAsync(model.ReturnUrl); + AuthorizationRequest context = await interaction.GetAuthorizationContextAsync(model.ReturnUrl, cancellationToken); if (context != null) { // if the user cancels, send a result back into IdentityServer as if they // denied the consent (even if this client does not require consent). // this will send back an access denied OIDC error response to the client. - await interaction.DenyAuthorizationAsync(context, AuthorizationError.AccessDenied); + await interaction.DenyAuthorizationAsync(context, InteractionError.AccessDenied, cancellationToken); // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null return Redirect(model.ReturnUrl); @@ -119,7 +122,7 @@ public async Task Login(LoginInputModel model, string button) if (user != null && await userManager.CheckPasswordAsync(user, model.Password)) { - await events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName)); + await events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName), cancellationToken); // only set explicit expiration here if user chooses "remember me". // otherwise we rely upon expiration configured in cookie middleware. @@ -143,11 +146,11 @@ public async Task Login(LoginInputModel model, string button) }; // issue authentication cookie with subject ID and username - await events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName)); + await events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName), cancellationToken); await HttpContext.SignInAsync(isuser, props); // link external login if cookie exists - await LinkIfExternalLogin(user); + await LinkIfExternalLogin(user, cancellationToken); // make sure the returnUrl is still valid, and if so redirect back to authorize endpoint or a local page if (interaction.IsValidReturnUrl(model.ReturnUrl) || Url.IsLocalUrl(model.ReturnUrl)) @@ -158,13 +161,13 @@ public async Task Login(LoginInputModel model, string button) return Redirect("~/"); } - await events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials")); + await events.RaiseAsync(new UserLoginFailureEvent(model.Username, "invalid credentials"), cancellationToken); ModelState.AddModelError("", "Invalid username or password"); } // something went wrong, show form with error - var vm = await accountService.BuildLoginViewModelAsync(model); + var vm = await accountService.BuildLoginViewModelAsync(model, cancellationToken); vm.LinkSetup = Request.Cookies["Identity.External"] != null; return View(vm); } @@ -247,7 +250,8 @@ public async Task ExternalLoginCallback() }; // issue local authentication cookie for user - await events.RaiseAsync(new UserLoginSuccessEvent(provider, userId, user.Id, user.UserName)); + CancellationToken cancellationToken = HttpContext.RequestAborted; + await events.RaiseAsync(new UserLoginSuccessEvent(provider, userId, user.Id, user.UserName), cancellationToken); await HttpContext.SignInAsync(isuser, props); // delete temporary cookie used during external authentication @@ -262,8 +266,10 @@ public async Task ExternalLoginCallback() [HttpGet] public async Task Logout(string logoutId) { + CancellationToken cancellationToken = HttpContext.RequestAborted; + // build a model so the logout page knows what to display - var vm = await accountService.BuildLogoutViewModelAsync(logoutId); + var vm = await accountService.BuildLogoutViewModelAsync(logoutId, cancellationToken); if (vm.ShowLogoutPrompt == false) { @@ -282,8 +288,10 @@ public async Task Logout(string logoutId) [ValidateAntiForgeryToken] public async Task Logout(LogoutInputModel model) { + CancellationToken cancellationToken = HttpContext.RequestAborted; + // build a model so the logged out page knows what to display - var vm = await accountService.BuildLoggedOutViewModelAsync(model.LogoutId); + var vm = await accountService.BuildLoggedOutViewModelAsync(model.LogoutId, cancellationToken); var user = HttpContext.User; if (user?.Identity.IsAuthenticated == true) @@ -292,7 +300,7 @@ public async Task Logout(LogoutInputModel model) await HttpContext.SignOutAsync(IdentityConstants.ApplicationScheme); // raise the logout event - await events.RaiseAsync(new UserLogoutSuccessEvent(user.GetSubjectId(), user.GetDisplayName())); + await events.RaiseAsync(new UserLogoutSuccessEvent(user.GetSubjectId(), user.GetDisplayName()), cancellationToken); } // check if we need to trigger sign-out at an upstream identity provider @@ -356,7 +364,7 @@ public async Task Register([FromForm] RegisterInputModel model) return View(vm); } - private async Task LinkIfExternalLogin(IdentityExpressUser localUser) + private async Task LinkIfExternalLogin(IdentityExpressUser localUser, CancellationToken cancellationToken) { // get external identity from external scheme cookie var result = await HttpContext.AuthenticateAsync("Identity.External"); @@ -373,7 +381,7 @@ private async Task LinkIfExternalLogin(IdentityExpressUser local var userId = userIdClaim.Value; var providerScheme = result.Properties.Items["scheme"]; - var provider = await externalProviderService.GetScheme(providerScheme); + var provider = await externalProviderService.GetScheme(providerScheme, cancellationToken); var outcome = await userManager.AddLoginAsync(localUser, new UserLoginInfo(provider.AuthenticationScheme, userId, provider.DisplayName)); await HttpContext.SignOutAsync("Identity.External"); return outcome; diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/ConsentController.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/ConsentController.cs index d0ca2df..0afe3d1 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/ConsentController.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/ConsentController.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer.Extensions; using Duende.IdentityServer.Services; @@ -37,7 +38,8 @@ public ConsentController( [HttpGet] public async Task Index(string returnUrl) { - var vm = await consent.BuildViewModelAsync(returnUrl); + CancellationToken cancellationToken = HttpContext.RequestAborted; + var vm = await consent.BuildViewModelAsync(returnUrl, cancellationToken); if (vm != null) { return View("Index", vm); @@ -53,7 +55,8 @@ public async Task Index(string returnUrl) [ValidateAntiForgeryToken] public async Task Index(ConsentInputModel model) { - var result = await consent.ProcessConsent(model, User.GetSubjectId()); + CancellationToken cancellationToken = HttpContext.RequestAborted; + var result = await consent.ProcessConsent(model, User.GetSubjectId(), cancellationToken); if (result.IsRedirect) { diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/GrantsController.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/GrantsController.cs index 0fafeba..ec9f471 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/GrantsController.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/GrantsController.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer.Services; using Duende.IdentityServer.Stores; @@ -50,21 +51,24 @@ public async Task Index() [ValidateAntiForgeryToken] public async Task Revoke(string clientId) { - await interaction.RevokeUserConsentAsync(clientId); + CancellationToken cancellationToken = HttpContext.RequestAborted; + await interaction.RevokeUserConsentAsync(clientId, cancellationToken); return RedirectToAction("Index"); } private async Task BuildViewModelAsync() { - var grants = await interaction.GetAllUserGrantsAsync(); + CancellationToken cancellationToken = HttpContext.RequestAborted; + + var grants = await interaction.GetAllUserGrantsAsync(cancellationToken); var list = new List(); foreach(var grant in grants) { - var client = await clients.FindClientByIdAsync(grant.ClientId); + var client = await clients.FindClientByIdAsync(grant.ClientId, cancellationToken); if (client != null) { - var resources = await this.resources.FindResourcesByScopeAsync(grant.Scopes); + var resources = await this.resources.FindResourcesByScopeAsync(grant.Scopes, cancellationToken); var item = new GrantViewModel { diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/HomeController.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/HomeController.cs index 002aa8a..d6554d2 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/HomeController.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/HomeController.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer.Services; using Microsoft.AspNetCore.Mvc; @@ -36,7 +37,8 @@ public async Task Error(string errorId) var vm = new ErrorViewModel(); // retrieve error details from IdentityServer - var message = await interaction.GetErrorContextAsync(errorId); + CancellationToken cancellationToken = HttpContext.RequestAborted; + var message = await interaction.GetErrorContextAsync(errorId, cancellationToken); //try and get more details regarding the error from the IdentityServer event cache var cachedEventInformation = eventStore.GetEventByTraceID(HttpContext.TraceIdentifier); diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/WebhookController.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/WebhookController.cs index 5d1af30..4c8b024 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/WebhookController.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Controllers/WebhookController.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer.Services; using IdentityExpress.Identity; @@ -52,10 +53,11 @@ public async Task DeleteServerSideSession([FromRoute] string id) { ArgumentNullException.ThrowIfNull(id); + CancellationToken cancellationToken = HttpContext.RequestAborted; await sessionManagementService.RemoveSessionsAsync(new RemoveSessionsContext { SessionId = id - }); + }, cancellationToken); return Ok(); } diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Demo/DemoCorsPolicy.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Demo/DemoCorsPolicy.cs index a21e460..7ba71b3 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Demo/DemoCorsPolicy.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Demo/DemoCorsPolicy.cs @@ -1,3 +1,4 @@ +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer.Services; @@ -8,7 +9,7 @@ namespace Rsk.Samples.IdentityServer.AdminUiIntegration.Demo /// public class DemoCorsPolicy : ICorsPolicyService { - public Task IsOriginAllowedAsync(string origin) + public Task IsOriginAllowedAsync(string origin, CancellationToken ct) { return Task.FromResult(true); } diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Demo/DemoRedirectUriValidator.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Demo/DemoRedirectUriValidator.cs index 92ed732..f5502b0 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Demo/DemoRedirectUriValidator.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Demo/DemoRedirectUriValidator.cs @@ -1,3 +1,4 @@ +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer.Models; using Duende.IdentityServer.Validation; @@ -14,7 +15,7 @@ public Task IsRedirectUriValidAsync(string requestedUri, Client client) return Task.FromResult(true); } - public Task IsPostLogoutRedirectUriValidAsync(string requestedUri, Client client) + public Task IsPostLogoutRedirectUriValidAsync(string requestedUri, Client client, CancellationToken ct) { return Task.FromResult(true); } diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Rsk.Samples.IdentityServer.AdminUiIntegration.csproj b/Rsk.Samples.IdentityServer.AdminUiIntegration/Rsk.Samples.IdentityServer.AdminUiIntegration.csproj index 2dbbfb6..01a746c 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Rsk.Samples.IdentityServer.AdminUiIntegration.csproj +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Rsk.Samples.IdentityServer.AdminUiIntegration.csproj @@ -24,36 +24,36 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - - - - - - + + + + + + - - - - - - + + + + + + - + diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/AccountService.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/AccountService.cs index cc1031e..6340125 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/AccountService.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/AccountService.cs @@ -3,15 +3,14 @@ using System.Linq; +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer; -using Duende.IdentityServer.Extensions; using Duende.IdentityServer.Services; using Duende.IdentityServer.Stores; using IdentityModel; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.DependencyInjection; using Rsk.Samples.IdentityServer.AdminUiIntegration.Models; namespace Rsk.Samples.IdentityServer.AdminUiIntegration.Services @@ -41,9 +40,9 @@ public AccountService( this.authenticationHandlerProvider = authenticationHandlerProvider; } - public async Task BuildLoginViewModelAsync(string returnUrl) + public async Task BuildLoginViewModelAsync(string returnUrl, CancellationToken cancellationToken) { - var context = await interaction.GetAuthorizationContextAsync(returnUrl); + var context = await interaction.GetAuthorizationContextAsync(returnUrl, cancellationToken); if (context?.IdP != null && await schemeProvider.GetSchemeAsync(context.IdP) != null) { var local = context.IdP == IdentityServerConstants.LocalIdentityProvider; @@ -64,12 +63,12 @@ public async Task BuildLoginViewModelAsync(string returnUrl) return vm; } - var providers = await externalProviderService.GetAll(); + var providers = await externalProviderService.GetAll(cancellationToken); var allowLocal = true; if (context?.Client.ClientId != null) { - var client = await clientStore.FindEnabledClientByIdAsync(context.Client.ClientId); + var client = await clientStore.FindEnabledClientByIdAsync(context.Client.ClientId, cancellationToken); if (client != null) { allowLocal = client.EnableLocalLogin; @@ -100,15 +99,15 @@ public LoginViewModel BuildLinkLoginViewModel(string returnUrl) }; } - public async Task BuildLoginViewModelAsync(LoginInputModel model) + public async Task BuildLoginViewModelAsync(LoginInputModel model, CancellationToken cancellationToken) { - var vm = await BuildLoginViewModelAsync(model.ReturnUrl); + var vm = await BuildLoginViewModelAsync(model.ReturnUrl, cancellationToken); vm.Username = model.Username; vm.RememberLogin = model.RememberLogin; return vm; } - public async Task BuildLogoutViewModelAsync(string logoutId) + public async Task BuildLogoutViewModelAsync(string logoutId, CancellationToken cancellationToken) { var vm = new LogoutViewModel { LogoutId = logoutId, ShowLogoutPrompt = true }; @@ -119,7 +118,7 @@ public async Task BuildLogoutViewModelAsync(string logoutId) return vm; } - var context = await interaction.GetLogoutContextAsync(logoutId); + var context = await interaction.GetLogoutContextAsync(logoutId, cancellationToken); if (context?.ShowSignoutPrompt == false) { // it's safe to automatically sign-out @@ -132,10 +131,10 @@ public async Task BuildLogoutViewModelAsync(string logoutId) return vm; } - public async Task BuildLoggedOutViewModelAsync(string logoutId) + public async Task BuildLoggedOutViewModelAsync(string logoutId, CancellationToken cancellationToken) { // get context information (client name, post logout redirect URI and iframe for federated signout) - var logout = await interaction.GetLogoutContextAsync(logoutId); + var logout = await interaction.GetLogoutContextAsync(logoutId, cancellationToken); var vm = new LoggedOutViewModel { @@ -161,7 +160,7 @@ public async Task BuildLoggedOutViewModelAsync(string logout // if there's no current logout context, we need to create one // this captures necessary info from the current logged in user // before we signout and redirect away to the external IdP for signout - vm.LogoutId = await interaction.CreateLogoutContextAsync(); + vm.LogoutId = await interaction.CreateLogoutContextAsync(cancellationToken); } vm.ExternalAuthenticationScheme = idp; diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/ConsentService.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/ConsentService.cs index f953d8d..2bc5397 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/ConsentService.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/ConsentService.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer; using Duende.IdentityServer.Events; @@ -32,12 +33,12 @@ public ConsentService( this.logger = logger; } - public async Task ProcessConsent(ConsentInputModel model, string userId) + public async Task ProcessConsent(ConsentInputModel model, string userId, CancellationToken cancellationToken) { var result = new ProcessConsentResult(); // validate return url is still valid - var request = await interaction.GetAuthorizationContextAsync(model.ReturnUrl); + var request = await interaction.GetAuthorizationContextAsync(model.ReturnUrl, cancellationToken); if (request == null) return result; ConsentResponse grantedConsent = null; @@ -45,11 +46,11 @@ public async Task ProcessConsent(ConsentInputModel model, // user clicked 'no' - send back the standard 'access_denied' response if (model.Button == "no") { - grantedConsent = new ConsentResponse {Error = AuthorizationError.AccessDenied}; + grantedConsent = new ConsentResponse {Error = InteractionError.AccessDenied}; // emit event await events.RaiseAsync(new ConsentDeniedEvent(userId, request.Client.ClientId, - request.ValidatedResources.RawScopeValues)); + request.ValidatedResources.RawScopeValues), cancellationToken); } // user clicked 'yes' - validate the data else if (model.Button == "yes") @@ -75,7 +76,7 @@ await events.RaiseAsync(new ConsentDeniedEvent(userId, request.Client.ClientId, // emit event await events.RaiseAsync(new ConsentGrantedEvent(userId, request.Client.ClientId, request.ValidatedResources.RawScopeValues, grantedConsent.ScopesValuesConsented, - grantedConsent.RememberConsent)); + grantedConsent.RememberConsent), cancellationToken); } else { @@ -90,7 +91,7 @@ await events.RaiseAsync(new ConsentGrantedEvent(userId, request.Client.ClientId, if (grantedConsent != null) { // communicate outcome of consent back to identityserver - await interaction.GrantConsentAsync(request, grantedConsent); + await interaction.GrantConsentAsync(request, grantedConsent, cancellationToken); // indicate that's it ok to redirect back to authorization endpoint result.RedirectUri = model.ReturnUrl; @@ -99,15 +100,15 @@ await events.RaiseAsync(new ConsentGrantedEvent(userId, request.Client.ClientId, else { // we need to redisplay the consent UI - result.ViewModel = await BuildViewModelAsync(model.ReturnUrl, model); + result.ViewModel = await BuildViewModelAsync(model.ReturnUrl, cancellationToken, model); } return result; } - public async Task BuildViewModelAsync(string returnUrl, ConsentInputModel model = null) + public async Task BuildViewModelAsync(string returnUrl, CancellationToken cancellationToken, ConsentInputModel model = null) { - var request = await interaction.GetAuthorizationContextAsync(returnUrl); + var request = await interaction.GetAuthorizationContextAsync(returnUrl, cancellationToken); if (request != null) { return CreateConsentViewModel(model, returnUrl, request); diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/CustomEventSink.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/CustomEventSink.cs index f05f931..c6bd603 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/CustomEventSink.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/CustomEventSink.cs @@ -1,5 +1,6 @@ using System; using System.Text.Json; +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer.Events; using Duende.IdentityServer.Services; @@ -22,7 +23,7 @@ public CustomEventSink(ILogger logger, IEventStore eventSto this.eventStore = eventStore; } - public Task PersistAsync(Event evt) + public Task PersistAsync(Event evt, CancellationToken cancellationToken) { try { diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/ExternalProviderService.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/ExternalProviderService.cs index 10bbe3e..ee2bb72 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/ExternalProviderService.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/ExternalProviderService.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Duende.IdentityServer.Stores; using Microsoft.AspNetCore.Authentication; @@ -25,7 +26,7 @@ public ExternalProviderService( this.configuration = configuration ?? throw new ArgumentNullException(nameof(configuration)); } - public async Task> GetAll() + public async Task> GetAll(CancellationToken cancellationToken) { var mode = configuration.GetValue("DynamicAuth:Mode"); var providers = new List(); @@ -36,16 +37,16 @@ public async Task> GetAll() providers.AddRange(await GetRskSchemes()); break; case "Duende": - providers.AddRange(await GetDuendeSchemes()); + providers.AddRange(await GetDuendeSchemes(cancellationToken)); break; } return providers; } - public async Task GetScheme(string scheme) + public async Task GetScheme(string scheme, CancellationToken cancellationToken) { - return (await GetAll()).FirstOrDefault(x => x.AuthenticationScheme == scheme); + return (await GetAll(cancellationToken)).FirstOrDefault(x => x.AuthenticationScheme == scheme); } private async Task> GetRskSchemes() @@ -61,9 +62,9 @@ private async Task> GetRskSchemes() }).ToList(); } - private async Task> GetDuendeSchemes() + private async Task> GetDuendeSchemes(CancellationToken cancellationToken) { - return (await identityProviderStore.GetAllSchemeNamesAsync()) + return (await identityProviderStore.GetAllSchemeNamesAsync(cancellationToken)) .Where(x => x.Enabled) .Select(x => new ExternalProvider { diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/IAccountService.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/IAccountService.cs index c05fdcc..39787cc 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/IAccountService.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/IAccountService.cs @@ -1,3 +1,4 @@ +using System.Threading; using System.Threading.Tasks; using Rsk.Samples.IdentityServer.AdminUiIntegration.Models; @@ -5,11 +6,11 @@ namespace Rsk.Samples.IdentityServer.AdminUiIntegration.Services; public interface IAccountService { - Task BuildLoginViewModelAsync(string returnUrl); + Task BuildLoginViewModelAsync(string returnUrl, CancellationToken cancellationToken); LoginViewModel BuildLinkLoginViewModel(string returnUrl); - Task BuildLoginViewModelAsync(LoginInputModel model); - Task BuildLogoutViewModelAsync(string logoutId); - Task BuildLoggedOutViewModelAsync(string logoutId); + Task BuildLoginViewModelAsync(LoginInputModel model, CancellationToken cancellationToken); + Task BuildLogoutViewModelAsync(string logoutId, CancellationToken cancellationToken); + Task BuildLoggedOutViewModelAsync(string logoutId, CancellationToken cancellationToken); RegisterViewModel BuildRegisterViewModel(); RegisterViewModel BuildRegisterViewModel(RegisterInputModel model, bool success); } \ No newline at end of file diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/IExternalProviderService.cs b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/IExternalProviderService.cs index 979e351..9d3f432 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/IExternalProviderService.cs +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Services/IExternalProviderService.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Threading; using System.Threading.Tasks; using Rsk.Samples.IdentityServer.AdminUiIntegration.Models; @@ -6,6 +7,6 @@ namespace Rsk.Samples.IdentityServer.AdminUiIntegration.Services; public interface IExternalProviderService { - Task> GetAll(); - Task GetScheme(string scheme); + Task> GetAll(CancellationToken cancellationToken); + Task GetScheme(string scheme, CancellationToken cancellationToken); } \ No newline at end of file From 0b1d825350c4fffd3a4ed096e3fa4f6c5e578686 Mon Sep 17 00:00:00 2001 From: NachoEscrig Date: Tue, 23 Jun 2026 07:43:07 +0100 Subject: [PATCH 2/2] Upgrade packages --- ...amples.IdentityServer.AdminUiIntegration.csproj | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Rsk.Samples.IdentityServer.AdminUiIntegration/Rsk.Samples.IdentityServer.AdminUiIntegration.csproj b/Rsk.Samples.IdentityServer.AdminUiIntegration/Rsk.Samples.IdentityServer.AdminUiIntegration.csproj index 01a746c..462772d 100644 --- a/Rsk.Samples.IdentityServer.AdminUiIntegration/Rsk.Samples.IdentityServer.AdminUiIntegration.csproj +++ b/Rsk.Samples.IdentityServer.AdminUiIntegration/Rsk.Samples.IdentityServer.AdminUiIntegration.csproj @@ -36,9 +36,9 @@ - - - + + + @@ -48,13 +48,13 @@ - - + + - - + + \ No newline at end of file