mirror of
https://github.com/bitwarden/server.git
synced 2024-11-22 12:15:36 +01:00
yubikey setup for 2FA
This commit is contained in:
parent
612697e815
commit
69de88cc32
@ -67,6 +67,51 @@ namespace Bit.Api.Controllers
|
||||
return response;
|
||||
}
|
||||
|
||||
[HttpPost("get-yubikey")]
|
||||
public async Task<TwoFactorYubiKeyResponseModel> GetYubiKey([FromBody]TwoFactorRequestModel model)
|
||||
{
|
||||
var user = await CheckPasswordAsync(model.MasterPasswordHash);
|
||||
var response = new TwoFactorYubiKeyResponseModel(user);
|
||||
return response;
|
||||
}
|
||||
|
||||
[HttpPut("yubikey")]
|
||||
[HttpPost("yubikey")]
|
||||
public async Task<TwoFactorYubiKeyResponseModel> PutYubiKey(
|
||||
[FromBody]UpdateTwoFactorYubicoOtpRequestModel model)
|
||||
{
|
||||
var user = await CheckPasswordAsync(model.MasterPasswordHash);
|
||||
model.ToUser(user);
|
||||
|
||||
await ValidateYubiKeyAsync(user, nameof(model.Key1), model.Key1);
|
||||
await ValidateYubiKeyAsync(user, nameof(model.Key2), model.Key2);
|
||||
await ValidateYubiKeyAsync(user, nameof(model.Key3), model.Key3);
|
||||
await ValidateYubiKeyAsync(user, nameof(model.Key4), model.Key4);
|
||||
await ValidateYubiKeyAsync(user, nameof(model.Key5), model.Key5);
|
||||
|
||||
await _userService.UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.YubiKey);
|
||||
var response = new TwoFactorYubiKeyResponseModel(user);
|
||||
return response;
|
||||
}
|
||||
|
||||
public async Task ValidateYubiKeyAsync(User user, string name, string value)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(value) || value.Length == 12)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!await _userManager.VerifyTwoFactorTokenAsync(user, TwoFactorProviderType.YubiKey.ToString(), value))
|
||||
{
|
||||
await Task.Delay(2000);
|
||||
throw new BadRequestException(name, $"{name} is invalid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(500);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("get-email")]
|
||||
public async Task<TwoFactorEmailResponseModel> GetEmail([FromBody]TwoFactorRequestModel model)
|
||||
{
|
||||
@ -74,7 +119,7 @@ namespace Bit.Api.Controllers
|
||||
var response = new TwoFactorEmailResponseModel(user);
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
[HttpPost("send-email")]
|
||||
public async Task SendEmail([FromBody]TwoFactorEmailRequestModel model)
|
||||
{
|
||||
@ -136,7 +181,7 @@ namespace Bit.Api.Controllers
|
||||
await Task.Delay(2000);
|
||||
throw new BadRequestException("MasterPasswordHash", "Invalid password.");
|
||||
}
|
||||
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ namespace Bit.Core.Identity
|
||||
|
||||
public Task<bool> ValidateAsync(string purpose, string token, UserManager<User> manager, User user)
|
||||
{
|
||||
if(token.Length != 44)
|
||||
if(string.IsNullOrWhiteSpace(token) || token.Length != 44)
|
||||
{
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
@ -45,7 +45,7 @@ namespace Bit.Core.Identity
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
var client = new YubicoClient(_globalSettings.Yubico.ClientId, _globalSettings.Yubico.ClientId);
|
||||
var client = new YubicoClient(_globalSettings.Yubico.ClientId, _globalSettings.Yubico.Key);
|
||||
var response = client.Verify(token);
|
||||
return Task.FromResult(response.Status == YubicoResponseStatus.Ok);
|
||||
}
|
||||
|
@ -57,12 +57,75 @@ namespace Bit.Core.Models.Api
|
||||
public string Key4 { get; set; }
|
||||
public string Key5 { get; set; }
|
||||
|
||||
public User ToUser(User extistingUser)
|
||||
{
|
||||
var providers = extistingUser.GetTwoFactorProviders();
|
||||
if(providers == null)
|
||||
{
|
||||
providers = new Dictionary<TwoFactorProviderType, TwoFactorProvider>();
|
||||
}
|
||||
else if(providers.ContainsKey(TwoFactorProviderType.YubiKey))
|
||||
{
|
||||
providers.Remove(TwoFactorProviderType.YubiKey);
|
||||
}
|
||||
|
||||
providers.Add(TwoFactorProviderType.YubiKey, new TwoFactorProvider
|
||||
{
|
||||
MetaData = new Dictionary<string, string>
|
||||
{
|
||||
["Key1"] = FormatKey(Key1),
|
||||
["Key2"] = FormatKey(Key2),
|
||||
["Key3"] = FormatKey(Key3),
|
||||
["Key4"] = FormatKey(Key4),
|
||||
["Key5"] = FormatKey(Key5)
|
||||
},
|
||||
Enabled = true
|
||||
});
|
||||
extistingUser.SetTwoFactorProviders(providers);
|
||||
return extistingUser;
|
||||
}
|
||||
|
||||
private string FormatKey(string keyValue)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(keyValue))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return keyValue.Substring(0, 12);
|
||||
}
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(Key1) && string.IsNullOrWhiteSpace(Key2) && string.IsNullOrWhiteSpace(Key3) &&
|
||||
string.IsNullOrWhiteSpace(Key4) && string.IsNullOrWhiteSpace(Key5))
|
||||
{
|
||||
yield return new ValidationResult("A Key is required.", new string[] { nameof(Key1) });
|
||||
yield return new ValidationResult("A key is required.", new string[] { nameof(Key1) });
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(Key1) && Key1.Length < 12)
|
||||
{
|
||||
yield return new ValidationResult("Key 1 in invalid.", new string[] { nameof(Key1) });
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(Key2) && Key2.Length < 12)
|
||||
{
|
||||
yield return new ValidationResult("Key 2 in invalid.", new string[] { nameof(Key2) });
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(Key3) && Key3.Length < 12)
|
||||
{
|
||||
yield return new ValidationResult("Key 3 in invalid.", new string[] { nameof(Key3) });
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(Key4) && Key4.Length < 12)
|
||||
{
|
||||
yield return new ValidationResult("Key 4 in invalid.", new string[] { nameof(Key4) });
|
||||
}
|
||||
|
||||
if(!string.IsNullOrWhiteSpace(Key5) && Key5.Length < 12)
|
||||
{
|
||||
yield return new ValidationResult("Key 5 in invalid.", new string[] { nameof(Key5) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace Bit.Core.Models.Api
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Email);
|
||||
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.YubiKey);
|
||||
if(provider?.MetaData != null && provider.MetaData.Count > 0)
|
||||
{
|
||||
Enabled = provider.Enabled;
|
||||
@ -29,7 +29,7 @@ namespace Bit.Core.Models.Api
|
||||
}
|
||||
if(provider.MetaData.ContainsKey("Key3"))
|
||||
{
|
||||
Key1 = provider.MetaData["Key3"];
|
||||
Key3 = provider.MetaData["Key3"];
|
||||
}
|
||||
if(provider.MetaData.ContainsKey("Key4"))
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user