diff --git a/src/Api/Controllers/TwoFactorController.cs b/src/Api/Controllers/TwoFactorController.cs index 7ff375609e..1f94c04f0d 100644 --- a/src/Api/Controllers/TwoFactorController.cs +++ b/src/Api/Controllers/TwoFactorController.cs @@ -220,48 +220,6 @@ namespace Bit.Api.Controllers return response; } - [HttpPost("get-u2f")] - public async Task GetU2f([FromBody]TwoFactorRequestModel model) - { - var user = await CheckAsync(model.MasterPasswordHash, true); - var response = new TwoFactorU2fResponseModel(user); - return response; - } - - [HttpPost("get-u2f-challenge")] - public async Task GetU2fChallenge( - [FromBody]TwoFactorRequestModel model) - { - var user = await CheckAsync(model.MasterPasswordHash, true); - var reg = await _userService.StartU2fRegistrationAsync(user); - var challenge = new TwoFactorU2fResponseModel.ChallengeModel(user, reg); - return challenge; - } - - [HttpPut("u2f")] - [HttpPost("u2f")] - public async Task PutU2f([FromBody]TwoFactorU2fRequestModel model) - { - var user = await CheckAsync(model.MasterPasswordHash, true); - var success = await _userService.CompleteU2fRegistrationAsync( - user, model.Id.Value, model.Name, model.DeviceResponse); - if (!success) - { - throw new BadRequestException("Unable to complete U2F key registration."); - } - var response = new TwoFactorU2fResponseModel(user); - return response; - } - - [HttpDelete("u2f")] - public async Task DeleteU2f([FromBody]TwoFactorU2fDeleteRequestModel model) - { - var user = await CheckAsync(model.MasterPasswordHash, true); - await _userService.DeleteU2fKeyAsync(user, model.Id.Value); - var response = new TwoFactorU2fResponseModel(user); - return response; - } - [HttpPost("get-webauthn")] public async Task GetWebAuthn([FromBody]TwoFactorRequestModel model) { diff --git a/src/Core/Models/Api/Request/TwoFactorRequestModels.cs b/src/Core/Models/Api/Request/TwoFactorRequestModels.cs index b491a9287d..e6bf6bacc4 100644 --- a/src/Core/Models/Api/Request/TwoFactorRequestModels.cs +++ b/src/Core/Models/Api/Request/TwoFactorRequestModels.cs @@ -224,27 +224,6 @@ namespace Bit.Core.Models.Api } } - public class TwoFactorU2fRequestModel : TwoFactorU2fDeleteRequestModel - { - [Required] - public string DeviceResponse { get; set; } - public string Name { get; set; } - } - - public class TwoFactorU2fDeleteRequestModel : TwoFactorRequestModel, IValidatableObject - { - [Required] - public int? Id { get; set; } - - public IEnumerable Validate(ValidationContext validationContext) - { - if (!Id.HasValue || Id < 0 || Id > 5) - { - yield return new ValidationResult("Invalid Key Id", new string[] { nameof(Id) }); - } - } - } - public class TwoFactorWebAuthnRequestModel : TwoFactorWebAuthnDeleteRequestModel { [Required] diff --git a/src/Core/Models/Api/Response/TwoFactor/TwoFactorU2fResponseModel.cs b/src/Core/Models/Api/Response/TwoFactor/TwoFactorU2fResponseModel.cs deleted file mode 100644 index 121be3d4be..0000000000 --- a/src/Core/Models/Api/Response/TwoFactor/TwoFactorU2fResponseModel.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System; -using Bit.Core.Models.Table; -using Bit.Core.Models.Business; -using Bit.Core.Enums; -using System.Collections.Generic; -using System.Linq; - -namespace Bit.Core.Models.Api -{ - public class TwoFactorU2fResponseModel : ResponseModel - { - public TwoFactorU2fResponseModel(User user) - : base("twoFactorU2f") - { - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); - Enabled = provider?.Enabled ?? false; - Keys = provider?.MetaData?.Select(k => new KeyModel(k.Key, - new TwoFactorProvider.U2fMetaData((dynamic)k.Value))); - } - - public bool Enabled { get; set; } - public IEnumerable Keys { get; set; } - - public class KeyModel - { - public KeyModel(string id, TwoFactorProvider.U2fMetaData data) - { - Name = data.Name; - Id = Convert.ToInt32(id.Replace("Key", string.Empty)); - Compromised = data.Compromised; - } - - public string Name { get; set; } - public int Id { get; set; } - public bool Compromised { get; set; } - } - - public class ChallengeModel - { - public ChallengeModel(User user, U2fRegistration registration) - { - UserId = user.Id.ToString(); - AppId = registration.AppId; - Challenge = registration.Challenge; - Version = registration.Version; - } - - public string UserId { get; set; } - public string AppId { get; set; } - public string Challenge { get; set; } - public string Version { get; set; } - } - } -} diff --git a/src/Core/Models/Business/U2fRegistration.cs b/src/Core/Models/Business/U2fRegistration.cs deleted file mode 100644 index c27afdc40a..0000000000 --- a/src/Core/Models/Business/U2fRegistration.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Bit.Core.Models.Business -{ - public class U2fRegistration - { - public string AppId { get; set; } - public string Challenge { get; set; } - public string Version { get; set; } - } -} diff --git a/src/Core/Services/IUserService.cs b/src/Core/Services/IUserService.cs index f5da901fdb..ebc18dd2eb 100644 --- a/src/Core/Services/IUserService.cs +++ b/src/Core/Services/IUserService.cs @@ -24,9 +24,6 @@ namespace Bit.Core.Services Task SendMasterPasswordHintAsync(string email); Task SendTwoFactorEmailAsync(User user); Task VerifyTwoFactorEmailAsync(User user, string token); - Task StartU2fRegistrationAsync(User user); - Task DeleteU2fKeyAsync(User user, int id); - Task CompleteU2fRegistrationAsync(User user, int id, string name, string deviceResponse); Task StartWebAuthnRegistrationAsync(User user); Task DeleteWebAuthnKeyAsync(User user, int id); Task CompleteWebAuthRegistrationAsync(User user, int value, string name, AuthenticatorAttestationRawResponse attestationResponse); diff --git a/src/Core/Services/Implementations/UserService.cs b/src/Core/Services/Implementations/UserService.cs index b5c9855185..e409563b50 100644 --- a/src/Core/Services/Implementations/UserService.cs +++ b/src/Core/Services/Implementations/UserService.cs @@ -18,7 +18,6 @@ using Bit.Core.Context; using Bit.Core.Exceptions; using Bit.Core.Utilities; using Bit.Core.Settings; -using U2F.Core.Exceptions; using System.IO; using Newtonsoft.Json; using Microsoft.AspNetCore.DataProtection; @@ -36,7 +35,6 @@ namespace Bit.Core.Services private readonly ICipherRepository _cipherRepository; private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationRepository _organizationRepository; - private readonly IU2fRepository _u2fRepository; private readonly IMailService _mailService; private readonly IPushNotificationService _pushService; private readonly IdentityErrorDescriber _identityErrorDescriber; @@ -60,7 +58,6 @@ namespace Bit.Core.Services ICipherRepository cipherRepository, IOrganizationUserRepository organizationUserRepository, IOrganizationRepository organizationRepository, - IU2fRepository u2fRepository, IMailService mailService, IPushNotificationService pushService, IUserStore store, @@ -98,7 +95,6 @@ namespace Bit.Core.Services _cipherRepository = cipherRepository; _organizationUserRepository = organizationUserRepository; _organizationRepository = organizationRepository; - _u2fRepository = u2fRepository; _mailService = mailService; _pushService = pushService; _identityOptions = optionsAccessor?.Value ?? new IdentityOptions(); @@ -367,133 +363,6 @@ namespace Bit.Core.Services "2faEmail:" + email, token); } - public async Task StartU2fRegistrationAsync(User user) - { - await _u2fRepository.DeleteManyByUserIdAsync(user.Id); - var reg = U2fLib.StartRegistration(CoreHelpers.U2fAppIdUrl(_globalSettings)); - await _u2fRepository.CreateAsync(new U2f - { - AppId = reg.AppId, - Challenge = reg.Challenge, - Version = reg.Version, - UserId = user.Id, - CreationDate = DateTime.UtcNow - }); - - return new U2fRegistration - { - AppId = reg.AppId, - Challenge = reg.Challenge, - Version = reg.Version - }; - } - - public async Task CompleteU2fRegistrationAsync(User user, int id, string name, string deviceResponse) - { - if (string.IsNullOrWhiteSpace(deviceResponse)) - { - return false; - } - - var challenges = await _u2fRepository.GetManyByUserIdAsync(user.Id); - if (!challenges?.Any() ?? true) - { - return false; - } - - var registerResponse = BaseModel.FromJson(deviceResponse); - - try - { - var challenge = challenges.OrderBy(i => i.Id).Last(i => i.KeyHandle == null); - var startedReg = new StartedRegistration(challenge.Challenge, challenge.AppId); - var reg = U2fLib.FinishRegistration(startedReg, registerResponse); - - await _u2fRepository.DeleteManyByUserIdAsync(user.Id); - - // Add device - var providers = user.GetTwoFactorProviders(); - if (providers == null) - { - providers = new Dictionary(); - } - var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); - if (provider == null) - { - provider = new TwoFactorProvider(); - } - if (provider.MetaData == null) - { - provider.MetaData = new Dictionary(); - } - - if (provider.MetaData.Count >= 5) - { - // Can only register up to 5 keys - return false; - } - - var keyId = $"Key{id}"; - if (provider.MetaData.ContainsKey(keyId)) - { - provider.MetaData.Remove(keyId); - } - - provider.Enabled = true; - provider.MetaData.Add(keyId, new TwoFactorProvider.U2fMetaData - { - Name = name, - KeyHandle = reg.KeyHandle == null ? null : Utils.ByteArrayToBase64String(reg.KeyHandle), - PublicKey = reg.PublicKey == null ? null : Utils.ByteArrayToBase64String(reg.PublicKey), - Certificate = reg.AttestationCert == null ? null : Utils.ByteArrayToBase64String(reg.AttestationCert), - Compromised = false, - Counter = reg.Counter - }); - - if (providers.ContainsKey(TwoFactorProviderType.U2f)) - { - providers.Remove(TwoFactorProviderType.U2f); - } - - providers.Add(TwoFactorProviderType.U2f, provider); - user.SetTwoFactorProviders(providers); - await UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.U2f); - return true; - } - catch (U2fException e) - { - Logger.LogError(e, "Complete U2F registration error."); - return false; - } - } - - public async Task DeleteU2fKeyAsync(User user, int id) - { - var providers = user.GetTwoFactorProviders(); - if (providers == null) - { - return false; - } - - var keyName = $"Key{id}"; - var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); - if (!provider?.MetaData?.ContainsKey(keyName) ?? true) - { - return false; - } - - if (provider.MetaData.Count < 2) - { - return false; - } - - provider.MetaData.Remove(keyName); - providers[TwoFactorProviderType.U2f] = provider; - user.SetTwoFactorProviders(providers); - await UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.U2f); - return true; - } - public async Task StartWebAuthnRegistrationAsync(User user) { var providers = user.GetTwoFactorProviders(); diff --git a/test/Core.Test/Services/UserServiceTests.cs b/test/Core.Test/Services/UserServiceTests.cs index 89c7949cf9..8180559442 100644 --- a/test/Core.Test/Services/UserServiceTests.cs +++ b/test/Core.Test/Services/UserServiceTests.cs @@ -23,7 +23,6 @@ namespace Bit.Core.Test.Services private readonly ICipherRepository _cipherRepository; private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationRepository _organizationRepository; - private readonly IU2fRepository _u2fRepository; private readonly IMailService _mailService; private readonly IPushNotificationService _pushService; private readonly IUserStore _userStore; @@ -53,7 +52,6 @@ namespace Bit.Core.Test.Services _cipherRepository = Substitute.For(); _organizationUserRepository = Substitute.For(); _organizationRepository = Substitute.For(); - _u2fRepository = Substitute.For(); _mailService = Substitute.For(); _pushService = Substitute.For(); _userStore = Substitute.For>(); @@ -82,7 +80,6 @@ namespace Bit.Core.Test.Services _cipherRepository, _organizationUserRepository, _organizationRepository, - _u2fRepository, _mailService, _pushService, _userStore,