mirror of
https://github.com/bitwarden/server.git
synced 2025-07-02 16:42:50 -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:
@ -0,0 +1,33 @@
|
||||
using Bit.Core;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Converters;
|
||||
public class DataProtectionConverter : ValueConverter<string, string>
|
||||
{
|
||||
public DataProtectionConverter(IDataProtector dataProtector) :
|
||||
base(s => Protect(dataProtector, s), s => Unprotect(dataProtector, s))
|
||||
{ }
|
||||
|
||||
private static string Protect(IDataProtector dataProtector, string value)
|
||||
{
|
||||
if (value?.StartsWith(Constants.DatabaseFieldProtectedPrefix) ?? true)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return string.Concat(
|
||||
Constants.DatabaseFieldProtectedPrefix, dataProtector.Protect(value));
|
||||
}
|
||||
|
||||
private static string Unprotect(IDataProtector dataProtector, string value)
|
||||
{
|
||||
if (!value?.StartsWith(Constants.DatabaseFieldProtectedPrefix) ?? true)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
return dataProtector.Unprotect(
|
||||
value.Substring(Constants.DatabaseFieldProtectedPrefix.Length));
|
||||
}
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Bit.Core;
|
||||
using Bit.Infrastructure.EntityFramework.Converters;
|
||||
using Bit.Infrastructure.EntityFramework.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using DP = Microsoft.AspNetCore.DataProtection;
|
||||
|
||||
namespace Bit.Infrastructure.EntityFramework.Repositories;
|
||||
|
||||
@ -113,6 +117,12 @@ public class DatabaseContext : DbContext
|
||||
eGrant.HasKey(x => x.Key);
|
||||
eGroupUser.HasKey(gu => new { gu.GroupId, gu.OrganizationUserId });
|
||||
|
||||
var dataProtector = this.GetService<DP.IDataProtectionProvider>().CreateProtector(
|
||||
Constants.DatabaseFieldProtectorPurpose);
|
||||
var dataProtectionConverter = new DataProtectionConverter(dataProtector);
|
||||
eUser.Property(c => c.Key).HasConversion(dataProtectionConverter);
|
||||
eUser.Property(c => c.MasterPassword).HasConversion(dataProtectionConverter);
|
||||
|
||||
if (Database.IsNpgsql())
|
||||
{
|
||||
// the postgres provider doesn't currently support database level non-deterministic collations.
|
||||
|
Reference in New Issue
Block a user