Still working on getting client credential flow complete, most of the request works but still working on generating the JWT.

This commit is contained in:
eelke 2026-03-16 19:15:04 +01:00
parent 1a8c63808a
commit 8782ef39c6
80 changed files with 1331 additions and 414 deletions

View file

@ -19,8 +19,16 @@ public class Client
public string? Description { get; set; }
[MaxLength(20)]
public string? SignatureAlgorithm { get; set; }
public JwtSigAlgName? SignatureAlgorithm { get; set; }
/// <summary>
/// Enables confidential flows
/// </summary>
public bool Confidential { get; set; }
/// <summary>
/// Enables the client credentials flow which required Confidential to be true too.
/// </summary>
public bool AllowClientCredentialsFlow { get; set; } = false;
public required DateTime CreatedAt { get; set; }

View file

@ -1,6 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using IdentityShroud.Core.Contracts;
using IdentityShroud.Core.Security;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
@ -14,8 +13,9 @@ public class ClientSecret
public int Id { get; set; }
public Guid ClientId { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? Expires { get; set; }
public DateTime? RevokedAt { get; set; }
public EncryptedValue? Secret { get; set; }
public required EncryptedValue Secret { get; set; }
}
public class ClientSecretConfiguration : IEntityTypeConfiguration<ClientSecret>

View file

@ -1,8 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using IdentityShroud.Core.Security;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace IdentityShroud.Core.Model;
@ -20,12 +17,17 @@ public class Realm
public string Name { get; set; } = "";
public List<Client> Clients { get; init; } = [];
public List<RealmKey> Keys { get; init; } = [];
/// <summary>
/// Note multiple keys can be in use at the same time because different clients may be configured to use
/// a different keytype depending on their clients requirements/capabilities.
/// </summary>
public List<RealmSigningKey> TokenSigningKeys { get; init; } = [];
public List<RealmDek> Deks { get; init; } = [];
public List<RealmDek> DataEncryptionKeys { get; init; } = [];
/// <summary>
/// Can be overriden per client
/// </summary>
public string DefaultSignatureAlgorithm { get; set; } = JsonWebAlgorithm.RS256;
public JwtSigAlgName DefaultSignatureAlgorithm { get; set; } = JwtSigAlgName.RS256;
}

View file

@ -1,16 +1,18 @@
using IdentityShroud.Core.Security;
using IdentityShroud.Core.Security.Keys;
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 KeyType Algorithm { get; init; }
public required EncryptedDek KeyData { get; init; }
public required Guid RealmId { get; init; }
public Guid RealmId { get; init; }
}
public class RealmDekConfiguration : IEntityTypeConfiguration<RealmDek>
@ -21,4 +23,5 @@ public class RealmDekConfiguration : IEntityTypeConfiguration<RealmDek>
b.HasKey(e => e.Id);
b.ComplexProperty(e => e.KeyData, e => e.IsRequired());
}
}
}

View file

@ -1,33 +1,34 @@
using System.ComponentModel.DataAnnotations.Schema;
using IdentityShroud.Core.Contracts;
using IdentityShroud.Core.Security;
using IdentityShroud.Core.Security.Keys;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
namespace IdentityShroud.Core.Model;
public record RealmKey
public record RealmSigningKey
{
public required Guid Id { get; init; }
public required string KeyType { get; init; }
public required RealmSigningKeyId Id { get; init; }
public required KeyType KeyType { get; init; }
public required EncryptedDek Key { get; init; }
public required DateTime CreatedAt { get; init; }
public DateTime? RevokedAt { get; set; }
/// <summary>
/// Key with highest priority will be used. While there is not really a use case for this I know some users
/// are more comfortable replacing keys by using priority then directly deactivating the old key.
/// </summary>
public int Priority { get; set; } = 10;
public Dictionary<string, string>? PublicKeyParameters { get; set; }
}
public class RealmKeyConfiguration : IEntityTypeConfiguration<RealmKey>
public class RealmKeyConfiguration : IEntityTypeConfiguration<RealmSigningKey>
{
public void Configure(EntityTypeBuilder<RealmKey> b)
public void Configure(EntityTypeBuilder<RealmSigningKey> b)
{
b.ToTable("realm_key");
b.HasKey(e => e.Id);
b.ComplexProperty(e => e.Key, e => e.IsRequired());
b.Property(e => e.PublicKeyParameters).HasColumnType("jsonb");
}
}
}

View file

@ -0,0 +1,24 @@
using System.Text.Json;
using System.Text.Json.Serialization;
namespace IdentityShroud.Core.Model;
[JsonConverter(typeof(RealmSigningKeyIdJsonConverter))]
public readonly record struct RealmSigningKeyId(Guid Id)
{
public override string ToString() => Id.ToString("N");
public static RealmSigningKeyId NewId()
{
return new(Guid.NewGuid());
}
}
public class RealmSigningKeyIdJsonConverter : JsonConverter<RealmSigningKeyId>
{
public override RealmSigningKeyId Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> new (reader.GetGuid());
public override void Write(Utf8JsonWriter writer, RealmSigningKeyId value, JsonSerializerOptions options)
=> writer.WriteStringValue(value.ToString());
}