From 91af02b9d28381430b1d617b94498a9e7d8d3ff1 Mon Sep 17 00:00:00 2001 From: Patrick Pimentel Date: Thu, 20 Nov 2025 14:54:33 -0500 Subject: [PATCH] test(auth-validator): [PM-22975] Client Version Validator - Fixed tests. --- .../RequestValidators/BaseRequestValidator.cs | 6 ++- .../BaseRequestValidatorTests.cs | 40 +++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/Identity/IdentityServer/RequestValidators/BaseRequestValidator.cs b/src/Identity/IdentityServer/RequestValidators/BaseRequestValidator.cs index 0b010be38a..92258c9289 100644 --- a/src/Identity/IdentityServer/RequestValidators/BaseRequestValidator.cs +++ b/src/Identity/IdentityServer/RequestValidators/BaseRequestValidator.cs @@ -128,7 +128,11 @@ public abstract class BaseRequestValidator where T : class // could use a known invalid client version and make a request for a user (before we know if they have // demonstrated ownership of the account via correct credentials) and identify if they exist by getting // an error response back from the validator saying the user is not compatible with the client. - await ValidateClientVersionAsync(context, validatorContext); + var clientVersionValid = await ValidateClientVersionAsync(context, validatorContext); + if (!clientVersionValid) + { + return; + } // 2. Decide if this user belongs to an organization that requires SSO. validatorContext.SsoRequired = await RequireSsoLoginAsync(user, request.GrantType); diff --git a/test/Identity.Test/IdentityServer/BaseRequestValidatorTests.cs b/test/Identity.Test/IdentityServer/BaseRequestValidatorTests.cs index 9a3d4dd711..6ef2df2301 100644 --- a/test/Identity.Test/IdentityServer/BaseRequestValidatorTests.cs +++ b/test/Identity.Test/IdentityServer/BaseRequestValidatorTests.cs @@ -101,6 +101,11 @@ public class BaseRequestValidatorTests _mailService, _userAccountKeysQuery, _clientVersionValidator); + + // Default client version validator behavior: allow to pass unless a test overrides. + _clientVersionValidator + .ValidateAsync(Arg.Any(), Arg.Any()) + .Returns(Task.FromResult(true)); } private void SetupRecoveryCodeSupportForSsoRequiredUsersFeatureFlag(bool recoveryCodeSupportEnabled) @@ -1246,6 +1251,41 @@ public class BaseRequestValidatorTests } } + [Theory] + [BitAutoData(true)] + [BitAutoData(false)] + public async Task ValidateAsync_ClientVersionValidator_IsInvoked_ForFeatureFlagStates( + bool featureFlagValue, + [AuthFixtures.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest, + [AuthFixtures.CustomValidatorRequestContext] CustomValidatorRequestContext requestContext, + GrantValidationResult grantResult) + { + // Arrange + SetupRecoveryCodeSupportForSsoRequiredUsersFeatureFlag(featureFlagValue); + var context = CreateContext(tokenRequest, requestContext, grantResult); + _sut.isValid = true; // ensure initial context validation passes + + // Force a grant type that will evaluate SSO after client version validation + context.ValidatedTokenRequest.GrantType = "password"; + + // Make client version validation succeed but ensure it's invoked + _clientVersionValidator + .ValidateAsync(requestContext.User, requestContext) + .Returns(Task.FromResult(true)); + + // Ensure SSO requirement triggers an early stop after version validation to avoid success path setup + _policyService.AnyPoliciesApplicableToUserAsync( + Arg.Any(), PolicyType.RequireSso, OrganizationUserStatusType.Confirmed) + .Returns(Task.FromResult(true)); + + // Act + await _sut.ValidateAsync(context); + + // Assert + await _clientVersionValidator.Received(1) + .ValidateAsync(requestContext.User, requestContext); + } + private BaseRequestValidationContextFake CreateContext( ValidatedTokenRequest tokenRequest, CustomValidatorRequestContext requestContext,