Switch Owned value types to ComplexProperty which is better fit.
This requires fluent configuration. Also made some conversion registration context wide.
This commit is contained in:
parent
07393f57fc
commit
1a8c63808a
11 changed files with 93 additions and 54 deletions
12
IdentityShroud.Core/EFCore/Converters/DekIdConverter.cs
Normal file
12
IdentityShroud.Core/EFCore/Converters/DekIdConverter.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
using IdentityShroud.Core.Security;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace IdentityShroud.Core;
|
||||||
|
|
||||||
|
public class DekIdConverter : ValueConverter<DekId, Guid>
|
||||||
|
{
|
||||||
|
public DekIdConverter()
|
||||||
|
: base(id => id.Id, guid => new DekId(guid))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
12
IdentityShroud.Core/EFCore/Converters/KekIdConverter.cs
Normal file
12
IdentityShroud.Core/EFCore/Converters/KekIdConverter.cs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
using IdentityShroud.Core.Security;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
namespace IdentityShroud.Core;
|
||||||
|
|
||||||
|
public class KekIdConverter : ValueConverter<KekId, Guid>
|
||||||
|
{
|
||||||
|
public KekIdConverter()
|
||||||
|
: base(id => id.Id, guid => new KekId(guid))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
|
using System.Linq.Expressions;
|
||||||
using IdentityShroud.Core.Model;
|
using IdentityShroud.Core.Model;
|
||||||
using IdentityShroud.Core.Security;
|
using IdentityShroud.Core.Security;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
|
@ -23,39 +23,6 @@ public class Db(
|
||||||
public virtual DbSet<RealmKey> Keys { get; set; }
|
public virtual DbSet<RealmKey> Keys { get; set; }
|
||||||
public virtual DbSet<RealmDek> Deks { 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)
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||||
{
|
{
|
||||||
optionsBuilder.UseNpgsql("<connection string>");
|
optionsBuilder.UseNpgsql("<connection string>");
|
||||||
|
|
@ -71,6 +38,18 @@ public class Db(
|
||||||
{
|
{
|
||||||
optionsBuilder.UseLoggerFactory(loggerFactory);
|
optionsBuilder.UseLoggerFactory(loggerFactory);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
modelBuilder.ApplyConfigurationsFromAssembly(typeof(Db).Assembly);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ConfigureConventions(ModelConfigurationBuilder b)
|
||||||
|
{
|
||||||
|
base.ConfigureConventions(b);
|
||||||
|
|
||||||
|
b.Properties<DekId>().HaveConversion<DekIdConverter>();
|
||||||
|
b.Properties<KekId>().HaveConversion<KekIdConverter>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=efcore_005Cconverters/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||||
|
|
@ -2,6 +2,8 @@ using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using IdentityShroud.Core.Contracts;
|
using IdentityShroud.Core.Contracts;
|
||||||
using IdentityShroud.Core.Security;
|
using IdentityShroud.Core.Security;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
namespace IdentityShroud.Core.Model;
|
namespace IdentityShroud.Core.Model;
|
||||||
|
|
||||||
|
|
@ -13,5 +15,15 @@ public class ClientSecret
|
||||||
public Guid ClientId { get; set; }
|
public Guid ClientId { get; set; }
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
public DateTime? RevokedAt { get; set; }
|
public DateTime? RevokedAt { get; set; }
|
||||||
public required EncryptedValue Secret { get; set; }
|
public EncryptedValue? Secret { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ClientSecretConfiguration : IEntityTypeConfiguration<ClientSecret>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<ClientSecret> b)
|
||||||
|
{
|
||||||
|
b.ToTable("client_secret");
|
||||||
|
b.HasKey(e => e.Id);
|
||||||
|
b.ComplexProperty(e => e.Secret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using IdentityShroud.Core.Security;
|
using IdentityShroud.Core.Security;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
namespace IdentityShroud.Core.Model;
|
namespace IdentityShroud.Core.Model;
|
||||||
|
|
||||||
[Table("realm")]
|
[Table("realm")]
|
||||||
public class Realm
|
public class Realm
|
||||||
{
|
{
|
||||||
|
|
||||||
public Guid Id { get; set; }
|
public Guid Id { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Note this is part of the url we should encourage users to keep it short but we do not want to limit them too much
|
/// Note this is part of the url we should encourage users to keep it short but we do not want to limit them too much
|
||||||
|
|
@ -27,14 +28,4 @@ public class Realm
|
||||||
/// Can be overriden per client
|
/// Can be overriden per client
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string DefaultSignatureAlgorithm { get; set; } = JsonWebAlgorithm.RS256;
|
public string DefaultSignatureAlgorithm { get; set; } = JsonWebAlgorithm.RS256;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Table("realm_dek")]
|
|
||||||
public record RealmDek
|
|
||||||
{
|
|
||||||
public required DekId Id { get; init; }
|
|
||||||
public required bool Active { get; set; }
|
|
||||||
public required string Algorithm { get; init; }
|
|
||||||
public required EncryptedDek KeyData { get; init; }
|
|
||||||
public required Guid RealmId { get; init; }
|
|
||||||
}
|
|
||||||
24
IdentityShroud.Core/Model/RealmDek.cs
Normal file
24
IdentityShroud.Core/Model/RealmDek.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
using IdentityShroud.Core.Security;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
|
namespace IdentityShroud.Core.Model;
|
||||||
|
|
||||||
|
public record RealmDek
|
||||||
|
{
|
||||||
|
public required DekId Id { get; init; }
|
||||||
|
public required bool Active { get; set; }
|
||||||
|
public required string Algorithm { get; init; }
|
||||||
|
public required EncryptedDek KeyData { get; init; }
|
||||||
|
public required Guid RealmId { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RealmDekConfiguration : IEntityTypeConfiguration<RealmDek>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<RealmDek> b)
|
||||||
|
{
|
||||||
|
b.ToTable("realm_dek");
|
||||||
|
b.HasKey(e => e.Id);
|
||||||
|
b.ComplexProperty(e => e.KeyData, e => e.IsRequired());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,17 +2,14 @@ using System.ComponentModel.DataAnnotations.Schema;
|
||||||
using IdentityShroud.Core.Contracts;
|
using IdentityShroud.Core.Contracts;
|
||||||
using IdentityShroud.Core.Security;
|
using IdentityShroud.Core.Security;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||||
|
|
||||||
namespace IdentityShroud.Core.Model;
|
namespace IdentityShroud.Core.Model;
|
||||||
|
|
||||||
|
|
||||||
[Table("realm_key")]
|
|
||||||
public record RealmKey
|
public record RealmKey
|
||||||
{
|
{
|
||||||
public required Guid Id { get; init; }
|
public required Guid Id { get; init; }
|
||||||
public required string KeyType { get; init; }
|
public required string KeyType { get; init; }
|
||||||
|
|
||||||
|
|
||||||
public required EncryptedDek Key { get; init; }
|
public required EncryptedDek Key { get; init; }
|
||||||
public required DateTime CreatedAt { get; init; }
|
public required DateTime CreatedAt { get; init; }
|
||||||
public DateTime? RevokedAt { get; set; }
|
public DateTime? RevokedAt { get; set; }
|
||||||
|
|
@ -22,6 +19,15 @@ public record RealmKey
|
||||||
/// are more comfortable replacing keys by using priority then directly deactivating the old key.
|
/// are more comfortable replacing keys by using priority then directly deactivating the old key.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int Priority { get; set; } = 10;
|
public int Priority { get; set; } = 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RealmKeyConfiguration : IEntityTypeConfiguration<RealmKey>
|
||||||
|
{
|
||||||
|
public void Configure(EntityTypeBuilder<RealmKey> b)
|
||||||
|
{
|
||||||
|
b.ToTable("realm_key");
|
||||||
|
b.HasKey(e => e.Id);
|
||||||
|
|
||||||
|
b.ComplexProperty(e => e.Key, e => e.IsRequired());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2,5 +2,4 @@ using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace IdentityShroud.Core.Security;
|
namespace IdentityShroud.Core.Security;
|
||||||
|
|
||||||
[Owned]
|
|
||||||
public record EncryptedDek(KekId KekId, byte[] Value);
|
public record EncryptedDek(KekId KekId, byte[] Value);
|
||||||
|
|
@ -2,7 +2,6 @@ using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace IdentityShroud.Core.Security;
|
namespace IdentityShroud.Core.Security;
|
||||||
|
|
||||||
[Owned]
|
|
||||||
public record EncryptedValue(DekId DekId, byte[] Value);
|
public record EncryptedValue(DekId DekId, byte[] Value);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@
|
||||||
|
|
||||||
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/DotNetCliExePath/@EntryValue">/home/eelke/.dotnet/dotnet</s:String>
|
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/DotNetCliExePath/@EntryValue">/home/eelke/.dotnet/dotnet</s:String>
|
||||||
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue">/home/eelke/.dotnet/sdk/10.0.102/MSBuild.dll</s:String>
|
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue">/home/eelke/.dotnet/sdk/10.0.102/MSBuild.dll</s:String>
|
||||||
|
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=c1fa4888_002D88fd_002D4859_002D8288_002D37c12fb8ef13/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||||
|
<Solution />
|
||||||
|
</SessionState></s:String>
|
||||||
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=ead9ca22_002Dfc70_002D4ddf_002Db4c7_002D534498815537/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=ead9ca22_002Dfc70_002D4ddf_002Db4c7_002D534498815537/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from Solution" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||||
<Solution />
|
<Solution />
|
||||||
</SessionState></s:String>
|
</SessionState></s:String>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue