IdentityShroud/IdentityShroud.Core/Db.cs
eelke 07393f57fc 5-improve-encrypted-storage (#6)
Added the use of DEK's for encryption of secrets. Both the KEK's and DEK's are stored in a way that you can have multiple key of which one is active. But the others are still available for decrypting. This allows for implementing key rotation.

Co-authored-by: eelke <eelke@eelkeklein.nl>
Co-authored-by: Eelke76 <31384324+Eelke76@users.noreply.github.com>
Reviewed-on: #6
2026-02-27 17:57:42 +00:00

76 lines
No EOL
2.4 KiB
C#

using IdentityShroud.Core.Model;
using IdentityShroud.Core.Security;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace IdentityShroud.Core;
public class DbConfiguration
{
public string ConnectionString { get; set; } = "";
public bool LogSensitiveData { get; set; } = false;
}
public class Db(
IOptions<DbConfiguration> configuration,
ILoggerFactory? loggerFactory)
: DbContext
{
public virtual DbSet<Client> Clients { get; set; }
public virtual DbSet<Realm> Realms { get; set; }
public virtual DbSet<RealmKey> Keys { get; set; }
public virtual DbSet<RealmDek> Deks { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var dekIdConverter = new ValueConverter<DekId, Guid>(
id => id.Id,
guid => new DekId(guid));
var kekIdConverter = new ValueConverter<KekId, Guid>(
id => id.Id,
guid => new KekId(guid));
modelBuilder.Entity<RealmDek>()
.Property(d => d.Id)
.HasConversion(dekIdConverter);
modelBuilder.Entity<RealmDek>()
.OwnsOne(d => d.KeyData, keyData =>
{
keyData.Property(k => k.KekId).HasConversion(kekIdConverter);
});
modelBuilder.Entity<RealmKey>()
.OwnsOne(k => k.Key, key =>
{
key.Property(k => k.KekId).HasConversion(kekIdConverter);
});
modelBuilder.Entity<ClientSecret>()
.OwnsOne(c => c.Secret, secret =>
{
secret.Property(s => s.DekId).HasConversion(dekIdConverter);
});
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseNpgsql("<connection string>");
optionsBuilder.UseNpgsql(
configuration.Value.ConnectionString,
o => o.MigrationsAssembly("IdentityShroud.Migrations")); // , o => o.UseNodaTime().UseVector().MigrationsAssembly("Migrations.KnowledgeBaseDB"));
optionsBuilder.UseSnakeCaseNamingConvention();
if (configuration.Value.LogSensitiveData)
optionsBuilder.EnableSensitiveDataLogging();
if (loggerFactory is { } )
{
optionsBuilder.UseLoggerFactory(loggerFactory);
}
}
}