mirror of
https://github.com/bitwarden/server.git
synced 2025-04-24 14:26:38 -05:00
Remove captcha enforcement and issuing/verification of bypass token
This commit is contained in:
parent
4ca39ab0b7
commit
1b11496d33
@ -1,5 +1,4 @@
|
||||
using Bit.Core.Auth.Models.Business;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Entities;
|
||||
using Duende.IdentityServer.Validation;
|
||||
|
||||
namespace Bit.Identity.IdentityServer;
|
||||
@ -9,7 +8,7 @@ public class CustomValidatorRequestContext
|
||||
public User User { get; set; }
|
||||
/// <summary>
|
||||
/// This is the device that the user is using to authenticate. It can be either known or unknown.
|
||||
/// We set it here since the ResourceOwnerPasswordValidator needs the device to know if CAPTCHA is required.
|
||||
/// We set it here since the ResourceOwnerPasswordValidator needs the device to do device validation.
|
||||
/// The option to set it here saves a trip to the database.
|
||||
/// </summary>
|
||||
public Device Device { get; set; }
|
||||
@ -39,5 +38,4 @@ public class CustomValidatorRequestContext
|
||||
/// This will be null if the authentication request is successful.
|
||||
/// </summary>
|
||||
public Dictionary<string, object> CustomResponse { get; set; }
|
||||
public CaptchaResponse CaptchaResponse { get; set; }
|
||||
}
|
||||
|
@ -77,23 +77,12 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
protected async Task ValidateAsync(T context, ValidatedTokenRequest request,
|
||||
CustomValidatorRequestContext validatorContext)
|
||||
{
|
||||
// 1. We need to check if the user is a bot and if their master password hash is correct.
|
||||
var isBot = validatorContext.CaptchaResponse?.IsBot ?? false;
|
||||
var valid = await ValidateContextAsync(context, validatorContext);
|
||||
// 1. We need to check if the user's master password hash is correct.
|
||||
var user = validatorContext.User;
|
||||
if (!valid || isBot)
|
||||
var valid = await ValidateContextAsync(context, validatorContext);
|
||||
if (!valid)
|
||||
{
|
||||
if (isBot)
|
||||
{
|
||||
_logger.LogInformation(Constants.BypassFiltersEventId,
|
||||
"Login attempt for {UserName} detected as a captcha bot with score {CaptchaScore}.",
|
||||
request.UserName, validatorContext.CaptchaResponse.Score);
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
await UpdateFailedAuthDetailsAsync(user, false, !validatorContext.KnownDevice);
|
||||
}
|
||||
await UpdateFailedAuthDetailsAsync(user, false, !validatorContext.KnownDevice);
|
||||
|
||||
await BuildErrorResultAsync("Username or password is incorrect. Try again.", false, context, user);
|
||||
return;
|
||||
|
@ -85,37 +85,8 @@ public class ResourceOwnerPasswordValidator : BaseRequestValidator<ResourceOwner
|
||||
Device = knownDevice ?? requestDevice,
|
||||
};
|
||||
|
||||
string bypassToken = null;
|
||||
if (!validatorContext.KnownDevice &&
|
||||
_captchaValidationService.RequireCaptchaValidation(_currentContext, user))
|
||||
{
|
||||
var captchaResponse = context.Request.Raw["captchaResponse"]?.ToString();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(captchaResponse))
|
||||
{
|
||||
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "Captcha required.",
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ _captchaValidationService.SiteKeyResponseKeyName, _captchaValidationService.SiteKey },
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
validatorContext.CaptchaResponse = await _captchaValidationService.ValidateCaptchaResponseAsync(
|
||||
captchaResponse, _currentContext.IpAddress, user);
|
||||
if (!validatorContext.CaptchaResponse.Success)
|
||||
{
|
||||
await BuildErrorResultAsync("Captcha is invalid. Please refresh and try again", false, context, null);
|
||||
return;
|
||||
}
|
||||
bypassToken = _captchaValidationService.GenerateCaptchaBypassToken(user);
|
||||
}
|
||||
|
||||
await ValidateAsync(context, context.Request, validatorContext);
|
||||
if (context.Result.CustomResponse != null && bypassToken != null)
|
||||
{
|
||||
context.Result.CustomResponse["CaptchaBypassToken"] = bypassToken;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected async override Task<bool> ValidateContextAsync(ResourceOwnerPasswordValidationContext context,
|
||||
|
@ -80,36 +80,6 @@ public class BaseRequestValidatorTests
|
||||
_userDecryptionOptionsBuilder);
|
||||
}
|
||||
|
||||
/* Logic path
|
||||
* ValidateAsync -> _Logger.LogInformation
|
||||
* |-> BuildErrorResultAsync -> _eventService.LogUserEventAsync
|
||||
* |-> SetErrorResult
|
||||
*/
|
||||
[Theory, BitAutoData]
|
||||
public async Task ValidateAsync_IsBot_UserNotNull_ShouldBuildErrorResult_ShouldLogFailedLoginEvent(
|
||||
[AuthFixtures.ValidatedTokenRequest] ValidatedTokenRequest tokenRequest,
|
||||
CustomValidatorRequestContext requestContext,
|
||||
GrantValidationResult grantResult)
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = true;
|
||||
_sut.isValid = true;
|
||||
|
||||
// Act
|
||||
await _sut.ValidateAsync(context);
|
||||
|
||||
var errorResponse = (ErrorResponseModel)context.GrantResult.CustomResponse["ErrorModel"];
|
||||
|
||||
// Assert
|
||||
await _eventService.Received(1)
|
||||
.LogUserEventAsync(context.CustomValidatorRequestContext.User.Id,
|
||||
EventType.User_FailedLogIn);
|
||||
Assert.True(context.GrantResult.IsError);
|
||||
Assert.Equal("Username or password is incorrect. Try again.", errorResponse.Message);
|
||||
}
|
||||
|
||||
/* Logic path
|
||||
* ValidateAsync -> UpdateFailedAuthDetailsAsync -> _mailService.SendFailedLoginAttemptsEmailAsync
|
||||
* |-> BuildErrorResultAsync -> _eventService.LogUserEventAsync
|
||||
@ -124,7 +94,6 @@ public class BaseRequestValidatorTests
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
_globalSettings.Captcha.Returns(new GlobalSettings.CaptchaSettings());
|
||||
_globalSettings.SelfHosted = true;
|
||||
_sut.isValid = false;
|
||||
@ -152,7 +121,6 @@ public class BaseRequestValidatorTests
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
// This needs to be n-1 of the max failed login attempts
|
||||
context.CustomValidatorRequestContext.User.FailedLoginCount = 2;
|
||||
context.CustomValidatorRequestContext.KnownDevice = false;
|
||||
@ -185,7 +153,6 @@ public class BaseRequestValidatorTests
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
// 1 -> to pass
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
_sut.isValid = true;
|
||||
|
||||
// 2 -> will result to false with no extra configuration
|
||||
@ -222,7 +189,6 @@ public class BaseRequestValidatorTests
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
// 1 -> to pass
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
_sut.isValid = true;
|
||||
|
||||
// 2 -> will result to false with no extra configuration
|
||||
@ -259,7 +225,6 @@ public class BaseRequestValidatorTests
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
_sut.isValid = true;
|
||||
|
||||
context.ValidatedTokenRequest.GrantType = grantType;
|
||||
@ -290,7 +255,6 @@ public class BaseRequestValidatorTests
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
_sut.isValid = true;
|
||||
|
||||
context.ValidatedTokenRequest.GrantType = grantType;
|
||||
@ -328,7 +292,6 @@ public class BaseRequestValidatorTests
|
||||
{
|
||||
// Arrange
|
||||
var context = CreateContext(tokenRequest, requestContext, grantResult);
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
_sut.isValid = true;
|
||||
|
||||
context.ValidatedTokenRequest.GrantType = grantType;
|
||||
@ -366,7 +329,6 @@ public class BaseRequestValidatorTests
|
||||
var user = context.CustomValidatorRequestContext.User;
|
||||
user.Key = null;
|
||||
|
||||
context.CustomValidatorRequestContext.CaptchaResponse.IsBot = false;
|
||||
context.ValidatedTokenRequest.ClientId = "Not Web";
|
||||
_sut.isValid = true;
|
||||
_twoFactorAuthenticationValidator
|
||||
|
Loading…
x
Reference in New Issue
Block a user