diff --git a/Directory.Packages.props b/Directory.Packages.props index ea3acabe..581c71af 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -145,6 +145,7 @@ + diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj index 04c251da..27545421 100644 --- a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj +++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/OpenIddict.Sandbox.AspNetCore.Client.csproj @@ -12,6 +12,7 @@ + diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Program.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Program.cs index 1891abf6..0620da17 100644 --- a/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Program.cs +++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Client/Program.cs @@ -14,6 +14,12 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddDbContext(options => { options.UseSqlite($"Filename={Path.Combine(Path.GetTempPath(), "openiddict-sandbox-aspnetcore-client.sqlite3")}"); + + // Developers who prefer using Microsoft SQL Server instead of SQLite can remove + // the previous line and configure OpenIddict to use the specified database: + // + // options.UseSqlServer($"Server=(localdb)\\MSSQLLocalDB;Database=openiddict-sandbox-aspnetcore-client;Trusted_Connection=True"); + options.UseOpenIddict(); }); diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj index 0fa209a0..5ca4a091 100644 --- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj +++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/OpenIddict.Sandbox.AspNetCore.Server.csproj @@ -15,6 +15,7 @@ + diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Program.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Program.cs index 856a71f1..113beae2 100644 --- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Program.cs +++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Program.cs @@ -20,6 +20,12 @@ builder.Services.AddMvc(); builder.Services.AddDbContext(options => { options.UseSqlite($"Filename={Path.Combine(Path.GetTempPath(), "openiddict-sandbox-aspnetcore-server.sqlite3")}"); + + // Developers who prefer using Microsoft SQL Server instead of SQLite can remove + // the previous line and configure OpenIddict to use the specified database: + // + // options.UseSqlServer($"Server=(localdb)\\MSSQLLocalDB;Database=openiddict-sandbox-aspnetcore-server;Trusted_Connection=True"); + options.UseOpenIddict(); }); diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictSerializer.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictSerializer.cs index ca7e8302..f5b7ab1b 100644 --- a/src/OpenIddict.Abstractions/Primitives/OpenIddictSerializer.cs +++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictSerializer.cs @@ -13,6 +13,8 @@ namespace OpenIddict.Abstractions; /// [EditorBrowsable(EditorBrowsableState.Never)] [JsonSerializable(typeof(bool))] +[JsonSerializable(typeof(IDictionary))] +[JsonSerializable(typeof(IDictionary))] [JsonSerializable(typeof(JsonArray))] [JsonSerializable(typeof(JsonElement))] [JsonSerializable(typeof(JsonNode))] diff --git a/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkApplication.cs b/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkApplication.cs index 1b104811..cfa52908 100644 --- a/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkApplication.cs +++ b/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkApplication.cs @@ -27,116 +27,112 @@ public class OpenIddictEntityFrameworkApplication where TToken : class { /// - /// Gets or sets the application type associated with the current application. + /// Gets or sets the application type of the application. /// public virtual string? ApplicationType { get; set; } /// - /// Gets the list of the authorizations associated with this application. + /// Gets the list of the authorizations associated with the application. /// public virtual ICollection Authorizations { get; } = new HashSet(); /// - /// Gets or sets the client identifier associated with the current application. + /// Gets or sets the client identifier of the application. /// public virtual string? ClientId { get; set; } /// - /// Gets or sets the client secret associated with the current application. - /// Note: depending on the application manager used to create this instance, - /// this property may be hashed or encrypted for security reasons. + /// Gets or sets the client secret of the application. /// /// + /// + /// Note: depending on the application manager used to create this instance, + /// this property may be hashed or encrypted for security reasons. + /// + /// /// Note: client authentication based on shared secrets is not recommended and should /// only be used for backward compatibility with legacy applications that only support /// client secrets. When possible, consider using public/private key pairs or TLS client /// certificates instead, as these client authentication methods are significantly safer. + /// /// public virtual string? ClientSecret { get; set; } /// - /// Gets or sets the client type associated with the current application. + /// Gets or sets the client type of the application. /// public virtual string? ClientType { get; set; } /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the application. /// public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the consent type associated with the current application. + /// Gets or sets the consent type of the application. /// public virtual string? ConsentType { get; set; } /// - /// Gets or sets the display name associated with the current application. + /// Gets or sets the display name of the application. /// public virtual string? DisplayName { get; set; } /// - /// Gets or sets the localized display names - /// associated with the current application, - /// serialized as a JSON object. + /// Gets or sets the localized display names of the application, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? DisplayNames { get; set; } /// - /// Gets or sets the unique identifier associated with the current application. + /// Gets or sets the unique identifier of the application. /// public virtual TKey? Id { get; set; } /// - /// Gets or sets the JSON Web Key Set associated with - /// the application, serialized as a JSON object. + /// Gets or sets the JSON Web Key Set of the application, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? JsonWebKeySet { get; set; } /// - /// Gets or sets the permissions associated with the - /// current application, serialized as a JSON array. + /// Gets or sets the permissions of the application, serialized as a JSON array. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Permissions { get; set; } /// - /// Gets or sets the post-logout redirect URIs associated with - /// the current application, serialized as a JSON array. + /// Gets or sets the post-logout redirect URIs of the application, serialized as a JSON array. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? PostLogoutRedirectUris { get; set; } /// - /// Gets or sets the additional properties serialized as a JSON object, - /// or if no bag was associated with the current application. + /// Gets or sets the additional properties of the application, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Properties { get; set; } /// - /// Gets or sets the redirect URIs associated with the - /// current application, serialized as a JSON array. + /// Gets or sets the redirect URIs of the application, serialized as a JSON array. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? RedirectUris { get; set; } /// - /// Gets or sets the requirements associated with the - /// current application, serialized as a JSON array. + /// Gets or sets the requirements of the application, serialized as a JSON array. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Requirements { get; set; } /// - /// Gets or sets the settings serialized as a JSON object. + /// Gets or sets the settings of the application, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Settings { get; set; } /// - /// Gets the list of the tokens associated with this application. + /// Gets the list of the tokens associated with the application. /// public virtual ICollection Tokens { get; } = new HashSet(); } diff --git a/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkAuthorization.cs b/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkAuthorization.cs index b6b74bcd..382248ae 100644 --- a/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkAuthorization.cs +++ b/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkAuthorization.cs @@ -27,56 +27,54 @@ public class OpenIddictEntityFrameworkAuthorization where TToken : class { /// - /// Gets or sets the application associated with the current authorization. + /// Gets or sets the application associated with the authorization. /// public virtual TApplication? Application { get; set; } /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the authorization. /// public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the UTC creation date of the current authorization. + /// Gets or sets the UTC creation date of the authorization. /// public virtual DateTime? CreationDate { get; set; } /// - /// Gets or sets the unique identifier associated with the current authorization. + /// Gets or sets the unique identifier of the authorization. /// public virtual TKey? Id { get; set; } /// - /// Gets or sets the additional properties serialized as a JSON object, - /// or if no bag was associated with the current authorization. + /// Gets or sets the additional properties of the authorization, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Properties { get; set; } /// - /// Gets or sets the scopes associated with the current - /// authorization, serialized as a JSON array. + /// Gets or sets the scopes of the authorization, serialized as a JSON array. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Scopes { get; set; } /// - /// Gets or sets the status of the current authorization. + /// Gets or sets the status of the authorization. /// public virtual string? Status { get; set; } /// - /// Gets or sets the subject associated with the current authorization. + /// Gets or sets the subject of the authorization. /// public virtual string? Subject { get; set; } /// - /// Gets the list of tokens associated with the current authorization. + /// Gets the list of tokens associated with the authorization. /// public virtual ICollection Tokens { get; } = new HashSet(); /// - /// Gets or sets the type of the current authorization. + /// Gets or sets the type of the authorization. /// public virtual string? Type { get; set; } } diff --git a/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkResource.cs b/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkResource.cs index d0989df0..c67e750c 100644 --- a/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkResource.cs +++ b/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkResource.cs @@ -24,48 +24,44 @@ public class OpenIddictEntityFrameworkResource : OpenIddictEntityFrameworkResour public class OpenIddictEntityFrameworkResource where TKey : notnull, IEquatable { /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the resource. /// public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the public description associated with the current resource. + /// Gets or sets the public description of the resource. /// public virtual string? Description { get; set; } /// - /// Gets or sets the localized public descriptions associated - /// with the current resource, serialized as a JSON object. + /// Gets or sets the localized public descriptions of the resource, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Descriptions { get; set; } /// - /// Gets or sets the display name associated with the current resource. + /// Gets or sets the display name of the resource. /// public virtual string? DisplayName { get; set; } /// - /// Gets or sets the localized display names - /// associated with the current application, - /// serialized as a JSON object. + /// Gets or sets the localized display names of the resource, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? DisplayNames { get; set; } /// - /// Gets or sets the unique identifier associated with the current resource. + /// Gets or sets the unique identifier of the resource. /// public virtual TKey? Id { get; set; } /// - /// Gets or sets the unique name associated with the current resource. + /// Gets or sets the unique name of the resource. /// public virtual string? Name { get; set; } /// - /// Gets or sets the additional properties serialized as a JSON object, - /// or if no bag was associated with the current resource. + /// Gets or sets the additional properties of the resource, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Properties { get; set; } diff --git a/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkScope.cs b/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkScope.cs index 14b09fff..183304b6 100644 --- a/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkScope.cs +++ b/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkScope.cs @@ -24,55 +24,50 @@ public class OpenIddictEntityFrameworkScope : OpenIddictEntityFrameworkScope where TKey : notnull, IEquatable { /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the scope. /// public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the public description associated with the current scope. + /// Gets or sets the public description of the scope. /// public virtual string? Description { get; set; } /// - /// Gets or sets the localized public descriptions associated - /// with the current scope, serialized as a JSON object. + /// Gets or sets the localized public descriptions of the scope, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Descriptions { get; set; } /// - /// Gets or sets the display name associated with the current scope. + /// Gets or sets the display name of the scope. /// public virtual string? DisplayName { get; set; } /// - /// Gets or sets the localized display names - /// associated with the current application, - /// serialized as a JSON object. + /// Gets or sets the localized display names of the scope, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? DisplayNames { get; set; } /// - /// Gets or sets the unique identifier associated with the current scope. + /// Gets or sets the unique identifier of the scope. /// public virtual TKey? Id { get; set; } /// - /// Gets or sets the unique name associated with the current scope. + /// Gets or sets the unique name of the scope. /// public virtual string? Name { get; set; } /// - /// Gets or sets the additional properties serialized as a JSON object, - /// or if no bag was associated with the current scope. + /// Gets or sets the additional properties of the scope, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Properties { get; set; } /// - /// Gets or sets the resources associated with the - /// current scope, serialized as a JSON array. + /// Gets or sets the resources of the scope, serialized as a JSON array. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Resources { get; set; } diff --git a/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkToken.cs b/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkToken.cs index 087a454d..9aa210ca 100644 --- a/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkToken.cs +++ b/src/OpenIddict.EntityFramework.Models/OpenIddictEntityFrameworkToken.cs @@ -27,74 +27,76 @@ public class OpenIddictEntityFrameworkToken where TAuthorization : class { /// - /// Gets or sets the application associated with the current token. + /// Gets or sets the application associated with the token. /// public virtual TApplication? Application { get; set; } /// - /// Gets or sets the authorization associated with the current token. + /// Gets or sets the authorization associated with the token. /// public virtual TAuthorization? Authorization { get; set; } /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the token. /// public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the UTC creation date of the current token. + /// Gets or sets the UTC creation date of the token. /// public virtual DateTime? CreationDate { get; set; } /// - /// Gets or sets the UTC expiration date of the current token. + /// Gets or sets the UTC expiration date of the token. /// public virtual DateTime? ExpirationDate { get; set; } /// - /// Gets or sets the unique identifier associated with the current token. + /// Gets or sets the unique identifier of the token. /// public virtual TKey? Id { get; set; } /// - /// Gets or sets the payload of the current token, if applicable. - /// Note: this property is only used for reference tokens - /// and may be encrypted for security reasons. + /// Gets or sets the payload of the token. /// + /// + /// Note: this property is only used for reference tokens + /// and may be hashed or encrypted for security reasons. + /// public virtual string? Payload { get; set; } /// - /// Gets or sets the additional properties serialized as a JSON object, - /// or if no bag was associated with the current token. + /// Gets or sets the additional properties of the token, serialized as a JSON object. /// [StringSyntax(StringSyntaxAttribute.Json)] public virtual string? Properties { get; set; } /// - /// Gets or sets the UTC redemption date of the current token. + /// Gets or sets the UTC redemption date of the token. /// public virtual DateTime? RedemptionDate { get; set; } /// - /// Gets or sets the reference identifier associated - /// with the current token, if applicable. + /// Gets or sets the reference identifier associated with the token. + /// + /// /// Note: this property is only used for reference tokens /// and may be hashed or encrypted for security reasons. - /// + /// public virtual string? ReferenceId { get; set; } /// - /// Gets or sets the status of the current token. + /// Gets or sets the status of the token. /// public virtual string? Status { get; set; } /// - /// Gets or sets the subject associated with the current token. + /// Gets or sets the subject associated with the token. /// public virtual string? Subject { get; set; } /// - /// Gets or sets the type of the current token. + /// Gets or sets the type of the token. /// public virtual string? Type { get; set; } } diff --git a/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkApplicationConfiguration.cs b/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkApplicationConfiguration.cs index 0edc45c6..8f8acd63 100644 --- a/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkApplicationConfiguration.cs +++ b/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkApplicationConfiguration.cs @@ -5,8 +5,6 @@ */ using System.ComponentModel; -using System.ComponentModel.DataAnnotations.Schema; -using System.Data.Entity.Infrastructure.Annotations; using System.Data.Entity.ModelConfiguration; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; @@ -38,17 +36,22 @@ public sealed class OpenIddictEntityFrameworkApplicationConfiguration< // Entity Framework would throw an exception due to the TKey generic parameter // being non-nullable when using value types like short, int, long or Guid. - HasKey(static application => application.Id); + HasMany(static application => application.Authorizations) + .WithOptional(static authorization => authorization.Application!) + .Map(static association => + { + association.MapKey(nameof(OpenIddictEntityFrameworkAuthorization.Application) + + nameof(OpenIddictEntityFrameworkApplication.Id)); + }); Property(static application => application.ApplicationType) .HasMaxLength(50); Property(static application => application.ClientId) - .HasMaxLength(100) - .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute - { - IsUnique = true - })); + .HasMaxLength(100); + + HasIndex(static application => application.ClientId) + .IsUnique(); Property(static application => application.ClientType) .HasMaxLength(50); @@ -60,6 +63,8 @@ public sealed class OpenIddictEntityFrameworkApplicationConfiguration< Property(static application => application.ConsentType) .HasMaxLength(50); + HasKey(static application => application.Id); + if (typeof(TKey) == typeof(string)) { var parameter = Expression.Parameter(typeof(TApplication), "application"); @@ -70,14 +75,6 @@ public sealed class OpenIddictEntityFrameworkApplicationConfiguration< Property(lambda).HasMaxLength(100); } - HasMany(static application => application.Authorizations) - .WithOptional(static authorization => authorization.Application!) - .Map(static association => - { - association.MapKey(nameof(OpenIddictEntityFrameworkAuthorization.Application) + - nameof(OpenIddictEntityFrameworkApplication.Id)); - }); - HasMany(static application => application.Tokens) .WithOptional(static token => token.Application!) .Map(static association => diff --git a/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkAuthorizationConfiguration.cs b/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkAuthorizationConfiguration.cs index 2daf0bae..fcdb5cb9 100644 --- a/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkAuthorizationConfiguration.cs +++ b/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkAuthorizationConfiguration.cs @@ -36,12 +36,12 @@ public sealed class OpenIddictEntityFrameworkAuthorizationConfiguration< // Entity Framework would throw an exception due to the TKey generic parameter // being non-nullable when using value types like short, int, long or Guid. - HasKey(static authorization => authorization.Id); - Property(static authorization => authorization.ConcurrencyToken) .HasMaxLength(50) .IsConcurrencyToken(); + HasKey(static authorization => authorization.Id); + if (typeof(TKey) == typeof(string)) { var parameter = Expression.Parameter(typeof(TAuthorization), "authorization"); @@ -58,15 +58,15 @@ public sealed class OpenIddictEntityFrameworkAuthorizationConfiguration< Property(static authorization => authorization.Subject) .HasMaxLength(400); - Property(static authorization => authorization.Type) - .HasMaxLength(50); - HasMany(static authorization => authorization.Tokens) .WithOptional(static token => token.Authorization!) .Map(static association => association.MapKey(nameof(OpenIddictEntityFrameworkToken.Authorization) + nameof(OpenIddictEntityFrameworkAuthorization.Id))) .WillCascadeOnDelete(); + Property(static authorization => authorization.Type) + .HasMaxLength(50); + ToTable("OpenIddictAuthorizations"); } } diff --git a/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkResourceConfiguration.cs b/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkResourceConfiguration.cs index 52c92596..14c7c5fc 100644 --- a/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkResourceConfiguration.cs +++ b/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkResourceConfiguration.cs @@ -5,8 +5,6 @@ */ using System.ComponentModel; -using System.ComponentModel.DataAnnotations.Schema; -using System.Data.Entity.Infrastructure.Annotations; using System.Data.Entity.ModelConfiguration; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; @@ -32,12 +30,12 @@ public sealed class OpenIddictEntityFrameworkResourceConfiguration< // Entity Framework would throw an exception due to the TKey generic parameter // being non-nullable when using value types like short, int, long or Guid. - HasKey(static resource => resource.Id); - Property(static resource => resource.ConcurrencyToken) .HasMaxLength(50) .IsConcurrencyToken(); + HasKey(static resource => resource.Id); + if (typeof(TKey) == typeof(string)) { var parameter = Expression.Parameter(typeof(TResource), "resource"); @@ -49,11 +47,10 @@ public sealed class OpenIddictEntityFrameworkResourceConfiguration< } Property(static resource => resource.Name) - .HasMaxLength(200) - .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute - { - IsUnique = true - })); + .HasMaxLength(200); + + HasIndex(static resource => resource.Name) + .IsUnique(); ToTable("OpenIddictResources"); } diff --git a/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkScopeConfiguration.cs b/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkScopeConfiguration.cs index 36093621..67a47459 100644 --- a/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkScopeConfiguration.cs +++ b/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkScopeConfiguration.cs @@ -5,8 +5,6 @@ */ using System.ComponentModel; -using System.ComponentModel.DataAnnotations.Schema; -using System.Data.Entity.Infrastructure.Annotations; using System.Data.Entity.ModelConfiguration; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; @@ -32,12 +30,12 @@ public sealed class OpenIddictEntityFrameworkScopeConfiguration< // Entity Framework would throw an exception due to the TKey generic parameter // being non-nullable when using value types like short, int, long or Guid. - HasKey(static scope => scope.Id); - Property(static scope => scope.ConcurrencyToken) .HasMaxLength(50) .IsConcurrencyToken(); + HasKey(static scope => scope.Id); + if (typeof(TKey) == typeof(string)) { var parameter = Expression.Parameter(typeof(TScope), "scope"); @@ -49,11 +47,10 @@ public sealed class OpenIddictEntityFrameworkScopeConfiguration< } Property(static scope => scope.Name) - .HasMaxLength(200) - .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute - { - IsUnique = true - })); + .HasMaxLength(200); + + HasIndex(static scope => scope.Name) + .IsUnique(); ToTable("OpenIddictScopes"); } diff --git a/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkTokenConfiguration.cs b/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkTokenConfiguration.cs index 93ec7b0c..d2b0d735 100644 --- a/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkTokenConfiguration.cs +++ b/src/OpenIddict.EntityFramework/Configurations/OpenIddictEntityFrameworkTokenConfiguration.cs @@ -5,8 +5,6 @@ */ using System.ComponentModel; -using System.ComponentModel.DataAnnotations.Schema; -using System.Data.Entity.Infrastructure.Annotations; using System.Data.Entity.ModelConfiguration; using System.Diagnostics.CodeAnalysis; using System.Linq.Expressions; @@ -38,12 +36,12 @@ public sealed class OpenIddictEntityFrameworkTokenConfiguration< // Entity Framework would throw an exception due to the TKey generic parameter // being non-nullable when using value types like short, int, long or Guid. - HasKey(static token => token.Id); - Property(static token => token.ConcurrencyToken) .HasMaxLength(50) .IsConcurrencyToken(); + HasKey(static token => token.Id); + if (typeof(TKey) == typeof(string)) { var parameter = Expression.Parameter(typeof(TToken), "token"); @@ -54,12 +52,13 @@ public sealed class OpenIddictEntityFrameworkTokenConfiguration< Property(lambda).HasMaxLength(100); } + Property(static token => token.ReferenceId) + .HasMaxLength(100); + // Warning: the index on the ReferenceId property MUST NOT be declared as // a unique index, as Entity Framework 6.x doesn't support creating indexes // with null-friendly WHERE conditions, unlike Entity Framework Core. - Property(static token => token.ReferenceId) - .HasMaxLength(100) - .HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute())); + HasIndex(static token => token.ReferenceId); Property(static token => token.Status) .HasMaxLength(50); diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs index 3ae99726..87716235 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs @@ -309,12 +309,7 @@ public class OpenIddictEntityFrameworkAuthorizationStore< { ArgumentNullException.ThrowIfNull(authorization); - if (authorization.CreationDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(authorization.CreationDate.Value, DateTimeKind.Utc)); + return new(authorization.CreationDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs index 40136706..b8c83f39 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs @@ -353,12 +353,7 @@ public class OpenIddictEntityFrameworkTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.CreationDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(token.CreationDate.Value, DateTimeKind.Utc)); + return new(token.CreationDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// @@ -366,12 +361,7 @@ public class OpenIddictEntityFrameworkTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.ExpirationDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(token.ExpirationDate.Value, DateTimeKind.Utc)); + return new(token.ExpirationDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// @@ -427,12 +417,7 @@ public class OpenIddictEntityFrameworkTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.RedemptionDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(token.RedemptionDate.Value, DateTimeKind.Utc)); + return new(token.RedemptionDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// diff --git a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddict.EntityFrameworkCore.Models.csproj b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddict.EntityFrameworkCore.Models.csproj index 24bc9f22..1400a04d 100644 --- a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddict.EntityFrameworkCore.Models.csproj +++ b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddict.EntityFrameworkCore.Models.csproj @@ -10,4 +10,8 @@ $(PackageTags);entityframeworkcore;models + + + + diff --git a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreApplication.cs b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreApplication.cs index eb7968b6..5c436636 100644 --- a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreApplication.cs +++ b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreApplication.cs @@ -5,7 +5,8 @@ */ using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; +using System.Text.Json; +using Microsoft.IdentityModel.Tokens; namespace OpenIddict.EntityFrameworkCore.Models; @@ -21,9 +22,7 @@ public class OpenIddictEntityFrameworkCoreApplication : OpenIddictEntityFramewor /// Represents an OpenIddict application. /// public class OpenIddictEntityFrameworkCoreApplication : OpenIddictEntityFrameworkCoreApplication, OpenIddictEntityFrameworkCoreToken> - where TKey : notnull, IEquatable -{ -} + where TKey : notnull, IEquatable; /// /// Represents an OpenIddict application. @@ -35,116 +34,104 @@ public class OpenIddictEntityFrameworkCoreApplication - /// Gets or sets the application type associated with the current application. + /// Gets or sets the application type of the application. /// public virtual string? ApplicationType { get; set; } /// - /// Gets the list of the authorizations associated with this application. + /// Gets the list of the authorizations associated with the application. /// public virtual ICollection Authorizations { get; } = new HashSet(); /// - /// Gets or sets the client identifier associated with the current application. + /// Gets or sets the client identifier of the application. /// public virtual string? ClientId { get; set; } /// - /// Gets or sets the client secret associated with the current application. - /// Note: depending on the application manager used to create this instance, - /// this property may be hashed or encrypted for security reasons. + /// Gets or sets the client secret of the application. /// /// + /// + /// Note: depending on the application manager used to create this instance, + /// this property may be hashed or encrypted for security reasons. + /// + /// /// Note: client authentication based on shared secrets is not recommended and should /// only be used for backward compatibility with legacy applications that only support /// client secrets. When possible, consider using public/private key pairs or TLS client /// certificates instead, as these client authentication methods are significantly safer. + /// /// public virtual string? ClientSecret { get; set; } /// - /// Gets or sets the client type associated with the current application. + /// Gets or sets the client type of the application. /// public virtual string? ClientType { get; set; } /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the application. /// public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the consent type associated with the current application. + /// Gets or sets the consent type of the application. /// public virtual string? ConsentType { get; set; } /// - /// Gets or sets the display name associated with the current application. + /// Gets or sets the display name of the application. /// public virtual string? DisplayName { get; set; } /// - /// Gets or sets the localized display names - /// associated with the current application, - /// serialized as a JSON object. + /// Gets or sets the localized display names of the application. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? DisplayNames { get; set; } + public virtual IDictionary? DisplayNames { get; set; } /// - /// Gets or sets the unique identifier associated with the current application. + /// Gets or sets the unique identifier of the application. /// public virtual TKey? Id { get; set; } /// - /// Gets or sets the JSON Web Key Set associated with - /// the application, serialized as a JSON object. + /// Gets or sets the JSON Web Key Set of the application. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? JsonWebKeySet { get; set; } + public virtual JsonWebKeySet? JsonWebKeySet { get; set; } /// - /// Gets or sets the permissions associated with the - /// current application, serialized as a JSON array. + /// Gets or sets the permissions of the application. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Permissions { get; set; } + public virtual string[]? Permissions { get; set; } /// - /// Gets or sets the post-logout redirect URIs associated with - /// the current application, serialized as a JSON array. + /// Gets or sets the post-logout redirect URIs of the application. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? PostLogoutRedirectUris { get; set; } + public virtual string[]? PostLogoutRedirectUris { get; set; } /// - /// Gets or sets the additional properties serialized as a JSON object, - /// or if no bag was associated with the current application. + /// Gets or sets the additional properties of the application. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Properties { get; set; } + public virtual IDictionary? Properties { get; set; } /// - /// Gets or sets the redirect URIs associated with the - /// current application, serialized as a JSON array. + /// Gets or sets the redirect URIs of the application. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? RedirectUris { get; set; } + public virtual string[]? RedirectUris { get; set; } /// - /// Gets or sets the requirements associated with the - /// current application, serialized as a JSON array. + /// Gets or sets the requirements of the application. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Requirements { get; set; } + public virtual string[]? Requirements { get; set; } /// - /// Gets or sets the settings serialized as a JSON object. + /// Gets or sets the settings of the application. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Settings { get; set; } + public virtual IDictionary? Settings { get; set; } /// - /// Gets the list of the tokens associated with this application. + /// Gets the list of the tokens associated with the application. /// public virtual ICollection Tokens { get; } = new HashSet(); } diff --git a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreAuthorization.cs b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreAuthorization.cs index ee5477a8..f6d883b9 100644 --- a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreAuthorization.cs +++ b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreAuthorization.cs @@ -5,7 +5,7 @@ */ using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; +using System.Text.Json; namespace OpenIddict.EntityFrameworkCore.Models; @@ -21,9 +21,7 @@ public class OpenIddictEntityFrameworkCoreAuthorization : OpenIddictEntityFramew /// Represents an OpenIddict authorization. /// public class OpenIddictEntityFrameworkCoreAuthorization : OpenIddictEntityFrameworkCoreAuthorization, OpenIddictEntityFrameworkCoreToken> - where TKey : notnull, IEquatable -{ -} + where TKey : notnull, IEquatable; /// /// Represents an OpenIddict authorization. @@ -35,55 +33,52 @@ public class OpenIddictEntityFrameworkCoreAuthorization - /// Gets or sets the application associated with the current authorization. + /// Gets or sets the application of the authorization. /// public virtual TApplication? Application { get; set; } /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the authorization. /// public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the UTC creation date of the current authorization. + /// Gets or sets the UTC creation date of the authorization. /// public virtual DateTime? CreationDate { get; set; } /// - /// Gets or sets the unique identifier associated with the current authorization. + /// Gets or sets the unique identifier of the authorization. /// public virtual TKey? Id { get; set; } /// - /// Gets or sets the additional properties serialized as a JSON object, - /// or if no bag was associated with the current authorization. + /// Gets or sets the additional properties of the authorization. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Properties { get; set; } + public virtual IDictionary? Properties { get; set; } /// - /// Gets or sets the scopes associated with the current - /// authorization, serialized as a JSON array. + /// Gets or sets the scopes of the authorization. /// - public virtual string? Scopes { get; set; } + public virtual string[]? Scopes { get; set; } /// - /// Gets or sets the status of the current authorization. + /// Gets or sets the status of the authorization. /// public virtual string? Status { get; set; } /// - /// Gets or sets the subject associated with the current authorization. + /// Gets or sets the subject of the authorization. /// public virtual string? Subject { get; set; } /// - /// Gets the list of tokens associated with the current authorization. + /// Gets the list of tokens associated with the authorization. /// public virtual ICollection Tokens { get; } = new HashSet(); /// - /// Gets or sets the type of the current authorization. + /// Gets or sets the type of the authorization. /// public virtual string? Type { get; set; } } diff --git a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreResource.cs b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreResource.cs index 2b7603a4..9a0b4acb 100644 --- a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreResource.cs +++ b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreResource.cs @@ -5,7 +5,7 @@ */ using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; +using System.Text.Json; namespace OpenIddict.EntityFrameworkCore.Models; @@ -24,49 +24,42 @@ public class OpenIddictEntityFrameworkCoreResource : OpenIddictEntityFrameworkCo public class OpenIddictEntityFrameworkCoreResource where TKey : notnull, IEquatable { /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the resource. /// public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the public description associated with the current resource. + /// Gets or sets the public description of the resource. /// public virtual string? Description { get; set; } /// - /// Gets or sets the localized public descriptions associated - /// with the current resource, serialized as a JSON object. + /// Gets or sets the localized public descriptions of the resource. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Descriptions { get; set; } + public virtual IDictionary? Descriptions { get; set; } /// - /// Gets or sets the display name associated with the current resource. + /// Gets or sets the display name of the resource. /// public virtual string? DisplayName { get; set; } /// - /// Gets or sets the localized display names - /// associated with the current application, - /// serialized as a JSON object. + /// Gets or sets the localized display names of the resource. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? DisplayNames { get; set; } + public virtual IDictionary? DisplayNames { get; set; } /// - /// Gets or sets the unique identifier associated with the current resource. + /// Gets or sets the unique identifier of the resource. /// public virtual TKey? Id { get; set; } /// - /// Gets or sets the unique name associated with the current resource. + /// Gets or sets the unique name of the resource. /// public virtual string? Name { get; set; } /// - /// Gets or sets the additional properties serialized as a JSON object, - /// or if no bag was associated with the current resource. + /// Gets or sets the additional properties of the resource. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Properties { get; set; } + public virtual IDictionary? Properties { get; set; } } diff --git a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreScope.cs b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreScope.cs index cbb035c3..1e1a3073 100644 --- a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreScope.cs +++ b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreScope.cs @@ -5,7 +5,7 @@ */ using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; +using System.Text.Json; namespace OpenIddict.EntityFrameworkCore.Models; @@ -24,56 +24,47 @@ public class OpenIddictEntityFrameworkCoreScope : OpenIddictEntityFrameworkCoreS public class OpenIddictEntityFrameworkCoreScope where TKey : notnull, IEquatable { /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the scope. /// public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the public description associated with the current scope. + /// Gets or sets the public description of the scope. /// public virtual string? Description { get; set; } /// - /// Gets or sets the localized public descriptions associated - /// with the current scope, serialized as a JSON object. + /// Gets or sets the localized public descriptions of the scope. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Descriptions { get; set; } + public virtual IDictionary? Descriptions { get; set; } /// - /// Gets or sets the display name associated with the current scope. + /// Gets or sets the display name of the scope. /// public virtual string? DisplayName { get; set; } /// - /// Gets or sets the localized display names - /// associated with the current application, - /// serialized as a JSON object. + /// Gets or sets the localized display names of the scope. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? DisplayNames { get; set; } + public virtual IDictionary? DisplayNames { get; set; } /// - /// Gets or sets the unique identifier associated with the current scope. + /// Gets or sets the unique identifier of the scope. /// public virtual TKey? Id { get; set; } /// - /// Gets or sets the unique name associated with the current scope. + /// Gets or sets the unique name of the scope. /// public virtual string? Name { get; set; } /// - /// Gets or sets the additional properties serialized as a JSON object, - /// or if no bag was associated with the current scope. + /// Gets or sets the additional properties of the scope. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Properties { get; set; } + public virtual IDictionary? Properties { get; set; } /// - /// Gets or sets the resources associated with the - /// current scope, serialized as a JSON array. + /// Gets or sets the resources of the scope. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Resources { get; set; } + public virtual string[]? Resources { get; set; } } diff --git a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreToken.cs b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreToken.cs index 1650359c..56b52235 100644 --- a/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreToken.cs +++ b/src/OpenIddict.EntityFrameworkCore.Models/OpenIddictEntityFrameworkCoreToken.cs @@ -5,7 +5,7 @@ */ using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; +using System.Text.Json; namespace OpenIddict.EntityFrameworkCore.Models; @@ -21,9 +21,7 @@ public class OpenIddictEntityFrameworkCoreToken : OpenIddictEntityFrameworkCoreT /// Represents an OpenIddict token. /// public class OpenIddictEntityFrameworkCoreToken : OpenIddictEntityFrameworkCoreToken, OpenIddictEntityFrameworkCoreAuthorization> - where TKey : notnull, IEquatable -{ -} + where TKey : notnull, IEquatable; /// /// Represents an OpenIddict token. @@ -45,64 +43,65 @@ public class OpenIddictEntityFrameworkCoreToken - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the token. /// public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the UTC creation date of the current token. + /// Gets or sets the UTC creation date of the token. /// public virtual DateTime? CreationDate { get; set; } /// - /// Gets or sets the UTC expiration date of the current token. + /// Gets or sets the UTC expiration date of the token. /// public virtual DateTime? ExpirationDate { get; set; } /// - /// Gets or sets the unique identifier associated with the current token. + /// Gets or sets the unique identifier of the token. /// public virtual TKey? Id { get; set; } /// - /// Gets or sets the payload of the current token, if applicable. - /// Note: this property is only used for reference tokens - /// and may be encrypted for security reasons. + /// Gets or sets the payload of the token. /// + /// + /// Note: this property is only used for reference tokens + /// and may be hashed or encrypted for security reasons. + /// public virtual string? Payload { get; set; } /// - /// Gets or sets the additional properties serialized as a JSON object, - /// or if no bag was associated with the current token. + /// Gets or sets the additional properties of the token. /// - [StringSyntax(StringSyntaxAttribute.Json)] - public virtual string? Properties { get; set; } + public virtual IDictionary? Properties { get; set; } /// - /// Gets or sets the UTC redemption date of the current token. + /// Gets or sets the UTC redemption date of the token. /// public virtual DateTime? RedemptionDate { get; set; } /// - /// Gets or sets the reference identifier associated - /// with the current token, if applicable. + /// Gets or sets the reference identifier of the token. + /// + /// /// Note: this property is only used for reference tokens /// and may be hashed or encrypted for security reasons. - /// + /// public virtual string? ReferenceId { get; set; } /// - /// Gets or sets the status of the current token. + /// Gets or sets the status of the token. /// public virtual string? Status { get; set; } /// - /// Gets or sets the subject associated with the current token. + /// Gets or sets the subject of the token. /// public virtual string? Subject { get; set; } /// - /// Gets or sets the type of the current token. + /// Gets or sets the type of the token. /// public virtual string? Type { get; set; } } diff --git a/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreApplicationConfiguration.cs b/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreApplicationConfiguration.cs index 399ea5f8..805eb02a 100644 --- a/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreApplicationConfiguration.cs +++ b/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreApplicationConfiguration.cs @@ -6,7 +6,9 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using Microsoft.EntityFrameworkCore.Metadata.Builders; +using Microsoft.IdentityModel.Tokens; using OpenIddict.EntityFrameworkCore.Models; namespace OpenIddict.EntityFrameworkCore; @@ -37,11 +39,15 @@ public sealed class OpenIddictEntityFrameworkCoreApplicationConfiguration< // Entity Framework would throw an exception due to the TKey generic parameter // being non-nullable when using value types like short, int, long or Guid. - builder.HasKey(static application => application.Id); - builder.Property(static application => application.ApplicationType) .HasMaxLength(50); + builder.HasMany(static application => application.Authorizations) + .WithOne(static authorization => authorization.Application!) + .HasForeignKey(nameof(OpenIddictEntityFrameworkCoreAuthorization.Application) + + nameof(OpenIddictEntityFrameworkCoreApplication.Id)) + .IsRequired(required: false); + builder.HasIndex(static application => application.ClientId) .IsUnique(); @@ -58,6 +64,13 @@ public sealed class OpenIddictEntityFrameworkCoreApplicationConfiguration< builder.Property(static application => application.ConsentType) .HasMaxLength(50); + builder.Property(static application => application.DisplayNames) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringString), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringString)); + + builder.HasKey(static application => application.Id); + builder.Property(static application => application.Id) .ValueGeneratedOnAdd(); @@ -67,11 +80,20 @@ public sealed class OpenIddictEntityFrameworkCoreApplicationConfiguration< .HasMaxLength(100); } - builder.HasMany(static application => application.Authorizations) - .WithOne(static authorization => authorization.Application!) - .HasForeignKey(nameof(OpenIddictEntityFrameworkCoreAuthorization.Application) + - nameof(OpenIddictEntityFrameworkCoreApplication.Id)) - .IsRequired(required: false); + builder.Property(static application => application.JsonWebKeySet) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.JsonWebKeySet), + static value => JsonWebKeySet.Create(value)); + + builder.Property(static application => application.Properties) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringJsonElement), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringJsonElement)); + + builder.Property(static application => application.Settings) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringString), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringString)); builder.HasMany(static application => application.Tokens) .WithOne(static token => token.Application!) diff --git a/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreAuthorizationConfiguration.cs b/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreAuthorizationConfiguration.cs index 61146224..bcf93313 100644 --- a/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreAuthorizationConfiguration.cs +++ b/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreAuthorizationConfiguration.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using Microsoft.EntityFrameworkCore.Metadata.Builders; using OpenIddict.EntityFrameworkCore.Models; @@ -37,8 +38,6 @@ public sealed class OpenIddictEntityFrameworkCoreAuthorizationConfiguration< // Entity Framework would throw an exception due to the TKey generic parameter // being non-nullable when using value types like short, int, long or Guid. - builder.HasKey(static authorization => authorization.Id); - builder.HasIndex( nameof(OpenIddictEntityFrameworkCoreAuthorization.Application) + nameof(OpenIddictEntityFrameworkCoreApplication.Id), nameof(OpenIddictEntityFrameworkCoreAuthorization.Status), @@ -49,6 +48,8 @@ public sealed class OpenIddictEntityFrameworkCoreAuthorizationConfiguration< .HasMaxLength(50) .IsConcurrencyToken(); + builder.HasKey(static authorization => authorization.Id); + builder.Property(static authorization => authorization.Id) .ValueGeneratedOnAdd(); @@ -58,21 +59,26 @@ public sealed class OpenIddictEntityFrameworkCoreAuthorizationConfiguration< .HasMaxLength(100); } + builder.Property(static authorization => authorization.Properties) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringJsonElement), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringJsonElement)); + builder.Property(static authorization => authorization.Status) .HasMaxLength(50); builder.Property(static authorization => authorization.Subject) .HasMaxLength(400); - builder.Property(static authorization => authorization.Type) - .HasMaxLength(50); - builder.HasMany(static authorization => authorization.Tokens) .WithOne(static token => token.Authorization!) .HasForeignKey(nameof(OpenIddictEntityFrameworkCoreToken.Authorization) + nameof(OpenIddictEntityFrameworkCoreAuthorization.Id)) .IsRequired(required: false); + builder.Property(static authorization => authorization.Type) + .HasMaxLength(50); + builder.ToTable("OpenIddictAuthorizations"); } } diff --git a/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreResourceConfiguration.cs b/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreResourceConfiguration.cs index 70636ec1..1b762a77 100644 --- a/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreResourceConfiguration.cs +++ b/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreResourceConfiguration.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using Microsoft.EntityFrameworkCore.Metadata.Builders; using OpenIddict.EntityFrameworkCore.Models; @@ -31,15 +32,22 @@ public sealed class OpenIddictEntityFrameworkCoreResourceConfiguration< // Entity Framework would throw an exception due to the TKey generic parameter // being non-nullable when using value types like short, int, long or Guid. - builder.HasKey(static resource => resource.Id); - - builder.HasIndex(static resource => resource.Name) - .IsUnique(); - builder.Property(static resource => resource.ConcurrencyToken) .HasMaxLength(50) .IsConcurrencyToken(); + builder.Property(static resource => resource.Descriptions) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringString), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringString)); + + builder.Property(static resource => resource.DisplayNames) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringString), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringString)); + + builder.HasKey(static resource => resource.Id); + builder.Property(static resource => resource.Id) .ValueGeneratedOnAdd(); @@ -52,6 +60,14 @@ public sealed class OpenIddictEntityFrameworkCoreResourceConfiguration< builder.Property(static resource => resource.Name) .HasMaxLength(200); + builder.HasIndex(static resource => resource.Name) + .IsUnique(); + + builder.Property(static resource => resource.Properties) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringJsonElement), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringJsonElement)); + builder.ToTable("OpenIddictResources"); } } diff --git a/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreScopeConfiguration.cs b/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreScopeConfiguration.cs index 98ed324f..6ce2b52d 100644 --- a/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreScopeConfiguration.cs +++ b/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreScopeConfiguration.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using Microsoft.EntityFrameworkCore.Metadata.Builders; using OpenIddict.EntityFrameworkCore.Models; @@ -31,15 +32,22 @@ public sealed class OpenIddictEntityFrameworkCoreScopeConfiguration< // Entity Framework would throw an exception due to the TKey generic parameter // being non-nullable when using value types like short, int, long or Guid. - builder.HasKey(static scope => scope.Id); - - builder.HasIndex(static scope => scope.Name) - .IsUnique(); - builder.Property(static scope => scope.ConcurrencyToken) .HasMaxLength(50) .IsConcurrencyToken(); + builder.Property(static scope => scope.Descriptions) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringString), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringString)); + + builder.Property(static scope => scope.DisplayNames) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringString), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringString)); + + builder.HasKey(static scope => scope.Id); + builder.Property(static scope => scope.Id) .ValueGeneratedOnAdd(); @@ -52,6 +60,14 @@ public sealed class OpenIddictEntityFrameworkCoreScopeConfiguration< builder.Property(static scope => scope.Name) .HasMaxLength(200); + builder.HasIndex(static scope => scope.Name) + .IsUnique(); + + builder.Property(static scope => scope.Properties) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringJsonElement), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringJsonElement)); + builder.ToTable("OpenIddictScopes"); } } diff --git a/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreTokenConfiguration.cs b/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreTokenConfiguration.cs index 775c1fab..dc1b39aa 100644 --- a/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreTokenConfiguration.cs +++ b/src/OpenIddict.EntityFrameworkCore/Configurations/OpenIddictEntityFrameworkCoreTokenConfiguration.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; +using System.Text.Json; using Microsoft.EntityFrameworkCore.Metadata.Builders; using OpenIddict.EntityFrameworkCore.Models; @@ -37,11 +38,6 @@ public sealed class OpenIddictEntityFrameworkCoreTokenConfiguration< // Entity Framework would throw an exception due to the TKey generic parameter // being non-nullable when using value types like short, int, long or Guid. - builder.HasKey(static token => token.Id); - - builder.HasIndex(static token => token.ReferenceId) - .IsUnique(); - builder.HasIndex( nameof(OpenIddictEntityFrameworkCoreToken.Application) + nameof(OpenIddictEntityFrameworkCoreApplication.Id), nameof(OpenIddictEntityFrameworkCoreToken.Status), @@ -52,6 +48,8 @@ public sealed class OpenIddictEntityFrameworkCoreTokenConfiguration< .HasMaxLength(50) .IsConcurrencyToken(); + builder.HasKey(static token => token.Id); + builder.Property(static token => token.Id) .ValueGeneratedOnAdd(); @@ -64,12 +62,20 @@ public sealed class OpenIddictEntityFrameworkCoreTokenConfiguration< builder.Property(static token => token.ReferenceId) .HasMaxLength(100); + builder.HasIndex(static token => token.ReferenceId) + .IsUnique(); + builder.Property(static token => token.Status) .HasMaxLength(50); builder.Property(static token => token.Subject) .HasMaxLength(400); + builder.Property(static token => token.Properties) + .HasConversion( + static value => JsonSerializer.Serialize(value, OpenIddictSerializer.Default.IDictionaryStringJsonElement), + static value => JsonSerializer.Deserialize(value, OpenIddictSerializer.Default.IDictionaryStringJsonElement)); + builder.Property(static token => token.Type) .HasMaxLength(150); diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs index 49de4576..e7deebe5 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreApplicationStore.cs @@ -10,10 +10,7 @@ using System.Data; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; -using System.Text; -using System.Text.Encodings.Web; using System.Text.Json; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using Microsoft.IdentityModel.Tokens; using OpenIddict.EntityFrameworkCore.Models; @@ -30,10 +27,9 @@ public class OpenIddictEntityFrameworkCoreApplicationStore : OpenIddictEntityFrameworkCoreToken, string> { public OpenIddictEntityFrameworkCoreApplicationStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) - : base(cache, context, options) + : base(context, options) { } } @@ -50,10 +46,9 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< where TKey : notnull, IEquatable { public OpenIddictEntityFrameworkCoreApplicationStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) - : base(cache, context, options) + : base(context, options) { } } @@ -76,20 +71,13 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< where TKey : notnull, IEquatable { public OpenIddictEntityFrameworkCoreApplicationStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) { - Cache = cache ?? throw new ArgumentNullException(nameof(cache)); Context = context ?? throw new ArgumentNullException(nameof(context)); Options = options ?? throw new ArgumentNullException(nameof(options)); } - /// - /// Gets the memory cache associated with the current store. - /// - protected IMemoryCache Cache { get; } - /// /// Gets the database context associated with the current store. /// @@ -314,29 +302,18 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentException.ThrowIfNullOrEmpty(uri); - // To optimize the efficiency of the query a bit, only applications whose stringified - // PostLogoutRedirectUris contains the specified URI are returned. Once the applications - // are retrieved, a second pass is made to ensure only valid elements are returned. - // Implementers that use this method in a hot path may want to override this method - // to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient. - return ExecuteAsync(cancellationToken); async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) { var context = await Context.GetDbContextAsync(cancellationToken); - var applications = (from application in context.Set().AsTracking() - where application.PostLogoutRedirectUris!.Contains(uri) - select application).AsAsyncEnumerable().WithCancellation(cancellationToken); - - await foreach (var application in applications) + await foreach (var application in + (from application in context.Set().AsTracking() + where application.PostLogoutRedirectUris!.Contains(uri) + select application).AsAsyncEnumerable().WithCancellation(cancellationToken)) { - var uris = await GetPostLogoutRedirectUrisAsync(application, cancellationToken); - if (uris.Contains(uri, StringComparer.Ordinal)) - { - yield return application; - } + yield return application; } } } @@ -347,29 +324,18 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentException.ThrowIfNullOrEmpty(uri); - // To optimize the efficiency of the query a bit, only applications whose stringified - // RedirectUris property contains the specified URI are returned. Once the applications - // are retrieved, a second pass is made to ensure only valid elements are returned. - // Implementers that use this method in a hot path may want to override this method - // to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient. - return ExecuteAsync(cancellationToken); async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) { var context = await Context.GetDbContextAsync(cancellationToken); - var applications = (from application in context.Set().AsTracking() - where application.RedirectUris!.Contains(uri) - select application).AsAsyncEnumerable().WithCancellation(cancellationToken); - - await foreach (var application in applications) + await foreach (var application in + (from application in context.Set().AsTracking() + where application.RedirectUris!.Contains(uri) + select application).AsAsyncEnumerable().WithCancellation(cancellationToken)) { - var uris = await GetRedirectUrisAsync(application, cancellationToken); - if (uris.Contains(uri, StringComparer.Ordinal)) - { - yield return application; - } + yield return application; } } } @@ -439,37 +405,9 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (string.IsNullOrEmpty(application.DisplayNames)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified display names is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("7762c378-c113-4564-b14b-1402b3949aaa", "\x1e", application.DisplayNames); - var names = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(application.DisplayNames); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - var value = property.Value.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder[CultureInfo.GetCultureInfo(property.Name)] = value; - } - - return builder.ToImmutable(); - })!; - - return new(names); + return new(application.DisplayNames is { Count: > 0 } names + ? names.ToImmutableDictionary(static pair => CultureInfo.GetCultureInfo(pair.Key), static pair => pair.Value) + : []); } /// @@ -485,23 +423,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (string.IsNullOrEmpty(application.JsonWebKeySet)) - { - return new(result: null); - } - - // Note: parsing the stringified JSON Web Key Set is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("1e0a697d-0623-481a-927a-5e6c31458782", "\x1e", application.JsonWebKeySet); - var set = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - return JsonWebKeySet.Create(application.JsonWebKeySet); - })!; - - return new(set); + return new(application.JsonWebKeySet); } /// @@ -509,37 +431,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (string.IsNullOrEmpty(application.Permissions)) - { - return new([]); - } - - // Note: parsing the stringified permissions is an expensive operation. - // To mitigate that, the resulting array is stored in the memory cache. - var key = string.Concat("0347e0aa-3a26-410a-97e8-a83bdeb21a1f", "\x1e", application.Permissions); - var permissions = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(application.Permissions); - var builder = ImmutableArray.CreateBuilder(document.RootElement.GetArrayLength()); - - foreach (var element in document.RootElement.EnumerateArray()) - { - var value = element.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder.Add(value); - } - - return builder.ToImmutable(); - }); - - return new(permissions); + return new(application.Permissions is { Length: > 0 } permissions ? [.. permissions] : []); } /// @@ -547,37 +439,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (string.IsNullOrEmpty(application.PostLogoutRedirectUris)) - { - return new([]); - } - - // Note: parsing the stringified URIs is an expensive operation. - // To mitigate that, the resulting array is stored in the memory cache. - var key = string.Concat("fb14dfb9-9216-4b77-bfa9-7e85f8201ff4", "\x1e", application.PostLogoutRedirectUris); - var uris = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(application.PostLogoutRedirectUris); - var builder = ImmutableArray.CreateBuilder(document.RootElement.GetArrayLength()); - - foreach (var element in document.RootElement.EnumerateArray()) - { - var value = element.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder.Add(value); - } - - return builder.ToImmutable(); - }); - - return new(uris); + return new(application.PostLogoutRedirectUris is { Length: > 0 } uris ? [.. uris] : []); } /// @@ -585,31 +447,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (string.IsNullOrEmpty(application.Properties)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified properties is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("2e3e9680-5654-48d8-a27d-b8bb4f0f1d50", "\x1e", application.Properties); - var properties = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(application.Properties); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - builder[property.Name] = property.Value.Clone(); - } - - return builder.ToImmutable(); - })!; - - return new(properties); + return new(application.Properties is { Count: > 0 } properties ? [.. properties] : []); } /// @@ -617,37 +455,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (string.IsNullOrEmpty(application.RedirectUris)) - { - return new([]); - } - - // Note: parsing the stringified URIs is an expensive operation. - // To mitigate that, the resulting array is stored in the memory cache. - var key = string.Concat("851d6f08-2ee0-4452-bbe5-ab864611ecaa", "\x1e", application.RedirectUris); - var uris = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(application.RedirectUris); - var builder = ImmutableArray.CreateBuilder(document.RootElement.GetArrayLength()); - - foreach (var element in document.RootElement.EnumerateArray()) - { - var value = element.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder.Add(value); - } - - return builder.ToImmutable(); - }); - - return new(uris); + return new(application.RedirectUris is { Length: > 0 } uris ? [.. uris] : []); } /// @@ -655,37 +463,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (string.IsNullOrEmpty(application.Requirements)) - { - return new([]); - } - - // Note: parsing the stringified requirements is an expensive operation. - // To mitigate that, the resulting array is stored in the memory cache. - var key = string.Concat("b4808a89-8969-4512-895f-a909c62a8995", "\x1e", application.Requirements); - var requirements = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(application.Requirements); - var builder = ImmutableArray.CreateBuilder(document.RootElement.GetArrayLength()); - - foreach (var element in document.RootElement.EnumerateArray()) - { - var value = element.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder.Add(value); - } - - return builder.ToImmutable(); - }); - - return new(requirements); + return new(application.Requirements is { Length: > 0 } requirements ? [.. requirements] : []); } /// @@ -693,37 +471,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (string.IsNullOrEmpty(application.Settings)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified settings is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("492ea63f-c26f-47ea-bf9b-b0a0c3d02656", "\x1e", application.Settings); - var settings = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(application.Settings); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - var value = property.Value.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder[property.Name] = value; - } - - return builder.ToImmutable(); - })!; - - return new(settings); + return new(application.Settings is { Count: > 0 } settings ? [.. settings] : []); } /// @@ -852,32 +600,9 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (names is not { Count: > 0 }) - { - application.DisplayNames = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var pair in names) - { - writer.WritePropertyName(pair.Key.Name); - writer.WriteStringValue(pair.Value); - } - - writer.WriteEndObject(); - writer.Flush(); - - application.DisplayNames = Encoding.UTF8.GetString(stream.ToArray()); + application.DisplayNames = names is { Count: > 0 } + ? names.ToImmutableDictionary(static pair => pair.Key.Name, static pair => pair.Value) + : null; return ValueTask.CompletedTask; } @@ -887,7 +612,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - application.JsonWebKeySet = set is not null ? JsonSerializer.Serialize(set, OpenIddictSerializer.Default.JsonWebKeySet) : null; + application.JsonWebKeySet = set; return ValueTask.CompletedTask; } @@ -904,24 +629,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< return ValueTask.CompletedTask; } - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartArray(); - - foreach (var permission in permissions) - { - writer.WriteStringValue(permission); - } - - writer.WriteEndArray(); - writer.Flush(); - - application.Permissions = Encoding.UTF8.GetString(stream.ToArray()); + application.Permissions = permissions.ToArray(); return ValueTask.CompletedTask; } @@ -939,24 +647,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< return ValueTask.CompletedTask; } - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartArray(); - - foreach (var uri in uris) - { - writer.WriteStringValue(uri); - } - - writer.WriteEndArray(); - writer.Flush(); - - application.PostLogoutRedirectUris = Encoding.UTF8.GetString(stream.ToArray()); + application.PostLogoutRedirectUris = uris.ToArray(); return ValueTask.CompletedTask; } @@ -967,32 +658,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (properties is not { Count: > 0 }) - { - application.Properties = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var property in properties) - { - writer.WritePropertyName(property.Key); - property.Value.WriteTo(writer); - } - - writer.WriteEndObject(); - writer.Flush(); - - application.Properties = Encoding.UTF8.GetString(stream.ToArray()); + application.Properties = properties; return ValueTask.CompletedTask; } @@ -1010,24 +676,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< return ValueTask.CompletedTask; } - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartArray(); - - foreach (var uri in uris) - { - writer.WriteStringValue(uri); - } - - writer.WriteEndArray(); - writer.Flush(); - - application.RedirectUris = Encoding.UTF8.GetString(stream.ToArray()); + application.RedirectUris = uris.ToArray(); return ValueTask.CompletedTask; } @@ -1044,24 +693,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< return ValueTask.CompletedTask; } - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartArray(); - - foreach (var requirement in requirements) - { - writer.WriteStringValue(requirement); - } - - writer.WriteEndArray(); - writer.Flush(); - - application.Requirements = Encoding.UTF8.GetString(stream.ToArray()); + application.Requirements = requirements.ToArray(); return ValueTask.CompletedTask; } @@ -1072,32 +704,7 @@ public class OpenIddictEntityFrameworkCoreApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (settings is not { Count: > 0 }) - { - application.Settings = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var setting in settings) - { - writer.WritePropertyName(setting.Key); - writer.WriteStringValue(setting.Value); - } - - writer.WriteEndObject(); - writer.Flush(); - - application.Settings = Encoding.UTF8.GetString(stream.ToArray()); + application.Settings = settings; return ValueTask.CompletedTask; } diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs index 22ea424d..be9ce639 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs @@ -9,10 +9,7 @@ using System.ComponentModel; using System.Data; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -using System.Text; -using System.Text.Encodings.Web; using System.Text.Json; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using OpenIddict.EntityFrameworkCore.Models; using static OpenIddict.Abstractions.OpenIddictExceptions; @@ -28,10 +25,9 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore : OpenIddictEntityFrameworkCoreToken, string> { public OpenIddictEntityFrameworkCoreAuthorizationStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) - : base(cache, context, options) + : base(context, options) { } } @@ -48,10 +44,9 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore< where TKey : notnull, IEquatable { public OpenIddictEntityFrameworkCoreAuthorizationStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) - : base(cache, context, options) + : base(context, options) { } } @@ -74,20 +69,13 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore< where TKey : notnull, IEquatable { public OpenIddictEntityFrameworkCoreAuthorizationStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) { - Cache = cache ?? throw new ArgumentNullException(nameof(cache)); Context = context ?? throw new ArgumentNullException(nameof(context)); Options = options ?? throw new ArgumentNullException(nameof(options)); } - /// - /// Gets the memory cache associated with the current store. - /// - protected IMemoryCache Cache { get; } - /// /// Gets the database context associated with the current store. /// @@ -393,12 +381,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore< { ArgumentNullException.ThrowIfNull(authorization); - if (authorization.CreationDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(authorization.CreationDate.Value, DateTimeKind.Utc)); + return new(authorization.CreationDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// @@ -414,31 +397,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore< { ArgumentNullException.ThrowIfNull(authorization); - if (string.IsNullOrEmpty(authorization.Properties)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified properties is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("68056e1a-dbcf-412b-9a6a-d791c7dbe726", "\x1e", authorization.Properties); - var properties = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(authorization.Properties); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - builder[property.Name] = property.Value.Clone(); - } - - return builder.ToImmutable(); - })!; - - return new(properties); + return new(authorization.Properties is { Count: > 0 } properties ? [.. properties] : []); } /// @@ -446,37 +405,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore< { ArgumentNullException.ThrowIfNull(authorization); - if (string.IsNullOrEmpty(authorization.Scopes)) - { - return new([]); - } - - // Note: parsing the stringified scopes is an expensive operation. - // To mitigate that, the resulting array is stored in the memory cache. - var key = string.Concat("2ba4ab0f-e2ec-4d48-b3bd-28e2bb660c75", "\x1e", authorization.Scopes); - var scopes = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(authorization.Scopes); - var builder = ImmutableArray.CreateBuilder(document.RootElement.GetArrayLength()); - - foreach (var element in document.RootElement.EnumerateArray()) - { - var value = element.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder.Add(value); - } - - return builder.ToImmutable(); - }); - - return new(scopes); + return new(authorization.Scopes is { Length: > 0 } scopes ? [.. scopes] : []); } /// @@ -939,32 +868,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore< { ArgumentNullException.ThrowIfNull(authorization); - if (properties is not { Count: > 0 }) - { - authorization.Properties = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var property in properties) - { - writer.WritePropertyName(property.Key); - property.Value.WriteTo(writer); - } - - writer.WriteEndObject(); - writer.Flush(); - - authorization.Properties = Encoding.UTF8.GetString(stream.ToArray()); + authorization.Properties = properties; return ValueTask.CompletedTask; } @@ -982,24 +886,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore< return ValueTask.CompletedTask; } - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartArray(); - - foreach (var scope in scopes) - { - writer.WriteStringValue(scope); - } - - writer.WriteEndArray(); - writer.Flush(); - - authorization.Scopes = Encoding.UTF8.GetString(stream.ToArray()); + authorization.Scopes = scopes.ToArray(); return ValueTask.CompletedTask; } diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreResourceStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreResourceStore.cs index 3294f0f2..ad668fb5 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreResourceStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreResourceStore.cs @@ -9,10 +9,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; -using System.Text; -using System.Text.Encodings.Web; using System.Text.Json; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using OpenIddict.EntityFrameworkCore.Models; using static OpenIddict.Abstractions.OpenIddictExceptions; @@ -25,10 +22,9 @@ namespace OpenIddict.EntityFrameworkCore; public class OpenIddictEntityFrameworkCoreResourceStore : OpenIddictEntityFrameworkCoreResourceStore { public OpenIddictEntityFrameworkCoreResourceStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) - : base(cache, context, options) + : base(context, options) { } } @@ -42,10 +38,9 @@ public class OpenIddictEntityFrameworkCoreResourceStore< where TKey : notnull, IEquatable { public OpenIddictEntityFrameworkCoreResourceStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) - : base(cache, context, options) + : base(context, options) { } } @@ -62,20 +57,13 @@ public class OpenIddictEntityFrameworkCoreResourceStore< where TKey : notnull, IEquatable { public OpenIddictEntityFrameworkCoreResourceStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) { - Cache = cache ?? throw new ArgumentNullException(nameof(cache)); Context = context ?? throw new ArgumentNullException(nameof(context)); Options = options ?? throw new ArgumentNullException(nameof(options)); } - /// - /// Gets the memory cache associated with the current store. - /// - protected IMemoryCache Cache { get; } - /// /// Gets the database context associated with the current store. /// @@ -232,37 +220,9 @@ public class OpenIddictEntityFrameworkCoreResourceStore< { ArgumentNullException.ThrowIfNull(resource); - if (string.IsNullOrEmpty(resource.Descriptions)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified descriptions is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("20e1ab51-b505-40b0-9a10-d0596b9f2143", "\x1e", resource.Descriptions); - var descriptions = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(resource.Descriptions); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - var value = property.Value.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder[CultureInfo.GetCultureInfo(property.Name)] = value; - } - - return builder.ToImmutable(); - })!; - - return new(descriptions); + return new(resource.Descriptions is { Count: > 0 } descriptions + ? descriptions.ToImmutableDictionary(static pair => CultureInfo.GetCultureInfo(pair.Key), static pair => pair.Value) + : []); } /// @@ -278,37 +238,9 @@ public class OpenIddictEntityFrameworkCoreResourceStore< { ArgumentNullException.ThrowIfNull(resource); - if (string.IsNullOrEmpty(resource.DisplayNames)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified display names is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("65c3ea08-ded7-488f-b001-5098de04172b", "\x1e", resource.DisplayNames); - var names = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(resource.DisplayNames); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - var value = property.Value.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder[CultureInfo.GetCultureInfo(property.Name)] = value; - } - - return builder.ToImmutable(); - })!; - - return new(names); + return new(resource.DisplayNames is { Count: > 0 } names + ? names.ToImmutableDictionary(static pair => CultureInfo.GetCultureInfo(pair.Key), static pair => pair.Value) + : []); } /// @@ -332,31 +264,7 @@ public class OpenIddictEntityFrameworkCoreResourceStore< { ArgumentNullException.ThrowIfNull(resource); - if (string.IsNullOrEmpty(resource.Properties)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified properties is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("1f414494-e5aa-4cad-9c5f-4f98688e3623", "\x1e", resource.Properties); - var properties = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(resource.Properties); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - builder[property.Name] = property.Value.Clone(); - } - - return builder.ToImmutable(); - })!; - - return new(properties); + return new(resource.Properties is { Count: > 0 } properties ? [.. properties] : []); } /// @@ -434,32 +342,9 @@ public class OpenIddictEntityFrameworkCoreResourceStore< { ArgumentNullException.ThrowIfNull(resource); - if (descriptions is not { Count: > 0 }) - { - resource.Descriptions = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var description in descriptions) - { - writer.WritePropertyName(description.Key.Name); - writer.WriteStringValue(description.Value); - } - - writer.WriteEndObject(); - writer.Flush(); - - resource.Descriptions = Encoding.UTF8.GetString(stream.ToArray()); + resource.Descriptions = descriptions is { Count: > 0 } + ? descriptions.ToImmutableDictionary(static pair => pair.Key.Name, static pair => pair.Value) + : null; return ValueTask.CompletedTask; } @@ -480,32 +365,9 @@ public class OpenIddictEntityFrameworkCoreResourceStore< { ArgumentNullException.ThrowIfNull(resource); - if (names is not { Count: > 0 }) - { - resource.DisplayNames = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var name in names) - { - writer.WritePropertyName(name.Key.Name); - writer.WriteStringValue(name.Value); - } - - writer.WriteEndObject(); - writer.Flush(); - - resource.DisplayNames = Encoding.UTF8.GetString(stream.ToArray()); + resource.DisplayNames = names is { Count: > 0 } + ? names.ToImmutableDictionary(static pair => pair.Key.Name, static pair => pair.Value) + : null; return ValueTask.CompletedTask; } @@ -526,32 +388,7 @@ public class OpenIddictEntityFrameworkCoreResourceStore< { ArgumentNullException.ThrowIfNull(resource); - if (properties is not { Count: > 0 }) - { - resource.Properties = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var property in properties) - { - writer.WritePropertyName(property.Key); - property.Value.WriteTo(writer); - } - - writer.WriteEndObject(); - writer.Flush(); - - resource.Properties = Encoding.UTF8.GetString(stream.ToArray()); + resource.Properties = properties; return ValueTask.CompletedTask; } diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs index 80593c3e..cda95a0e 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreScopeStore.cs @@ -9,10 +9,7 @@ using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; -using System.Text; -using System.Text.Encodings.Web; using System.Text.Json; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using OpenIddict.EntityFrameworkCore.Models; using static OpenIddict.Abstractions.OpenIddictExceptions; @@ -25,10 +22,9 @@ namespace OpenIddict.EntityFrameworkCore; public class OpenIddictEntityFrameworkCoreScopeStore : OpenIddictEntityFrameworkCoreScopeStore { public OpenIddictEntityFrameworkCoreScopeStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) - : base(cache, context, options) + : base(context, options) { } } @@ -42,10 +38,9 @@ public class OpenIddictEntityFrameworkCoreScopeStore< where TKey : notnull, IEquatable { public OpenIddictEntityFrameworkCoreScopeStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) - : base(cache, context, options) + : base(context, options) { } } @@ -62,20 +57,13 @@ public class OpenIddictEntityFrameworkCoreScopeStore< where TKey : notnull, IEquatable { public OpenIddictEntityFrameworkCoreScopeStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) { - Cache = cache ?? throw new ArgumentNullException(nameof(cache)); Context = context ?? throw new ArgumentNullException(nameof(context)); Options = options ?? throw new ArgumentNullException(nameof(options)); } - /// - /// Gets the memory cache associated with the current store. - /// - protected IMemoryCache Cache { get; } - /// /// Gets the database context associated with the current store. /// @@ -212,29 +200,17 @@ public class OpenIddictEntityFrameworkCoreScopeStore< { ArgumentException.ThrowIfNullOrEmpty(resource); - // To optimize the efficiency of the query a bit, only scopes whose stringified - // Resources column contains the specified resource are returned. Once the scopes - // are retrieved, a second pass is made to ensure only valid elements are returned. - // Implementers that use this method in a hot path may want to override this method - // to use SQL Server 2016 functions like JSON_VALUE to make the query more efficient. - return ExecuteAsync(cancellationToken); async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) { var context = await Context.GetDbContextAsync(cancellationToken); - var scopes = (from scope in context.Set().AsTracking() - where scope.Resources!.Contains(resource) - select scope).AsAsyncEnumerable().WithCancellation(cancellationToken); - - await foreach (var scope in scopes) + await foreach (var scope in (from scope in context.Set().AsTracking() + where scope.Resources!.Contains(resource) + select scope).AsAsyncEnumerable().WithCancellation(cancellationToken)) { - var resources = await GetResourcesAsync(scope, cancellationToken); - if (resources.Contains(resource, StringComparer.Ordinal)) - { - yield return scope; - } + yield return scope; } } } @@ -264,37 +240,9 @@ public class OpenIddictEntityFrameworkCoreScopeStore< { ArgumentNullException.ThrowIfNull(scope); - if (string.IsNullOrEmpty(scope.Descriptions)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified descriptions is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("42891062-8f69-43ba-9111-db7e8ded2553", "\x1e", scope.Descriptions); - var descriptions = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(scope.Descriptions); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - var value = property.Value.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder[CultureInfo.GetCultureInfo(property.Name)] = value; - } - - return builder.ToImmutable(); - })!; - - return new(descriptions); + return new(scope.Descriptions is { Count: > 0 } descriptions + ? descriptions.ToImmutableDictionary(static pair => CultureInfo.GetCultureInfo(pair.Key), static pair => pair.Value) + : ImmutableDictionary.Create()); } /// @@ -310,37 +258,9 @@ public class OpenIddictEntityFrameworkCoreScopeStore< { ArgumentNullException.ThrowIfNull(scope); - if (string.IsNullOrEmpty(scope.DisplayNames)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified display names is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("e17d437b-bdd2-43f3-974e-46d524f4bae1", "\x1e", scope.DisplayNames); - var names = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(scope.DisplayNames); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - var value = property.Value.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder[CultureInfo.GetCultureInfo(property.Name)] = value; - } - - return builder.ToImmutable(); - })!; - - return new(names); + return new(scope.DisplayNames is { Count: > 0 } names + ? names.ToImmutableDictionary(static pair => CultureInfo.GetCultureInfo(pair.Key), static pair => pair.Value) + : []); } /// @@ -364,31 +284,7 @@ public class OpenIddictEntityFrameworkCoreScopeStore< { ArgumentNullException.ThrowIfNull(scope); - if (string.IsNullOrEmpty(scope.Properties)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified properties is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("78d8dfdd-3870-442e-b62e-dc9bf6eaeff7", "\x1e", scope.Properties); - var properties = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(scope.Properties); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - builder[property.Name] = property.Value.Clone(); - } - - return builder.ToImmutable(); - })!; - - return new(properties); + return new(scope.Properties is { Count: > 0 } properties ? [.. properties] : []); } /// @@ -396,37 +292,7 @@ public class OpenIddictEntityFrameworkCoreScopeStore< { ArgumentNullException.ThrowIfNull(scope); - if (string.IsNullOrEmpty(scope.Resources)) - { - return new([]); - } - - // Note: parsing the stringified resources is an expensive operation. - // To mitigate that, the resulting array is stored in the memory cache. - var key = string.Concat("b6148250-aede-4fb9-a621-07c9bcf238c3", "\x1e", scope.Resources); - var resources = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(scope.Resources); - var builder = ImmutableArray.CreateBuilder(document.RootElement.GetArrayLength()); - - foreach (var element in document.RootElement.EnumerateArray()) - { - var value = element.GetString(); - if (string.IsNullOrEmpty(value)) - { - continue; - } - - builder.Add(value); - } - - return builder.ToImmutable(); - }); - - return new(resources); + return new(scope.Resources is { Length: > 0 } resources ? [.. resources] : []); } /// @@ -504,32 +370,9 @@ public class OpenIddictEntityFrameworkCoreScopeStore< { ArgumentNullException.ThrowIfNull(scope); - if (descriptions is not { Count: > 0 }) - { - scope.Descriptions = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var description in descriptions) - { - writer.WritePropertyName(description.Key.Name); - writer.WriteStringValue(description.Value); - } - - writer.WriteEndObject(); - writer.Flush(); - - scope.Descriptions = Encoding.UTF8.GetString(stream.ToArray()); + scope.Descriptions = descriptions is { Count: > 0 } + ? descriptions.ToImmutableDictionary(static pair => pair.Key.Name, static pair => pair.Value) + : null; return ValueTask.CompletedTask; } @@ -550,32 +393,9 @@ public class OpenIddictEntityFrameworkCoreScopeStore< { ArgumentNullException.ThrowIfNull(scope); - if (names is not { Count: > 0 }) - { - scope.DisplayNames = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var name in names) - { - writer.WritePropertyName(name.Key.Name); - writer.WriteStringValue(name.Value); - } - - writer.WriteEndObject(); - writer.Flush(); - - scope.DisplayNames = Encoding.UTF8.GetString(stream.ToArray()); + scope.DisplayNames = names is { Count: > 0 } + ? names.ToImmutableDictionary(static pair => pair.Key.Name, static pair => pair.Value) + : null; return ValueTask.CompletedTask; } @@ -596,32 +416,7 @@ public class OpenIddictEntityFrameworkCoreScopeStore< { ArgumentNullException.ThrowIfNull(scope); - if (properties is not { Count: > 0 }) - { - scope.Properties = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var property in properties) - { - writer.WritePropertyName(property.Key); - property.Value.WriteTo(writer); - } - - writer.WriteEndObject(); - writer.Flush(); - - scope.Properties = Encoding.UTF8.GetString(stream.ToArray()); + scope.Properties = properties; return ValueTask.CompletedTask; } @@ -638,24 +433,7 @@ public class OpenIddictEntityFrameworkCoreScopeStore< return ValueTask.CompletedTask; } - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartArray(); - - foreach (var resource in resources) - { - writer.WriteStringValue(resource); - } - - writer.WriteEndArray(); - writer.Flush(); - - scope.Resources = Encoding.UTF8.GetString(stream.ToArray()); + scope.Resources = resources.ToArray(); return ValueTask.CompletedTask; } diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs index d21d45df..e67eb4db 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs @@ -9,10 +9,7 @@ using System.ComponentModel; using System.Data; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; -using System.Text; -using System.Text.Encodings.Web; using System.Text.Json; -using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Options; using OpenIddict.EntityFrameworkCore.Models; using static OpenIddict.Abstractions.OpenIddictExceptions; @@ -28,10 +25,9 @@ public class OpenIddictEntityFrameworkCoreTokenStore : OpenIddictEntityFrameworkCoreAuthorization, string> { public OpenIddictEntityFrameworkCoreTokenStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) - : base(cache, context, options) + : base(context, options) { } } @@ -48,10 +44,9 @@ public class OpenIddictEntityFrameworkCoreTokenStore< where TKey : notnull, IEquatable { public OpenIddictEntityFrameworkCoreTokenStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) - : base(cache, context, options) + : base(context, options) { } } @@ -74,20 +69,13 @@ public class OpenIddictEntityFrameworkCoreTokenStore< where TKey : notnull, IEquatable { public OpenIddictEntityFrameworkCoreTokenStore( - IMemoryCache cache, IOpenIddictEntityFrameworkCoreContext context, IOptionsMonitor options) { - Cache = cache ?? throw new ArgumentNullException(nameof(cache)); Context = context ?? throw new ArgumentNullException(nameof(context)); Options = options ?? throw new ArgumentNullException(nameof(options)); } - /// - /// Gets the memory cache associated with the current store. - /// - protected IMemoryCache Cache { get; } - /// /// Gets the database context associated with the current store. /// @@ -400,12 +388,7 @@ public class OpenIddictEntityFrameworkCoreTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.CreationDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(token.CreationDate.Value, DateTimeKind.Utc)); + return new(token.CreationDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// @@ -413,12 +396,7 @@ public class OpenIddictEntityFrameworkCoreTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.ExpirationDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(token.ExpirationDate.Value, DateTimeKind.Utc)); + return new(token.ExpirationDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// @@ -442,31 +420,7 @@ public class OpenIddictEntityFrameworkCoreTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (string.IsNullOrEmpty(token.Properties)) - { - return new(ImmutableDictionary.Create()); - } - - // Note: parsing the stringified properties is an expensive operation. - // To mitigate that, the resulting object is stored in the memory cache. - var key = string.Concat("d0509397-1bbf-40e7-97e1-5e6d7bc2536c", "\x1e", token.Properties); - var properties = Cache.GetOrCreate(key, entry => - { - entry.SetPriority(CacheItemPriority.High) - .SetSlidingExpiration(TimeSpan.FromMinutes(1)); - - using var document = JsonDocument.Parse(token.Properties); - var builder = ImmutableDictionary.CreateBuilder(); - - foreach (var property in document.RootElement.EnumerateObject()) - { - builder[property.Name] = property.Value.Clone(); - } - - return builder.ToImmutable(); - })!; - - return new(properties); + return new(token.Properties is { Count: > 0 } properties ? [.. properties] : []); } /// @@ -474,12 +428,7 @@ public class OpenIddictEntityFrameworkCoreTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.RedemptionDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(token.RedemptionDate.Value, DateTimeKind.Utc)); + return new(token.RedemptionDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// @@ -1070,32 +1019,7 @@ public class OpenIddictEntityFrameworkCoreTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (properties is not { Count: > 0 }) - { - token.Properties = null; - - return ValueTask.CompletedTask; - } - - using var stream = new MemoryStream(); - using var writer = new Utf8JsonWriter(stream, new JsonWriterOptions - { - Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, - Indented = false - }); - - writer.WriteStartObject(); - - foreach (var property in properties) - { - writer.WritePropertyName(property.Key); - property.Value.WriteTo(writer); - } - - writer.WriteEndObject(); - writer.Flush(); - - token.Properties = Encoding.UTF8.GetString(stream.ToArray()); + token.Properties = properties; return ValueTask.CompletedTask; } diff --git a/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbApplication.cs b/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbApplication.cs index 87f09f94..ab7a6c87 100644 --- a/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbApplication.cs +++ b/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbApplication.cs @@ -16,105 +16,109 @@ namespace OpenIddict.MongoDb.Models; public class OpenIddictMongoDbApplication { /// - /// Gets or sets the application type associated with the current application. + /// Gets or sets the application type of the application. /// [BsonElement("application_type"), BsonIgnoreIfNull] public virtual string? ApplicationType { get; set; } /// - /// Gets or sets the client identifier associated with the current application. + /// Gets or sets the client identifier of the application. /// [BsonElement("client_id"), BsonIgnoreIfNull] public virtual string? ClientId { get; set; } /// - /// Gets or sets the client secret associated with the current application. - /// Note: depending on the application manager used to create this instance, - /// this property may be hashed or encrypted for security reasons. + /// Gets or sets the client secret of the application. /// /// + /// + /// Note: depending on the application manager used to create this instance, + /// this property may be hashed or encrypted for security reasons. + /// + /// /// Note: client authentication based on shared secrets is not recommended and should /// only be used for backward compatibility with legacy applications that only support /// client secrets. When possible, consider using public/private key pairs or TLS client /// certificates instead, as these client authentication methods are significantly safer. + /// /// [BsonElement("client_secret"), BsonIgnoreIfNull] public virtual string? ClientSecret { get; set; } /// - /// Gets or sets the client type associated with the current application. + /// Gets or sets the client type of the application. /// [BsonElement("client_type"), BsonIgnoreIfNull] public virtual string? ClientType { get; set; } /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the application. /// [BsonElement("concurrency_token"), BsonIgnoreIfNull] public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the consent type associated with the current application. + /// Gets or sets the consent type of the application. /// [BsonElement("consent_type"), BsonIgnoreIfNull] public virtual string? ConsentType { get; set; } /// - /// Gets or sets the display name associated with the current application. + /// Gets or sets the display name of the application. /// [BsonElement("display_name"), BsonIgnoreIfNull] public virtual string? DisplayName { get; set; } /// - /// Gets or sets the localized display names associated with the current application. + /// Gets or sets the localized display names of the application. /// [BsonElement("display_names"), BsonIgnoreIfNull] public virtual ImmutableDictionary? DisplayNames { get; set; } /// - /// Gets or sets the unique identifier associated with the current application. + /// Gets or sets the unique identifier of the application. /// [BsonId, BsonRequired] public virtual ObjectId Id { get; set; } /// - /// Gets or sets the JSON Web Key Set associated with the application. + /// Gets or sets the JSON Web Key Set of the application. /// [BsonElement("json_web_key_set"), BsonIgnoreIfNull] public virtual BsonDocument? JsonWebKeySet { get; set; } /// - /// Gets or sets the permissions associated with the current application. + /// Gets or sets the permissions of the application. /// [BsonElement("permissions"), BsonIgnoreIfNull] public virtual ImmutableArray? Permissions { get; set; } /// - /// Gets or sets the post-logout redirect URIs associated with the current application. + /// Gets or sets the post-logout redirect URIs of the application. /// [BsonElement("post_logout_redirect_uris"), BsonIgnoreIfNull] public virtual ImmutableArray? PostLogoutRedirectUris { get; set; } /// - /// Gets or sets the additional properties associated with the current application. + /// Gets or sets the additional properties of the application. /// [BsonElement("properties"), BsonIgnoreIfNull] public virtual BsonDocument? Properties { get; set; } /// - /// Gets or sets the redirect URIs associated with the current application. + /// Gets or sets the redirect URIs of the application. /// [BsonElement("redirect_uris"), BsonIgnoreIfNull] public virtual ImmutableArray? RedirectUris { get; set; } /// - /// Gets or sets the requirements associated with the current application. + /// Gets or sets the requirements of the application. /// [BsonElement("requirements"), BsonIgnoreIfNull] public virtual ImmutableArray? Requirements { get; set; } /// - /// Gets or sets the settings associated with the current application. + /// Gets or sets the settings of the application. /// [BsonElement("settings"), BsonIgnoreIfNull] public virtual ImmutableDictionary? Settings { get; set; } diff --git a/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbAuthorization.cs b/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbAuthorization.cs index df91d6df..cd71d00f 100644 --- a/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbAuthorization.cs +++ b/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbAuthorization.cs @@ -16,55 +16,55 @@ namespace OpenIddict.MongoDb.Models; public class OpenIddictMongoDbAuthorization { /// - /// Gets or sets the identifier of the application associated with the current authorization. + /// Gets or sets the identifier of the application associated with the authorization. /// [BsonElement("application_id"), BsonIgnoreIfDefault] public virtual ObjectId ApplicationId { get; set; } /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the authorization. /// [BsonElement("concurrency_token"), BsonIgnoreIfNull] public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the UTC creation date of the current authorization. + /// Gets or sets the UTC creation date of the authorization. /// [BsonElement("creation_date"), BsonIgnoreIfNull] public virtual DateTime? CreationDate { get; set; } /// - /// Gets or sets the unique identifier associated with the current authorization. + /// Gets or sets the unique identifier of the authorization. /// [BsonId, BsonRequired] public virtual ObjectId Id { get; set; } /// - /// Gets or sets the additional properties associated with the current authorization. + /// Gets or sets the additional properties of the authorization. /// [BsonElement("properties"), BsonIgnoreIfNull] public virtual BsonDocument? Properties { get; set; } /// - /// Gets or sets the scopes associated with the current authorization. + /// Gets or sets the scopes of the authorization. /// [BsonElement("scopes"), BsonIgnoreIfNull] public virtual ImmutableArray? Scopes { get; set; } /// - /// Gets or sets the status of the current authorization. + /// Gets or sets the status of the authorization. /// [BsonElement("status"), BsonIgnoreIfNull] public virtual string? Status { get; set; } /// - /// Gets or sets the subject associated with the current authorization. + /// Gets or sets the subject associated with the authorization. /// [BsonElement("subject"), BsonIgnoreIfNull] public virtual string? Subject { get; set; } /// - /// Gets or sets the type of the current authorization. + /// Gets or sets the type of the authorization. /// [BsonElement("type"), BsonIgnoreIfNull] public virtual string? Type { get; set; } diff --git a/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbResource.cs b/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbResource.cs index 76109501..b22bc969 100644 --- a/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbResource.cs +++ b/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbResource.cs @@ -16,49 +16,49 @@ namespace OpenIddict.MongoDb.Models; public class OpenIddictMongoDbResource { /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the resource. /// [BsonElement("concurrency_token"), BsonIgnoreIfNull] public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the public description associated with the current resource. + /// Gets or sets the public description of the resource. /// [BsonElement("description"), BsonIgnoreIfNull] public virtual string? Description { get; set; } /// - /// Gets or sets the localized public descriptions associated with the current resource. + /// Gets or sets the localized public descriptions of the resource. /// [BsonElement("descriptions"), BsonIgnoreIfNull] public virtual ImmutableDictionary? Descriptions { get; set; } /// - /// Gets or sets the display name associated with the current resource. + /// Gets or sets the display name of the resource. /// [BsonElement("display_name"), BsonIgnoreIfNull] public virtual string? DisplayName { get; set; } /// - /// Gets or sets the localized display names associated with the current resource. + /// Gets or sets the localized display names of the resource. /// [BsonElement("display_names"), BsonIgnoreIfNull] public virtual ImmutableDictionary? DisplayNames { get; set; } /// - /// Gets or sets the unique identifier associated with the current resource. + /// Gets or sets the unique identifier of the resource. /// [BsonId, BsonRequired] public virtual ObjectId Id { get; set; } /// - /// Gets or sets the unique name associated with the current resource. + /// Gets or sets the unique name of the resource. /// [BsonElement("name"), BsonIgnoreIfNull] public virtual string? Name { get; set; } /// - /// Gets or sets the additional properties associated with the current resource. + /// Gets or sets the additional properties of the resource. /// [BsonElement("properties"), BsonIgnoreIfNull] public virtual BsonDocument? Properties { get; set; } diff --git a/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbScope.cs b/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbScope.cs index 227c9866..9bec260f 100644 --- a/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbScope.cs +++ b/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbScope.cs @@ -16,55 +16,55 @@ namespace OpenIddict.MongoDb.Models; public class OpenIddictMongoDbScope { /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the scope. /// [BsonElement("concurrency_token"), BsonIgnoreIfNull] public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the public description associated with the current scope. + /// Gets or sets the public description of the scope. /// [BsonElement("description"), BsonIgnoreIfNull] public virtual string? Description { get; set; } /// - /// Gets or sets the localized public descriptions associated with the current scope. + /// Gets or sets the localized public descriptions of the scope. /// [BsonElement("descriptions"), BsonIgnoreIfNull] public virtual ImmutableDictionary? Descriptions { get; set; } /// - /// Gets or sets the display name associated with the current scope. + /// Gets or sets the display name of the scope. /// [BsonElement("display_name"), BsonIgnoreIfNull] public virtual string? DisplayName { get; set; } /// - /// Gets or sets the localized display names associated with the current scope. + /// Gets or sets the localized display names of the scope. /// [BsonElement("display_names"), BsonIgnoreIfNull] public virtual ImmutableDictionary? DisplayNames { get; set; } /// - /// Gets or sets the unique identifier associated with the current scope. + /// Gets or sets the unique identifier of the scope. /// [BsonId, BsonRequired] public virtual ObjectId Id { get; set; } /// - /// Gets or sets the unique name associated with the current scope. + /// Gets or sets the unique name of the scope. /// [BsonElement("name"), BsonIgnoreIfNull] public virtual string? Name { get; set; } /// - /// Gets or sets the additional properties associated with the current scope. + /// Gets or sets the additional properties of the scope. /// [BsonElement("properties"), BsonIgnoreIfNull] public virtual BsonDocument? Properties { get; set; } /// - /// Gets or sets the resources associated with the current scope. + /// Gets or sets the resources associated with the scope. /// [BsonElement("resources"), BsonIgnoreIfNull] public virtual ImmutableArray? Resources { get; set; } diff --git a/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbToken.cs b/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbToken.cs index f566ef68..063759a6 100644 --- a/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbToken.cs +++ b/src/OpenIddict.MongoDb.Models/OpenIddictMongoDbToken.cs @@ -15,84 +15,87 @@ namespace OpenIddict.MongoDb.Models; public class OpenIddictMongoDbToken { /// - /// Gets or sets the identifier of the application associated with the current token. + /// Gets or sets the identifier of the application associated with the token. /// [BsonElement("application_id"), BsonIgnoreIfDefault] public virtual ObjectId ApplicationId { get; set; } /// - /// Gets or sets the identifier of the authorization associated with the current token. + /// Gets or sets the identifier of the authorization associated with the token. /// [BsonElement("authorization_id"), BsonIgnoreIfDefault] public virtual ObjectId AuthorizationId { get; set; } /// - /// Gets or sets the concurrency token. + /// Gets or sets the concurrency token of the token. /// [BsonElement("concurrency_token"), BsonIgnoreIfNull] public virtual string? ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); /// - /// Gets or sets the UTC creation date of the current token. + /// Gets or sets the UTC creation date of the token. /// [BsonElement("creation_date"), BsonIgnoreIfNull] public virtual DateTime? CreationDate { get; set; } /// - /// Gets or sets the UTC expiration date of the current token. + /// Gets or sets the UTC expiration date of the token. /// [BsonElement("expiration_date"), BsonIgnoreIfNull] public virtual DateTime? ExpirationDate { get; set; } /// - /// Gets or sets the unique identifier associated with the current token. + /// Gets or sets the unique identifier of the token. /// [BsonId, BsonRequired] public virtual ObjectId Id { get; set; } /// - /// Gets or sets the payload of the current token, if applicable. - /// Note: this property is only used for reference tokens - /// and may be encrypted for security reasons. + /// Gets or sets the payload of the token. /// + /// + /// Note: this property is only used for reference tokens + /// and may be hashed or encrypted for security reasons. + /// [BsonElement("payload"), BsonIgnoreIfNull] public virtual string? Payload { get; set; } /// - /// Gets or sets the additional properties associated with the current token. + /// Gets or sets the additional properties associated with the token. /// [BsonElement("properties"), BsonIgnoreIfNull] public virtual BsonDocument? Properties { get; set; } /// - /// Gets or sets the UTC redemption date of the current token. + /// Gets or sets the UTC redemption date of the token. /// [BsonElement("redemption_date"), BsonIgnoreIfNull] public virtual DateTime? RedemptionDate { get; set; } /// - /// Gets or sets the reference identifier associated - /// with the current token, if applicable. + /// Gets or sets the reference identifier associated with the token. + /// + /// /// Note: this property is only used for reference tokens /// and may be hashed or encrypted for security reasons. - /// + /// [BsonElement("reference_id"), BsonIgnoreIfNull] public virtual string? ReferenceId { get; set; } /// - /// Gets or sets the status of the current token. + /// Gets or sets the status of the token. /// [BsonElement("status"), BsonIgnoreIfNull] public virtual string? Status { get; set; } /// - /// Gets or sets the subject associated with the current token. + /// Gets or sets the subject associated with the token. /// [BsonElement("subject"), BsonIgnoreIfNull] public virtual string? Subject { get; set; } /// - /// Gets or sets the type of the current token. + /// Gets or sets the type of the token. /// [BsonElement("type"), BsonIgnoreIfNull] public virtual string? Type { get; set; } diff --git a/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbApplicationStore.cs b/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbApplicationStore.cs index a6174f00..a80b3735 100644 --- a/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbApplicationStore.cs +++ b/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbApplicationStore.cs @@ -263,12 +263,7 @@ public class OpenIddictMongoDbApplicationStore< { ArgumentNullException.ThrowIfNull(application); - if (application.JsonWebKeySet is null) - { - return new(result: null); - } - - return new(JsonWebKeySet.Create(application.JsonWebKeySet.ToJson())); + return new(application.JsonWebKeySet is BsonDocument set ? JsonWebKeySet.Create(set.ToJson()) : null); } /// diff --git a/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs b/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs index 6adaa4de..b350b43c 100644 --- a/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs +++ b/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs @@ -211,12 +211,7 @@ public class OpenIddictMongoDbAuthorizationStore< { ArgumentNullException.ThrowIfNull(authorization); - if (authorization.ApplicationId == ObjectId.Empty) - { - return new(result: null); - } - - return new(authorization.ApplicationId.ToString()); + return new(authorization.ApplicationId != ObjectId.Empty ? authorization.ApplicationId.ToString() : null); } /// @@ -237,12 +232,7 @@ public class OpenIddictMongoDbAuthorizationStore< { ArgumentNullException.ThrowIfNull(authorization); - if (authorization.CreationDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(authorization.CreationDate.Value, DateTimeKind.Utc)); + return new(authorization.CreationDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// diff --git a/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs b/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs index ec935d4c..541c18e4 100644 --- a/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs +++ b/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs @@ -226,12 +226,7 @@ public class OpenIddictMongoDbTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.ApplicationId == ObjectId.Empty) - { - return new(result: null); - } - - return new(token.ApplicationId.ToString()); + return new(token.ApplicationId != ObjectId.Empty ? token.ApplicationId.ToString() : null); } /// @@ -252,12 +247,7 @@ public class OpenIddictMongoDbTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.AuthorizationId == ObjectId.Empty) - { - return new(result: null); - } - - return new(token.AuthorizationId.ToString()); + return new(token.AuthorizationId != ObjectId.Empty ? token.AuthorizationId.ToString() : null); } /// @@ -265,12 +255,7 @@ public class OpenIddictMongoDbTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.CreationDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(token.CreationDate.Value, DateTimeKind.Utc)); + return new(token.CreationDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// @@ -278,12 +263,7 @@ public class OpenIddictMongoDbTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.ExpirationDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(token.ExpirationDate.Value, DateTimeKind.Utc)); + return new(token.ExpirationDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } /// @@ -328,12 +308,7 @@ public class OpenIddictMongoDbTokenStore< { ArgumentNullException.ThrowIfNull(token); - if (token.RedemptionDate is null) - { - return new(result: null); - } - - return new(DateTime.SpecifyKind(token.RedemptionDate.Value, DateTimeKind.Utc)); + return new(token.RedemptionDate is DateTime date ? DateTime.SpecifyKind(date, DateTimeKind.Utc) : null); } ///