1
0
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:
Kyle Spearrin
2023-01-18 13:16:57 -05:00
committed by GitHub
parent 22201bf30a
commit 6f04298e17
8 changed files with 199 additions and 14 deletions

View File

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

View File

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