1
0
mirror of https://github.com/bitwarden/server synced 2026-01-28 23:36:12 +00:00

chore: dotnet format

test: updating tests to match new approach.
This commit is contained in:
Ike Kottlowski
2026-01-27 22:50:09 -05:00
parent 41348b3158
commit 6fa44296b6
4 changed files with 25 additions and 18 deletions

View File

@@ -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);
}

View File

@@ -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
};

View File

@@ -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<IOtpTokenProvider<DefaultOtpTokenProviderOptions>>()
@@ -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<IOtpTokenProvider<DefaultOtpTokenProviderOptions>>()

View File

@@ -51,7 +51,7 @@ public class SendNeverAuthenticateRequestValidatorTests
}
[Theory, BitAutoData]
public async Task ValidateRequestAsync_EmailErrorSelected_HasEmail_ReturnsEmailInvalid(
public async Task ValidateRequestAsync_EmailErrorSelected_HasEmail_ReturnsEmailAndOtpRequired(
SutProvider<SendNeverAuthenticateRequestValidator> 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<string, object>;
Assert.NotNull(customResponse);
Assert.Equal(SendAccessConstants.EmailOtpValidatorResults.EmailInvalid, customResponse[SendAccessConstants.SendAccessError]);
Assert.Equal(SendAccessConstants.EmailOtpValidatorResults.EmailAndOtpRequired, customResponse[SendAccessConstants.SendAccessError]);
}
[Theory, BitAutoData]