mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 07:36:14 -05:00
Data protection for user columns at rest (#2571)
* ServerProtectedData for user entity * remove using statements * formatting * use data protection libs * no async * add data protection to ef user repo * switch to `SetApplicationName` per ASPNET docs * null checks * cleanup * value converter for EF * new line at eof * fix using * remove folder ref * restore ctor * fix lint * use global constant * UseApplicationServiceProvider for integration tests * implement constant for DatabaseFieldProtectedPrefix * Fix EF IntegrationTest * restore original values after protect and save * lint fixes * Use Constants Co-authored-by: Justin Baur <19896123+justindbaur@users.noreply.github.com>
This commit is contained in:
@ -1,8 +1,12 @@
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using AutoFixture;
|
||||
using AutoFixture.Kernel;
|
||||
using AutoFixture.Xunit2;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Test.Helpers.Factories;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Moq;
|
||||
|
||||
namespace Bit.Test.Common.AutoFixture;
|
||||
|
||||
@ -15,13 +19,34 @@ public class GlobalSettingsBuilder : ISpecimenBuilder
|
||||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
var pi = request as ParameterInfo;
|
||||
var fixture = new Fixture();
|
||||
|
||||
if (pi == null || pi.ParameterType != typeof(Bit.Core.Settings.GlobalSettings))
|
||||
if (request is not ParameterInfo pi)
|
||||
{
|
||||
return new NoSpecimen();
|
||||
}
|
||||
|
||||
return GlobalSettingsFactory.GlobalSettings;
|
||||
if (pi.ParameterType == typeof(Bit.Core.Settings.GlobalSettings))
|
||||
{
|
||||
return GlobalSettingsFactory.GlobalSettings;
|
||||
}
|
||||
|
||||
if (pi.ParameterType == typeof(IDataProtectionProvider))
|
||||
{
|
||||
var dataProtector = new Mock<IDataProtector>();
|
||||
dataProtector
|
||||
.Setup(d => d.Unprotect(It.IsAny<byte[]>()))
|
||||
.Returns<byte[]>(data => Encoding.UTF8.GetBytes(Constants.DatabaseFieldProtectedPrefix + Encoding.UTF8.GetString(data)));
|
||||
|
||||
var dataProtectionProvider = new Mock<IDataProtectionProvider>();
|
||||
dataProtectionProvider
|
||||
.Setup(x => x.CreateProtector(Constants.DatabaseFieldProtectorPurpose))
|
||||
.Returns(dataProtector.Object);
|
||||
|
||||
return dataProtectionProvider.Object;
|
||||
}
|
||||
|
||||
return new NoSpecimen();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,11 @@
|
||||
using Bit.Core.Test.Helpers.Factories;
|
||||
using System.Text;
|
||||
using Bit.Core;
|
||||
using Bit.Core.Test.Helpers.Factories;
|
||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
|
||||
namespace Bit.Infrastructure.EFIntegration.Test.Helpers;
|
||||
|
||||
@ -10,16 +15,39 @@ public static class DatabaseOptionsFactory
|
||||
|
||||
static DatabaseOptionsFactory()
|
||||
{
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton(sp =>
|
||||
{
|
||||
var dataProtector = new Mock<IDataProtector>();
|
||||
dataProtector
|
||||
.Setup(d => d.Unprotect(It.IsAny<byte[]>()))
|
||||
.Returns<byte[]>(data => Encoding.UTF8.GetBytes(Constants.DatabaseFieldProtectedPrefix + Encoding.UTF8.GetString(data)));
|
||||
|
||||
var dataProtectionProvider = new Mock<IDataProtectionProvider>();
|
||||
dataProtectionProvider
|
||||
.Setup(x => x.CreateProtector(Constants.DatabaseFieldProtectorPurpose))
|
||||
.Returns(dataProtector.Object);
|
||||
|
||||
return dataProtectionProvider.Object;
|
||||
})
|
||||
.BuildServiceProvider();
|
||||
|
||||
var globalSettings = GlobalSettingsFactory.GlobalSettings;
|
||||
if (!string.IsNullOrWhiteSpace(GlobalSettingsFactory.GlobalSettings.PostgreSql?.ConnectionString))
|
||||
{
|
||||
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
|
||||
Options.Add(new DbContextOptionsBuilder<DatabaseContext>().UseNpgsql(globalSettings.PostgreSql.ConnectionString).Options);
|
||||
Options.Add(new DbContextOptionsBuilder<DatabaseContext>()
|
||||
.UseNpgsql(globalSettings.PostgreSql.ConnectionString)
|
||||
.UseApplicationServiceProvider(services)
|
||||
.Options);
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(GlobalSettingsFactory.GlobalSettings.MySql?.ConnectionString))
|
||||
{
|
||||
var mySqlConnectionString = globalSettings.MySql.ConnectionString;
|
||||
Options.Add(new DbContextOptionsBuilder<DatabaseContext>().UseMySql(mySqlConnectionString, ServerVersion.AutoDetect(mySqlConnectionString)).Options);
|
||||
Options.Add(new DbContextOptionsBuilder<DatabaseContext>()
|
||||
.UseMySql(mySqlConnectionString, ServerVersion.AutoDetect(mySqlConnectionString))
|
||||
.UseApplicationServiceProvider(services)
|
||||
.Options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -56,10 +56,11 @@ public abstract class WebApplicationFactoryBase<T> : WebApplicationFactory<T>
|
||||
{
|
||||
var dbContextOptions = services.First(sd => sd.ServiceType == typeof(DbContextOptions<DatabaseContext>));
|
||||
services.Remove(dbContextOptions);
|
||||
services.AddScoped(_ =>
|
||||
services.AddScoped(services =>
|
||||
{
|
||||
return new DbContextOptionsBuilder<DatabaseContext>()
|
||||
.UseInMemoryDatabase(DatabaseName)
|
||||
.UseApplicationServiceProvider(services)
|
||||
.Options;
|
||||
});
|
||||
|
||||
|
Reference in New Issue
Block a user