using IdentityShroud.Core.Contracts; using IdentityShroud.Core.EFCore; using IdentityShroud.Core.Helpers; using IdentityShroud.Core.Messages.Realm; using IdentityShroud.Core.Model; using IdentityShroud.Core.Security; using IdentityShroud.Core.Security.Keys; using IdentityShroud.Core.Security.Keys.Aes; using IdentityShroud.Core.Security.Keys.Rsa; using Microsoft.EntityFrameworkCore; namespace IdentityShroud.Core.Services; public class RealmService( Db db, IKeyService keyService, IDekEncryptionService dekCryptor, IClock clock) : IRealmService { public async Task FindById(Guid id, CancellationToken ct = default) { return await db.Realms .SingleOrDefaultAsync(r => r.Id == id, ct); } public async Task FindBySlug(string slug, CancellationToken ct = default) { return await db.Realms .SingleOrDefaultAsync(r => r.Slug == slug, ct); } public async Task> Create(RealmCreateRequest request, CancellationToken ct = default) { Realm realm = new() { Id = request.Id ?? Guid.CreateVersion7(), Slug = request.Slug ?? SlugHelper.GenerateSlug(request.Name), Name = request.Name, }; realm.TokenSigningKeys.Add(CreateSigningKey(realm)); realm.DataEncryptionKeys.Add(CreateDataEncryptionKey(realm)); db.Add(realm); await db.SaveChangesAsync(ct); return realm; } private RealmSigningKey CreateSigningKey(Realm realm) { var k = keyService.CreateKey(GetSigningKeyPolicy(realm)); return new RealmSigningKey { Id = RealmSigningKeyId.NewId(), KeyType = k.KeyType, Key = dekCryptor.Encrypt(k.Key.PrivateKey), PublicKeyParameters = k.Key.PublicKeyParameters, CreatedAt = clock.UtcNow(), }; } private RealmDek CreateDataEncryptionKey(Realm realm) { var k = keyService.CreateKey(GetDataKeyPolicy(realm)); return new RealmDek() { Id = DekId.NewId(), Active = true, Algorithm = k.KeyType, KeyData = dekCryptor.Encrypt(k.Key.PrivateKey), }; } /// /// Place holder for getting policies from the realm and falling back to sane defaults when no policies have been set. /// /// /// private KeyPolicy GetSigningKeyPolicy(Realm _) => new RsaKeyPolicy(); private KeyPolicy GetDataKeyPolicy(Realm _) => new AesKeyPolicy(); public async Task LoadActiveKeys(Realm realm) { await db.Entry(realm).Collection(r => r.TokenSigningKeys) .Query() .Where(k => k.RevokedAt == null) .LoadAsync(); } public async Task LoadDeks(Realm realm) { await db.Entry(realm).Collection(r => r.DataEncryptionKeys) .Query() .LoadAsync(); } }