mirror of
https://github.com/bitwarden/server.git
synced 2026-01-31 14:13:18 +08:00
refactor(2fa-webauthn) [PM-29890]: Add delete WebAuthn credential command.
This commit is contained in:
@@ -42,6 +42,7 @@ public class TwoFactorController : Controller
|
||||
private readonly ITwoFactorEmailService _twoFactorEmailService;
|
||||
private readonly IStartTwoFactorWebAuthnRegistrationCommand _startTwoFactorWebAuthnRegistrationCommand;
|
||||
private readonly ICompleteTwoFactorWebAuthnRegistrationCommand _completeTwoFactorWebAuthnRegistrationCommand;
|
||||
private readonly IDeleteTwoFactorWebAuthnCredentialCommand _deleteTwoFactorWebAuthnCredentialCommand;
|
||||
|
||||
public TwoFactorController(
|
||||
IUserService userService,
|
||||
@@ -55,7 +56,8 @@ public class TwoFactorController : Controller
|
||||
IDataProtectorTokenFactory<SsoEmail2faSessionTokenable> ssoEmailTwoFactorSessionDataProtector,
|
||||
ITwoFactorEmailService twoFactorEmailService,
|
||||
IStartTwoFactorWebAuthnRegistrationCommand startTwoFactorWebAuthnRegistrationCommand,
|
||||
ICompleteTwoFactorWebAuthnRegistrationCommand completeTwoFactorWebAuthnRegistrationCommand)
|
||||
ICompleteTwoFactorWebAuthnRegistrationCommand completeTwoFactorWebAuthnRegistrationCommand,
|
||||
IDeleteTwoFactorWebAuthnCredentialCommand deleteTwoFactorWebAuthnCredentialCommand)
|
||||
{
|
||||
_userService = userService;
|
||||
_organizationRepository = organizationRepository;
|
||||
@@ -69,6 +71,7 @@ public class TwoFactorController : Controller
|
||||
_twoFactorEmailService = twoFactorEmailService;
|
||||
_startTwoFactorWebAuthnRegistrationCommand = startTwoFactorWebAuthnRegistrationCommand;
|
||||
_completeTwoFactorWebAuthnRegistrationCommand = completeTwoFactorWebAuthnRegistrationCommand;
|
||||
_deleteTwoFactorWebAuthnCredentialCommand = deleteTwoFactorWebAuthnCredentialCommand;
|
||||
}
|
||||
|
||||
[HttpGet("")]
|
||||
@@ -321,7 +324,18 @@ public class TwoFactorController : Controller
|
||||
[FromBody] TwoFactorWebAuthnDeleteRequestModel model)
|
||||
{
|
||||
var user = await CheckAsync(model, false);
|
||||
await _userService.DeleteWebAuthnKeyAsync(user, model.Id.Value);
|
||||
|
||||
if (!model.Id.HasValue)
|
||||
{
|
||||
throw new BadRequestException("Unable to delete WebAuthn credential.");
|
||||
}
|
||||
|
||||
var success = await _deleteTwoFactorWebAuthnCredentialCommand.DeleteTwoFactorWebAuthnCredentialAsync(user, model.Id.Value);
|
||||
if (!success)
|
||||
{
|
||||
throw new BadRequestException("Unable to delete WebAuthn credential.");
|
||||
}
|
||||
|
||||
var response = new TwoFactorWebAuthnResponseModel(user);
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.Auth.UserFeatures.TwoFactorAuth;
|
||||
|
||||
public interface IDeleteTwoFactorWebAuthnCredentialCommand
|
||||
{
|
||||
/// <summary>
|
||||
/// Deletes a Two-factor WebAuthn credential by ID.
|
||||
/// </summary>
|
||||
/// <param name="user">The current user.</param>
|
||||
/// <param name="id">ID of the credential to delete.</param>
|
||||
/// <returns>Whether deletion was successful.</returns>
|
||||
Task<bool> DeleteTwoFactorWebAuthnCredentialAsync(User user, int id);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using Bit.Core.Auth.Enums;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Services;
|
||||
|
||||
namespace Bit.Core.Auth.UserFeatures.TwoFactorAuth.Implementations;
|
||||
|
||||
public class DeleteTwoFactorWebAuthnCredentialCommand : IDeleteTwoFactorWebAuthnCredentialCommand
|
||||
{
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public DeleteTwoFactorWebAuthnCredentialCommand(IUserService userService)
|
||||
{
|
||||
_userService = userService;
|
||||
}
|
||||
public async Task<bool> DeleteTwoFactorWebAuthnCredentialAsync(User user, int id)
|
||||
{
|
||||
var providers = user.GetTwoFactorProviders();
|
||||
if (providers == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var keyName = $"Key{id}";
|
||||
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.WebAuthn);
|
||||
if (!provider?.MetaData?.ContainsKey(keyName) ?? true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (provider.MetaData.Count < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
provider.MetaData.Remove(keyName);
|
||||
providers[TwoFactorProviderType.WebAuthn] = provider;
|
||||
user.SetTwoFactorProviders(providers);
|
||||
await _userService.UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.WebAuthn);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,7 @@ public static class UserServiceCollectionExtensions
|
||||
services
|
||||
.AddScoped<IStartTwoFactorWebAuthnRegistrationCommand,
|
||||
StartTwoFactorWebAuthnRegistrationCommand>();
|
||||
services.AddScoped<IDeleteTwoFactorWebAuthnCredentialCommand, DeleteTwoFactorWebAuthnCredentialCommand>();
|
||||
services.AddScoped<ITwoFactorIsEnabledQuery, TwoFactorIsEnabledQuery>();
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,6 @@ public interface IUserService
|
||||
Task<IdentityResult> CreateUserAsync(User user);
|
||||
Task<IdentityResult> CreateUserAsync(User user, string masterPasswordHash);
|
||||
Task SendMasterPasswordHintAsync(string email);
|
||||
Task<bool> DeleteWebAuthnKeyAsync(User user, int id);
|
||||
Task SendEmailVerificationAsync(User user);
|
||||
Task<IdentityResult> ConfirmEmailAsync(User user, string token);
|
||||
Task InitiateEmailChangeAsync(User user, string newEmail);
|
||||
|
||||
@@ -344,33 +344,6 @@ public class UserService : UserManager<User>, IUserService
|
||||
await _mailService.SendMasterPasswordHintEmailAsync(email, user.MasterPasswordHint);
|
||||
}
|
||||
|
||||
public async Task<bool> DeleteWebAuthnKeyAsync(User user, int id)
|
||||
{
|
||||
var providers = user.GetTwoFactorProviders();
|
||||
if (providers == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var keyName = $"Key{id}";
|
||||
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.WebAuthn);
|
||||
if (!provider?.MetaData?.ContainsKey(keyName) ?? true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (provider.MetaData.Count < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
provider.MetaData.Remove(keyName);
|
||||
providers[TwoFactorProviderType.WebAuthn] = provider;
|
||||
user.SetTwoFactorProviders(providers);
|
||||
await UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.WebAuthn);
|
||||
return true;
|
||||
}
|
||||
|
||||
public async Task SendEmailVerificationAsync(User user)
|
||||
{
|
||||
if (user.EmailVerified)
|
||||
|
||||
Reference in New Issue
Block a user