diff --git a/identity-server/hosts/Shared/Customization/HostProfileService.cs b/identity-server/hosts/Shared/Customization/HostProfileService.cs index ddc29152a..f9f7dc4ee 100644 --- a/identity-server/hosts/Shared/Customization/HostProfileService.cs +++ b/identity-server/hosts/Shared/Customization/HostProfileService.cs @@ -9,10 +9,10 @@ namespace Duende.IdentityServer.Hosts.Shared.Customization; public class HostProfileService(TestUserStore users, ILogger logger) : TestUserProfileService(users, logger) { - public override async Task GetProfileDataAsync(ProfileDataRequestContext context) + public override async Task GetProfileDataAsync(ProfileDataRequestContext context, CT ct) { ArgumentNullException.ThrowIfNull(context); - await base.GetProfileDataAsync(context); + await base.GetProfileDataAsync(context, ct); var transaction = context.RequestedResources.ParsedScopes.FirstOrDefault(x => x.ParsedName == "transaction"); if (transaction?.ParsedParameter != null) diff --git a/identity-server/src/AspNetIdentity/ProfileService.cs b/identity-server/src/AspNetIdentity/ProfileService.cs index b8dc6638a..3743d9799 100644 --- a/identity-server/src/AspNetIdentity/ProfileService.cs +++ b/identity-server/src/AspNetIdentity/ProfileService.cs @@ -65,8 +65,9 @@ public class ProfileService : IProfileService /// This method is called whenever claims about the user are requested (e.g. during token creation or via the userinfo endpoint) /// /// The context. + /// A token that can be used to request cancellation of the asynchronous operation. /// - public virtual async Task GetProfileDataAsync(ProfileDataRequestContext context) + public virtual async Task GetProfileDataAsync(ProfileDataRequestContext context, CT ct) { var sub = context.Subject?.GetSubjectId(); if (sub == null) @@ -125,8 +126,9 @@ public class ProfileService : IProfileService /// (e.g. during token issuance or validation). /// /// The context. + /// A token that can be used to request cancellation of the asynchronous operation. /// - public virtual async Task IsActiveAsync(IsActiveContext context) + public virtual async Task IsActiveAsync(IsActiveContext context, CT ct) { var sub = context.Subject?.GetSubjectId(); if (sub == null) diff --git a/identity-server/src/IdentityServer/ResponseHandling/Default/AuthorizeInteractionResponseGenerator.cs b/identity-server/src/IdentityServer/ResponseHandling/Default/AuthorizeInteractionResponseGenerator.cs index 77d94222f..ef8714e2e 100644 --- a/identity-server/src/IdentityServer/ResponseHandling/Default/AuthorizeInteractionResponseGenerator.cs +++ b/identity-server/src/IdentityServer/ResponseHandling/Default/AuthorizeInteractionResponseGenerator.cs @@ -208,7 +208,7 @@ public class AuthorizeInteractionResponseGenerator : IAuthorizeInteractionRespon if (isAuthenticated) { var isActiveCtx = new IsActiveContext(request.Subject, request.Client, IdentityServerConstants.ProfileIsActiveCallers.AuthorizeEndpoint); - await Profile.IsActiveAsync(isActiveCtx); + await Profile.IsActiveAsync(isActiveCtx, ct); isActive = isActiveCtx.IsActive; } diff --git a/identity-server/src/IdentityServer/ResponseHandling/Default/UserInfoResponseGenerator.cs b/identity-server/src/IdentityServer/ResponseHandling/Default/UserInfoResponseGenerator.cs index ea1be9e23..4924f740b 100644 --- a/identity-server/src/IdentityServer/ResponseHandling/Default/UserInfoResponseGenerator.cs +++ b/identity-server/src/IdentityServer/ResponseHandling/Default/UserInfoResponseGenerator.cs @@ -75,7 +75,7 @@ public class UserInfoResponseGenerator : IUserInfoResponseGenerator requestedClaimTypes); context.RequestedResources = validatedResources; - await Profile.GetProfileDataAsync(context); + await Profile.GetProfileDataAsync(context, default); var profileClaims = context.IssuedClaims; // construct outgoing claims diff --git a/identity-server/src/IdentityServer/Services/Default/DefaultClaimsService.cs b/identity-server/src/IdentityServer/Services/Default/DefaultClaimsService.cs index 5dcbc1fe3..4712ac4cc 100644 --- a/identity-server/src/IdentityServer/Services/Default/DefaultClaimsService.cs +++ b/identity-server/src/IdentityServer/Services/Default/DefaultClaimsService.cs @@ -76,7 +76,7 @@ public class DefaultClaimsService : IClaimsService ValidatedRequest = request }; - await Profile.GetProfileDataAsync(context); + await Profile.GetProfileDataAsync(context, ct); var claims = FilterProtocolClaims(context.IssuedClaims); if (claims != null) @@ -189,7 +189,7 @@ public class DefaultClaimsService : IClaimsService ValidatedRequest = request }; - await Profile.GetProfileDataAsync(context); + await Profile.GetProfileDataAsync(context, ct); var claims = FilterProtocolClaims(context.IssuedClaims); if (claims != null) diff --git a/identity-server/src/IdentityServer/Services/Default/DefaultProfileService.cs b/identity-server/src/IdentityServer/Services/Default/DefaultProfileService.cs index 6aabf62ae..33909d854 100644 --- a/identity-server/src/IdentityServer/Services/Default/DefaultProfileService.cs +++ b/identity-server/src/IdentityServer/Services/Default/DefaultProfileService.cs @@ -29,8 +29,9 @@ public class DefaultProfileService : IProfileService /// This method is called whenever claims about the user are requested (e.g. during token creation or via the userinfo endpoint) /// /// The context. + /// A token that can be used to request cancellation of the asynchronous operation. /// - public virtual Task GetProfileDataAsync(ProfileDataRequestContext context) + public virtual Task GetProfileDataAsync(ProfileDataRequestContext context, CT ct) { using var activity = Tracing.ServiceActivitySource.StartActivity("DefaultProfileService.GetProfileData"); @@ -46,8 +47,9 @@ public class DefaultProfileService : IProfileService /// (e.g. during token issuance or validation). /// /// The context. + /// A token that can be used to request cancellation of the asynchronous operation. /// - public virtual Task IsActiveAsync(IsActiveContext context) + public virtual Task IsActiveAsync(IsActiveContext context, CT ct) { using var activity = Tracing.ServiceActivitySource.StartActivity("DefaultProfileService.IsActive"); diff --git a/identity-server/src/IdentityServer/Services/Default/DefaultRefreshTokenService.cs b/identity-server/src/IdentityServer/Services/Default/DefaultRefreshTokenService.cs index 1dce8591a..06b725907 100644 --- a/identity-server/src/IdentityServer/Services/Default/DefaultRefreshTokenService.cs +++ b/identity-server/src/IdentityServer/Services/Default/DefaultRefreshTokenService.cs @@ -136,7 +136,7 @@ public class DefaultRefreshTokenService : IRefreshTokenService client, IdentityServerConstants.ProfileIsActiveCallers.RefreshTokenValidation); - await Profile.IsActiveAsync(isActiveCtx); + await Profile.IsActiveAsync(isActiveCtx, ct); if (isActiveCtx.IsActive == false) { diff --git a/identity-server/src/IdentityServer/Services/IProfileService.cs b/identity-server/src/IdentityServer/Services/IProfileService.cs index 1b614e70b..8a7b6ba22 100644 --- a/identity-server/src/IdentityServer/Services/IProfileService.cs +++ b/identity-server/src/IdentityServer/Services/IProfileService.cs @@ -17,14 +17,16 @@ public interface IProfileService /// This method is called whenever claims about the user are requested (e.g. during token creation or via the userinfo endpoint) /// /// The context. + /// A token that can be used to request cancellation of the asynchronous operation. /// - Task GetProfileDataAsync(ProfileDataRequestContext context); + Task GetProfileDataAsync(ProfileDataRequestContext context, CT ct); /// /// This method gets called whenever identity server needs to determine if the user is valid or active (e.g. if the user's account has been deactivated since they logged in). /// (e.g. during token issuance or validation). /// /// The context. + /// A token that can be used to request cancellation of the asynchronous operation. /// - Task IsActiveAsync(IsActiveContext context); + Task IsActiveAsync(IsActiveContext context, CT ct); } diff --git a/identity-server/src/IdentityServer/Test/TestUserProfileService.cs b/identity-server/src/IdentityServer/Test/TestUserProfileService.cs index 03419f328..26bffbe47 100644 --- a/identity-server/src/IdentityServer/Test/TestUserProfileService.cs +++ b/identity-server/src/IdentityServer/Test/TestUserProfileService.cs @@ -40,8 +40,9 @@ public class TestUserProfileService : IProfileService /// This method is called whenever claims about the user are requested (e.g. during token creation or via the userinfo endpoint) /// /// The context. + /// A token that can be used to request cancellation of the asynchronous operation. /// - public virtual Task GetProfileDataAsync(ProfileDataRequestContext context) + public virtual Task GetProfileDataAsync(ProfileDataRequestContext context, CT ct) { context.LogProfileRequest(Logger); @@ -64,8 +65,9 @@ public class TestUserProfileService : IProfileService /// (e.g. during token issuance or validation). /// /// The context. + /// A token that can be used to request cancellation of the asynchronous operation. /// - public virtual Task IsActiveAsync(IsActiveContext context) + public virtual Task IsActiveAsync(IsActiveContext context, CT ct) { Logger.LogDebug("IsActive called from: {caller}", context.Caller); diff --git a/identity-server/src/IdentityServer/Validation/Default/BackchannelAuthenticationRequestIdValidator.cs b/identity-server/src/IdentityServer/Validation/Default/BackchannelAuthenticationRequestIdValidator.cs index 62851ab1f..6b2d147b1 100644 --- a/identity-server/src/IdentityServer/Validation/Default/BackchannelAuthenticationRequestIdValidator.cs +++ b/identity-server/src/IdentityServer/Validation/Default/BackchannelAuthenticationRequestIdValidator.cs @@ -92,7 +92,7 @@ internal class BackchannelAuthenticationRequestIdValidator : IBackchannelAuthent // make sure user is enabled var isActiveCtx = new IsActiveContext(request.Subject, context.Request.Client, IdentityServerConstants.ProfileIsActiveCallers.BackchannelAuthenticationRequestIdValidation); - await _profile.IsActiveAsync(isActiveCtx); + await _profile.IsActiveAsync(isActiveCtx, ct); if (isActiveCtx.IsActive == false) { diff --git a/identity-server/src/IdentityServer/Validation/Default/DeviceCodeValidator.cs b/identity-server/src/IdentityServer/Validation/Default/DeviceCodeValidator.cs index fe305a9e4..8b22af02b 100644 --- a/identity-server/src/IdentityServer/Validation/Default/DeviceCodeValidator.cs +++ b/identity-server/src/IdentityServer/Validation/Default/DeviceCodeValidator.cs @@ -103,7 +103,7 @@ internal class DeviceCodeValidator : IDeviceCodeValidator // make sure user is enabled var isActiveCtx = new IsActiveContext(deviceCode.Subject, context.Request.Client, IdentityServerConstants.ProfileIsActiveCallers.DeviceCodeValidation); - await _profile.IsActiveAsync(isActiveCtx); + await _profile.IsActiveAsync(isActiveCtx, ct); if (isActiveCtx.IsActive == false) { diff --git a/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs b/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs index 33026793e..50e99951f 100644 --- a/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs +++ b/identity-server/src/IdentityServer/Validation/Default/TokenRequestValidator.cs @@ -513,7 +513,7 @@ internal class TokenRequestValidator : ITokenRequestValidator // make sure user is enabled ///////////////////////////////////////////// var isActiveCtx = new IsActiveContext(_validatedRequest.AuthorizationCode.Subject, _validatedRequest.Client, IdentityServerConstants.ProfileIsActiveCallers.AuthorizationCodeValidation); - await _profile.IsActiveAsync(isActiveCtx); + await _profile.IsActiveAsync(isActiveCtx, _ct); if (isActiveCtx.IsActive == false) { @@ -663,7 +663,7 @@ internal class TokenRequestValidator : ITokenRequestValidator // make sure user is enabled ///////////////////////////////////////////// var isActiveCtx = new IsActiveContext(resourceOwnerContext.Result.Subject, _validatedRequest.Client, IdentityServerConstants.ProfileIsActiveCallers.ResourceOwnerValidation); - await _profile.IsActiveAsync(isActiveCtx); + await _profile.IsActiveAsync(isActiveCtx, _ct); if (isActiveCtx.IsActive == false) { @@ -1074,7 +1074,7 @@ internal class TokenRequestValidator : ITokenRequestValidator _validatedRequest.Client, IdentityServerConstants.ProfileIsActiveCallers.ExtensionGrantValidation); - await _profile.IsActiveAsync(isActiveCtx); + await _profile.IsActiveAsync(isActiveCtx, _ct); if (isActiveCtx.IsActive == false) { diff --git a/identity-server/src/IdentityServer/Validation/Default/TokenValidator.cs b/identity-server/src/IdentityServer/Validation/Default/TokenValidator.cs index 4b12c9440..b507b70cc 100644 --- a/identity-server/src/IdentityServer/Validation/Default/TokenValidator.cs +++ b/identity-server/src/IdentityServer/Validation/Default/TokenValidator.cs @@ -207,7 +207,7 @@ internal class TokenValidator : ITokenValidator var isActiveCtx = new IsActiveContext(principal, result.Client, IdentityServerConstants.ProfileIsActiveCallers.AccessTokenValidation); - await _profile.IsActiveAsync(isActiveCtx); + await _profile.IsActiveAsync(isActiveCtx, ct); if (isActiveCtx.IsActive == false) { diff --git a/identity-server/src/IdentityServer/Validation/Default/UserInfoRequestValidator.cs b/identity-server/src/IdentityServer/Validation/Default/UserInfoRequestValidator.cs index 681503c12..afa66f061 100644 --- a/identity-server/src/IdentityServer/Validation/Default/UserInfoRequestValidator.cs +++ b/identity-server/src/IdentityServer/Validation/Default/UserInfoRequestValidator.cs @@ -115,7 +115,7 @@ internal class UserInfoRequestValidator : IUserInfoRequestValidator // make sure user is still active var isActiveContext = new IsActiveContext(subject, tokenResult.Client!, IdentityServerConstants.ProfileIsActiveCallers.UserInfoRequestValidation); - await _profile.IsActiveAsync(isActiveContext); + await _profile.IsActiveAsync(isActiveContext, ct); if (isActiveContext.IsActive == false) { diff --git a/identity-server/test/IdentityServer.IntegrationTests/Clients/Setup/CustomProfileService.cs b/identity-server/test/IdentityServer.IntegrationTests/Clients/Setup/CustomProfileService.cs index 14cf0eaea..88c0dfe18 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Clients/Setup/CustomProfileService.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Clients/Setup/CustomProfileService.cs @@ -13,9 +13,9 @@ internal class CustomProfileService : TestUserProfileService public CustomProfileService(TestUserStore users, ILogger logger) : base(users, logger) { } - public override async Task GetProfileDataAsync(ProfileDataRequestContext context) + public override async Task GetProfileDataAsync(ProfileDataRequestContext context, CT ct) { - await base.GetProfileDataAsync(context); + await base.GetProfileDataAsync(context, ct); if (context.Subject.Identity.AuthenticationType == "custom") { diff --git a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs index a95f5b739..1064e56a6 100644 --- a/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs +++ b/identity-server/test/IdentityServer.IntegrationTests/Extensibility/CustomProfileServiceTests.cs @@ -82,7 +82,7 @@ public class CustomProfileServiceTests public class CustomProfileService : IProfileService { - public Task GetProfileDataAsync(ProfileDataRequestContext context) + public Task GetProfileDataAsync(ProfileDataRequestContext context, CT ct) { var claims = new Claim[] { @@ -92,7 +92,7 @@ public class CustomProfileService : IProfileService return Task.CompletedTask; } - public Task IsActiveAsync(IsActiveContext context) + public Task IsActiveAsync(IsActiveContext context, CT ct) { context.IsActive = true; return Task.CompletedTask; diff --git a/identity-server/test/IdentityServer.UnitTests/Common/MockProfileService.cs b/identity-server/test/IdentityServer.UnitTests/Common/MockProfileService.cs index 48772d32e..f3d090a6b 100644 --- a/identity-server/test/IdentityServer.UnitTests/Common/MockProfileService.cs +++ b/identity-server/test/IdentityServer.UnitTests/Common/MockProfileService.cs @@ -19,14 +19,14 @@ public class MockProfileService : IProfileService public bool IsActiveWasCalled => ActiveContext != null; public IsActiveContext ActiveContext { get; set; } - public Task GetProfileDataAsync(ProfileDataRequestContext context) + public Task GetProfileDataAsync(ProfileDataRequestContext context, CT ct) { ProfileContext = context; context.IssuedClaims = ProfileClaims.ToList(); return Task.CompletedTask; } - public Task IsActiveAsync(IsActiveContext context) + public Task IsActiveAsync(IsActiveContext context, CT ct) { ActiveContext = context; context.IsActive = IsActive; diff --git a/identity-server/test/IdentityServer.UnitTests/Validation/Setup/TestProfileService.cs b/identity-server/test/IdentityServer.UnitTests/Validation/Setup/TestProfileService.cs index eca68ba61..92e418f86 100644 --- a/identity-server/test/IdentityServer.UnitTests/Validation/Setup/TestProfileService.cs +++ b/identity-server/test/IdentityServer.UnitTests/Validation/Setup/TestProfileService.cs @@ -13,9 +13,9 @@ internal class TestProfileService : IProfileService public TestProfileService(bool shouldBeActive = true) => _shouldBeActive = shouldBeActive; - public Task GetProfileDataAsync(ProfileDataRequestContext context) => Task.CompletedTask; + public Task GetProfileDataAsync(ProfileDataRequestContext context, CT ct) => Task.CompletedTask; - public Task IsActiveAsync(IsActiveContext context) + public Task IsActiveAsync(IsActiveContext context, CT ct) { context.IsActive = _shouldBeActive; return Task.CompletedTask;