74 changed files with 5806 additions and 3782 deletions
@ -0,0 +1,75 @@ |
|||||
|
using System; |
||||
|
using System.Runtime.Serialization; |
||||
|
|
||||
|
namespace OpenIddict.Abstractions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents an OpenIddict exception.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictException : Exception |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Creates a new <see cref="OpenIddictException"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="reason">The reason of the exception.</param>
|
||||
|
/// <param name="message">The exception message.</param>
|
||||
|
public OpenIddictException(string reason, string message) |
||||
|
: base(message) |
||||
|
{ |
||||
|
Reason = reason; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creates a new <see cref="OpenIddictException"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="reason">The reason of the exception.</param>
|
||||
|
/// <param name="message">The exception message.</param>
|
||||
|
/// <param name="innerException">The inner exception.</param>
|
||||
|
public OpenIddictException(string reason, string message, Exception innerException) |
||||
|
: base(message, innerException) |
||||
|
{ |
||||
|
Reason = reason; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Creates a new <see cref="OpenIddictException"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="info">
|
||||
|
/// The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.
|
||||
|
/// </param>
|
||||
|
/// <param name="context">
|
||||
|
/// The <see cref="StreamingContext"/> that contains contextual information about the source or destination.
|
||||
|
/// </param>
|
||||
|
protected OpenIddictException(SerializationInfo info, StreamingContext context) |
||||
|
: base(info, context) |
||||
|
{ |
||||
|
Reason = info.GetString(nameof(Reason)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the reason that caused the exception to be thrown.
|
||||
|
/// </summary>
|
||||
|
public string Reason { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Serializes the members of this class.
|
||||
|
/// </summary>
|
||||
|
/// <param name="info">
|
||||
|
/// The <see cref="SerializationInfo"/> that holds the serialized object data about the exception being thrown.
|
||||
|
/// </param>
|
||||
|
/// <param name="context">
|
||||
|
/// The <see cref="StreamingContext"/> that contains contextual information about the source or destination.
|
||||
|
/// </param>
|
||||
|
public override void GetObjectData(SerializationInfo info, StreamingContext context) |
||||
|
{ |
||||
|
if (info == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(info)); |
||||
|
} |
||||
|
|
||||
|
info.AddValue(nameof(Reason), Reason); |
||||
|
|
||||
|
base.GetObjectData(info, context); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,105 @@ |
|||||
|
/* |
||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
* See https://github.com/openiddict/openiddict-core for more information concerning
|
||||
|
* the license and the contributors participating to this project. |
||||
|
*/ |
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace OpenIddict.EntityFramework.Models |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents an OpenIddict application.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictApplication : OpenIddictApplication<string, OpenIddictAuthorization, OpenIddictToken> |
||||
|
{ |
||||
|
public OpenIddictApplication() |
||||
|
{ |
||||
|
// Generate a new string identifier.
|
||||
|
Id = Guid.NewGuid().ToString(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Represents an OpenIddict application.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictApplication<TKey, TAuthorization, TToken> where TKey : IEquatable<TKey> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets the list of the authorizations associated with this application.
|
||||
|
/// </summary>
|
||||
|
public virtual IList<TAuthorization> Authorizations { get; } = new List<TAuthorization>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the client identifier
|
||||
|
/// associated with the current application.
|
||||
|
/// </summary>
|
||||
|
public virtual string ClientId { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 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.
|
||||
|
/// </summary>
|
||||
|
public virtual string ClientSecret { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the concurrency token.
|
||||
|
/// </summary>
|
||||
|
public virtual string ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the consent type
|
||||
|
/// associated with the current application.
|
||||
|
/// </summary>
|
||||
|
public virtual string ConsentType { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the display name
|
||||
|
/// associated with the current application.
|
||||
|
/// </summary>
|
||||
|
public virtual string DisplayName { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the unique identifier
|
||||
|
/// associated with the current application.
|
||||
|
/// </summary>
|
||||
|
public virtual TKey Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the permissions associated with the
|
||||
|
/// current application, serialized as a JSON array.
|
||||
|
/// </summary>
|
||||
|
public virtual string Permissions { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the logout callback URLs associated with
|
||||
|
/// the current application, serialized as a JSON array.
|
||||
|
/// </summary>
|
||||
|
public virtual string PostLogoutRedirectUris { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the additional properties serialized as a JSON object,
|
||||
|
/// or <c>null</c> if no bag was associated with the current application.
|
||||
|
/// </summary>
|
||||
|
public virtual string Properties { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the callback URLs associated with the
|
||||
|
/// current application, serialized as a JSON array.
|
||||
|
/// </summary>
|
||||
|
public virtual string RedirectUris { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the list of the tokens associated with this application.
|
||||
|
/// </summary>
|
||||
|
public virtual IList<TToken> Tokens { get; } = new List<TToken>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the application type
|
||||
|
/// associated with the current application.
|
||||
|
/// </summary>
|
||||
|
public virtual string Type { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,77 @@ |
|||||
|
/* |
||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
* See https://github.com/openiddict/openiddict-core for more information concerning
|
||||
|
* the license and the contributors participating to this project. |
||||
|
*/ |
||||
|
|
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace OpenIddict.EntityFramework.Models |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents an OpenIddict authorization.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictAuthorization : OpenIddictAuthorization<string, OpenIddictApplication, OpenIddictToken> |
||||
|
{ |
||||
|
public OpenIddictAuthorization() |
||||
|
{ |
||||
|
// Generate a new string identifier.
|
||||
|
Id = Guid.NewGuid().ToString(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Represents an OpenIddict authorization.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictAuthorization<TKey, TApplication, TToken> where TKey : IEquatable<TKey> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the application associated with the current authorization.
|
||||
|
/// </summary>
|
||||
|
public virtual TApplication Application { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the concurrency token.
|
||||
|
/// </summary>
|
||||
|
public virtual string ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the unique identifier
|
||||
|
/// associated with the current authorization.
|
||||
|
/// </summary>
|
||||
|
public virtual TKey Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the additional properties serialized as a JSON object,
|
||||
|
/// or <c>null</c> if no bag was associated with the current authorization.
|
||||
|
/// </summary>
|
||||
|
public virtual string Properties { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the scopes associated with the current
|
||||
|
/// authorization, serialized as a JSON array.
|
||||
|
/// </summary>
|
||||
|
public virtual string Scopes { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the status of the current authorization.
|
||||
|
/// </summary>
|
||||
|
public virtual string Status { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the subject associated with the current authorization.
|
||||
|
/// </summary>
|
||||
|
public virtual string Subject { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the list of tokens associated with the current authorization.
|
||||
|
/// </summary>
|
||||
|
public virtual IList<TToken> Tokens { get; } = new List<TToken>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the type of the current authorization.
|
||||
|
/// </summary>
|
||||
|
public virtual string Type { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,97 @@ |
|||||
|
/* |
||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
* See https://github.com/openiddict/openiddict-core for more information concerning
|
||||
|
* the license and the contributors participating to this project. |
||||
|
*/ |
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace OpenIddict.EntityFramework.Models |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents an OpenIddict token.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictToken : OpenIddictToken<string, OpenIddictApplication, OpenIddictAuthorization> |
||||
|
{ |
||||
|
public OpenIddictToken() |
||||
|
{ |
||||
|
// Generate a new string identifier.
|
||||
|
Id = Guid.NewGuid().ToString(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Represents an OpenIddict token.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictToken<TKey, TApplication, TAuthorization> where TKey : IEquatable<TKey> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the application associated with the current token.
|
||||
|
/// </summary>
|
||||
|
public virtual TApplication Application { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the authorization associated with the current token.
|
||||
|
/// </summary>
|
||||
|
public virtual TAuthorization Authorization { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the concurrency token.
|
||||
|
/// </summary>
|
||||
|
public virtual string ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the date on which the token
|
||||
|
/// will start to be considered valid.
|
||||
|
/// </summary>
|
||||
|
public virtual DateTimeOffset? CreationDate { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the date on which the token
|
||||
|
/// will no longer be considered valid.
|
||||
|
/// </summary>
|
||||
|
public virtual DateTimeOffset? ExpirationDate { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the unique identifier
|
||||
|
/// associated with the current token.
|
||||
|
/// </summary>
|
||||
|
public virtual TKey Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 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.
|
||||
|
/// </summary>
|
||||
|
public virtual string Payload { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the additional properties serialized as a JSON object,
|
||||
|
/// or <c>null</c> if no bag was associated with the current token.
|
||||
|
/// </summary>
|
||||
|
public virtual string Properties { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the reference identifier associated
|
||||
|
/// with the current token, if applicable.
|
||||
|
/// Note: this property is only used for reference tokens
|
||||
|
/// and may be hashed or encrypted for security reasons.
|
||||
|
/// </summary>
|
||||
|
public virtual string ReferenceId { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the status of the current token.
|
||||
|
/// </summary>
|
||||
|
public virtual string Status { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the subject associated with the current token.
|
||||
|
/// </summary>
|
||||
|
public virtual string Subject { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the type of the current token.
|
||||
|
/// </summary>
|
||||
|
public virtual string Type { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,111 @@ |
|||||
|
/* |
||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
* See https://github.com/openiddict/openiddict-core for more information concerning
|
||||
|
* the license and the contributors participating to this project. |
||||
|
*/ |
||||
|
|
||||
|
using System; |
||||
|
using System.ComponentModel; |
||||
|
using System.Data.Entity; |
||||
|
using JetBrains.Annotations; |
||||
|
using OpenIddict.Core; |
||||
|
using OpenIddict.EntityFramework; |
||||
|
using OpenIddict.EntityFramework.Models; |
||||
|
|
||||
|
namespace Microsoft.Extensions.DependencyInjection |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Exposes the necessary methods required to configure the OpenIddict Entity Framework 6.x services.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictEntityFrameworkBuilder |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of <see cref="OpenIddictEntityFrameworkBuilder"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="services">The services collection.</param>
|
||||
|
public OpenIddictEntityFrameworkBuilder([NotNull] IServiceCollection services) |
||||
|
{ |
||||
|
if (services == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(services)); |
||||
|
} |
||||
|
|
||||
|
Services = services; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the services collection.
|
||||
|
/// </summary>
|
||||
|
[EditorBrowsable(EditorBrowsableState.Never)] |
||||
|
public IServiceCollection Services { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Amends the default OpenIddict Entity Framework 6.x configuration.
|
||||
|
/// </summary>
|
||||
|
/// <param name="configuration">The delegate used to configure the OpenIddict options.</param>
|
||||
|
/// <remarks>This extension can be safely called multiple times.</remarks>
|
||||
|
/// <returns>The <see cref="OpenIddictEntityFrameworkBuilder"/>.</returns>
|
||||
|
public OpenIddictEntityFrameworkBuilder Configure([NotNull] Action<OpenIddictEntityFrameworkOptions> configuration) |
||||
|
{ |
||||
|
if (configuration == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(configuration)); |
||||
|
} |
||||
|
|
||||
|
Services.Configure(configuration); |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Configures the OpenIddict Entity Framework 6.x stores to use the specified database context type.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TContext">The type of the <see cref="DbContext"/> used by OpenIddict.</typeparam>
|
||||
|
/// <returns>The <see cref="OpenIddictEntityFrameworkBuilder"/>.</returns>
|
||||
|
public OpenIddictEntityFrameworkBuilder UseDbContext<TContext>() |
||||
|
where TContext : DbContext => UseDbContext(typeof(TContext)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Configures the OpenIddict Entity Framework 6.x stores to use the specified database context type.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type of the <see cref="DbContext"/> used by OpenIddict.</param>
|
||||
|
/// <returns>The <see cref="OpenIddictEntityFrameworkBuilder"/>.</returns>
|
||||
|
public OpenIddictEntityFrameworkBuilder UseDbContext([NotNull] Type type) |
||||
|
{ |
||||
|
if (type == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(type)); |
||||
|
} |
||||
|
|
||||
|
if (!typeof(DbContext).IsAssignableFrom(type)) |
||||
|
{ |
||||
|
throw new ArgumentException("The specified type is invalid.", nameof(type)); |
||||
|
} |
||||
|
|
||||
|
return Configure(options => options.ContextType = type); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Configures OpenIddict to use the specified entities, derived
|
||||
|
/// from the default OpenIddict Entity Framework 6.x entities.
|
||||
|
/// </summary>
|
||||
|
/// <returns>The <see cref="OpenIddictEntityFrameworkBuilder"/>.</returns>
|
||||
|
public OpenIddictEntityFrameworkBuilder ReplaceDefaultEntities<TApplication, TAuthorization, TScope, TToken, TKey>() |
||||
|
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>, new() |
||||
|
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>, new() |
||||
|
where TScope : OpenIddictScope<TKey>, new() |
||||
|
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>, new() |
||||
|
where TKey : IEquatable<TKey> |
||||
|
{ |
||||
|
Services.Configure<OpenIddictCoreOptions>(options => |
||||
|
{ |
||||
|
options.DefaultApplicationType = typeof(TApplication); |
||||
|
options.DefaultAuthorizationType = typeof(TAuthorization); |
||||
|
options.DefaultScopeType = typeof(TScope); |
||||
|
options.DefaultTokenType = typeof(TToken); |
||||
|
}); |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
/* |
||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
* See https://github.com/openiddict/openiddict-core for more information concerning
|
||||
|
* the license and the contributors participating to this project. |
||||
|
*/ |
||||
|
|
||||
|
using System; |
||||
|
using System.Data.Entity; |
||||
|
|
||||
|
namespace OpenIddict.EntityFramework |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Provides various settings needed to configure
|
||||
|
/// the OpenIddict Entity Framework 6.x integration.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictEntityFrameworkOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the concrete type of the <see cref="DbContext"/> used by the
|
||||
|
/// OpenIddict Entity Framework 6.x stores. If this property is not populated,
|
||||
|
/// an exception is thrown at runtime when trying to use the stores.
|
||||
|
/// </summary>
|
||||
|
public Type ContextType { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
|
||||
|
<Import Project="..\..\build\packages.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>netstandard2.0</TargetFramework> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<Description>Relational entities for the Entity Framework Core stores.</Description> |
||||
|
<Authors>Kévin Chalet</Authors> |
||||
|
<PackageTags>aspnetcore;authentication;jwt;openidconnect;openiddict;security</PackageTags> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,69 @@ |
|||||
|
/* |
||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
* See https://github.com/openiddict/openiddict-core for more information concerning
|
||||
|
* the license and the contributors participating to this project. |
||||
|
*/ |
||||
|
|
||||
|
using System; |
||||
|
|
||||
|
namespace OpenIddict.EntityFrameworkCore.Models |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents an OpenIddict scope.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictScope : OpenIddictScope<string> |
||||
|
{ |
||||
|
public OpenIddictScope() |
||||
|
{ |
||||
|
// Generate a new string identifier.
|
||||
|
Id = Guid.NewGuid().ToString(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Represents an OpenIddict scope.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictScope<TKey> where TKey : IEquatable<TKey> |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the concurrency token.
|
||||
|
/// </summary>
|
||||
|
public virtual string ConcurrencyToken { get; set; } = Guid.NewGuid().ToString(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the public description
|
||||
|
/// associated with the current scope.
|
||||
|
/// </summary>
|
||||
|
public virtual string Description { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the display name
|
||||
|
/// associated with the current scope.
|
||||
|
/// </summary>
|
||||
|
public virtual string DisplayName { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the unique identifier
|
||||
|
/// associated with the current scope.
|
||||
|
/// </summary>
|
||||
|
public virtual TKey Id { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the unique name
|
||||
|
/// associated with the current scope.
|
||||
|
/// </summary>
|
||||
|
public virtual string Name { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the additional properties serialized as a JSON object,
|
||||
|
/// or <c>null</c> if no bag was associated with the current scope.
|
||||
|
/// </summary>
|
||||
|
public virtual string Properties { get; set; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets or sets the resources associated with the
|
||||
|
/// current scope, serialized as a JSON array.
|
||||
|
/// </summary>
|
||||
|
public virtual string Resources { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,123 @@ |
|||||
|
/* |
||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
* See https://github.com/openiddict/openiddict-core for more information concerning
|
||||
|
* the license and the contributors participating to this project. |
||||
|
*/ |
||||
|
|
||||
|
using System; |
||||
|
using System.ComponentModel; |
||||
|
using JetBrains.Annotations; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using OpenIddict.Core; |
||||
|
using OpenIddict.EntityFrameworkCore; |
||||
|
using OpenIddict.EntityFrameworkCore.Models; |
||||
|
|
||||
|
namespace Microsoft.Extensions.DependencyInjection |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Exposes the necessary methods required to configure the OpenIddict Entity Framework Core services.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictEntityFrameworkCoreBuilder |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of <see cref="OpenIddictEntityFrameworkCoreBuilder"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="services">The services collection.</param>
|
||||
|
public OpenIddictEntityFrameworkCoreBuilder([NotNull] IServiceCollection services) |
||||
|
{ |
||||
|
if (services == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(services)); |
||||
|
} |
||||
|
|
||||
|
Services = services; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Gets the services collection.
|
||||
|
/// </summary>
|
||||
|
[EditorBrowsable(EditorBrowsableState.Never)] |
||||
|
public IServiceCollection Services { get; } |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Amends the default OpenIddict Entity Framework Core configuration.
|
||||
|
/// </summary>
|
||||
|
/// <param name="configuration">The delegate used to configure the OpenIddict options.</param>
|
||||
|
/// <remarks>This extension can be safely called multiple times.</remarks>
|
||||
|
/// <returns>The <see cref="OpenIddictEntityFrameworkCoreBuilder"/>.</returns>
|
||||
|
public OpenIddictEntityFrameworkCoreBuilder Configure([NotNull] Action<OpenIddictEntityFrameworkCoreOptions> configuration) |
||||
|
{ |
||||
|
if (configuration == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(configuration)); |
||||
|
} |
||||
|
|
||||
|
Services.Configure(configuration); |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Configures the OpenIddict Entity Framework Core stores to use the specified database context type.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="TContext">The type of the <see cref="DbContext"/> used by OpenIddict.</typeparam>
|
||||
|
/// <returns>The <see cref="OpenIddictEntityFrameworkCoreBuilder"/>.</returns>
|
||||
|
public OpenIddictEntityFrameworkCoreBuilder UseDbContext<TContext>() |
||||
|
where TContext : DbContext => UseDbContext(typeof(TContext)); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Configures the OpenIddict Entity Framework Core stores to use the specified database context type.
|
||||
|
/// </summary>
|
||||
|
/// <param name="type">The type of the <see cref="DbContext"/> used by OpenIddict.</param>
|
||||
|
/// <returns>The <see cref="OpenIddictEntityFrameworkCoreBuilder"/>.</returns>
|
||||
|
public OpenIddictEntityFrameworkCoreBuilder UseDbContext([NotNull] Type type) |
||||
|
{ |
||||
|
if (type == null) |
||||
|
{ |
||||
|
throw new ArgumentNullException(nameof(type)); |
||||
|
} |
||||
|
|
||||
|
if (!typeof(DbContext).IsAssignableFrom(type)) |
||||
|
{ |
||||
|
throw new ArgumentException("The specified type is invalid.", nameof(type)); |
||||
|
} |
||||
|
|
||||
|
return Configure(options => options.ContextType = type); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Configures OpenIddict to use the default OpenIddict
|
||||
|
/// Entity Framework Core entities, with the specified key type.
|
||||
|
/// </summary>
|
||||
|
/// <returns>The <see cref="OpenIddictEntityFrameworkCoreBuilder"/>.</returns>
|
||||
|
public OpenIddictEntityFrameworkCoreBuilder ReplaceDefaultEntities<TKey>() |
||||
|
where TKey : IEquatable<TKey> |
||||
|
=> ReplaceDefaultEntities<OpenIddictApplication<TKey>, |
||||
|
OpenIddictAuthorization<TKey>, |
||||
|
OpenIddictScope<TKey>, |
||||
|
OpenIddictToken<TKey>, TKey>(); |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Configures OpenIddict to use the specified entities, derived
|
||||
|
/// from the default OpenIddict Entity Framework Core entities.
|
||||
|
/// </summary>
|
||||
|
/// <returns>The <see cref="OpenIddictEntityFrameworkCoreBuilder"/>.</returns>
|
||||
|
public OpenIddictEntityFrameworkCoreBuilder ReplaceDefaultEntities<TApplication, TAuthorization, TScope, TToken, TKey>() |
||||
|
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>, new() |
||||
|
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>, new() |
||||
|
where TScope : OpenIddictScope<TKey>, new() |
||||
|
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>, new() |
||||
|
where TKey : IEquatable<TKey> |
||||
|
{ |
||||
|
Services.Configure<OpenIddictCoreOptions>(options => |
||||
|
{ |
||||
|
options.DefaultApplicationType = typeof(TApplication); |
||||
|
options.DefaultAuthorizationType = typeof(TAuthorization); |
||||
|
options.DefaultScopeType = typeof(TScope); |
||||
|
options.DefaultTokenType = typeof(TToken); |
||||
|
}); |
||||
|
|
||||
|
return this; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
/* |
||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
* See https://github.com/openiddict/openiddict-core for more information concerning
|
||||
|
* the license and the contributors participating to this project. |
||||
|
*/ |
||||
|
|
||||
|
using System; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
|
||||
|
namespace OpenIddict.EntityFrameworkCore |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Provides various settings needed to configure
|
||||
|
/// the OpenIddict Entity Framework Core integration.
|
||||
|
/// </summary>
|
||||
|
public class OpenIddictEntityFrameworkCoreOptions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets or sets the concrete type of the <see cref="DbContext"/> used by the
|
||||
|
/// OpenIddict Entity Framework Core stores. If this property is not populated,
|
||||
|
/// an exception is thrown at runtime when trying to use the stores.
|
||||
|
/// </summary>
|
||||
|
public Type ContextType { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -1,25 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<Import Project="..\..\build\packages.props" /> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFramework>netstandard2.0</TargetFramework> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<Description>Default base stores for OpenIddict.</Description> |
|
||||
<Authors>Kévin Chalet</Authors> |
|
||||
<PackageTags>aspnetcore;authentication;jwt;openidconnect;openiddict;security</PackageTags> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<ProjectReference Include="..\OpenIddict.Abstractions\OpenIddict.Abstractions.csproj" /> |
|
||||
<ProjectReference Include="..\OpenIddict.Models\OpenIddict.Models.csproj" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="JetBrains.Annotations" Version="$(JetBrainsVersion)" PrivateAssets="All" /> |
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="$(AspNetCoreVersion)" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
@ -1,832 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Immutable; |
|
||||
using System.ComponentModel; |
|
||||
using System.Linq; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
using Newtonsoft.Json; |
|
||||
using Newtonsoft.Json.Linq; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.Models; |
|
||||
|
|
||||
namespace OpenIddict.Stores |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides methods allowing to manage the applications stored in a database.
|
|
||||
/// Note: this base class can only be used with the default OpenIddict entities.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|
||||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|
||||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|
||||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|
||||
public abstract class OpenIddictApplicationStore<TApplication, TAuthorization, TToken, TKey> : IOpenIddictApplicationStore<TApplication> |
|
||||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>, new() |
|
||||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>, new() |
|
||||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>, new() |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
protected OpenIddictApplicationStore([NotNull] IMemoryCache cache) |
|
||||
{ |
|
||||
if (cache == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(cache)); |
|
||||
} |
|
||||
|
|
||||
Cache = cache; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the memory cached associated with the current store.
|
|
||||
/// </summary>
|
|
||||
protected IMemoryCache Cache { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of applications that exist in the database.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of applications in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<long> CountAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
return CountAsync(applications => applications, cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of applications that match the specified query.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of applications that match the specified query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TApplication>, IQueryable<TResult>> query, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Creates a new application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application to create.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task CreateAsync([NotNull] TApplication application, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Removes an existing application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application to delete.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task DeleteAsync([NotNull] TApplication application, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves an application using its unique identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The unique identifier associated with the application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the client application corresponding to the identifier.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<TApplication> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TApplication> Query(IQueryable<TApplication> applications, TKey key) |
|
||||
=> from application in applications |
|
||||
where application.Id.Equals(key) |
|
||||
select application; |
|
||||
|
|
||||
return GetAsync((applications, key) => Query(applications, key), ConvertIdentifierFromString(identifier), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves an application using its client identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The client identifier associated with the application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the client application corresponding to the identifier.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<TApplication> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TApplication> Query(IQueryable<TApplication> applications, string id) |
|
||||
=> from application in applications |
|
||||
where application.ClientId == id |
|
||||
select application; |
|
||||
|
|
||||
return GetAsync((applications, id) => Query(applications, id), identifier, cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves all the applications associated with the specified post_logout_redirect_uri.
|
|
||||
/// </summary>
|
|
||||
/// <param name="address">The post_logout_redirect_uri associated with the applications.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
|
|
||||
/// returns the client applications corresponding to the specified post_logout_redirect_uri.
|
|
||||
/// </returns>
|
|
||||
public virtual async Task<ImmutableArray<TApplication>> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(address)) |
|
||||
{ |
|
||||
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); |
|
||||
} |
|
||||
|
|
||||
// To optimize the efficiency of the query a bit, only applications whose stringified
|
|
||||
// PostLogoutRedirectUris contains the specified URL 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.
|
|
||||
IQueryable<TApplication> Query(IQueryable<TApplication> applications, string uri) |
|
||||
=> from application in applications |
|
||||
where application.PostLogoutRedirectUris.Contains(uri) |
|
||||
select application; |
|
||||
|
|
||||
var builder = ImmutableArray.CreateBuilder<TApplication>(); |
|
||||
|
|
||||
foreach (var application in await ListAsync((applications, uri) => Query(applications, uri), address, cancellationToken)) |
|
||||
{ |
|
||||
foreach (var uri in await GetPostLogoutRedirectUrisAsync(application, cancellationToken)) |
|
||||
{ |
|
||||
// Note: the post_logout_redirect_uri must be compared
|
|
||||
// using case-sensitive "Simple String Comparison".
|
|
||||
if (string.Equals(uri, address, StringComparison.Ordinal)) |
|
||||
{ |
|
||||
builder.Add(application); |
|
||||
|
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return builder.Count == builder.Capacity ? |
|
||||
builder.MoveToImmutable() : |
|
||||
builder.ToImmutable(); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves all the applications associated with the specified redirect_uri.
|
|
||||
/// </summary>
|
|
||||
/// <param name="address">The redirect_uri associated with the applications.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation, whose result
|
|
||||
/// returns the client applications corresponding to the specified redirect_uri.
|
|
||||
/// </returns>
|
|
||||
public virtual async Task<ImmutableArray<TApplication>> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(address)) |
|
||||
{ |
|
||||
throw new ArgumentException("The address cannot be null or empty.", nameof(address)); |
|
||||
} |
|
||||
|
|
||||
// To optimize the efficiency of the query a bit, only applications whose stringified
|
|
||||
// RedirectUris property contains the specified URL 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.
|
|
||||
IQueryable<TApplication> Query(IQueryable<TApplication> applications, string uri) |
|
||||
=> from application in applications |
|
||||
where application.RedirectUris.Contains(uri) |
|
||||
select application; |
|
||||
|
|
||||
var builder = ImmutableArray.CreateBuilder<TApplication>(); |
|
||||
|
|
||||
foreach (var application in await ListAsync((applications, uri) => Query(applications, uri), address, cancellationToken)) |
|
||||
{ |
|
||||
foreach (var uri in await GetRedirectUrisAsync(application, cancellationToken)) |
|
||||
{ |
|
||||
// Note: the redirect_uri must be compared using case-sensitive "Simple String Comparison".
|
|
||||
// See http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest for more information.
|
|
||||
if (string.Equals(uri, address, StringComparison.Ordinal)) |
|
||||
{ |
|
||||
builder.Add(application); |
|
||||
|
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return builder.Count == builder.Capacity ? |
|
||||
builder.MoveToImmutable() : |
|
||||
builder.ToImmutable(); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns the first element.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the first element returned when executing the query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<TResult> GetAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the client identifier associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the client identifier associated with the application.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetClientIdAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(application.ClientId); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the client secret associated with an application.
|
|
||||
/// Note: depending on the manager used to create the application,
|
|
||||
/// the client secret may be hashed for security reasons.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the client secret associated with the application.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetClientSecretAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(application.ClientSecret); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the client type associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the client type of the application (by default, "public").
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetClientTypeAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(application.Type); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the consent type associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the consent type of the application (by default, "explicit").
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetConsentTypeAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(application.ConsentType); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the display name associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the display name associated with the application.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetDisplayNameAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(application.DisplayName); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the unique identifier associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the unique identifier associated with the application.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetIdAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(ConvertIdentifierToString(application.Id)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the permissions associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the permissions associated with the application.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<ImmutableArray<string>> GetPermissionsAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(application.Permissions)) |
|
||||
{ |
|
||||
return new ValueTask<ImmutableArray<string>>(ImmutableArray.Create<string>()); |
|
||||
} |
|
||||
|
|
||||
// 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)); |
|
||||
|
|
||||
return JArray.Parse(application.Permissions) |
|
||||
.Select(element => (string) element) |
|
||||
.ToImmutableArray(); |
|
||||
}); |
|
||||
|
|
||||
return new ValueTask<ImmutableArray<string>>(permissions); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the logout callback addresses associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the post_logout_redirect_uri associated with the application.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<ImmutableArray<string>> GetPostLogoutRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(application.PostLogoutRedirectUris)) |
|
||||
{ |
|
||||
return new ValueTask<ImmutableArray<string>>(ImmutableArray.Create<string>()); |
|
||||
} |
|
||||
|
|
||||
// Note: parsing the stringified addresses 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 addresses = Cache.GetOrCreate(key, entry => |
|
||||
{ |
|
||||
entry.SetPriority(CacheItemPriority.High) |
|
||||
.SetSlidingExpiration(TimeSpan.FromMinutes(1)); |
|
||||
|
|
||||
return JArray.Parse(application.PostLogoutRedirectUris) |
|
||||
.Select(element => (string) element) |
|
||||
.ToImmutableArray(); |
|
||||
}); |
|
||||
|
|
||||
return new ValueTask<ImmutableArray<string>>(addresses); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the additional properties associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the additional properties associated with the application.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<JObject> GetPropertiesAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(application.Properties)) |
|
||||
{ |
|
||||
return new ValueTask<JObject>(new JObject()); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<JObject>(JObject.Parse(application.Properties)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the callback addresses associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the redirect_uri associated with the application.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<ImmutableArray<string>> GetRedirectUrisAsync([NotNull] TApplication application, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(application.RedirectUris)) |
|
||||
{ |
|
||||
return new ValueTask<ImmutableArray<string>>(ImmutableArray.Create<string>()); |
|
||||
} |
|
||||
|
|
||||
// Note: parsing the stringified addresses 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 addresses = Cache.GetOrCreate(key, entry => |
|
||||
{ |
|
||||
entry.SetPriority(CacheItemPriority.High) |
|
||||
.SetSlidingExpiration(TimeSpan.FromMinutes(1)); |
|
||||
|
|
||||
return JArray.Parse(application.RedirectUris) |
|
||||
.Select(element => (string) element) |
|
||||
.ToImmutableArray(); |
|
||||
}); |
|
||||
|
|
||||
return new ValueTask<ImmutableArray<string>>(addresses); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Instantiates a new application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the instantiated application, that can be persisted in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<TApplication> InstantiateAsync(CancellationToken cancellationToken) |
|
||||
=> new ValueTask<TApplication>(new TApplication()); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <param name="count">The number of results to return.</param>
|
|
||||
/// <param name="offset">The number of results to skip.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the elements returned when executing the specified query.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TApplication>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
IQueryable<TApplication> Query(IQueryable<TApplication> applications, int? skip, int? take) |
|
||||
{ |
|
||||
var query = applications.OrderBy(application => application.Id).AsQueryable(); |
|
||||
|
|
||||
if (skip.HasValue) |
|
||||
{ |
|
||||
query = query.Skip(skip.Value); |
|
||||
} |
|
||||
|
|
||||
if (take.HasValue) |
|
||||
{ |
|
||||
query = query.Take(take.Value); |
|
||||
} |
|
||||
|
|
||||
return query; |
|
||||
} |
|
||||
|
|
||||
return ListAsync((applications, state) => Query(applications, state.offset, state.count), (offset, count), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the elements returned when executing the specified query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<ImmutableArray<TResult>> ListAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TApplication>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the client identifier associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="identifier">The client identifier associated with the application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetClientIdAsync([NotNull] TApplication application, |
|
||||
[CanBeNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
application.ClientId = identifier; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the client secret associated with an application.
|
|
||||
/// Note: depending on the manager used to create the application,
|
|
||||
/// the client secret may be hashed for security reasons.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="secret">The client secret associated with the application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetClientSecretAsync([NotNull] TApplication application, |
|
||||
[CanBeNull] string secret, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
application.ClientSecret = secret; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the client type associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="type">The client type associated with the application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetClientTypeAsync([NotNull] TApplication application, |
|
||||
[CanBeNull] string type, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
application.Type = type; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the consent type associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="type">The consent type associated with the application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetConsentTypeAsync([NotNull] TApplication application, |
|
||||
[CanBeNull] string type, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
application.ConsentType = type; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the display name associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="name">The display name associated with the application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetDisplayNameAsync([NotNull] TApplication application, |
|
||||
[CanBeNull] string name, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
application.DisplayName = name; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the permissions associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="permissions">The permissions associated with the application </param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetPermissionsAsync([NotNull] TApplication application, ImmutableArray<string> permissions, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
if (permissions.IsDefaultOrEmpty) |
|
||||
{ |
|
||||
application.Permissions = null; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
application.Permissions = new JArray(permissions.ToArray()).ToString(Formatting.None); |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the logout callback addresses associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="addresses">The logout callback addresses associated with the application </param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetPostLogoutRedirectUrisAsync([NotNull] TApplication application, |
|
||||
ImmutableArray<string> addresses, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
if (addresses.IsDefaultOrEmpty) |
|
||||
{ |
|
||||
application.PostLogoutRedirectUris = null; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
application.PostLogoutRedirectUris = new JArray(addresses.ToArray()).ToString(Formatting.None); |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the additional properties associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="properties">The additional properties associated with the application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetPropertiesAsync([NotNull] TApplication application, [CanBeNull] JObject properties, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
if (properties == null) |
|
||||
{ |
|
||||
application.Properties = null; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
application.Properties = properties.ToString(Formatting.None); |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the callback addresses associated with an application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application.</param>
|
|
||||
/// <param name="addresses">The callback addresses associated with the application </param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetRedirectUrisAsync([NotNull] TApplication application, |
|
||||
ImmutableArray<string> addresses, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (application == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(application)); |
|
||||
} |
|
||||
|
|
||||
if (addresses.IsDefaultOrEmpty) |
|
||||
{ |
|
||||
application.RedirectUris = null; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
application.RedirectUris = new JArray(addresses.ToArray()).ToString(Formatting.None); |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Updates an existing application.
|
|
||||
/// </summary>
|
|
||||
/// <param name="application">The application to update.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task UpdateAsync([NotNull] TApplication application, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to a strongly typed key object.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns>
|
|
||||
public virtual TKey ConvertIdentifierFromString([CanBeNull] string identifier) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
return (TKey) TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(identifier); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to its string representation.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns>
|
|
||||
public virtual string ConvertIdentifierToString([CanBeNull] TKey identifier) |
|
||||
{ |
|
||||
if (Equals(identifier, default(TKey))) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return TypeDescriptor.GetConverter(typeof(TKey)).ConvertToInvariantString(identifier); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,694 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Immutable; |
|
||||
using System.ComponentModel; |
|
||||
using System.Linq; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
using Newtonsoft.Json; |
|
||||
using Newtonsoft.Json.Linq; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.Models; |
|
||||
|
|
||||
namespace OpenIddict.Stores |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides methods allowing to manage the authorizations stored in a database.
|
|
||||
/// Note: this base class can only be used with the default OpenIddict entities.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|
||||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|
||||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|
||||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|
||||
public abstract class OpenIddictAuthorizationStore<TAuthorization, TApplication, TToken, TKey> : IOpenIddictAuthorizationStore<TAuthorization> |
|
||||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>, new() |
|
||||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>, new() |
|
||||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>, new() |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
protected OpenIddictAuthorizationStore([NotNull] IMemoryCache cache) |
|
||||
{ |
|
||||
if (cache == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(cache)); |
|
||||
} |
|
||||
|
|
||||
Cache = cache; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the memory cached associated with the current store.
|
|
||||
/// </summary>
|
|
||||
protected IMemoryCache Cache { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of authorizations that exist in the database.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of authorizations in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<long> CountAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
return CountAsync(authorizations => authorizations, cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of authorizations that match the specified query.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of authorizations that match the specified query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TAuthorization>, IQueryable<TResult>> query, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Creates a new authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization to create.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task CreateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Removes an existing authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization to delete.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task DeleteAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the authorizations corresponding to the specified
|
|
||||
/// subject and associated with the application identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="client">The client associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the authorizations corresponding to the subject/client.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TAuthorization>> FindAsync( |
|
||||
[NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(subject)) |
|
||||
{ |
|
||||
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(client)) |
|
||||
{ |
|
||||
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations, TKey key, string principal) |
|
||||
=> from authorization in authorizations |
|
||||
where authorization.Application != null && |
|
||||
authorization.Application.Id.Equals(key) && |
|
||||
authorization.Subject == principal |
|
||||
select authorization; |
|
||||
|
|
||||
return ListAsync( |
|
||||
(authorizations, state) => Query(authorizations, state.key, state.principal), |
|
||||
(key: ConvertIdentifierFromString(client), principal: subject), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the authorizations matching the specified parameters.
|
|
||||
/// </summary>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="client">The client associated with the authorization.</param>
|
|
||||
/// <param name="status">The authorization status.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the authorizations corresponding to the criteria.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TAuthorization>> FindAsync( |
|
||||
[NotNull] string subject, [NotNull] string client, |
|
||||
[NotNull] string status, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(subject)) |
|
||||
{ |
|
||||
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(client)) |
|
||||
{ |
|
||||
throw new ArgumentException("The client cannot be null or empty.", nameof(client)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(status)) |
|
||||
{ |
|
||||
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations, TKey key, string principal, string state) |
|
||||
=> from authorization in authorizations |
|
||||
where authorization.Application != null && |
|
||||
authorization.Application.Id.Equals(key) && |
|
||||
authorization.Subject == principal && |
|
||||
authorization.Status == state |
|
||||
select authorization; |
|
||||
|
|
||||
return ListAsync( |
|
||||
(authorizations, state) => Query(authorizations, state.key, state.principal, state.state), |
|
||||
(key: ConvertIdentifierFromString(client), principal: subject, state: status), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the authorizations matching the specified parameters.
|
|
||||
/// </summary>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="client">The client associated with the authorization.</param>
|
|
||||
/// <param name="status">The authorization status.</param>
|
|
||||
/// <param name="type">The authorization type.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the authorizations corresponding to the criteria.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TAuthorization>> FindAsync( |
|
||||
[NotNull] string subject, [NotNull] string client, |
|
||||
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(subject)) |
|
||||
{ |
|
||||
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(client)) |
|
||||
{ |
|
||||
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(status)) |
|
||||
{ |
|
||||
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(type)) |
|
||||
{ |
|
||||
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations, |
|
||||
TKey key, string principal, string state, string kind) |
|
||||
=> from authorization in authorizations |
|
||||
where authorization.Application != null && |
|
||||
authorization.Application.Id.Equals(key) && |
|
||||
authorization.Subject == principal && |
|
||||
authorization.Status == state && |
|
||||
authorization.Type == kind |
|
||||
select authorization; |
|
||||
|
|
||||
return ListAsync( |
|
||||
(authorizations, state) => Query(authorizations, state.key, state.principal, state.state, state.kind), |
|
||||
(key: ConvertIdentifierFromString(client), principal: subject, state: status, kind: type), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves an authorization using its unique identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The unique identifier associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the authorization corresponding to the identifier.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<TAuthorization> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations, TKey key) |
|
||||
=> from authorization in authorizations |
|
||||
where authorization.Id.Equals(key) |
|
||||
select authorization; |
|
||||
|
|
||||
return GetAsync((authorizations, key) => Query(authorizations, key), ConvertIdentifierFromString(identifier), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves all the authorizations corresponding to the specified subject.
|
|
||||
/// </summary>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the authorizations corresponding to the specified subject.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TAuthorization>> FindBySubjectAsync( |
|
||||
[NotNull] string subject, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(subject)) |
|
||||
{ |
|
||||
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations, string principal) |
|
||||
=> from authorization in authorizations |
|
||||
where authorization.Subject == principal |
|
||||
select authorization; |
|
||||
|
|
||||
return ListAsync((authorizations, principal) => Query(authorizations, principal), subject, cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the optional application identifier associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the application identifier associated with the authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetApplicationIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
if (authorization.Application != null) |
|
||||
{ |
|
||||
return new ValueTask<string>(ConvertIdentifierToString(authorization.Application.Id)); |
|
||||
} |
|
||||
|
|
||||
async Task<string> RetrieveApplicationIdAsync() |
|
||||
{ |
|
||||
IQueryable<TKey> Query(IQueryable<TAuthorization> authorizations, TKey key) |
|
||||
=> from element in authorizations |
|
||||
where element.Id.Equals(key) && |
|
||||
element.Application != null |
|
||||
select element.Application.Id; |
|
||||
|
|
||||
return ConvertIdentifierToString(await GetAsync( |
|
||||
(authorizations, key) => Query(authorizations, key), authorization.Id, cancellationToken)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(RetrieveApplicationIdAsync()); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns the first element.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the first element returned when executing the query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<TResult> GetAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the unique identifier associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the unique identifier associated with the authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetIdAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(ConvertIdentifierToString(authorization.Id)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the additional properties associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the additional properties associated with the authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<JObject> GetPropertiesAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(authorization.Properties)) |
|
||||
{ |
|
||||
return new ValueTask<JObject>(new JObject()); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<JObject>(JObject.Parse(authorization.Properties)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the scopes associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the scopes associated with the specified authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<ImmutableArray<string>> GetScopesAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(authorization.Scopes)) |
|
||||
{ |
|
||||
return new ValueTask<ImmutableArray<string>>(ImmutableArray.Create<string>()); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<ImmutableArray<string>>(JArray.Parse(authorization.Scopes).Select(element => (string) element).ToImmutableArray()); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the status associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the status associated with the specified authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetStatusAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(authorization.Status); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the subject associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the subject associated with the specified authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetSubjectAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(authorization.Subject); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the type associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the type associated with the specified authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetTypeAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(authorization.Type); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Instantiates a new authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the instantiated authorization, that can be persisted in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<TAuthorization> InstantiateAsync(CancellationToken cancellationToken) |
|
||||
=> new ValueTask<TAuthorization>(new TAuthorization()); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <param name="count">The number of results to return.</param>
|
|
||||
/// <param name="offset">The number of results to skip.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the elements returned when executing the specified query.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TAuthorization>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
IQueryable<TAuthorization> Query(IQueryable<TAuthorization> authorizations, int? skip, int? take) |
|
||||
{ |
|
||||
var query = authorizations.OrderBy(authorization => authorization.Id).AsQueryable(); |
|
||||
|
|
||||
if (skip.HasValue) |
|
||||
{ |
|
||||
query = query.Skip(skip.Value); |
|
||||
} |
|
||||
|
|
||||
if (take.HasValue) |
|
||||
{ |
|
||||
query = query.Take(take.Value); |
|
||||
} |
|
||||
|
|
||||
return query; |
|
||||
} |
|
||||
|
|
||||
return ListAsync((authorizations, state) => Query(authorizations, state.offset, state.count), (offset, count), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the elements returned when executing the specified query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<ImmutableArray<TResult>> ListAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TAuthorization>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid token attached.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task PruneAsync(CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the application identifier associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="identifier">The unique identifier associated with the client application.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task SetApplicationIdAsync([NotNull] TAuthorization authorization, |
|
||||
[CanBeNull] string identifier, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the additional properties associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="properties">The additional properties associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetPropertiesAsync([NotNull] TAuthorization authorization, [CanBeNull] JObject properties, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
if (properties == null) |
|
||||
{ |
|
||||
authorization.Properties = null; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
authorization.Properties = properties.ToString(Formatting.None); |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the scopes associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="scopes">The scopes associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetScopesAsync([NotNull] TAuthorization authorization, |
|
||||
ImmutableArray<string> scopes, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
if (scopes.IsDefaultOrEmpty) |
|
||||
{ |
|
||||
authorization.Scopes = null; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
authorization.Scopes = new JArray(scopes.ToArray()).ToString(Formatting.None); |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the status associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="status">The status associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetStatusAsync([NotNull] TAuthorization authorization, |
|
||||
[CanBeNull] string status, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
authorization.Status = status; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the subject associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="subject">The subject associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetSubjectAsync([NotNull] TAuthorization authorization, |
|
||||
[CanBeNull] string subject, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
authorization.Subject = subject; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the type associated with an authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization.</param>
|
|
||||
/// <param name="type">The type associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetTypeAsync([NotNull] TAuthorization authorization, |
|
||||
[CanBeNull] string type, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (authorization == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(authorization)); |
|
||||
} |
|
||||
|
|
||||
authorization.Type = type; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Updates an existing authorization.
|
|
||||
/// </summary>
|
|
||||
/// <param name="authorization">The authorization to update.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task UpdateAsync([NotNull] TAuthorization authorization, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to a strongly typed key object.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns>
|
|
||||
public virtual TKey ConvertIdentifierFromString([CanBeNull] string identifier) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
return (TKey) TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(identifier); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to its string representation.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns>
|
|
||||
public virtual string ConvertIdentifierToString([CanBeNull] TKey identifier) |
|
||||
{ |
|
||||
if (Equals(identifier, default(TKey))) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return TypeDescriptor.GetConverter(typeof(TKey)).ConvertToInvariantString(identifier); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,577 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Immutable; |
|
||||
using System.ComponentModel; |
|
||||
using System.Linq; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
using Newtonsoft.Json; |
|
||||
using Newtonsoft.Json.Linq; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.Models; |
|
||||
|
|
||||
namespace OpenIddict.Stores |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides methods allowing to manage the scopes stored in a database.
|
|
||||
/// Note: this base class can only be used with the default OpenIddict entities.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
|
|
||||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|
||||
public abstract class OpenIddictScopeStore<TScope, TKey> : IOpenIddictScopeStore<TScope> |
|
||||
where TScope : OpenIddictScope<TKey>, new() |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
protected OpenIddictScopeStore([NotNull] IMemoryCache cache) |
|
||||
{ |
|
||||
if (cache == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(cache)); |
|
||||
} |
|
||||
|
|
||||
Cache = cache; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the memory cached associated with the current store.
|
|
||||
/// </summary>
|
|
||||
protected IMemoryCache Cache { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of scopes that exist in the database.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of scopes in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<long> CountAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
return CountAsync(scopes => scopes, cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of scopes that match the specified query.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of scopes that match the specified query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TScope>, IQueryable<TResult>> query, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Creates a new scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope to create.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task CreateAsync([NotNull] TScope scope, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Removes an existing scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope to delete.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task DeleteAsync([NotNull] TScope scope, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves a scope using its unique identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The unique identifier associated with the scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the scope corresponding to the identifier.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<TScope> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TScope> Query(IQueryable<TScope> scopes, TKey key) |
|
||||
=> from scope in scopes |
|
||||
where scope.Id.Equals(key) |
|
||||
select scope; |
|
||||
|
|
||||
return GetAsync((scopes, key) => Query(scopes, key), ConvertIdentifierFromString(identifier), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves a scope using its name.
|
|
||||
/// </summary>
|
|
||||
/// <param name="name">The name associated with the scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the scope corresponding to the specified name.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<TScope> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(name)) |
|
||||
{ |
|
||||
throw new ArgumentException("The scope name cannot be null or empty.", nameof(name)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TScope> Query(IQueryable<TScope> scopes, string state) |
|
||||
=> from scope in scopes |
|
||||
where scope.Name == state |
|
||||
select scope; |
|
||||
|
|
||||
return GetAsync((scopes, state) => Query(scopes, state), name, cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves a list of scopes using their name.
|
|
||||
/// </summary>
|
|
||||
/// <param name="names">The names associated with the scopes.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the scopes corresponding to the specified names.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TScope>> FindByNamesAsync( |
|
||||
ImmutableArray<string> names, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (names.Any(name => string.IsNullOrEmpty(name))) |
|
||||
{ |
|
||||
throw new ArgumentException("Scope names cannot be null or empty.", nameof(names)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TScope> Query(IQueryable<TScope> scopes, string[] values) |
|
||||
=> from scope in scopes |
|
||||
where values.Contains(scope.Name) |
|
||||
select scope; |
|
||||
|
|
||||
return ListAsync((scopes, values) => Query(scopes, values), names.ToArray(), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves all the scopes that contain the specified resource.
|
|
||||
/// </summary>
|
|
||||
/// <param name="resource">The resource associated with the scopes.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the scopes associated with the specified resource.
|
|
||||
/// </returns>
|
|
||||
public virtual async Task<ImmutableArray<TScope>> FindByResourceAsync( |
|
||||
[NotNull] string resource, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(resource)) |
|
||||
{ |
|
||||
throw new ArgumentException("The resource cannot be null or empty.", nameof(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.
|
|
||||
IQueryable<TScope> Query(IQueryable<TScope> scopes, string state) |
|
||||
=> from scope in scopes |
|
||||
where scope.Resources.Contains(state) |
|
||||
select scope; |
|
||||
|
|
||||
var builder = ImmutableArray.CreateBuilder<TScope>(); |
|
||||
|
|
||||
foreach (var application in await ListAsync((applications, state) => Query(applications, state), resource, cancellationToken)) |
|
||||
{ |
|
||||
var resources = await GetResourcesAsync(application, cancellationToken); |
|
||||
if (resources.Contains(resource, StringComparer.OrdinalIgnoreCase)) |
|
||||
{ |
|
||||
builder.Add(application); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return builder.ToImmutable(); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns the first element.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the first element returned when executing the query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<TResult> GetAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the description associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the description associated with the specified scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetDescriptionAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(scope.Description); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the display name associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the display name associated with the scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetDisplayNameAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(scope.DisplayName); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the unique identifier associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the unique identifier associated with the scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetIdAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(ConvertIdentifierToString(scope.Id)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the name associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the name associated with the specified scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetNameAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(scope.Name); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the additional properties associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the additional properties associated with the scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<JObject> GetPropertiesAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(scope.Properties)) |
|
||||
{ |
|
||||
return new ValueTask<JObject>(new JObject()); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<JObject>(JObject.Parse(scope.Properties)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the resources associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the resources associated with the scope.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<ImmutableArray<string>> GetResourcesAsync([NotNull] TScope scope, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(scope.Resources)) |
|
||||
{ |
|
||||
return new ValueTask<ImmutableArray<string>>(ImmutableArray.Create<string>()); |
|
||||
} |
|
||||
|
|
||||
// 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)); |
|
||||
|
|
||||
return JArray.Parse(scope.Resources) |
|
||||
.Select(element => (string) element) |
|
||||
.ToImmutableArray(); |
|
||||
}); |
|
||||
|
|
||||
return new ValueTask<ImmutableArray<string>>(resources); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Instantiates a new scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the instantiated scope, that can be persisted in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<TScope> InstantiateAsync(CancellationToken cancellationToken) |
|
||||
=> new ValueTask<TScope>(new TScope()); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <param name="count">The number of results to return.</param>
|
|
||||
/// <param name="offset">The number of results to skip.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the elements returned when executing the specified query.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TScope>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
IQueryable<TScope> Query(IQueryable<TScope> scopes, int? skip, int? take) |
|
||||
{ |
|
||||
var query = scopes.OrderBy(scope => scope.Id).AsQueryable(); |
|
||||
|
|
||||
if (skip.HasValue) |
|
||||
{ |
|
||||
query = query.Skip(skip.Value); |
|
||||
} |
|
||||
|
|
||||
if (take.HasValue) |
|
||||
{ |
|
||||
query = query.Take(take.Value); |
|
||||
} |
|
||||
|
|
||||
return query; |
|
||||
} |
|
||||
|
|
||||
return ListAsync((scopes, state) => Query(scopes, state.offset, state.count), (offset, count), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the elements returned when executing the specified query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<ImmutableArray<TResult>> ListAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TScope>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the description associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="description">The description associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetDescriptionAsync([NotNull] TScope scope, [CanBeNull] string description, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
scope.Description = description; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the display name associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="name">The display name associated with the scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetDisplayNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
scope.DisplayName = name; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the name associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="name">The name associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetNameAsync([NotNull] TScope scope, [CanBeNull] string name, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
scope.Name = name; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the additional properties associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="properties">The additional properties associated with the scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetPropertiesAsync([NotNull] TScope scope, [CanBeNull] JObject properties, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
if (properties == null) |
|
||||
{ |
|
||||
scope.Properties = null; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
scope.Properties = properties.ToString(Formatting.None); |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the resources associated with a scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope.</param>
|
|
||||
/// <param name="resources">The resources associated with the scope.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetResourcesAsync([NotNull] TScope scope, ImmutableArray<string> resources, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (scope == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(scope)); |
|
||||
} |
|
||||
|
|
||||
if (resources.IsDefaultOrEmpty) |
|
||||
{ |
|
||||
scope.Resources = null; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
scope.Resources = new JArray(resources.ToArray()).ToString(Formatting.None); |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Updates an existing scope.
|
|
||||
/// </summary>
|
|
||||
/// <param name="scope">The scope to update.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task UpdateAsync([NotNull] TScope scope, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to a strongly typed key object.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns>
|
|
||||
public virtual TKey ConvertIdentifierFromString([CanBeNull] string identifier) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
return (TKey) TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(identifier); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to its string representation.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns>
|
|
||||
public virtual string ConvertIdentifierToString([CanBeNull] TKey identifier) |
|
||||
{ |
|
||||
if (Equals(identifier, default(TKey))) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return TypeDescriptor.GetConverter(typeof(TKey)).ConvertToInvariantString(identifier); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,805 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Immutable; |
|
||||
using System.ComponentModel; |
|
||||
using System.Linq; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
using JetBrains.Annotations; |
|
||||
using Microsoft.Extensions.Caching.Memory; |
|
||||
using Newtonsoft.Json; |
|
||||
using Newtonsoft.Json.Linq; |
|
||||
using OpenIddict.Abstractions; |
|
||||
using OpenIddict.Models; |
|
||||
|
|
||||
namespace OpenIddict.Stores |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Provides methods allowing to manage the tokens stored in a database.
|
|
||||
/// Note: this base class can only be used with the default OpenIddict entities.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
|
|
||||
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
|
|
||||
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
|
|
||||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|
||||
public abstract class OpenIddictTokenStore<TToken, TApplication, TAuthorization, TKey> : IOpenIddictTokenStore<TToken> |
|
||||
where TToken : OpenIddictToken<TKey, TApplication, TAuthorization>, new() |
|
||||
where TApplication : OpenIddictApplication<TKey, TAuthorization, TToken>, new() |
|
||||
where TAuthorization : OpenIddictAuthorization<TKey, TApplication, TToken>, new() |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
protected OpenIddictTokenStore([NotNull] IMemoryCache cache) |
|
||||
{ |
|
||||
if (cache == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(cache)); |
|
||||
} |
|
||||
|
|
||||
Cache = cache; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Gets the memory cached associated with the current store.
|
|
||||
/// </summary>
|
|
||||
protected IMemoryCache Cache { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of tokens that exist in the database.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of applications in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<long> CountAsync(CancellationToken cancellationToken) |
|
||||
{ |
|
||||
return CountAsync(tokens => tokens, cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Determines the number of tokens that match the specified query.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the number of tokens that match the specified query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<TToken>, IQueryable<TResult>> query, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Creates a new token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token to create.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task CreateAsync([NotNull] TToken token, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Removes a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token to delete.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>A <see cref="Task"/> that can be used to monitor the asynchronous operation.</returns>
|
|
||||
public abstract Task DeleteAsync([NotNull] TToken token, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the list of tokens corresponding to the specified application identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The application identifier associated with the tokens.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the tokens corresponding to the specified application.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TToken>> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TToken> Query(IQueryable<TToken> tokens, TKey key) |
|
||||
=> from token in tokens |
|
||||
where token.Application != null && |
|
||||
token.Application.Id.Equals(key) |
|
||||
select token; |
|
||||
|
|
||||
return ListAsync((tokens, key) => Query(tokens, key), ConvertIdentifierFromString(identifier), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the list of tokens corresponding to the specified authorization identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The authorization identifier associated with the tokens.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the tokens corresponding to the specified authorization.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TToken>> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TToken> Query(IQueryable<TToken> tokens, TKey key) |
|
||||
=> from token in tokens |
|
||||
where token.Authorization != null && |
|
||||
token.Authorization.Id.Equals(key) |
|
||||
select token; |
|
||||
|
|
||||
return ListAsync((tokens, key) => Query(tokens, key), ConvertIdentifierFromString(identifier), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves a token using its unique identifier.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The unique identifier associated with the token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the token corresponding to the unique identifier.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<TToken> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TToken> Query(IQueryable<TToken> tokens, TKey key) |
|
||||
=> from token in tokens |
|
||||
where token.Id.Equals(key) |
|
||||
select token; |
|
||||
|
|
||||
return GetAsync((tokens, key) => Query(tokens, key), ConvertIdentifierFromString(identifier), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the list of tokens corresponding to the specified reference identifier.
|
|
||||
/// Note: the reference identifier may be hashed or encrypted for security reasons.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The reference identifier associated with the tokens.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the tokens corresponding to the specified reference identifier.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<TToken> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
throw new ArgumentException("The identifier cannot be null or empty.", nameof(identifier)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TToken> Query(IQueryable<TToken> tokens, string id) |
|
||||
=> from token in tokens |
|
||||
where token.ReferenceId == id |
|
||||
select token; |
|
||||
|
|
||||
return GetAsync((tokens, id) => Query(tokens, identifier), identifier, cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the list of tokens corresponding to the specified subject.
|
|
||||
/// </summary>
|
|
||||
/// <param name="subject">The subject associated with the tokens.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the tokens corresponding to the specified subject.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TToken>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(subject)) |
|
||||
{ |
|
||||
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
||||
} |
|
||||
|
|
||||
IQueryable<TToken> Query(IQueryable<TToken> tokens, string principal) |
|
||||
=> from token in tokens |
|
||||
where token.Subject == principal |
|
||||
select token; |
|
||||
|
|
||||
return ListAsync((tokens, principal) => Query(tokens, principal), subject, cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns the first element.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the first element returned when executing the query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<TResult> GetAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the optional application identifier associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the application identifier associated with the token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetApplicationIdAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
if (token.Application != null) |
|
||||
{ |
|
||||
return new ValueTask<string>(ConvertIdentifierToString(token.Application.Id)); |
|
||||
} |
|
||||
|
|
||||
async Task<string> RetrieveApplicationIdAsync() |
|
||||
{ |
|
||||
IQueryable<TKey> Query(IQueryable<TToken> tokens, TKey key) |
|
||||
=> from element in tokens |
|
||||
where element.Id.Equals(key) && |
|
||||
element.Application != null |
|
||||
select element.Application.Id; |
|
||||
|
|
||||
return ConvertIdentifierToString(await GetAsync((tokens, key) => Query(tokens, key), token.Id, cancellationToken)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(RetrieveApplicationIdAsync()); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the optional authorization identifier associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the authorization identifier associated with the token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetAuthorizationIdAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
if (token.Authorization != null) |
|
||||
{ |
|
||||
return new ValueTask<string>(ConvertIdentifierToString(token.Authorization.Id)); |
|
||||
} |
|
||||
|
|
||||
async Task<string> RetrieveAuthorizationIdAsync() |
|
||||
{ |
|
||||
IQueryable<TKey> Query(IQueryable<TToken> tokens, TKey key) |
|
||||
=> from element in tokens |
|
||||
where element.Id.Equals(key) && |
|
||||
element.Authorization != null |
|
||||
select element.Authorization.Id; |
|
||||
|
|
||||
return ConvertIdentifierToString(await GetAsync((tokens, key) => Query(tokens, key), token.Id, cancellationToken)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(RetrieveAuthorizationIdAsync()); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the creation date associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the creation date associated with the specified token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<DateTimeOffset?> GetCreationDateAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<DateTimeOffset?>(token.CreationDate); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the expiration date associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the expiration date associated with the specified token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<DateTimeOffset?> GetExpirationDateAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<DateTimeOffset?>(token.ExpirationDate); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the unique identifier associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the unique identifier associated with the token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetIdAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(ConvertIdentifierToString(token.Id)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the payload associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the payload associated with the specified token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetPayloadAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(token.Payload); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the additional properties associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the additional properties associated with the token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<JObject> GetPropertiesAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(token.Properties)) |
|
||||
{ |
|
||||
return new ValueTask<JObject>(new JObject()); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<JObject>(JObject.Parse(token.Properties)); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the reference identifier associated with a token.
|
|
||||
/// Note: depending on the manager used to create the token,
|
|
||||
/// the reference identifier may be hashed for security reasons.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the reference identifier associated with the specified token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetReferenceIdAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(token.ReferenceId); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the status associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the status associated with the specified token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetStatusAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(token.Status); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the subject associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the subject associated with the specified token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetSubjectAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(token.Subject); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Retrieves the token type associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the token type associated with the specified token.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<string> GetTokenTypeAsync([NotNull] TToken token, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
return new ValueTask<string>(token.Type); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Instantiates a new token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="ValueTask{TResult}"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns the instantiated token, that can be persisted in the database.
|
|
||||
/// </returns>
|
|
||||
public virtual ValueTask<TToken> InstantiateAsync(CancellationToken cancellationToken) |
|
||||
=> new ValueTask<TToken>(new TToken()); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <param name="count">The number of results to return.</param>
|
|
||||
/// <param name="offset">The number of results to skip.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the elements returned when executing the specified query.
|
|
||||
/// </returns>
|
|
||||
public virtual Task<ImmutableArray<TToken>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
IQueryable<TToken> Query(IQueryable<TToken> tokens, int? skip, int? take) |
|
||||
{ |
|
||||
var query = tokens.OrderBy(token => token.Id).AsQueryable(); |
|
||||
|
|
||||
if (skip.HasValue) |
|
||||
{ |
|
||||
query = query.Skip(skip.Value); |
|
||||
} |
|
||||
|
|
||||
if (take.HasValue) |
|
||||
{ |
|
||||
query = query.Take(take.Value); |
|
||||
} |
|
||||
|
|
||||
return query; |
|
||||
} |
|
||||
|
|
||||
return ListAsync((tokens, state) => Query(tokens, state.offset, state.count), (offset, count), cancellationToken); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Executes the specified query and returns all the corresponding elements.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TState">The state type.</typeparam>
|
|
||||
/// <typeparam name="TResult">The result type.</typeparam>
|
|
||||
/// <param name="query">The query to execute.</param>
|
|
||||
/// <param name="state">The optional state.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
||||
/// whose result returns all the elements returned when executing the specified query.
|
|
||||
/// </returns>
|
|
||||
public abstract Task<ImmutableArray<TResult>> ListAsync<TState, TResult>( |
|
||||
[NotNull] Func<IQueryable<TToken>, TState, IQueryable<TResult>> query, |
|
||||
[CanBeNull] TState state, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Removes the tokens that are marked as expired or invalid.
|
|
||||
/// </summary>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task PruneAsync(CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the authorization identifier associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="identifier">The unique identifier associated with the token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task SetAuthorizationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the application identifier associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="identifier">The unique identifier associated with the token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task SetApplicationIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the creation date associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="date">The creation date.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetCreationDateAsync([NotNull] TToken token, |
|
||||
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
token.CreationDate = date; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the expiration date associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="date">The expiration date.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetExpirationDateAsync([NotNull] TToken token, |
|
||||
[CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
token.ExpirationDate = date; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the payload associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="payload">The payload associated with the token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetPayloadAsync([NotNull] TToken token, [CanBeNull] string payload, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
token.Payload = payload; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the additional properties associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="properties">The additional properties associated with the token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetPropertiesAsync([NotNull] TToken token, [CanBeNull] JObject properties, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
if (properties == null) |
|
||||
{ |
|
||||
token.Properties = null; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
token.Properties = properties.ToString(Formatting.None); |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the reference identifier associated with a token.
|
|
||||
/// Note: depending on the manager used to create the token,
|
|
||||
/// the reference identifier may be hashed for security reasons.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="identifier">The reference identifier associated with the token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetReferenceIdAsync([NotNull] TToken token, [CanBeNull] string identifier, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
token.ReferenceId = identifier; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the status associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="status">The status associated with the authorization.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetStatusAsync([NotNull] TToken token, [CanBeNull] string status, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(status)) |
|
||||
{ |
|
||||
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); |
|
||||
} |
|
||||
|
|
||||
token.Status = status; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the subject associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="subject">The subject associated with the token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetSubjectAsync([NotNull] TToken token, [CanBeNull] string subject, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(subject)) |
|
||||
{ |
|
||||
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
||||
} |
|
||||
|
|
||||
token.Subject = subject; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Sets the token type associated with a token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token.</param>
|
|
||||
/// <param name="type">The token type associated with the token.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public virtual Task SetTokenTypeAsync([NotNull] TToken token, [CanBeNull] string type, CancellationToken cancellationToken) |
|
||||
{ |
|
||||
if (token == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(token)); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(type)) |
|
||||
{ |
|
||||
throw new ArgumentException("The token type cannot be null or empty.", nameof(type)); |
|
||||
} |
|
||||
|
|
||||
token.Type = type; |
|
||||
|
|
||||
return Task.CompletedTask; |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Updates an existing token.
|
|
||||
/// </summary>
|
|
||||
/// <param name="token">The token to update.</param>
|
|
||||
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
|
|
||||
/// <returns>
|
|
||||
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
|
|
||||
/// </returns>
|
|
||||
public abstract Task UpdateAsync([NotNull] TToken token, CancellationToken cancellationToken); |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to a strongly typed key object.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>An instance of <typeparamref name="TKey"/> representing the provided identifier.</returns>
|
|
||||
public virtual TKey ConvertIdentifierFromString([CanBeNull] string identifier) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(identifier)) |
|
||||
{ |
|
||||
return default; |
|
||||
} |
|
||||
|
|
||||
return (TKey) TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(identifier); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Converts the provided identifier to its string representation.
|
|
||||
/// </summary>
|
|
||||
/// <param name="identifier">The identifier to convert.</param>
|
|
||||
/// <returns>A <see cref="string"/> representation of the provided identifier.</returns>
|
|
||||
public virtual string ConvertIdentifierToString([CanBeNull] TKey identifier) |
|
||||
{ |
|
||||
if (Equals(identifier, default(TKey))) |
|
||||
{ |
|
||||
return null; |
|
||||
} |
|
||||
|
|
||||
return TypeDescriptor.GetConverter(typeof(TKey)).ConvertToInvariantString(identifier); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,57 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using JetBrains.Annotations; |
|
||||
using OpenIddict.Models; |
|
||||
|
|
||||
namespace Microsoft.Extensions.DependencyInjection |
|
||||
{ |
|
||||
public static class OpenIddictExtensions |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// Configures OpenIddict to use the default entities, with the default entity key type (string).
|
|
||||
/// The default entities are <see cref="OpenIddictApplication"/>, <see cref="OpenIddictAuthorization"/>,
|
|
||||
/// <see cref="OpenIddictScope"/> and <see cref="OpenIddictToken"/>.
|
|
||||
/// </summary>
|
|
||||
/// <param name="builder">The services builder used by OpenIddict to register new services</param>
|
|
||||
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
|
|
||||
public static OpenIddictCoreBuilder UseDefaultModels([NotNull] this OpenIddictCoreBuilder builder) |
|
||||
{ |
|
||||
if (builder == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(builder)); |
|
||||
} |
|
||||
|
|
||||
return builder.UseCustomModels<OpenIddictApplication, |
|
||||
OpenIddictAuthorization, |
|
||||
OpenIddictScope, |
|
||||
OpenIddictToken>(); |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Configures OpenIddict to use the default entities, with the specified entity key type.
|
|
||||
/// The default entities are <see cref="OpenIddictApplication{TKey}"/>, <see cref="OpenIddictAuthorization{TKey}"/>,
|
|
||||
/// <see cref="OpenIddictScope{TKey}"/> and <see cref="OpenIddictToken{TKey}"/>.
|
|
||||
/// </summary>
|
|
||||
/// <typeparam name="TKey">The type of the entity primary keys.</typeparam>
|
|
||||
/// <param name="builder">The services builder used by OpenIddict to register new services</param>
|
|
||||
/// <returns>The <see cref="OpenIddictCoreBuilder"/>.</returns>
|
|
||||
public static OpenIddictCoreBuilder UseDefaultModels<TKey>([NotNull] this OpenIddictCoreBuilder builder) |
|
||||
where TKey : IEquatable<TKey> |
|
||||
{ |
|
||||
if (builder == null) |
|
||||
{ |
|
||||
throw new ArgumentNullException(nameof(builder)); |
|
||||
} |
|
||||
|
|
||||
return builder.UseCustomModels<OpenIddictApplication<TKey>, |
|
||||
OpenIddictAuthorization<TKey>, |
|
||||
OpenIddictScope<TKey>, |
|
||||
OpenIddictToken<TKey>>(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,57 @@ |
|||||
|
/* |
||||
|
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
||||
|
* See https://github.com/openiddict/openiddict-core for more information concerning
|
||||
|
* the license and the contributors participating to this project. |
||||
|
*/ |
||||
|
|
||||
|
using System; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using OpenIddict.Core; |
||||
|
using OpenIddict.EntityFramework; |
||||
|
using OpenIddict.EntityFramework.Models; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace OpenIddict.EntityFramework.Tests |
||||
|
{ |
||||
|
public class OpenIddictEntityFrameworkExtensionsTests |
||||
|
{ |
||||
|
[Theory] |
||||
|
[InlineData(typeof(OpenIddictApplicationStoreResolver))] |
||||
|
[InlineData(typeof(OpenIddictAuthorizationStoreResolver))] |
||||
|
[InlineData(typeof(OpenIddictScopeStoreResolver))] |
||||
|
[InlineData(typeof(OpenIddictTokenStoreResolver))] |
||||
|
public void AddEntityFrameworkStores_RegistersEntityFrameworkStoreFactories(Type type) |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var services = new ServiceCollection(); |
||||
|
var builder = services.AddOpenIddict().AddCore(); |
||||
|
|
||||
|
// Act
|
||||
|
builder.UseEntityFramework(); |
||||
|
|
||||
|
// Assert
|
||||
|
Assert.Contains(services, service => service.ImplementationType == type); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void UseEntityFrameworkModels_KeyTypeDefaultsToString() |
||||
|
{ |
||||
|
// Arrange
|
||||
|
var services = new ServiceCollection(); |
||||
|
var builder = services.AddOpenIddict().AddCore(); |
||||
|
|
||||
|
// Act
|
||||
|
builder.UseEntityFramework(); |
||||
|
|
||||
|
// Assert
|
||||
|
var provider = services.BuildServiceProvider(); |
||||
|
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue; |
||||
|
|
||||
|
Assert.Equal(typeof(OpenIddictApplication), options.DefaultApplicationType); |
||||
|
Assert.Equal(typeof(OpenIddictAuthorization), options.DefaultAuthorizationType); |
||||
|
Assert.Equal(typeof(OpenIddictScope), options.DefaultScopeType); |
||||
|
Assert.Equal(typeof(OpenIddictToken), options.DefaultTokenType); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,35 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using System.Data.Entity; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using OpenIddict.EntityFramework; |
|
||||
using Xunit; |
|
||||
|
|
||||
namespace OpenIddict.EntityFrameworkCore.Tests |
|
||||
{ |
|
||||
public class OpenIddictExtensionsTests |
|
||||
{ |
|
||||
[Theory] |
|
||||
[InlineData(typeof(OpenIddictApplicationStoreResolver<DbContext>))] |
|
||||
[InlineData(typeof(OpenIddictAuthorizationStoreResolver<DbContext>))] |
|
||||
[InlineData(typeof(OpenIddictScopeStoreResolver<DbContext>))] |
|
||||
[InlineData(typeof(OpenIddictTokenStoreResolver<DbContext>))] |
|
||||
public void AddEntityFrameworkStores_RegistersEntityFrameworkStoreFactories(Type type) |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
var builder = services.AddOpenIddict().AddCore(); |
|
||||
|
|
||||
// Act
|
|
||||
builder.AddEntityFrameworkStores<DbContext>(); |
|
||||
|
|
||||
// Assert
|
|
||||
Assert.Contains(services, service => service.ImplementationType == type); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,34 +0,0 @@ |
|||||
/* |
|
||||
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
|
|
||||
* See https://github.com/openiddict/openiddict-core for more information concerning
|
|
||||
* the license and the contributors participating to this project. |
|
||||
*/ |
|
||||
|
|
||||
using System; |
|
||||
using Microsoft.EntityFrameworkCore; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Xunit; |
|
||||
|
|
||||
namespace OpenIddict.EntityFrameworkCore.Tests |
|
||||
{ |
|
||||
public class OpenIddictExtensionsTests |
|
||||
{ |
|
||||
[Theory] |
|
||||
[InlineData(typeof(OpenIddictApplicationStoreResolver<DbContext>))] |
|
||||
[InlineData(typeof(OpenIddictAuthorizationStoreResolver<DbContext>))] |
|
||||
[InlineData(typeof(OpenIddictScopeStoreResolver<DbContext>))] |
|
||||
[InlineData(typeof(OpenIddictTokenStoreResolver<DbContext>))] |
|
||||
public void AddEntityFrameworkCoreStores_RegistersEntityFrameworkCoreStoreFactories(Type type) |
|
||||
{ |
|
||||
// Arrange
|
|
||||
var services = new ServiceCollection(); |
|
||||
var builder = services.AddOpenIddict().AddCore(); |
|
||||
|
|
||||
// Act
|
|
||||
builder.AddEntityFrameworkCoreStores<DbContext>(); |
|
||||
|
|
||||
// Assert
|
|
||||
Assert.Contains(services, service => service.ImplementationType == type); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -1,27 +0,0 @@ |
|||||
<Project Sdk="Microsoft.NET.Sdk"> |
|
||||
|
|
||||
<Import Project="..\..\build\tests.props" /> |
|
||||
|
|
||||
<PropertyGroup> |
|
||||
<TargetFrameworks>netcoreapp2.0;net461</TargetFrameworks> |
|
||||
<TargetFrameworks Condition=" $([Microsoft.Build.Utilities.ToolLocationHelper]::GetPathToReferenceAssemblies('.NETFramework', '4.7', '').Count) != 0 ">$(TargetFrameworks);net47</TargetFrameworks> |
|
||||
<TargetFrameworks Condition=" '$(OS)' != 'Windows_NT' ">netcoreapp2.0</TargetFrameworks> |
|
||||
</PropertyGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<ProjectReference Include="..\..\src\OpenIddict\OpenIddict.csproj" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="$(AspNetCoreVersion)" /> |
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(TestSdkVersion)" /> |
|
||||
<PackageReference Include="Moq" Version="$(MoqVersion)" /> |
|
||||
<PackageReference Include="xunit" Version="$(XunitVersion)" /> |
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="$(XunitVersion)" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
<ItemGroup> |
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" /> |
|
||||
</ItemGroup> |
|
||||
|
|
||||
</Project> |
|
||||
Loading…
Reference in new issue