mirror of
https://github.com/bitwarden/server.git
synced 2025-07-01 08:02:49 -05:00
[SG-698] Refactored 2fa send email and identity to cater for passwordless (#2346)
* Allow for auth request validation for sending two factor emails * Refactored 2fa send email and identity to cater for passwordless * Refactored 2fa send email and identity to cater for passwordless Signed-off-by: gbubemismith <gsmithwalter@gmail.com> * Inform that we track issues outside of Github (#2331) * Inform that we track issues outside of Github * Use checkboxes for info acknowledgement Signed-off-by: gbubemismith <gsmithwalter@gmail.com> * Refactored 2fa send email and identity to cater for passwordless * ran dotnet format Signed-off-by: gbubemismith <gsmithwalter@gmail.com> Co-authored-by: addison <addisonbeck1@gmail.com>
This commit is contained in:
@ -6,6 +6,7 @@ using Bit.Core.Context;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.LoginFeatures.PasswordlessLogin.Interfaces;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
@ -28,6 +29,7 @@ public class TwoFactorController : Controller
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly UserManager<User> _userManager;
|
||||
private readonly ICurrentContext _currentContext;
|
||||
private readonly IVerifyAuthRequestCommand _verifyAuthRequestCommand;
|
||||
|
||||
public TwoFactorController(
|
||||
IUserService userService,
|
||||
@ -35,7 +37,8 @@ public class TwoFactorController : Controller
|
||||
IOrganizationService organizationService,
|
||||
GlobalSettings globalSettings,
|
||||
UserManager<User> userManager,
|
||||
ICurrentContext currentContext)
|
||||
ICurrentContext currentContext,
|
||||
IVerifyAuthRequestCommand verifyAuthRequestCommand)
|
||||
{
|
||||
_userService = userService;
|
||||
_organizationRepository = organizationRepository;
|
||||
@ -43,6 +46,7 @@ public class TwoFactorController : Controller
|
||||
_globalSettings = globalSettings;
|
||||
_userManager = userManager;
|
||||
_currentContext = currentContext;
|
||||
_verifyAuthRequestCommand = verifyAuthRequestCommand;
|
||||
}
|
||||
|
||||
[HttpGet("")]
|
||||
@ -285,19 +289,27 @@ public class TwoFactorController : Controller
|
||||
var user = await _userManager.FindByEmailAsync(model.Email.ToLowerInvariant());
|
||||
if (user != null)
|
||||
{
|
||||
if (await _userService.VerifySecretAsync(user, model.Secret))
|
||||
// check if 2FA email is from passwordless
|
||||
if (!string.IsNullOrEmpty(model.AuthRequestAccessCode))
|
||||
{
|
||||
var isBecauseNewDeviceLogin = false;
|
||||
if (user.GetTwoFactorProvider(TwoFactorProviderType.Email) is null
|
||||
&&
|
||||
await _userService.Needs2FABecauseNewDeviceAsync(user, model.DeviceIdentifier, null))
|
||||
if (await _verifyAuthRequestCommand
|
||||
.VerifyAuthRequestAsync(model.AuthRequestId, model.AuthRequestAccessCode))
|
||||
{
|
||||
model.ToUser(user);
|
||||
isBecauseNewDeviceLogin = true;
|
||||
}
|
||||
var isBecauseNewDeviceLogin = await IsNewDeviceLoginAsync(user, model);
|
||||
|
||||
await _userService.SendTwoFactorEmailAsync(user, isBecauseNewDeviceLogin);
|
||||
return;
|
||||
await _userService.SendTwoFactorEmailAsync(user, isBecauseNewDeviceLogin);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (await _userService.VerifySecretAsync(user, model.Secret))
|
||||
{
|
||||
var isBecauseNewDeviceLogin = await IsNewDeviceLoginAsync(user, model);
|
||||
|
||||
await _userService.SendTwoFactorEmailAsync(user, isBecauseNewDeviceLogin);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,4 +467,17 @@ public class TwoFactorController : Controller
|
||||
await Task.Delay(500);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> IsNewDeviceLoginAsync(User user, TwoFactorEmailRequestModel model)
|
||||
{
|
||||
if (user.GetTwoFactorProvider(TwoFactorProviderType.Email) is null
|
||||
&&
|
||||
await _userService.Needs2FABecauseNewDeviceAsync(user, model.DeviceIdentifier, null))
|
||||
{
|
||||
model.ToUser(user);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -7,13 +7,14 @@ public class SecretVerificationRequestModel : IValidatableObject
|
||||
[StringLength(300)]
|
||||
public string MasterPasswordHash { get; set; }
|
||||
public string OTP { get; set; }
|
||||
public string AuthRequestAccessCode { get; set; }
|
||||
public string Secret => !string.IsNullOrEmpty(MasterPasswordHash) ? MasterPasswordHash : OTP;
|
||||
|
||||
public virtual IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (string.IsNullOrEmpty(Secret))
|
||||
if (string.IsNullOrEmpty(Secret) && string.IsNullOrEmpty(AuthRequestAccessCode))
|
||||
{
|
||||
yield return new ValidationResult("MasterPasswordHash or OTP must be supplied.");
|
||||
yield return new ValidationResult("MasterPasswordHash, OTP or AccessCode must be supplied.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -204,6 +204,8 @@ public class TwoFactorEmailRequestModel : SecretVerificationRequestModel
|
||||
|
||||
public string DeviceIdentifier { get; set; }
|
||||
|
||||
public Guid AuthRequestId { get; set; }
|
||||
|
||||
public User ToUser(User extistingUser)
|
||||
{
|
||||
var providers = extistingUser.GetTwoFactorProviders();
|
||||
|
Reference in New Issue
Block a user