From f28ae5ccd9a5f154de3c1158ba8dcce82412752a Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Thu, 22 Jun 2017 17:03:35 -0400 Subject: [PATCH] fixes for configuring u2f device --- src/Api/Controllers/TwoFactorController.cs | 35 ++++++++++++++++++- src/Api/Properties/launchSettings.json | 4 +-- src/Api/Startup.cs | 6 ++-- src/Api/settings.Preview.json | 6 +++- src/Api/settings.Production.json | 6 +++- src/Api/settings.Staging.json | 6 +++- src/Api/settings.json | 3 +- src/Billing/settings.json | 1 + src/Core/Core.csproj | 3 +- src/Core/GlobalSettings.cs | 1 + src/Core/Identity/U2fTokenProvider.cs | 13 +++---- .../TwoFactor/TwoFactorU2fResponseModel.cs | 2 +- src/Core/Models/TwoFactorProvider.cs | 2 +- .../Services/Implementations/UserService.cs | 13 +++---- src/Core/Utilities/CoreHelpers.cs | 6 ++++ src/Identity/Properties/launchSettings.json | 6 ++-- src/Identity/settings.json | 1 + src/Sql/dbo/Stored Procedures/U2f_Create.sql | 2 -- src/Sql/dbo/Tables/U2f.sql | 6 ++-- 19 files changed, 89 insertions(+), 33 deletions(-) diff --git a/src/Api/Controllers/TwoFactorController.cs b/src/Api/Controllers/TwoFactorController.cs index 405c23cfe7..2a64d69ae0 100644 --- a/src/Api/Controllers/TwoFactorController.cs +++ b/src/Api/Controllers/TwoFactorController.cs @@ -9,6 +9,8 @@ using Microsoft.AspNetCore.Identity; using Bit.Core.Models.Table; using Bit.Core.Enums; using System.Linq; +using Bit.Core; +using Newtonsoft.Json; namespace Bit.Api.Controllers { @@ -17,13 +19,16 @@ namespace Bit.Api.Controllers public class TwoFactorController : Controller { private readonly IUserService _userService; + private readonly GlobalSettings _globalSettings; private readonly UserManager _userManager; public TwoFactorController( IUserService userService, + GlobalSettings globalSettings, UserManager userManager) { _userService = userService; + _globalSettings = globalSettings; _userManager = userManager; } @@ -117,7 +122,7 @@ namespace Bit.Api.Controllers { var user = await CheckPasswordAsync(model.MasterPasswordHash); var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); - if(!provider.Enabled || (provider?.MetaData != null && provider.MetaData.Count > 0)) + if(provider == null || !provider.Enabled || (provider.MetaData?.Count ?? 0) > 0) { var reg = await _userService.StartU2fRegistrationAsync(user); var response = new TwoFactorU2fResponseModel(user, provider, reg); @@ -130,6 +135,34 @@ namespace Bit.Api.Controllers } } + [HttpGet("~/app-id.json")] + //[Produces("application/fido.trusted-apps+json")] + [AllowAnonymous] + public string GetU2fAppId() + { + return JsonConvert.SerializeObject(new + { + trustedFacets = new object[] + { + new + { + version = new + { + major = 1, + minor = 1 + }, + ids = new string[] + { + _globalSettings.U2f.AppId, + //"ios:bundle-id:com.8bit.bitwarden", + //"android:apk-key-hash:585215fd5153209a7e246f53286035838a0be227", + //"chrome-extension://nngceckbapebfimnlniiiahkandclblb" + } + } + } + }); + } + [HttpPut("u2f")] [HttpPost("u2f")] public async Task PutU2f([FromBody]TwoFactorU2fRequestModel model) diff --git a/src/Api/Properties/launchSettings.json b/src/Api/Properties/launchSettings.json index d21f646a3e..d56f373353 100644 --- a/src/Api/Properties/launchSettings.json +++ b/src/Api/Properties/launchSettings.json @@ -4,7 +4,7 @@ "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:4000", - "sslPort": 0 + "sslPort": 44377 } }, "profiles": { @@ -24,4 +24,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/Api/Startup.cs b/src/Api/Startup.cs index c156a9cde3..45771229ab 100644 --- a/src/Api/Startup.cs +++ b/src/Api/Startup.cs @@ -153,9 +153,9 @@ namespace Bit.Api // Add IdentityServer to the request pipeline. app.UseIdentityServer(); app.UseIdentityServerAuthentication( - GetIdentityOptions(env, IdentityServerAuthority(env, "identity", "33656"), "3")); + GetIdentityOptions(env, IdentityServerAuthority(env, "identity", "44392"), "3")); app.UseIdentityServerAuthentication( - GetIdentityOptions(env, IdentityServerAuthority(env, "api", "4000"), "2")); + GetIdentityOptions(env, IdentityServerAuthority(env, "api", "44377"), "2")); // Add current context app.UseMiddleware(); @@ -195,7 +195,7 @@ namespace Bit.Api } else { - return $"http://localhost:{port}"; + return $"https://localhost:{port}"; //return $"http://192.168.1.6:{port}"; // Desktop external } } diff --git a/src/Api/settings.Preview.json b/src/Api/settings.Preview.json index 3e61d2d4ce..43fea18cd3 100644 --- a/src/Api/settings.Preview.json +++ b/src/Api/settings.Preview.json @@ -1,5 +1,9 @@ { "globalSettings": { - "baseVaultUri": "https://preview-vault.bitwarden.com/#" + "baseVaultUri": "https://preview-vault.bitwarden.com/#", + "baseApiUri": "https://preview-api.bitwarden.com/", + "u2f": { + "appId": "https://preview-vault.bitwarden.com" + } } } diff --git a/src/Api/settings.Production.json b/src/Api/settings.Production.json index 8cb3e0000a..3ee9f6dbf0 100644 --- a/src/Api/settings.Production.json +++ b/src/Api/settings.Production.json @@ -1,5 +1,9 @@ { "globalSettings": { - "baseVaultUri": "https://vault.bitwarden.com/#" + "baseVaultUri": "https://vault.bitwarden.com/#", + "baseApiUri": "https://api.bitwarden.com/", + "u2f": { + "appId": "https://vault.bitwarden.com" + } } } diff --git a/src/Api/settings.Staging.json b/src/Api/settings.Staging.json index 8cb3e0000a..3ee9f6dbf0 100644 --- a/src/Api/settings.Staging.json +++ b/src/Api/settings.Staging.json @@ -1,5 +1,9 @@ { "globalSettings": { - "baseVaultUri": "https://vault.bitwarden.com/#" + "baseVaultUri": "https://vault.bitwarden.com/#", + "baseApiUri": "https://api.bitwarden.com/", + "u2f": { + "appId": "https://vault.bitwarden.com" + } } } diff --git a/src/Api/settings.json b/src/Api/settings.json index b8d65c7412..c67b8d510d 100644 --- a/src/Api/settings.json +++ b/src/Api/settings.json @@ -2,6 +2,7 @@ "globalSettings": { "siteName": "bitwarden", "baseVaultUri": "http://localhost:4001/#", + "baseApiUri": "http://localhost:4000/", "jwtSigningKey": "THIS IS A SECRET. IT KEEPS YOUR TOKEN SAFE. :)", "stripeApiKey": "SECRET", "sqlServer": { @@ -47,7 +48,7 @@ "aKey": "SECRET" }, "u2f": { - "appId": "https://bitwarden.com" + "appId": "https://localhost:4001" } }, "IpRateLimitOptions": { diff --git a/src/Billing/settings.json b/src/Billing/settings.json index a6d8e2e760..cc5b06d6d9 100644 --- a/src/Billing/settings.json +++ b/src/Billing/settings.json @@ -2,6 +2,7 @@ "globalSettings": { "siteName": "bitwarden", "baseVaultUri": "http://localhost:4001/#", + "baseApiUri": "http://localhost:4000/", "jwtSigningKey": "THIS IS A SECRET. IT KEEPS YOUR TOKEN SAFE. :)", "stripeApiKey": "SECRET", "sqlServer": { diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj index 2784bfec9e..55aef19abc 100644 --- a/src/Core/Core.csproj +++ b/src/Core/Core.csproj @@ -49,13 +49,14 @@ + - + diff --git a/src/Core/GlobalSettings.cs b/src/Core/GlobalSettings.cs index aa22660be9..88e2926c16 100644 --- a/src/Core/GlobalSettings.cs +++ b/src/Core/GlobalSettings.cs @@ -4,6 +4,7 @@ { public virtual string SiteName { get; set; } public virtual string BaseVaultUri { get; set; } + public virtual string BaseApiUri { get; set; } public virtual string JwtSigningKey { get; set; } public virtual string StripeApiKey { get; set; } public virtual SqlServerSettings SqlServer { get; set; } = new SqlServerSettings(); diff --git a/src/Core/Identity/U2fTokenProvider.cs b/src/Core/Identity/U2fTokenProvider.cs index eba3e0e43d..a49086dcbe 100644 --- a/src/Core/Identity/U2fTokenProvider.cs +++ b/src/Core/Identity/U2fTokenProvider.cs @@ -5,12 +5,13 @@ using Bit.Core.Enums; using Bit.Core.Models; using Bit.Core.Services; using Bit.Core.Repositories; -using U2F.Core.Models; -using U2fLib = U2F.Core.Crypto.U2F; using Newtonsoft.Json; using System.Collections.Generic; using System.Linq; -using U2F.Core.Exceptions; +using u2flib.Data; +using u2flib; +using u2flib.Data.Messages; +using u2flib.Exceptions; namespace Bit.Core.Identity { @@ -65,7 +66,7 @@ namespace Bit.Core.Identity { var registration = new DeviceRegistration(key.KeyHandleBytes, key.PublicKeyBytes, key.CertificateBytes, key.Counter); - var auth = U2fLib.StartAuthentication(_globalSettings.U2f.AppId, registration); + var auth = U2F.StartAuthentication(Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings), registration); // Maybe move this to a bulk create when we support more than 1 key? await _u2fRepository.CreateAsync(new U2f @@ -116,7 +117,7 @@ namespace Bit.Core.Identity return false; } - var authenticateResponse = BaseModel.FromJson(token); + var authenticateResponse = DataObject.FromJson(token); var key = keys.FirstOrDefault(f => f.KeyHandle == authenticateResponse.KeyHandle); if(key == null) @@ -139,7 +140,7 @@ namespace Bit.Core.Identity try { var auth = new StartedAuthentication(challenge.Challenge, challenge.AppId, challenge.KeyHandle); - U2fLib.FinishAuthentication(auth, authenticateResponse, registration); + U2F.FinishAuthentication(auth, authenticateResponse, registration); } catch(U2fException) { diff --git a/src/Core/Models/Api/Response/TwoFactor/TwoFactorU2fResponseModel.cs b/src/Core/Models/Api/Response/TwoFactor/TwoFactorU2fResponseModel.cs index 9ba0959794..1f934089a0 100644 --- a/src/Core/Models/Api/Response/TwoFactor/TwoFactorU2fResponseModel.cs +++ b/src/Core/Models/Api/Response/TwoFactor/TwoFactorU2fResponseModel.cs @@ -19,7 +19,7 @@ namespace Bit.Core.Models.Api { Challenge = new ChallengeModel(user, registration); } - Enabled = provider.Enabled; + Enabled = provider?.Enabled ?? false; } public TwoFactorU2fResponseModel(User user) diff --git a/src/Core/Models/TwoFactorProvider.cs b/src/Core/Models/TwoFactorProvider.cs index 9ec16ccc22..81e5820508 100644 --- a/src/Core/Models/TwoFactorProvider.cs +++ b/src/Core/Models/TwoFactorProvider.cs @@ -1,6 +1,6 @@ using System; using System.Collections.Generic; -using U2F.Core.Utils; +using u2flib.Util; namespace Bit.Core.Models { diff --git a/src/Core/Services/Implementations/UserService.cs b/src/Core/Services/Implementations/UserService.cs index 5168db085b..58a1e7fe5b 100644 --- a/src/Core/Services/Implementations/UserService.cs +++ b/src/Core/Services/Implementations/UserService.cs @@ -10,11 +10,12 @@ using System.Linq; using Microsoft.AspNetCore.Builder; using Bit.Core.Enums; using System.Security.Claims; -using U2fLib = U2F.Core.Crypto.U2F; -using U2F.Core.Models; using Bit.Core.Models; using Bit.Core.Models.Business; -using U2F.Core.Utils; +using u2flib.Data.Messages; +using u2flib.Util; +using u2flib; +using u2flib.Data; namespace Bit.Core.Services { @@ -219,7 +220,7 @@ namespace Bit.Core.Services public async Task StartU2fRegistrationAsync(User user) { await _u2fRepository.DeleteManyByUserIdAsync(user.Id); - var reg = U2fLib.StartRegistration(_globalSettings.U2f.AppId); + var reg = U2F.StartRegistration(Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings)); await _u2fRepository.CreateAsync(new U2f { AppId = reg.AppId, @@ -249,11 +250,11 @@ namespace Bit.Core.Services return false; } - var registerResponse = BaseModel.FromJson(deviceResponse); + var registerResponse = DataObject.FromJson(deviceResponse); var challenge = challenges.OrderBy(i => i.Id).Last(i => i.KeyHandle == null); var statedReg = new StartedRegistration(challenge.Challenge, challenge.AppId); - var reg = U2fLib.FinishRegistration(statedReg, registerResponse); + var reg = U2F.FinishRegistration(statedReg, registerResponse); await _u2fRepository.DeleteManyByUserIdAsync(user.Id); diff --git a/src/Core/Utilities/CoreHelpers.cs b/src/Core/Utilities/CoreHelpers.cs index 85b482b846..5c3abd74ff 100644 --- a/src/Core/Utilities/CoreHelpers.cs +++ b/src/Core/Utilities/CoreHelpers.cs @@ -119,5 +119,11 @@ namespace Bit.Core.Utilities { return _epoc.AddMilliseconds(milliseconds); } + + public static string U2fAppIdUrl(GlobalSettings globalSettings) + { + //return $"{globalSettings.BaseApiUri}app-id.json"; + return globalSettings.U2f.AppId; + } } } diff --git a/src/Identity/Properties/launchSettings.json b/src/Identity/Properties/launchSettings.json index b1a7cdd262..d822506f3f 100644 --- a/src/Identity/Properties/launchSettings.json +++ b/src/Identity/Properties/launchSettings.json @@ -1,10 +1,10 @@ -{ +{ "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:33656/", - "sslPort": 0 + "sslPort": 44392 } }, "profiles": { @@ -24,4 +24,4 @@ "applicationUrl": "http://localhost:33657" } } -} +} \ No newline at end of file diff --git a/src/Identity/settings.json b/src/Identity/settings.json index d15eca2585..e052969322 100644 --- a/src/Identity/settings.json +++ b/src/Identity/settings.json @@ -2,6 +2,7 @@ "globalSettings": { "siteName": "bitwarden", "baseVaultUri": "http://localhost:4001/#", + "baseApiUri": "http://localhost:4000/", "jwtSigningKey": "THIS IS A SECRET. IT KEEPS YOUR TOKEN SAFE. :)", "stripeApiKey": "SECRET", "sqlServer": { diff --git a/src/Sql/dbo/Stored Procedures/U2f_Create.sql b/src/Sql/dbo/Stored Procedures/U2f_Create.sql index b446e431d5..8cd95cd5a0 100644 --- a/src/Sql/dbo/Stored Procedures/U2f_Create.sql +++ b/src/Sql/dbo/Stored Procedures/U2f_Create.sql @@ -12,7 +12,6 @@ BEGIN INSERT INTO [dbo].[U2f] ( - [Id], [UserId], [KeyHandle], [Challenge], @@ -22,7 +21,6 @@ BEGIN ) VALUES ( - @Id, @UserId, @KeyHandle, @Challenge, diff --git a/src/Sql/dbo/Tables/U2f.sql b/src/Sql/dbo/Tables/U2f.sql index 7f8e8cdb8a..1d513c9f9c 100644 --- a/src/Sql/dbo/Tables/U2f.sql +++ b/src/Sql/dbo/Tables/U2f.sql @@ -1,10 +1,10 @@ CREATE TABLE [dbo].[U2f] ( [Id] INT IDENTITY (1, 1) NOT NULL, [UserId] UNIQUEIDENTIFIER NOT NULL, - [KeyHandle] VARCHAR (50) NOT NULL, - [Challenge] VARCHAR (50) NOT NULL, + [KeyHandle] VARCHAR (MAX) NULL, + [Challenge] VARCHAR (MAX) NOT NULL, [AppId] VARCHAR (50) NOT NULL, - [Version] VARCHAR (50) NOT NULL, + [Version] VARCHAR (20) NOT NULL, [CreationDate] DATETIME2 (7) NOT NULL, CONSTRAINT [PK_U2f] PRIMARY KEY CLUSTERED ([Id] ASC), CONSTRAINT [FK_U2f_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])