mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 15:42:48 -05:00
Remove the u2f lib (#1820)
This commit is contained in:
@ -9,8 +9,8 @@ using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Sso;
|
||||
using Bit.Core.Utilities;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
using U2F.Core.Utils;
|
||||
|
||||
namespace Bit.Api.Models.Request.Organizations
|
||||
{
|
||||
@ -147,7 +147,7 @@ namespace Bit.Api.Models.Request.Organizations
|
||||
ValidationResult failedResult = null;
|
||||
try
|
||||
{
|
||||
var certData = StripPemCertificateElements(IdpX509PublicCert).Base64StringToByteArray();
|
||||
var certData = CoreHelpers.Base64UrlDecode(StripPemCertificateElements(IdpX509PublicCert));
|
||||
new X509Certificate2(certData);
|
||||
}
|
||||
catch (FormatException)
|
||||
|
@ -50,7 +50,6 @@
|
||||
<PackageReference Include="AspNetCoreRateLimit" Version="2.1.0" />
|
||||
<PackageReference Include="Braintree" Version="4.18.0" />
|
||||
<PackageReference Include="Stripe.net" Version="37.26.0" />
|
||||
<PackageReference Include="U2F.Core" Version="1.0.4" />
|
||||
<PackageReference Include="Otp.NET" Version="1.2.2" />
|
||||
<PackageReference Include="YubicoDotNetClient" Version="1.2.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Redis" Version="2.2.0" />
|
||||
|
@ -1,26 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Bit.Core.Entities
|
||||
{
|
||||
public class U2f : ITableObject<int>
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
[MaxLength(200)]
|
||||
public string KeyHandle { get; set; }
|
||||
[MaxLength(200)]
|
||||
public string Challenge { get; set; }
|
||||
[MaxLength(50)]
|
||||
public string AppId { get; set; }
|
||||
[MaxLength(20)]
|
||||
public string Version { get; set; }
|
||||
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
||||
|
||||
public void SetNewId()
|
||||
{
|
||||
// int will be auto-populated
|
||||
Id = 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@
|
||||
Email = 1,
|
||||
Duo = 2,
|
||||
YubiKey = 3,
|
||||
U2f = 4,
|
||||
// U2f = 4, // Deprecated
|
||||
Remember = 5,
|
||||
OrganizationDuo = 6,
|
||||
WebAuthn = 7,
|
||||
|
@ -1,221 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Settings;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using U2F.Core.Exceptions;
|
||||
using U2F.Core.Models;
|
||||
using U2F.Core.Utils;
|
||||
using U2fLib = U2F.Core.Crypto.U2F;
|
||||
|
||||
namespace Bit.Core.Identity
|
||||
{
|
||||
public class U2fTokenProvider : IUserTwoFactorTokenProvider<User>
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IU2fRepository _u2fRepository;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
|
||||
public U2fTokenProvider(
|
||||
IServiceProvider serviceProvider,
|
||||
IU2fRepository u2fRepository,
|
||||
GlobalSettings globalSettings)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_u2fRepository = u2fRepository;
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
public async Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
|
||||
{
|
||||
var userService = _serviceProvider.GetRequiredService<IUserService>();
|
||||
if (!(await userService.CanAccessPremium(user)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f);
|
||||
if (!HasProperMetaData(provider))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return await userService.TwoFactorProviderIsEnabledAsync(TwoFactorProviderType.U2f, user);
|
||||
}
|
||||
|
||||
public async Task<string> GenerateAsync(string purpose, UserManager<User> manager, User user)
|
||||
{
|
||||
var userService = _serviceProvider.GetRequiredService<IUserService>();
|
||||
if (!(await userService.CanAccessPremium(user)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f);
|
||||
var keys = LoadKeys(provider);
|
||||
if (keys.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
await _u2fRepository.DeleteManyByUserIdAsync(user.Id);
|
||||
|
||||
try
|
||||
{
|
||||
var challengeBytes = U2fLib.Crypto.GenerateChallenge();
|
||||
var appId = Utilities.CoreHelpers.U2fAppIdUrl(_globalSettings);
|
||||
var oldChallenges = new List<object>();
|
||||
var challengeKeys = new List<object>();
|
||||
foreach (var key in keys)
|
||||
{
|
||||
var registration = new DeviceRegistration(key.Item2.KeyHandleBytes, key.Item2.PublicKeyBytes,
|
||||
key.Item2.CertificateBytes, key.Item2.Counter);
|
||||
var auth = U2fLib.StartAuthentication(appId, registration, challengeBytes);
|
||||
|
||||
// TODO: Maybe move this to a bulk create?
|
||||
await _u2fRepository.CreateAsync(new U2f
|
||||
{
|
||||
AppId = auth.AppId,
|
||||
Challenge = auth.Challenge,
|
||||
KeyHandle = auth.KeyHandle,
|
||||
Version = auth.Version,
|
||||
UserId = user.Id,
|
||||
CreationDate = DateTime.UtcNow
|
||||
});
|
||||
|
||||
challengeKeys.Add(new
|
||||
{
|
||||
keyHandle = auth.KeyHandle,
|
||||
version = auth.Version
|
||||
});
|
||||
|
||||
// TODO: Old challenges array is here for backwards compat. Remove in the future.
|
||||
oldChallenges.Add(new
|
||||
{
|
||||
appId = auth.AppId,
|
||||
challenge = auth.Challenge,
|
||||
keyHandle = auth.KeyHandle,
|
||||
version = auth.Version
|
||||
});
|
||||
}
|
||||
|
||||
var oldToken = JsonSerializer.Serialize(oldChallenges);
|
||||
var token = JsonSerializer.Serialize(new
|
||||
{
|
||||
appId = appId,
|
||||
challenge = challengeBytes.ByteArrayToBase64String(),
|
||||
keys = challengeKeys
|
||||
});
|
||||
return $"{token}|{oldToken}";
|
||||
}
|
||||
catch (U2fException)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> ValidateAsync(string purpose, string token, UserManager<User> manager, User user)
|
||||
{
|
||||
var userService = _serviceProvider.GetRequiredService<IUserService>();
|
||||
if (!(await userService.CanAccessPremium(user)) || string.IsNullOrWhiteSpace(token))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f);
|
||||
var keys = LoadKeys(provider);
|
||||
if (keys.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var authenticateResponse = BaseModel.FromJson<AuthenticateResponse>(token);
|
||||
var key = keys.FirstOrDefault(f => f.Item2.KeyHandle == authenticateResponse.KeyHandle);
|
||||
|
||||
if (key == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var challenges = await _u2fRepository.GetManyByUserIdAsync(user.Id);
|
||||
if (challenges.Count == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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.FirstOrDefault(c => c.KeyHandle == authenticateResponse.KeyHandle);
|
||||
if (challenge == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var success = true;
|
||||
var registration = new DeviceRegistration(key.Item2.KeyHandleBytes, key.Item2.PublicKeyBytes,
|
||||
key.Item2.CertificateBytes, key.Item2.Counter);
|
||||
try
|
||||
{
|
||||
var auth = new StartedAuthentication(challenge.Challenge, challenge.AppId, challenge.KeyHandle);
|
||||
U2fLib.FinishAuthentication(auth, authenticateResponse, registration);
|
||||
}
|
||||
catch (U2fException)
|
||||
{
|
||||
success = false;
|
||||
}
|
||||
|
||||
// Update database
|
||||
await _u2fRepository.DeleteManyByUserIdAsync(user.Id);
|
||||
key.Item2.Counter = registration.Counter;
|
||||
if (key.Item2.Counter > 0)
|
||||
{
|
||||
key.Item2.Compromised = registration.IsCompromised;
|
||||
}
|
||||
|
||||
var providers = user.GetTwoFactorProviders();
|
||||
providers[TwoFactorProviderType.U2f].MetaData[key.Item1] = key.Item2;
|
||||
user.SetTwoFactorProviders(providers);
|
||||
await manager.UpdateAsync(user);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private bool HasProperMetaData(TwoFactorProvider provider)
|
||||
{
|
||||
return (provider?.MetaData?.Count ?? 0) > 0;
|
||||
}
|
||||
|
||||
private List<Tuple<string, TwoFactorProvider.U2fMetaData>> LoadKeys(TwoFactorProvider provider)
|
||||
{
|
||||
var keys = new List<Tuple<string, TwoFactorProvider.U2fMetaData>>();
|
||||
if (!HasProperMetaData(provider))
|
||||
{
|
||||
return keys;
|
||||
}
|
||||
|
||||
// Support up to 5 keys
|
||||
for (var i = 1; i <= 5; i++)
|
||||
{
|
||||
var keyName = $"Key{i}";
|
||||
if (provider.MetaData.ContainsKey(keyName))
|
||||
{
|
||||
var key = new TwoFactorProvider.U2fMetaData((dynamic)provider.MetaData[keyName]);
|
||||
if (!key?.Compromised ?? false)
|
||||
{
|
||||
keys.Add(new Tuple<string, TwoFactorProvider.U2fMetaData>(keyName, key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
}
|
@ -375,7 +375,6 @@ namespace Bit.Core.IdentityServer
|
||||
case TwoFactorProviderType.Email:
|
||||
case TwoFactorProviderType.Duo:
|
||||
case TwoFactorProviderType.YubiKey:
|
||||
case TwoFactorProviderType.U2f:
|
||||
case TwoFactorProviderType.WebAuthn:
|
||||
case TwoFactorProviderType.Remember:
|
||||
if (type != TwoFactorProviderType.Remember &&
|
||||
@ -403,7 +402,6 @@ namespace Bit.Core.IdentityServer
|
||||
switch (type)
|
||||
{
|
||||
case TwoFactorProviderType.Duo:
|
||||
case TwoFactorProviderType.U2f:
|
||||
case TwoFactorProviderType.WebAuthn:
|
||||
case TwoFactorProviderType.Email:
|
||||
case TwoFactorProviderType.YubiKey:
|
||||
@ -422,16 +420,6 @@ namespace Bit.Core.IdentityServer
|
||||
["Signature"] = token
|
||||
};
|
||||
}
|
||||
else if (type == TwoFactorProviderType.U2f)
|
||||
{
|
||||
// TODO: Remove "Challenges" in a future update. Deprecated.
|
||||
var tokens = token?.Split('|');
|
||||
return new Dictionary<string, object>
|
||||
{
|
||||
["Challenge"] = tokens != null && tokens.Length > 0 ? tokens[0] : null,
|
||||
["Challenges"] = tokens != null && tokens.Length > 1 ? tokens[1] : null
|
||||
};
|
||||
}
|
||||
else if (type == TwoFactorProviderType.WebAuthn)
|
||||
{
|
||||
if (token == null)
|
||||
|
@ -1,12 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json.Serialization;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Utilities;
|
||||
using Fido2NetLib.Objects;
|
||||
using PeterO.Cbor;
|
||||
using U2F.Core.Utils;
|
||||
|
||||
namespace Bit.Core.Models
|
||||
{
|
||||
@ -15,79 +11,6 @@ namespace Bit.Core.Models
|
||||
public bool Enabled { get; set; }
|
||||
public Dictionary<string, object> MetaData { get; set; } = new Dictionary<string, object>();
|
||||
|
||||
public class U2fMetaData
|
||||
{
|
||||
public U2fMetaData() { }
|
||||
|
||||
public U2fMetaData(dynamic o)
|
||||
{
|
||||
Name = o.Name;
|
||||
KeyHandle = o.KeyHandle;
|
||||
PublicKey = o.PublicKey;
|
||||
Certificate = o.Certificate;
|
||||
Counter = o.Counter;
|
||||
Compromised = o.Compromised;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
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; }
|
||||
public bool Compromised { get; set; }
|
||||
|
||||
private static CBORObject CreatePublicKeyFromU2fRegistrationData(byte[] keyHandleData, byte[] publicKeyData)
|
||||
{
|
||||
var x = new byte[32];
|
||||
var y = new byte[32];
|
||||
Buffer.BlockCopy(publicKeyData, 1, x, 0, 32);
|
||||
Buffer.BlockCopy(publicKeyData, 33, y, 0, 32);
|
||||
|
||||
var point = new ECPoint
|
||||
{
|
||||
X = x,
|
||||
Y = y,
|
||||
};
|
||||
|
||||
var coseKey = CBORObject.NewMap();
|
||||
|
||||
coseKey.Add(COSE.KeyCommonParameter.KeyType, COSE.KeyType.EC2);
|
||||
coseKey.Add(COSE.KeyCommonParameter.Alg, -7);
|
||||
|
||||
coseKey.Add(COSE.KeyTypeParameter.Crv, COSE.EllipticCurve.P256);
|
||||
|
||||
coseKey.Add(COSE.KeyTypeParameter.X, point.X);
|
||||
coseKey.Add(COSE.KeyTypeParameter.Y, point.Y);
|
||||
|
||||
return coseKey;
|
||||
}
|
||||
|
||||
public WebAuthnData ToWebAuthnData()
|
||||
{
|
||||
return new WebAuthnData
|
||||
{
|
||||
Name = Name,
|
||||
Descriptor = new PublicKeyCredentialDescriptor
|
||||
{
|
||||
Id = KeyHandleBytes,
|
||||
Type = PublicKeyCredentialType.PublicKey
|
||||
},
|
||||
PublicKey = CreatePublicKeyFromU2fRegistrationData(KeyHandleBytes, PublicKeyBytes).EncodeToBytes(),
|
||||
SignatureCounter = Counter,
|
||||
Migrated = true,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public class WebAuthnData
|
||||
{
|
||||
public WebAuthnData() { }
|
||||
@ -130,7 +53,6 @@ namespace Bit.Core.Models
|
||||
{
|
||||
case TwoFactorProviderType.Duo:
|
||||
case TwoFactorProviderType.YubiKey:
|
||||
case TwoFactorProviderType.U2f:
|
||||
case TwoFactorProviderType.WebAuthn:
|
||||
return true;
|
||||
default:
|
||||
|
@ -1,13 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Entities;
|
||||
|
||||
namespace Bit.Core.Repositories
|
||||
{
|
||||
public interface IU2fRepository : IRepository<U2f, int>
|
||||
{
|
||||
Task<ICollection<U2f>> GetManyByUserIdAsync(Guid userId);
|
||||
Task DeleteManyByUserIdAsync(Guid userId);
|
||||
}
|
||||
}
|
@ -21,7 +21,6 @@ using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using File = System.IO.File;
|
||||
using U2fLib = U2F.Core.Crypto.U2F;
|
||||
|
||||
namespace Bit.Core.Services
|
||||
{
|
||||
@ -481,25 +480,6 @@ namespace Bit.Core.Services
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delete U2F token is this is a migrated WebAuthn token.
|
||||
var entry = new TwoFactorProvider.WebAuthnData(provider.MetaData[keyName]);
|
||||
if (entry?.Migrated ?? false)
|
||||
{
|
||||
var u2fProvider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f);
|
||||
if (u2fProvider?.MetaData?.ContainsKey(keyName) ?? false)
|
||||
{
|
||||
u2fProvider.MetaData.Remove(keyName);
|
||||
if (u2fProvider.MetaData.Count > 0)
|
||||
{
|
||||
providers[TwoFactorProviderType.U2f] = u2fProvider;
|
||||
}
|
||||
else
|
||||
{
|
||||
providers.Remove(TwoFactorProviderType.U2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider.MetaData.Remove(keyName);
|
||||
providers[TwoFactorProviderType.WebAuthn] = provider;
|
||||
user.SetTwoFactorProviders(providers);
|
||||
@ -899,13 +879,6 @@ namespace Bit.Core.Services
|
||||
return;
|
||||
}
|
||||
|
||||
// Since the user can no longer directly manipulate U2F tokens, we should
|
||||
// disable them when the user disables WebAuthn.
|
||||
if (type == TwoFactorProviderType.WebAuthn)
|
||||
{
|
||||
providers.Remove(TwoFactorProviderType.U2f);
|
||||
}
|
||||
|
||||
providers.Remove(type);
|
||||
user.SetTwoFactorProviders(providers);
|
||||
await SaveUserAsync(user);
|
||||
|
@ -31,7 +31,6 @@ namespace Bit.Infrastructure.Dapper
|
||||
services.AddSingleton<IProviderUserRepository, ProviderUserRepository>();
|
||||
services.AddSingleton<IProviderOrganizationRepository, ProviderOrganizationRepository>();
|
||||
services.AddSingleton<ITransactionRepository, TransactionRepository>();
|
||||
services.AddSingleton<IU2fRepository, U2fRepository>();
|
||||
services.AddSingleton<IUserRepository, UserRepository>();
|
||||
|
||||
if (selfHosted)
|
||||
|
@ -1,63 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Settings;
|
||||
using Dapper;
|
||||
|
||||
namespace Bit.Infrastructure.Dapper.Repositories
|
||||
{
|
||||
public class U2fRepository : Repository<U2f, int>, IU2fRepository
|
||||
{
|
||||
public U2fRepository(GlobalSettings globalSettings)
|
||||
: this(globalSettings.SqlServer.ConnectionString, globalSettings.SqlServer.ReadOnlyConnectionString)
|
||||
{ }
|
||||
|
||||
public U2fRepository(string connectionString, string readOnlyConnectionString)
|
||||
: base(connectionString, readOnlyConnectionString)
|
||||
{ }
|
||||
|
||||
public async Task<ICollection<U2f>> GetManyByUserIdAsync(Guid userId)
|
||||
{
|
||||
using (var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
var results = await connection.QueryAsync<U2f>(
|
||||
$"[{Schema}].[U2f_ReadByUserId]",
|
||||
new { UserId = userId },
|
||||
commandType: CommandType.StoredProcedure);
|
||||
|
||||
return results.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteManyByUserIdAsync(Guid userId)
|
||||
{
|
||||
using (var connection = new SqlConnection(ConnectionString))
|
||||
{
|
||||
await connection.ExecuteAsync(
|
||||
$"[{Schema}].[U2f_DeleteByUserId]",
|
||||
new { UserId = userId },
|
||||
commandType: CommandType.StoredProcedure);
|
||||
}
|
||||
}
|
||||
|
||||
public override Task ReplaceAsync(U2f obj)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override Task UpsertAsync(U2f obj)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override Task DeleteAsync(U2f obj)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -50,7 +50,6 @@ namespace Bit.Infrastructure.EntityFramework
|
||||
services.AddSingleton<ISsoUserRepository, SsoUserRepository>();
|
||||
services.AddSingleton<ITaxRateRepository, TaxRateRepository>();
|
||||
services.AddSingleton<ITransactionRepository, TransactionRepository>();
|
||||
services.AddSingleton<IU2fRepository, U2fRepository>();
|
||||
services.AddSingleton<IUserRepository, UserRepository>();
|
||||
services.AddSingleton<IProviderRepository, ProviderRepository>();
|
||||
services.AddSingleton<IProviderUserRepository, ProviderUserRepository>();
|
||||
|
@ -1,17 +0,0 @@
|
||||
using AutoMapper;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Models
|
||||
{
|
||||
public class U2f : Core.Entities.U2f
|
||||
{
|
||||
public virtual User User { get; set; }
|
||||
}
|
||||
|
||||
public class U2fMapperProfile : Profile
|
||||
{
|
||||
public U2fMapperProfile()
|
||||
{
|
||||
CreateMap<Core.Entities.U2f, U2f>().ReverseMap();
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@ namespace Bit.Infrastructure.EntityFramework.Models
|
||||
public virtual ICollection<OrganizationUser> OrganizationUsers { get; set; }
|
||||
public virtual ICollection<SsoUser> SsoUsers { get; set; }
|
||||
public virtual ICollection<Transaction> Transactions { get; set; }
|
||||
public virtual ICollection<U2f> U2fs { get; set; }
|
||||
}
|
||||
|
||||
public class UserMapperProfile : Profile
|
||||
|
@ -36,7 +36,6 @@ namespace Bit.Infrastructure.EntityFramework.Repositories
|
||||
public DbSet<SsoUser> SsoUsers { get; set; }
|
||||
public DbSet<TaxRate> TaxRates { get; set; }
|
||||
public DbSet<Transaction> Transactions { get; set; }
|
||||
public DbSet<U2f> U2fs { get; set; }
|
||||
public DbSet<User> Users { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
@ -66,7 +65,6 @@ namespace Bit.Infrastructure.EntityFramework.Repositories
|
||||
var eSsoUser = builder.Entity<SsoUser>();
|
||||
var eTaxRate = builder.Entity<TaxRate>();
|
||||
var eTransaction = builder.Entity<Transaction>();
|
||||
var eU2f = builder.Entity<U2f>();
|
||||
var eUser = builder.Entity<User>();
|
||||
|
||||
eCipher.Property(c => c.Id).ValueGeneratedNever();
|
||||
@ -128,7 +126,6 @@ namespace Bit.Infrastructure.EntityFramework.Repositories
|
||||
eSsoUser.ToTable(nameof(SsoUser));
|
||||
eTaxRate.ToTable(nameof(TaxRate));
|
||||
eTransaction.ToTable(nameof(Transaction));
|
||||
eU2f.ToTable(nameof(U2f));
|
||||
eUser.ToTable(nameof(User));
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories
|
||||
{
|
||||
public class U2fRepository : Repository<Core.Entities.U2f, U2f, int>, IU2fRepository
|
||||
{
|
||||
public U2fRepository(IServiceScopeFactory serviceScopeFactory, IMapper mapper)
|
||||
: base(serviceScopeFactory, mapper, (DatabaseContext context) => context.U2fs)
|
||||
{ }
|
||||
|
||||
public async Task<ICollection<Core.Entities.U2f>> GetManyByUserIdAsync(Guid userId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var results = await dbContext.U2fs.Where(u => u.UserId == userId).ToListAsync();
|
||||
return (ICollection<Core.Entities.U2f>)results;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task DeleteManyByUserIdAsync(Guid userId)
|
||||
{
|
||||
using (var scope = ServiceScopeFactory.CreateScope())
|
||||
{
|
||||
var dbContext = GetDatabaseContext(scope);
|
||||
var u2fs = dbContext.U2fs.Where(u => u.UserId == userId);
|
||||
dbContext.RemoveRange(u2fs);
|
||||
await dbContext.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public override Task ReplaceAsync(Core.Entities.U2f obj)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override Task UpsertAsync(Core.Entities.U2f obj)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override Task DeleteAsync(Core.Entities.U2f obj)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -335,8 +335,6 @@ namespace Bit.SharedWeb.Utilities
|
||||
CoreHelpers.CustomProviderName(TwoFactorProviderType.YubiKey))
|
||||
.AddTokenProvider<DuoWebTokenProvider>(
|
||||
CoreHelpers.CustomProviderName(TwoFactorProviderType.Duo))
|
||||
.AddTokenProvider<U2fTokenProvider>(
|
||||
CoreHelpers.CustomProviderName(TwoFactorProviderType.U2f))
|
||||
.AddTokenProvider<TwoFactorRememberTokenProvider>(
|
||||
CoreHelpers.CustomProviderName(TwoFactorProviderType.Remember))
|
||||
.AddTokenProvider<EmailTokenProvider<User>>(TokenOptions.DefaultEmailProvider)
|
||||
|
@ -83,7 +83,6 @@
|
||||
<Build Include="dbo\Tables\Grant.sql" />
|
||||
<Build Include="dbo\Tables\SsoConfig.sql" />
|
||||
<Build Include="dbo\Tables\User.sql" />
|
||||
<Build Include="dbo\Tables\U2f.sql" />
|
||||
<Build Include="dbo\Tables\Device.sql" />
|
||||
<Build Include="dbo\Tables\Folder.sql" />
|
||||
<Build Include="dbo\Tables\Cipher.sql" />
|
||||
@ -103,7 +102,6 @@
|
||||
<Build Include="dbo\Views\SsoConfigView.sql" />
|
||||
<Build Include="dbo\Views\SsoUserView.sql" />
|
||||
<Build Include="dbo\Views\UserView.sql" />
|
||||
<Build Include="dbo\Views\U2fView.sql" />
|
||||
<Build Include="dbo\Views\CipherView.sql" />
|
||||
<Build Include="dbo\Views\DeviceView.sql" />
|
||||
<Build Include="dbo\Views\GroupView.sql" />
|
||||
@ -164,9 +162,6 @@
|
||||
<Build Include="dbo\Stored Procedures\CollectionCipher_Delete.sql" />
|
||||
<Build Include="dbo\Stored Procedures\CollectionCipher_UpdateCollections.sql" />
|
||||
<Build Include="dbo\Stored Procedures\CollectionCipher_UpdateCollectionsAdmin.sql" />
|
||||
<Build Include="dbo\Stored Procedures\U2f_Create.sql" />
|
||||
<Build Include="dbo\Stored Procedures\U2f_DeleteByUserId.sql" />
|
||||
<Build Include="dbo\Stored Procedures\U2f_ReadByUserId.sql" />
|
||||
<Build Include="dbo\Stored Procedures\Folder_Create.sql" />
|
||||
<Build Include="dbo\Stored Procedures\Folder_DeleteById.sql" />
|
||||
<Build Include="dbo\Stored Procedures\Folder_Update.sql" />
|
||||
@ -271,7 +266,6 @@
|
||||
<Build Include="dbo\Stored Procedures\CollectionCipher_UpdateCollectionsForCiphers.sql" />
|
||||
<Build Include="dbo\Stored Procedures\User_UpdateRenewalReminderDate.sql" />
|
||||
<Build Include="dbo\Stored Procedures\Grant_DeleteExpired.sql" />
|
||||
<Build Include="dbo\Stored Procedures\U2f_DeleteOld.sql" />
|
||||
<Build Include="dbo\Stored Procedures\User_ReadKdfByEmail.sql" />
|
||||
<Build Include="dbo\Stored Procedures\Cipher_DeleteByOrganizationId.sql" />
|
||||
<Build Include="dbo\Stored Procedures\AzureSQLMaintenance.sql" />
|
||||
|
@ -1,33 +0,0 @@
|
||||
CREATE PROCEDURE [dbo].[U2f_Create]
|
||||
@Id INT OUTPUT,
|
||||
@UserId UNIQUEIDENTIFIER,
|
||||
@KeyHandle VARCHAR(200),
|
||||
@Challenge VARCHAR(200),
|
||||
@AppId VARCHAR(50),
|
||||
@Version VARCHAR(20),
|
||||
@CreationDate DATETIME2(7)
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
INSERT INTO [dbo].[U2f]
|
||||
(
|
||||
[UserId],
|
||||
[KeyHandle],
|
||||
[Challenge],
|
||||
[AppId],
|
||||
[Version],
|
||||
[CreationDate]
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@UserId,
|
||||
@KeyHandle,
|
||||
@Challenge,
|
||||
@AppId,
|
||||
@Version,
|
||||
@CreationDate
|
||||
)
|
||||
|
||||
SET @Id = (SELECT SCOPE_IDENTITY())
|
||||
END
|
@ -1,12 +0,0 @@
|
||||
CREATE PROCEDURE [dbo].[U2f_DeleteByUserId]
|
||||
@UserId UNIQUEIDENTIFIER
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
DELETE
|
||||
FROM
|
||||
[dbo].[U2f]
|
||||
WHERE
|
||||
[UserId] = @UserId
|
||||
END
|
@ -1,20 +0,0 @@
|
||||
CREATE PROCEDURE [dbo].[U2f_DeleteOld]
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
DECLARE @BatchSize INT = 100
|
||||
DECLARE @Threshold DATETIME2(7) = DATEADD (day, -7, GETUTCDATE())
|
||||
|
||||
WHILE @BatchSize > 0
|
||||
BEGIN
|
||||
DELETE TOP(@BatchSize)
|
||||
FROM
|
||||
[dbo].[U2f]
|
||||
WHERE
|
||||
[CreationDate] IS NULL
|
||||
OR [CreationDate] < @Threshold
|
||||
|
||||
SET @BatchSize = @@ROWCOUNT
|
||||
END
|
||||
END
|
@ -1,13 +0,0 @@
|
||||
CREATE PROCEDURE [dbo].[U2f_ReadByUserId]
|
||||
@UserId UNIQUEIDENTIFIER
|
||||
AS
|
||||
BEGIN
|
||||
SET NOCOUNT ON
|
||||
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
[dbo].[U2fView]
|
||||
WHERE
|
||||
[UserId] = @UserId
|
||||
END
|
@ -72,13 +72,6 @@ BEGIN
|
||||
WHERE
|
||||
[UserId] = @Id
|
||||
|
||||
-- Delete U2F logins
|
||||
DELETE
|
||||
FROM
|
||||
[dbo].[U2f]
|
||||
WHERE
|
||||
[UserId] = @Id
|
||||
|
||||
-- Delete SSO Users
|
||||
DELETE
|
||||
FROM
|
||||
|
@ -1,22 +0,0 @@
|
||||
CREATE TABLE [dbo].[U2f] (
|
||||
[Id] INT IDENTITY (1, 1) NOT NULL,
|
||||
[UserId] UNIQUEIDENTIFIER 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,
|
||||
CONSTRAINT [PK_U2f] PRIMARY KEY CLUSTERED ([Id] ASC),
|
||||
CONSTRAINT [FK_U2f_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])
|
||||
);
|
||||
|
||||
|
||||
GO
|
||||
CREATE NONCLUSTERED INDEX [IX_U2f_CreationDate]
|
||||
ON [dbo].[U2f]([CreationDate] ASC)
|
||||
|
||||
|
||||
GO
|
||||
CREATE NONCLUSTERED INDEX [IX_U2f_UserId]
|
||||
ON [dbo].[U2f]([UserId] ASC);
|
||||
|
@ -1,6 +0,0 @@
|
||||
CREATE VIEW [dbo].[U2fView]
|
||||
AS
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
[dbo].[U2f]
|
Reference in New Issue
Block a user