1
0
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:
Oscar Hinton
2022-01-24 12:14:04 +01:00
committed by GitHub
parent 5268f2781e
commit ac8ca46f0f
44 changed files with 3489 additions and 1247 deletions

View File

@ -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)

View File

@ -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" />

View File

@ -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;
}
}
}

View File

@ -6,7 +6,7 @@
Email = 1,
Duo = 2,
YubiKey = 3,
U2f = 4,
// U2f = 4, // Deprecated
Remember = 5,
OrganizationDuo = 6,
WebAuthn = 7,

View File

@ -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;
}
}
}

View File

@ -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)

View File

@ -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:

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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)

View File

@ -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();
}
}
}

View File

@ -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>();

View File

@ -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();
}
}
}

View File

@ -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

View File

@ -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));
}
}

View File

@ -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();
}
}
}

View File

@ -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)

View File

@ -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" />

View File

@ -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

View File

@ -1,12 +0,0 @@
CREATE PROCEDURE [dbo].[U2f_DeleteByUserId]
@UserId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
DELETE
FROM
[dbo].[U2f]
WHERE
[UserId] = @UserId
END

View File

@ -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

View File

@ -1,13 +0,0 @@
CREATE PROCEDURE [dbo].[U2f_ReadByUserId]
@UserId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
*
FROM
[dbo].[U2fView]
WHERE
[UserId] = @UserId
END

View File

@ -72,13 +72,6 @@ BEGIN
WHERE
[UserId] = @Id
-- Delete U2F logins
DELETE
FROM
[dbo].[U2f]
WHERE
[UserId] = @Id
-- Delete SSO Users
DELETE
FROM

View File

@ -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);

View File

@ -1,6 +0,0 @@
CREATE VIEW [dbo].[U2fView]
AS
SELECT
*
FROM
[dbo].[U2f]