1
0
mirror of https://github.com/bitwarden/server.git synced 2025-04-18 03:28:15 -05:00

update u2f lib. send 2fa login email

This commit is contained in:
Kyle Spearrin 2017-06-24 09:20:12 -04:00
parent 64189067cd
commit 59b8438a0f
6 changed files with 46 additions and 17 deletions

View File

@ -207,6 +207,24 @@ namespace Bit.Api.Controllers
await _userService.SendTwoFactorEmailAsync(user); await _userService.SendTwoFactorEmailAsync(user);
} }
[AllowAnonymous]
[HttpPost("send-email-login")]
public async Task SendEmailLogin([FromBody]TwoFactorEmailRequestModel model)
{
var user = await _userManager.FindByEmailAsync(model.Email.ToLowerInvariant());
if(user != null)
{
if(await _userManager.CheckPasswordAsync(user, model.MasterPasswordHash))
{
await _userService.SendTwoFactorEmailAsync(user);
return;
}
}
await Task.Delay(2000);
throw new BadRequestException("Cannot send two-factor email.");
}
[HttpPut("email")] [HttpPut("email")]
[HttpPost("email")] [HttpPost("email")]
public async Task<TwoFactorEmailResponseModel> PutEmail([FromBody]UpdateTwoFactorEmailRequestModel model) public async Task<TwoFactorEmailResponseModel> PutEmail([FromBody]UpdateTwoFactorEmailRequestModel model)

View File

@ -56,7 +56,7 @@
<PackageReference Include="Serilog.Extensions.Logging" Version="1.4.0" /> <PackageReference Include="Serilog.Extensions.Logging" Version="1.4.0" />
<PackageReference Include="Serilog.Sinks.AzureDocumentDB" Version="3.6.1" /> <PackageReference Include="Serilog.Sinks.AzureDocumentDB" Version="3.6.1" />
<PackageReference Include="Stripe.net" Version="7.8.0" /> <PackageReference Include="Stripe.net" Version="7.8.0" />
<PackageReference Include="u2flib" Version="1.0.5" /> <PackageReference Include="U2F.Core" Version="1.0.3" />
<PackageReference Include="WindowsAzure.Storage" Version="8.1.1" /> <PackageReference Include="WindowsAzure.Storage" Version="8.1.1" />
<PackageReference Include="Otp.NET" Version="1.0.1" /> <PackageReference Include="Otp.NET" Version="1.0.1" />
<PackageReference Include="YubicoDotNetClient" Version="1.0.0" /> <PackageReference Include="YubicoDotNetClient" Version="1.0.0" />

View File

