diff --git a/src/Core/Identity/U2fTokenProvider.cs b/src/Core/Identity/U2fTokenProvider.cs index a49086dcbe..340a32041f 100644 --- a/src/Core/Identity/U2fTokenProvider.cs +++ b/src/Core/Identity/U2fTokenProvider.cs @@ -3,7 +3,6 @@ using Microsoft.AspNetCore.Identity; using Bit.Core.Models.Table; using Bit.Core.Enums; using Bit.Core.Models; -using Bit.Core.Services; using Bit.Core.Repositories; using Newtonsoft.Json; using System.Collections.Generic; @@ -18,16 +17,13 @@ namespace Bit.Core.Identity public class U2fTokenProvider : IUserTwoFactorTokenProvider { private readonly IU2fRepository _u2fRepository; - private readonly IUserService _userService; private readonly GlobalSettings _globalSettings; public U2fTokenProvider( IU2fRepository u2fRepository, - IUserService userService, GlobalSettings globalSettings) { _u2fRepository = u2fRepository; - _userService = userService; _globalSettings = globalSettings; } @@ -48,7 +44,7 @@ namespace Bit.Core.Identity var keys = new List(); - var key1 = provider.MetaData["Key1"] as TwoFactorProvider.U2fMetaData; + var key1 = new TwoFactorProvider.U2fMetaData((dynamic)provider.MetaData["Key1"]); if(!key1?.Compromised ?? false) { keys.Add(key1); @@ -98,7 +94,7 @@ namespace Bit.Core.Identity return false; } - var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo); + var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); if(!HasProperMetaData(provider)) { return false; @@ -106,7 +102,7 @@ namespace Bit.Core.Identity var keys = new List(); - var key1 = provider.MetaData["Key1"] as TwoFactorProvider.U2fMetaData; + var key1 = new TwoFactorProvider.U2fMetaData((dynamic)provider.MetaData["Key1"]); if(!key1?.Compromised ?? false) { keys.Add(key1); @@ -131,10 +127,15 @@ namespace Bit.Core.Identity return false; } - var success = true; // User will have a authentication request for each device they have registered so get the one that matches // the device key handle - var challenge = challenges.First(c => c.KeyHandle == authenticateResponse.KeyHandle); + var challenge = challenges.FirstOrDefault(c => c.KeyHandle == authenticateResponse.KeyHandle); + if(challenge == null) + { + return false; + } + + var success = true; var registration = new DeviceRegistration(key.KeyHandleBytes, key.PublicKeyBytes, key.CertificateBytes, key.Counter); try @@ -155,7 +156,7 @@ namespace Bit.Core.Identity var providers = user.GetTwoFactorProviders(); providers[TwoFactorProviderType.U2f].MetaData["Key1"] = key; user.SetTwoFactorProviders(providers); - await _userService.SaveUserAsync(user); + await manager.UpdateAsync(user); return success; } diff --git a/src/Core/Models/TwoFactorProvider.cs b/src/Core/Models/TwoFactorProvider.cs index 81e5820508..1f8e809674 100644 --- a/src/Core/Models/TwoFactorProvider.cs +++ b/src/Core/Models/TwoFactorProvider.cs @@ -1,4 +1,5 @@ -using System; +using Newtonsoft.Json; +using System; using System.Collections.Generic; using u2flib.Util; @@ -11,13 +12,27 @@ namespace Bit.Core.Models public class U2fMetaData { + public U2fMetaData() { } + + public U2fMetaData(dynamic o) + { + KeyHandle = o.KeyHandle; + PublicKey = o.PublicKey; + Certificate = o.Certificate; + Counter = o.Counter; + Compromised = o.Compromised; + } + public string KeyHandle { get; set; } + [JsonIgnore] public byte[] KeyHandleBytes => string.IsNullOrWhiteSpace(KeyHandle) ? null : Utils.Base64StringToByteArray(KeyHandle); public string PublicKey { get; set; } + [JsonIgnore] public byte[] PublicKeyBytes => string.IsNullOrWhiteSpace(PublicKey) ? null : Utils.Base64StringToByteArray(PublicKey); public string Certificate { get; set; } + [JsonIgnore] public byte[] CertificateBytes => string.IsNullOrWhiteSpace(Certificate) ? null : Utils.Base64StringToByteArray(Certificate); public uint Counter { get; set; } diff --git a/src/Core/Utilities/ServiceCollectionExtensions.cs b/src/Core/Utilities/ServiceCollectionExtensions.cs index 712cbe364f..b5a749d0e2 100644 --- a/src/Core/Utilities/ServiceCollectionExtensions.cs +++ b/src/Core/Utilities/ServiceCollectionExtensions.cs @@ -101,6 +101,7 @@ namespace Bit.Core.Utilities .AddTokenProvider(TwoFactorProviderType.Authenticator.ToString()) .AddTokenProvider(TwoFactorProviderType.YubiKey.ToString()) .AddTokenProvider(TwoFactorProviderType.Duo.ToString()) + .AddTokenProvider(TwoFactorProviderType.U2f.ToString()) .AddTokenProvider>(TokenOptions.DefaultEmailProvider); return identityBuilder; diff --git a/src/Identity/settings.json b/src/Identity/settings.json index e052969322..467b1611eb 100644 --- a/src/Identity/settings.json +++ b/src/Identity/settings.json @@ -44,7 +44,7 @@ "aKey": "SECRET" }, "u2f": { - "appId": "https://bitwarden.com" + "appId": "https://localhost:4001" } } } diff --git a/src/Sql/dbo/Stored Procedures/U2f_Create.sql b/src/Sql/dbo/Stored Procedures/U2f_Create.sql index 8cd95cd5a0..c7b85b3569 100644 --- a/src/Sql/dbo/Stored Procedures/U2f_Create.sql +++ b/src/Sql/dbo/Stored Procedures/U2f_Create.sql @@ -1,10 +1,10 @@ CREATE PROCEDURE [dbo].[U2f_Create] @Id INT, @UserId UNIQUEIDENTIFIER, - @KeyHandle VARCHAR(50), - @Challenge VARCHAR(50), + @KeyHandle VARCHAR(200), + @Challenge VARCHAR(200), @AppId VARCHAR(50), - @Version VARCHAR(50), + @Version VARCHAR(20), @CreationDate DATETIME2(7) AS BEGIN diff --git a/src/Sql/dbo/Tables/U2f.sql b/src/Sql/dbo/Tables/U2f.sql index 1d513c9f9c..6abdf1f3cd 100644 --- a/src/Sql/dbo/Tables/U2f.sql +++ b/src/Sql/dbo/Tables/U2f.sql @@ -1,8 +1,8 @@ CREATE TABLE [dbo].[U2f] ( [Id] INT IDENTITY (1, 1) NOT NULL, [UserId] UNIQUEIDENTIFIER NOT NULL, - [KeyHandle] VARCHAR (MAX) NULL, - [Challenge] VARCHAR (MAX) NOT NULL, + [KeyHandle] VARCHAR (200) NULL, + [Challenge] VARCHAR (200) NOT NULL, [AppId] VARCHAR (50) NOT NULL, [Version] VARCHAR (20) NOT NULL, [CreationDate] DATETIME2 (7) NOT NULL,