From 6fa44296b68d781b25d910e15809d231149ecd3f Mon Sep 17 00:00:00 2001 From: Ike Kottlowski Date: Tue, 27 Jan 2026 22:50:09 -0500 Subject: [PATCH] chore: dotnet format test: updating tests to match new approach. --- .../SendEmailOtpRequestValidator.cs | 24 +++++++++++-------- .../SendNeverAuthenticateRequestValidator.cs | 5 +++- .../SendEmailOtpRequestValidatorTests.cs | 6 ++--- .../SendNeverAuthenticateValidatorTests.cs | 8 +++---- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/Identity/IdentityServer/RequestValidators/SendAccess/SendEmailOtpRequestValidator.cs b/src/Identity/IdentityServer/RequestValidators/SendAccess/SendEmailOtpRequestValidator.cs index baaec7168e..c7ead714c4 100644 --- a/src/Identity/IdentityServer/RequestValidators/SendAccess/SendEmailOtpRequestValidator.cs +++ b/src/Identity/IdentityServer/RequestValidators/SendAccess/SendEmailOtpRequestValidator.cs @@ -32,17 +32,21 @@ public class SendEmailOtpRequestValidator( // get email var email = request.Get(SendAccessConstants.TokenRequest.Email); - /* - * It is an invalid request if the email is missing or is not in the list of emails in the EmailOtp array. - * This is somewhat contradictory to our process here where a poor shape means invalid_request and invalid - * data is invalid_grant. - * In this case the shape is correct but the data is invalid but to protect against enumeration we treat missing - * or incorrect emails as invalid requests. The response for a request with a correct email which needs an OTP and a request - * that has an invalid email need to be the same otherwise an attacker can enumerate until a valid email is found. - */ - if (string.IsNullOrEmpty(email) || !authMethod.Emails.Contains(email)) + // It is an invalid request if the email is missing. + if (string.IsNullOrEmpty(email)) + { + // Request is the wrong shape and doesn't contain an email field.' + return BuildErrorResult(SendAccessConstants.EmailOtpValidatorResults.EmailRequired); + } + /* + * This is somewhat contradictory to our process where a poor shape means invalid_request and invalid + * data is invalid_grant. + * In this case the shape is correct and the data is invalid but to protect against enumeration we treat incorrect emails + * as invalid requests. The response for a request with a correct email which needs an OTP and a request + * that has an invalid email need to be the same otherwise an attacker could enumerate until a valid email is found. + */ + if (!authMethod.Emails.Contains(email)) { - // Request is the wrong shape and doesn't contain an email field. return BuildErrorResult(SendAccessConstants.EmailOtpValidatorResults.EmailAndOtpRequired); } diff --git a/src/Identity/IdentityServer/RequestValidators/SendAccess/SendNeverAuthenticateRequestValidator.cs b/src/Identity/IdentityServer/RequestValidators/SendAccess/SendNeverAuthenticateRequestValidator.cs index caa0160a0d..aabafaafd8 100644 --- a/src/Identity/IdentityServer/RequestValidators/SendAccess/SendNeverAuthenticateRequestValidator.cs +++ b/src/Identity/IdentityServer/RequestValidators/SendAccess/SendNeverAuthenticateRequestValidator.cs @@ -37,7 +37,9 @@ public class SendNeverAuthenticateRequestValidator(GlobalSettings globalSettings errorType = SendAccessConstants.SendIdGuidValidatorResults.InvalidSendId; break; case SendAccessConstants.EnumerationProtection.Email: - errorType = SendAccessConstants.EmailOtpValidatorResults.EmailAndOtpRequired; + var hasEmail = request.Get(SendAccessConstants.TokenRequest.Email) is not null; + errorType = hasEmail ? SendAccessConstants.EmailOtpValidatorResults.EmailAndOtpRequired + : SendAccessConstants.EmailOtpValidatorResults.EmailRequired; break; case SendAccessConstants.EnumerationProtection.Password: var hasPassword = request.Get(SendAccessConstants.TokenRequest.ClientB64HashedPassword) is not null; @@ -63,6 +65,7 @@ public class SendNeverAuthenticateRequestValidator(GlobalSettings globalSettings SendAccessConstants.PasswordValidatorResults.RequestPasswordIsRequired => TokenRequestErrors.InvalidGrant, SendAccessConstants.PasswordValidatorResults.RequestPasswordDoesNotMatch => TokenRequestErrors.InvalidRequest, SendAccessConstants.EmailOtpValidatorResults.EmailAndOtpRequired => TokenRequestErrors.InvalidRequest, + SendAccessConstants.EmailOtpValidatorResults.EmailRequired => TokenRequestErrors.InvalidRequest, _ => TokenRequestErrors.InvalidGrant }; diff --git a/test/Identity.Test/IdentityServer/SendAccess/SendEmailOtpRequestValidatorTests.cs b/test/Identity.Test/IdentityServer/SendAccess/SendEmailOtpRequestValidatorTests.cs index 7fdfacf428..ee59e7087f 100644 --- a/test/Identity.Test/IdentityServer/SendAccess/SendEmailOtpRequestValidatorTests.cs +++ b/test/Identity.Test/IdentityServer/SendAccess/SendEmailOtpRequestValidatorTests.cs @@ -67,8 +67,8 @@ public class SendEmailOtpRequestValidatorTests // Assert Assert.True(result.IsError); - Assert.Equal(OidcConstants.TokenErrors.InvalidGrant, result.Error); - Assert.Equal("email is invalid.", result.ErrorDescription); + Assert.Equal(OidcConstants.TokenErrors.InvalidRequest, result.Error); + Assert.Equal("email and otp are required.", result.ErrorDescription); // Verify no OTP generation or email sending occurred await sutProvider.GetDependency>() @@ -113,7 +113,7 @@ public class SendEmailOtpRequestValidatorTests // Assert Assert.True(result.IsError); Assert.Equal(OidcConstants.TokenErrors.InvalidRequest, result.Error); - Assert.Equal("email otp sent.", result.ErrorDescription); + Assert.Equal("email and otp are required.", result.ErrorDescription); // Verify OTP generation await sutProvider.GetDependency>() diff --git a/test/Identity.Test/IdentityServer/SendAccess/SendNeverAuthenticateValidatorTests.cs b/test/Identity.Test/IdentityServer/SendAccess/SendNeverAuthenticateValidatorTests.cs index ae0434af83..2ac4bf3255 100644 --- a/test/Identity.Test/IdentityServer/SendAccess/SendNeverAuthenticateValidatorTests.cs +++ b/test/Identity.Test/IdentityServer/SendAccess/SendNeverAuthenticateValidatorTests.cs @@ -51,7 +51,7 @@ public class SendNeverAuthenticateRequestValidatorTests } [Theory, BitAutoData] - public async Task ValidateRequestAsync_EmailErrorSelected_HasEmail_ReturnsEmailInvalid( + public async Task ValidateRequestAsync_EmailErrorSelected_HasEmail_ReturnsEmailAndOtpRequired( SutProvider sutProvider, [AutoFixture.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest, string email) @@ -69,12 +69,12 @@ public class SendNeverAuthenticateRequestValidatorTests // Assert Assert.True(result.IsError); - Assert.Equal(OidcConstants.TokenErrors.InvalidGrant, result.Error); - Assert.Equal(SendAccessConstants.EmailOtpValidatorResults.EmailInvalid, result.ErrorDescription); + Assert.Equal(OidcConstants.TokenErrors.InvalidRequest, result.Error); + Assert.Equal(SendAccessConstants.EmailOtpValidatorResults.EmailAndOtpRequired, result.ErrorDescription); var customResponse = result.CustomResponse as Dictionary; Assert.NotNull(customResponse); - Assert.Equal(SendAccessConstants.EmailOtpValidatorResults.EmailInvalid, customResponse[SendAccessConstants.SendAccessError]); + Assert.Equal(SendAccessConstants.EmailOtpValidatorResults.EmailAndOtpRequired, customResponse[SendAccessConstants.SendAccessError]); } [Theory, BitAutoData]