@ -7,10 +7,9 @@ using Bit.Core.Repositories;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using u2flib.Data; using U2fLib = U2F.Core.Crypto.U2F;
using u2flib; using U2F.Core.Models;
using u2flib.Data.Messages; using U2F.Core.Exceptions;
using u2flib.Exceptions;
namespace Bit.Core.Identity namespace Bit.Core.Identity
{ {
@ -62,7 +61,7 @@ namespace Bit.Core.Identity
{ {
var registration = new DeviceRegistration(key.KeyHandleBytes, key.PublicKeyBytes, var registration = new DeviceRegistration(key.KeyHandleBytes, key.PublicKeyBytes,
key.CertificateBytes, key.Counter); key.CertificateBytes, key.Counter);
var auth = U2F.StartAuthentication(Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings), registration); var auth = U2fLib.StartAuthentication(Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings), registration);
// Maybe move this to a bulk create when we support more than 1 key? // Maybe move this to a bulk create when we support more than 1 key?
await _u2fRepository.CreateAsync(new U2f await _u2fRepository.CreateAsync(new U2f
@ -113,7 +112,7 @@ namespace Bit.Core.Identity
return false; return false;
} }
var authenticateResponse = DataObject.FromJson<AuthenticateResponse>(token); var authenticateResponse = BaseModel.FromJson<AuthenticateResponse>(token);
var key = keys.FirstOrDefault(f => f.KeyHandle == authenticateResponse.KeyHandle); var key = keys.FirstOrDefault(f => f.KeyHandle == authenticateResponse.KeyHandle);
if(key == null) if(key == null)
@ -141,7 +140,7 @@ namespace Bit.Core.Identity
try try
{ {
var auth = new StartedAuthentication(challenge.Challenge, challenge.AppId, challenge.KeyHandle); var auth = new StartedAuthentication(challenge.Challenge, challenge.AppId, challenge.KeyHandle);
U2F.FinishAuthentication(auth, authenticateResponse, registration); U2fLib.FinishAuthentication(auth, authenticateResponse, registration);
} }
catch(U2fException) catch(U2fException)
{ {

View File

@ -120,7 +120,14 @@ namespace Bit.Core.IdentityServer
{ {
var providerKeys = new List<byte>(); var providerKeys = new List<byte>();
var providers = new Dictionary<byte, Dictionary<string, object>>(); var providers = new Dictionary<byte, Dictionary<string, object>>();
foreach(var provider in user.GetTwoFactorProviders().Where(p => p.Value.Enabled)) var enabledProviders = user.GetTwoFactorProviders()?.Where(p => p.Value.Enabled);
if(enabledProviders == null)
{
BuildErrorResult(false, context);
return;
}
foreach(var provider in enabledProviders)
{ {
providerKeys.Add((byte)provider.Key); providerKeys.Add((byte)provider.Key);
var infoDict = await BuildTwoFactorParams(user, provider.Key, provider.Value); var infoDict = await BuildTwoFactorParams(user, provider.Key, provider.Value);
@ -133,6 +140,12 @@ namespace Bit.Core.IdentityServer
{ "TwoFactorProviders", providers.Keys }, { "TwoFactorProviders", providers.Keys },
{ "TwoFactorProviders2", providers } { "TwoFactorProviders2", providers }
}); });
if(enabledProviders.Count() == 1 && enabledProviders.First().Key == TwoFactorProviderType.Email)
{
// Send email now if this is their only 2FA method
await _userService.SendTwoFactorEmailAsync(user);
}
} }
private void BuildErrorResult(bool twoFactorRequest, ResourceOwnerPasswordValidationContext context) private void BuildErrorResult(bool twoFactorRequest, ResourceOwnerPasswordValidationContext context)

View File

@ -1,7 +1,7 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using u2flib.Util; using U2F.Core.Utils;
namespace Bit.Core.Models namespace Bit.Core.Models
{ {

View File

@ -12,10 +12,9 @@ using Bit.Core.Enums;
using System.Security.Claims; using System.Security.Claims;
using Bit.Core.Models; using Bit.Core.Models;
using Bit.Core.Models.Business; using Bit.Core.Models.Business;
using u2flib.Data.Messages; using U2fLib = U2F.Core.Crypto.U2F;
using u2flib.Util; using U2F.Core.Models;
using u2flib; using U2F.Core.Utils;
using u2flib.Data;
namespace Bit.Core.Services namespace Bit.Core.Services
{ {
@ -220,7 +219,7 @@ namespace Bit.Core.Services
public async Task<U2fRegistration> StartU2fRegistrationAsync(User user) public async Task<U2fRegistration> StartU2fRegistrationAsync(User user)
{ {
await _u2fRepository.DeleteManyByUserIdAsync(user.Id); await _u2fRepository.DeleteManyByUserIdAsync(user.Id);
var reg = U2F.StartRegistration(Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings)); var reg = U2fLib.StartRegistration(Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings));
await _u2fRepository.CreateAsync(new U2f await _u2fRepository.CreateAsync(new U2f
{ {
AppId = reg.AppId, AppId = reg.AppId,
@ -250,11 +249,11 @@ namespace Bit.Core.Services
return false; return false;
} }
var registerResponse = DataObject.FromJson<RegisterResponse>(deviceResponse); var registerResponse = BaseModel.FromJson<RegisterResponse>(deviceResponse);
var challenge = challenges.OrderBy(i => i.Id).Last(i => i.KeyHandle == null); var challenge = challenges.OrderBy(i => i.Id).Last(i => i.KeyHandle == null);
var statedReg = new StartedRegistration(challenge.Challenge, challenge.AppId); var statedReg = new StartedRegistration(challenge.Challenge, challenge.AppId);
var reg = U2F.FinishRegistration(statedReg, registerResponse); var reg = U2fLib.FinishRegistration(statedReg, registerResponse);
await _u2fRepository.DeleteManyByUserIdAsync(user.Id); await _u2fRepository.DeleteManyByUserIdAsync(user.Id);