Browse Source

Introduce non-generic manager interfaces and update the token server/validation services to use them

pull/601/head
Kévin Chalet 8 years ago
parent
commit
9515954ac9
  1. 2
      src/OpenIddict.Abstractions/Descriptors/OpenIddictApplicationDescriptor.cs
  2. 2
      src/OpenIddict.Abstractions/Descriptors/OpenIddictAuthorizationDescriptor.cs
  3. 2
      src/OpenIddict.Abstractions/Descriptors/OpenIddictScopeDescriptor.cs
  4. 2
      src/OpenIddict.Abstractions/Descriptors/OpenIddictTokenDescriptor.cs
  5. 421
      src/OpenIddict.Abstractions/Managers/IOpenIddictApplicationManager.cs
  6. 419
      src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs
  7. 290
      src/OpenIddict.Abstractions/Managers/IOpenIddictScopeManager.cs
  8. 452
      src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs
  9. 1
      src/OpenIddict.Abstractions/OpenIddict.Abstractions.csproj
  10. 114
      src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs
  11. 114
      src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
  12. 78
      src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs
  13. 126
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  14. 5
      src/OpenIddict.Core/OpenIddict.Core.csproj
  15. 66
      src/OpenIddict.Core/OpenIddictCoreExtensions.cs
  16. 12
      src/OpenIddict.Core/OpenIddictCoreOptions.cs
  17. 2
      src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
  18. 2
      src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs
  19. 2
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
  20. 2
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs
  21. 26
      src/OpenIddict.Server/Internal/OpenIddictServerInitializer.cs
  22. 109
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Authentication.cs
  23. 3
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Discovery.cs
  24. 83
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Exchange.cs
  25. 156
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Helpers.cs
  26. 47
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Introspection.cs
  27. 63
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Revocation.cs
  28. 3
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Serialization.cs
  29. 24
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Session.cs
  30. 3
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.Userinfo.cs
  31. 60
      src/OpenIddict.Server/Internal/OpenIddictServerProvider.cs
  32. 3
      src/OpenIddict.Server/OpenIddict.Server.csproj
  33. 5
      src/OpenIddict.Server/OpenIddictServerBuilder.cs
  34. 42
      src/OpenIddict.Server/OpenIddictServerExtensions.cs
  35. 26
      src/OpenIddict.Server/OpenIddictServerOptions.cs
  36. 31
      src/OpenIddict.Validation/Internal/OpenIddictValidationHandler.cs
  37. 12
      src/OpenIddict.Validation/Internal/OpenIddictValidationInitializer.cs
  38. 2
      src/OpenIddict.Validation/OpenIddict.Validation.csproj
  39. 48
      src/OpenIddict.Validation/OpenIddictValidationExtensions.cs
  40. 6
      src/OpenIddict.Validation/OpenIddictValidationOptions.cs
  41. 1
      src/OpenIddict/OpenIddict.csproj

2
src/OpenIddict.Core/Descriptors/OpenIddictApplicationDescriptor.cs → src/OpenIddict.Abstractions/Descriptors/OpenIddictApplicationDescriptor.cs

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
namespace OpenIddict.Core
namespace OpenIddict.Abstractions
{
/// <summary>
/// Represents an OpenIddict application descriptor.

2
src/OpenIddict.Core/Descriptors/OpenIddictAuthorizationDescriptor.cs → src/OpenIddict.Abstractions/Descriptors/OpenIddictAuthorizationDescriptor.cs

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Security.Claims;
namespace OpenIddict.Core
namespace OpenIddict.Abstractions
{
/// <summary>
/// Represents an OpenIddict authorization descriptor.

2
src/OpenIddict.Core/Descriptors/OpenIddictScopeDescriptor.cs → src/OpenIddict.Abstractions/Descriptors/OpenIddictScopeDescriptor.cs

@ -1,7 +1,7 @@
using System;
using System.Collections.Generic;
namespace OpenIddict.Core
namespace OpenIddict.Abstractions
{
/// <summary>
/// Represents an OpenIddict scope descriptor.

2
src/OpenIddict.Core/Descriptors/OpenIddictTokenDescriptor.cs → src/OpenIddict.Abstractions/Descriptors/OpenIddictTokenDescriptor.cs

@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Security.Claims;
namespace OpenIddict.Core
namespace OpenIddict.Abstractions
{
/// <summary>
/// Represents an OpenIddict token descriptor.

421
src/OpenIddict.Abstractions/Managers/IOpenIddictApplicationManager.cs

@ -0,0 +1,421 @@
using System;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace OpenIddict.Abstractions
{
/// <summary>
/// Provides methods allowing to manage the applications stored in the store.
/// Note: this interface is not meant to be implemented by custom managers,
/// that should inherit from the generic OpenIddictApplicationManager class.
/// It is primarily intended to be used by services that cannot easily depend
/// on the generic application manager. The actual application entity type
/// is automatically determined at runtime based on the OpenIddict core options.
/// </summary>
public interface IOpenIddictApplicationManager
{
/// <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>
Task<long> CountAsync(CancellationToken cancellationToken = default);
/// <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>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new application based on the specified descriptor.
/// Note: the default implementation automatically hashes the client
/// secret before storing it in the database, for security reasons.
/// </summary>
/// <param name="descriptor">The application descriptor.</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 unique identifier associated with the application.
/// </returns>
Task<object> CreateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <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>
Task CreateAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new application.
/// Note: the default implementation automatically hashes the client
/// secret before storing it in the database, for security reasons.
/// </summary>
/// <param name="application">The application to create.</param>
/// <param name="secret">The client secret associated with the application, if applicable.</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>
Task CreateAsync([NotNull] object application, [CanBeNull] string secret, CancellationToken cancellationToken = default);
/// <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>
Task DeleteAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <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>
Task<object> FindByClientIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <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>
Task<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> FindByPostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> FindByRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns the first element.
/// </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 first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <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>
Task<TResult> GetAsync<TState, TResult>([NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query, [CanBeNull] TState state, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetClientIdAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetClientTypeAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetConsentTypeAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetDisplayNameAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetIdAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <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>
ValueTask<ImmutableArray<string>> GetPermissionsAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <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>
ValueTask<ImmutableArray<string>> GetPostLogoutRedirectUrisAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <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>
ValueTask<ImmutableArray<string>> GetRedirectUrisAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether the specified permission has been granted to the application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="permission">The permission.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application has been granted the specified permission, <c>false</c> otherwise.</returns>
Task<bool> HasPermissionAsync([NotNull] object application, [NotNull] string permission, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether an application is a confidential client.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application is a confidential client, <c>false</c> otherwise.</returns>
Task<bool> IsConfidentialAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether an application is a hybrid client.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application is a hybrid client, <c>false</c> otherwise.</returns>
Task<bool> IsHybridAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether an application is a public client.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the application is a public client, <c>false</c> otherwise.</returns>
Task<bool> IsPublicAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </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 all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>([NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query, [CanBeNull] TState state, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the specified descriptor using the properties exposed by the application.
/// </summary>
/// <param name="descriptor">The descriptor.</param>
/// <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="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] OpenIddictApplicationDescriptor descriptor, [NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the application using the specified descriptor.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="descriptor">The descriptor.</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>
Task PopulateAsync([NotNull] object application, [NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <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>
Task UpdateAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing application.
/// </summary>
/// <param name="application">The application to update.</param>
/// <param name="descriptor">The descriptor used to update 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>
Task UpdateAsync([NotNull] object application, [NotNull] OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing application and replaces the existing secret.
/// Note: the default implementation automatically hashes the client
/// secret before storing it in the database, for security reasons.
/// </summary>
/// <param name="application">The application to update.</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>
Task UpdateAsync([NotNull] object application, [CanBeNull] string secret, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the application to ensure it's in a consistent state.
/// </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="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the application.
/// </returns>
Task<ImmutableArray<ValidationResult>> ValidateAsync([NotNull] object application, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the client_secret associated with an application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="secret">The secret that should be compared to the client_secret stored in the database.</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>
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns a boolean indicating whether the client secret was valid.
/// </returns>
Task<bool> ValidateClientSecretAsync([NotNull] object application, string secret, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the specified post_logout_redirect_uri.
/// </summary>
/// <param name="address">The address that should be compared to the post_logout_redirect_uri stored in the database.</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 a boolean indicating whether the post_logout_redirect_uri was valid.
/// </returns>
Task<bool> ValidatePostLogoutRedirectUriAsync([NotNull] string address, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the redirect_uri to ensure it's associated with an application.
/// </summary>
/// <param name="application">The application.</param>
/// <param name="address">The address that should be compared to one of the redirect_uri stored in the database.</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 a boolean indicating whether the redirect_uri was valid.
/// </returns>
Task<bool> ValidateRedirectUriAsync([NotNull] object application, [NotNull] string address, CancellationToken cancellationToken = default);
}
}

419
src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs

@ -0,0 +1,419 @@
using System;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace OpenIddict.Abstractions
{
/// <summary>
/// Provides methods allowing to manage the authorizations stored in the store.
/// Note: this interface is not meant to be implemented by custom managers,
/// that should inherit from the generic OpenIddictAuthorizationManager class.
/// It is primarily intended to be used by services that cannot easily depend
/// on the generic authorization manager. The actual authorization entity type
/// is automatically determined at runtime based on the OpenIddict core options.
/// </summary>
public interface IOpenIddictAuthorizationManager
{
/// <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>
Task<long> CountAsync(CancellationToken cancellationToken = default);
/// <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>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new permanent authorization based on the specified parameters.
/// </summary>
/// <param name="principal">The principal associated with the authorization.</param>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="type">The authorization type.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param>
/// <param name="properties">The authentication 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, whose result returns the authorization.
/// </returns>
Task<object> CreateAsync([NotNull] ClaimsPrincipal principal, [NotNull] string subject, [NotNull] string client, [NotNull] string type, ImmutableArray<string> scopes, [CanBeNull] ImmutableDictionary<string, string> properties, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new authorization based on the specified descriptor.
/// </summary>
/// <param name="descriptor">The authorization descriptor.</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.
/// </returns>
Task<object> CreateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new authorization.
/// </summary>
/// <param name="authorization">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>
Task CreateAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <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>
Task DeleteAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> FindAsync([NotNull] string subject, [NotNull] string client, [NotNull] string status, CancellationToken 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>
Task<ImmutableArray<object>> FindAsync([NotNull] string subject, [NotNull] string client, [NotNull] string status, [NotNull] string type, CancellationToken cancellationToken = default);
/// <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="scopes">The minimal 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,
/// whose result returns the authorizations corresponding to the criteria.
/// </returns>
Task<ImmutableArray<object>> FindAsync([NotNull] string subject, [NotNull] string client, [NotNull] string status, [NotNull] string type, ImmutableArray<string> scopes, CancellationToken cancellationToken = default);
/// <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>
Task<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetApplicationIdAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns the first element.
/// </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 first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <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>
Task<TResult> GetAsync<TState, TResult>([NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query, [CanBeNull] TState state, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetIdAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <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>
ValueTask<ImmutableArray<string>> GetScopesAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetStatusAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetSubjectAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetTypeAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether the specified scopes are included in the authorization.
/// </summary>
/// <param name="authorization">The authorization.</param>
/// <param name="scopes">The scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the scopes are included in the authorization, <c>false</c> otherwise.</returns>
Task<bool> HasScopesAsync([NotNull] object authorization, ImmutableArray<string> scopes, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given authorization is ad hoc.
/// </summary>
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization is ad hoc, <c>false</c> otherwise.</returns>
Task<bool> IsAdHocAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given authorization is permanent.
/// </summary>
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization is permanent, <c>false</c> otherwise.</returns>
Task<bool> IsPermanentAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given authorization has been revoked.
/// </summary>
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization has been revoked, <c>false</c> otherwise.</returns>
Task<bool> IsRevokedAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given authorization is valid.
/// </summary>
/// <param name="authorization">The authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the authorization is valid, <c>false</c> otherwise.</returns>
Task<bool> IsValidAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </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 all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>([NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query, [CanBeNull] TState state, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the specified descriptor using the properties exposed by the authorization.
/// </summary>
/// <param name="descriptor">The descriptor.</param>
/// <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="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] OpenIddictAuthorizationDescriptor descriptor, [NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the authorization using the specified descriptor.
/// </summary>
/// <param name="authorization">The authorization.</param>
/// <param name="descriptor">The descriptor.</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>
Task PopulateAsync([NotNull] object authorization, [NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <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>
Task PruneAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Revokes an authorization.
/// </summary>
/// <param name="authorization">The authorization to revoke.</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>
Task RevokeAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <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>
Task SetApplicationIdAsync([NotNull] object authorization, [CanBeNull] string identifier, CancellationToken cancellationToken = default);
/// <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>
Task UpdateAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing authorization.
/// </summary>
/// <param name="authorization">The authorization to update.</param>
/// <param name="descriptor">The descriptor used to update 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>
Task UpdateAsync([NotNull] object authorization, [NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the authorization to ensure it's in a consistent state.
/// </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="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the authorization.
/// </returns>
Task<ImmutableArray<ValidationResult>> ValidateAsync([NotNull] object authorization, CancellationToken cancellationToken = default);
}
}

290
src/OpenIddict.Abstractions/Managers/IOpenIddictScopeManager.cs

@ -0,0 +1,290 @@
using System;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace OpenIddict.Abstractions
{
/// <summary>
/// Provides methods allowing to manage the scopes stored in the store.
/// Note: this interface is not meant to be implemented by custom managers,
/// that should inherit from the generic OpenIddictScopeManager class.
/// It is primarily intended to be used by services that cannot easily
/// depend on the generic scope manager. The actual scope entity type is
/// automatically determined at runtime based on the OpenIddict core options.
/// </summary>
public interface IOpenIddictScopeManager
{
/// <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>
Task<long> CountAsync(CancellationToken cancellationToken = default);
/// <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>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new scope based on the specified descriptor.
/// </summary>
/// <param name="descriptor">The scope descriptor.</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.
/// </returns>
Task<object> CreateAsync([NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default);
/// <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>
Task CreateAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <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>
Task DeleteAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <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>
Task<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <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>
Task<object> FindByNameAsync([NotNull] string name, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns the first element.
/// </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 first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <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>
Task<TResult> GetAsync<TState, TResult>([NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query, [CanBeNull] TState state, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetDescriptionAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetDisplayNameAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetIdAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetNameAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <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>
ValueTask<ImmutableArray<string>> GetResourcesAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </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 all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>([NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query, [CanBeNull] TState state, CancellationToken cancellationToken = default);
/// <summary>
/// Lists all the resources associated with the specified scopes.
/// </summary>
/// <param name="scopes">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 all the resources associated with the specified scopes.
/// </returns>
Task<ImmutableArray<string>> ListResourcesAsync(ImmutableArray<string> scopes, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the specified descriptor using the properties exposed by the scope.
/// </summary>
/// <param name="descriptor">The descriptor.</param>
/// <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="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] OpenIddictScopeDescriptor descriptor, [NotNull] object scope, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the scope using the specified descriptor.
/// </summary>
/// <param name="scope">The scope.</param>
/// <param name="descriptor">The descriptor.</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>
Task PopulateAsync([NotNull] object scope, [NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default);
/// <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>
Task UpdateAsync([NotNull] object scope, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing scope.
/// </summary>
/// <param name="scope">The scope to update.</param>
/// <param name="descriptor">The descriptor used to update 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>
Task UpdateAsync([NotNull] object scope, [NotNull] OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the scope to ensure it's in a consistent state.
/// </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="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the scope.
/// </returns>
Task<ImmutableArray<ValidationResult>> ValidateAsync([NotNull] object scope, CancellationToken cancellationToken = default);
}
}

452
src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs

@ -0,0 +1,452 @@
using System;
using System.Collections.Immutable;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using JetBrains.Annotations;
namespace OpenIddict.Abstractions
{
/// <summary>
/// Provides methods allowing to manage the tokens stored in the store.
/// Note: this interface is not meant to be implemented by custom managers,
/// that should inherit from the generic OpenIddictTokenManager class.
/// It is primarily intended to be used by services that cannot easily
/// depend on the generic token manager. The actual token entity type is
/// automatically determined at runtime based on the OpenIddict core options.
/// </summary>
public interface IOpenIddictTokenManager
{
/// <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 tokens in the database.
/// </returns>
Task<long> CountAsync(CancellationToken cancellationToken = default);
/// <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>
Task<long> CountAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new token based on the specified descriptor.
/// </summary>
/// <param name="descriptor">The token descriptor.</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.
/// </returns>
Task<object> CreateAsync([NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Creates a new 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="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task CreateAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Removes an existing 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>
Task DeleteAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Extends the specified token by replacing its expiration date.
/// </summary>
/// <param name="token">The token.</param>
/// <param name="date">The date on which the token will no longer be considered valid.</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>
Task ExtendAsync([NotNull] object token, [CanBeNull] DateTimeOffset? date, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> FindByApplicationIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> FindByAuthorizationIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <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>
Task<object> FindByIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <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>
Task<object> FindByReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> FindBySubjectAsync([NotNull] string subject, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetApplicationIdAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns the first element.
/// </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 first element returned when executing the query.
/// </returns>
Task<TResult> GetAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <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>
Task<TResult> GetAsync<TState, TResult>([NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query, [CanBeNull] TState state, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetAuthorizationIdAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <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>
ValueTask<DateTimeOffset?> GetCreationDateAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <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>
ValueTask<DateTimeOffset?> GetExpirationDateAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetIdAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetPayloadAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetReferenceIdAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetStatusAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetSubjectAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <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>
ValueTask<string> GetTokenTypeAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given token has already been redemeed.
/// </summary>
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the token has already been redemeed, <c>false</c> otherwise.</returns>
Task<bool> IsRedeemedAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given token has been revoked.
/// </summary>
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the token has been revoked, <c>false</c> otherwise.</returns>
Task<bool> IsRevokedAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Determines whether a given token is valid.
/// </summary>
/// <param name="token">The token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns><c>true</c> if the token is valid, <c>false</c> otherwise.</returns>
Task<bool> IsValidAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<object>> ListAsync([CanBeNull] int? count, [CanBeNull] int? offset, CancellationToken cancellationToken = default);
/// <summary>
/// Executes the specified query and returns all the corresponding elements.
/// </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 all the elements returned when executing the specified query.
/// </returns>
Task<ImmutableArray<TResult>> ListAsync<TResult>([NotNull] Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken = default);
/// <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>
Task<ImmutableArray<TResult>> ListAsync<TState, TResult>([NotNull] Func<IQueryable<object>, TState, IQueryable<TResult>> query, [CanBeNull] TState state, CancellationToken cancellationToken = default);
/// <summary>
/// Obfuscates the specified reference identifier so it can be safely stored in a database.
/// By default, this method returns a simple hashed representation computed using SHA256.
/// </summary>
/// <param name="identifier">The client identifier.</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>
Task<string> ObfuscateReferenceIdAsync([NotNull] string identifier, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the specified descriptor using the properties exposed by the token.
/// </summary>
/// <param name="descriptor">The descriptor.</param>
/// <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="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
Task PopulateAsync([NotNull] OpenIddictTokenDescriptor descriptor, [NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Populates the token using the specified descriptor.
/// </summary>
/// <param name="token">The token.</param>
/// <param name="descriptor">The descriptor.</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>
Task PopulateAsync([NotNull] object token, [NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default);
/// <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>
Task PruneAsync(CancellationToken cancellationToken = default);
/// <summary>
/// Redeems a token.
/// </summary>
/// <param name="token">The token to redeem.</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>
Task RedeemAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes a token.
/// </summary>
/// <param name="token">The token to revoke.</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>
Task RevokeAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <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 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>
Task SetApplicationIdAsync([NotNull] object token, [CanBeNull] string identifier, CancellationToken cancellationToken = default);
/// <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 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>
Task SetAuthorizationIdAsync([NotNull] object token, [CanBeNull] string identifier, CancellationToken cancellationToken = default);
/// <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>
Task UpdateAsync([NotNull] object token, CancellationToken cancellationToken = default);
/// <summary>
/// Updates an existing token.
/// </summary>
/// <param name="token">The token to update.</param>
/// <param name="descriptor">The descriptor used to update 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>
Task UpdateAsync([NotNull] object token, [NotNull] OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Validates the token to ensure it's in a consistent state.
/// </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="Task"/> that can be used to monitor the asynchronous operation,
/// whose result returns the validation error encountered when validating the token.
/// </returns>
Task<ImmutableArray<ValidationResult>> ValidateAsync([NotNull] object token, CancellationToken cancellationToken = default);
}
}

1
src/OpenIddict.Abstractions/OpenIddict.Abstractions.csproj

@ -17,6 +17,7 @@
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(JsonNetVersion)" />
<PackageReference Include="System.Collections.Immutable" Version="$(ImmutableCollectionsVersion)" />
<PackageReference Include="System.ComponentModel.Annotations" Version="$(DataAnnotationsVersion)" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="$(TasksExtensionsVersion)" />
</ItemGroup>

114
src/OpenIddict.Core/Managers/OpenIddictApplicationManager.cs

@ -22,7 +22,7 @@ namespace OpenIddict.Core
/// Provides methods allowing to manage the applications stored in the store.
/// </summary>
/// <typeparam name="TApplication">The type of the Application entity.</typeparam>
public class OpenIddictApplicationManager<TApplication> where TApplication : class
public class OpenIddictApplicationManager<TApplication> : IOpenIddictApplicationManager where TApplication : class
{
public OpenIddictApplicationManager(
[NotNull] IOpenIddictApplicationStoreResolver resolver,
@ -58,9 +58,7 @@ namespace OpenIddict.Core
/// whose result returns the number of applications in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken = default)
{
return Store.CountAsync(cancellationToken);
}
=> Store.CountAsync(cancellationToken);
/// <summary>
/// Determines the number of applications that match the specified query.
@ -1349,5 +1347,113 @@ namespace OpenIddict.Core
return Task.FromResult(false);
}
}
Task<long> IOpenIddictApplicationManager.CountAsync(CancellationToken cancellationToken)
=> CountAsync(cancellationToken);
Task<long> IOpenIddictApplicationManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> CountAsync(query, cancellationToken);
async Task<object> IOpenIddictApplicationManager.CreateAsync(OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
=> await CreateAsync(descriptor, cancellationToken);
Task IOpenIddictApplicationManager.CreateAsync(object application, CancellationToken cancellationToken)
=> CreateAsync((TApplication) application, cancellationToken);
Task IOpenIddictApplicationManager.CreateAsync(object application, string secret, CancellationToken cancellationToken)
=> CreateAsync((TApplication) application, secret, cancellationToken);
Task IOpenIddictApplicationManager.DeleteAsync(object application, CancellationToken cancellationToken)
=> DeleteAsync((TApplication) application, cancellationToken);
async Task<object> IOpenIddictApplicationManager.FindByClientIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByClientIdAsync(identifier, cancellationToken);
async Task<object> IOpenIddictApplicationManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByIdAsync(identifier, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictApplicationManager.FindByPostLogoutRedirectUriAsync(string address, CancellationToken cancellationToken)
=> (await FindByPostLogoutRedirectUriAsync(address, cancellationToken)).CastArray<object>();
async Task<ImmutableArray<object>> IOpenIddictApplicationManager.FindByRedirectUriAsync(string address, CancellationToken cancellationToken)
=> (await FindByRedirectUriAsync(address, cancellationToken)).CastArray<object>();
Task<TResult> IOpenIddictApplicationManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> GetAsync(query, cancellationToken);
Task<TResult> IOpenIddictApplicationManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> GetAsync(query, state, cancellationToken);
ValueTask<string> IOpenIddictApplicationManager.GetClientIdAsync(object application, CancellationToken cancellationToken)
=> GetClientIdAsync((TApplication) application, cancellationToken);
ValueTask<string> IOpenIddictApplicationManager.GetClientTypeAsync(object application, CancellationToken cancellationToken)
=> GetClientTypeAsync((TApplication) application, cancellationToken);
ValueTask<string> IOpenIddictApplicationManager.GetConsentTypeAsync(object application, CancellationToken cancellationToken)
=> GetConsentTypeAsync((TApplication) application, cancellationToken);
ValueTask<string> IOpenIddictApplicationManager.GetDisplayNameAsync(object application, CancellationToken cancellationToken)
=> GetDisplayNameAsync((TApplication) application, cancellationToken);
ValueTask<string> IOpenIddictApplicationManager.GetIdAsync(object application, CancellationToken cancellationToken)
=> GetIdAsync((TApplication) application, cancellationToken);
ValueTask<ImmutableArray<string>> IOpenIddictApplicationManager.GetPermissionsAsync(object application, CancellationToken cancellationToken)
=> GetPermissionsAsync((TApplication) application, cancellationToken);
ValueTask<ImmutableArray<string>> IOpenIddictApplicationManager.GetPostLogoutRedirectUrisAsync(object application, CancellationToken cancellationToken)
=> GetPostLogoutRedirectUrisAsync((TApplication) application, cancellationToken);
ValueTask<ImmutableArray<string>> IOpenIddictApplicationManager.GetRedirectUrisAsync(object application, CancellationToken cancellationToken)
=> GetRedirectUrisAsync((TApplication) application, cancellationToken);
Task<bool> IOpenIddictApplicationManager.HasPermissionAsync(object application, string permission, CancellationToken cancellationToken)
=> HasPermissionAsync((TApplication) application, permission, cancellationToken);
Task<bool> IOpenIddictApplicationManager.IsConfidentialAsync(object application, CancellationToken cancellationToken)
=> IsConfidentialAsync((TApplication) application, cancellationToken);
Task<bool> IOpenIddictApplicationManager.IsHybridAsync(object application, CancellationToken cancellationToken)
=> IsHybridAsync((TApplication) application, cancellationToken);
Task<bool> IOpenIddictApplicationManager.IsPublicAsync(object application, CancellationToken cancellationToken)
=> IsPublicAsync((TApplication) application, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictApplicationManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> (await ListAsync(count, offset, cancellationToken)).CastArray<object>();
Task<ImmutableArray<TResult>> IOpenIddictApplicationManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> ListAsync(query, cancellationToken);
Task<ImmutableArray<TResult>> IOpenIddictApplicationManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> ListAsync(query, state, cancellationToken);
Task IOpenIddictApplicationManager.PopulateAsync(OpenIddictApplicationDescriptor descriptor, object application, CancellationToken cancellationToken)
=> PopulateAsync(descriptor, (TApplication) application, cancellationToken);
Task IOpenIddictApplicationManager.PopulateAsync(object application, OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
=> PopulateAsync((TApplication) application, descriptor, cancellationToken);
Task IOpenIddictApplicationManager.UpdateAsync(object application, CancellationToken cancellationToken)
=> UpdateAsync((TApplication) application, cancellationToken);
Task IOpenIddictApplicationManager.UpdateAsync(object application, OpenIddictApplicationDescriptor descriptor, CancellationToken cancellationToken)
=> UpdateAsync((TApplication) application, descriptor, cancellationToken);
Task IOpenIddictApplicationManager.UpdateAsync(object application, string secret, CancellationToken cancellationToken)
=> UpdateAsync((TApplication) application, secret, cancellationToken);
Task<ImmutableArray<ValidationResult>> IOpenIddictApplicationManager.ValidateAsync(object application, CancellationToken cancellationToken)
=> ValidateAsync((TApplication) application, cancellationToken);
Task<bool> IOpenIddictApplicationManager.ValidateClientSecretAsync(object application, string secret, CancellationToken cancellationToken)
=> ValidateClientSecretAsync((TApplication) application, secret, cancellationToken);
Task<bool> IOpenIddictApplicationManager.ValidatePostLogoutRedirectUriAsync(string address, CancellationToken cancellationToken)
=> ValidatePostLogoutRedirectUriAsync(address, cancellationToken);
Task<bool> IOpenIddictApplicationManager.ValidateRedirectUriAsync(object application, string address, CancellationToken cancellationToken)
=> ValidateRedirectUriAsync((TApplication) application, address, cancellationToken);
}
}

114
src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs

@ -22,7 +22,7 @@ namespace OpenIddict.Core
/// Provides methods allowing to manage the authorizations stored in the store.
/// </summary>
/// <typeparam name="TAuthorization">The type of the Authorization entity.</typeparam>
public class OpenIddictAuthorizationManager<TAuthorization> where TAuthorization : class
public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthorizationManager where TAuthorization : class
{
public OpenIddictAuthorizationManager(
[NotNull] IOpenIddictAuthorizationStoreResolver resolver,
@ -58,9 +58,7 @@ namespace OpenIddict.Core
/// whose result returns the number of authorizations in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken = default)
{
return Store.CountAsync(cancellationToken);
}
=> Store.CountAsync(cancellationToken);
/// <summary>
/// Determines the number of authorizations that match the specified query.
@ -1035,5 +1033,113 @@ namespace OpenIddict.Core
builder.MoveToImmutable() :
builder.ToImmutable();
}
Task<long> IOpenIddictAuthorizationManager.CountAsync(CancellationToken cancellationToken)
=> CountAsync(cancellationToken);
Task<long> IOpenIddictAuthorizationManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> CountAsync(query, cancellationToken);
async Task<object> IOpenIddictAuthorizationManager.CreateAsync(ClaimsPrincipal principal, string subject, string client, string type, ImmutableArray<string> scopes, ImmutableDictionary<string, string> properties, CancellationToken cancellationToken)
=> await CreateAsync(principal, subject, client, type, scopes, properties, cancellationToken);
async Task<object> IOpenIddictAuthorizationManager.CreateAsync(OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
=> await CreateAsync(descriptor, cancellationToken);
Task IOpenIddictAuthorizationManager.CreateAsync(object authorization, CancellationToken cancellationToken)
=> CreateAsync((TAuthorization) authorization, cancellationToken);
Task IOpenIddictAuthorizationManager.DeleteAsync(object authorization, CancellationToken cancellationToken)
=> DeleteAsync((TAuthorization) authorization, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, cancellationToken)).CastArray<object>();
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, status, cancellationToken)).CastArray<object>();
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, status, type, cancellationToken)).CastArray<object>();
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, string type, ImmutableArray<string> scopes, CancellationToken cancellationToken)
=> (await FindAsync(subject, client, status, type, scopes, cancellationToken)).CastArray<object>();
async Task<object> IOpenIddictAuthorizationManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByIdAsync(identifier, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.FindBySubjectAsync(string subject, CancellationToken cancellationToken)
=> (await FindBySubjectAsync(subject, cancellationToken)).CastArray<object>();
ValueTask<string> IOpenIddictAuthorizationManager.GetApplicationIdAsync(object authorization, CancellationToken cancellationToken)
=> GetApplicationIdAsync((TAuthorization) authorization, cancellationToken);
Task<TResult> IOpenIddictAuthorizationManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> GetAsync(query, cancellationToken);
Task<TResult> IOpenIddictAuthorizationManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> GetAsync(query, state, cancellationToken);
ValueTask<string> IOpenIddictAuthorizationManager.GetIdAsync(object authorization, CancellationToken cancellationToken)
=> GetIdAsync((TAuthorization) authorization, cancellationToken);
ValueTask<ImmutableArray<string>> IOpenIddictAuthorizationManager.GetScopesAsync(object authorization, CancellationToken cancellationToken)
=> GetScopesAsync((TAuthorization) authorization, cancellationToken);
ValueTask<string> IOpenIddictAuthorizationManager.GetStatusAsync(object authorization, CancellationToken cancellationToken)
=> GetStatusAsync((TAuthorization) authorization, cancellationToken);
ValueTask<string> IOpenIddictAuthorizationManager.GetSubjectAsync(object authorization, CancellationToken cancellationToken)
=> GetSubjectAsync((TAuthorization) authorization, cancellationToken);
ValueTask<string> IOpenIddictAuthorizationManager.GetTypeAsync(object authorization, CancellationToken cancellationToken)
=> GetTypeAsync((TAuthorization) authorization, cancellationToken);
Task<bool> IOpenIddictAuthorizationManager.HasScopesAsync(object authorization, ImmutableArray<string> scopes, CancellationToken cancellationToken)
=> HasScopesAsync((TAuthorization) authorization, scopes, cancellationToken);
Task<bool> IOpenIddictAuthorizationManager.IsAdHocAsync(object authorization, CancellationToken cancellationToken)
=> IsAdHocAsync((TAuthorization) authorization, cancellationToken);
Task<bool> IOpenIddictAuthorizationManager.IsPermanentAsync(object authorization, CancellationToken cancellationToken)
=> IsPermanentAsync((TAuthorization) authorization, cancellationToken);
Task<bool> IOpenIddictAuthorizationManager.IsRevokedAsync(object authorization, CancellationToken cancellationToken)
=> IsRevokedAsync((TAuthorization) authorization, cancellationToken);
Task<bool> IOpenIddictAuthorizationManager.IsValidAsync(object authorization, CancellationToken cancellationToken)
=> IsValidAsync((TAuthorization) authorization, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictAuthorizationManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> (await ListAsync(count, offset, cancellationToken)).CastArray<object>();
Task<ImmutableArray<TResult>> IOpenIddictAuthorizationManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> ListAsync(query, cancellationToken);
Task<ImmutableArray<TResult>> IOpenIddictAuthorizationManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> ListAsync(query, state, cancellationToken);
Task IOpenIddictAuthorizationManager.PopulateAsync(OpenIddictAuthorizationDescriptor descriptor, object authorization, CancellationToken cancellationToken)
=> PopulateAsync(descriptor, (TAuthorization) authorization, cancellationToken);
Task IOpenIddictAuthorizationManager.PopulateAsync(object authorization, OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
=> PopulateAsync((TAuthorization) authorization, descriptor, cancellationToken);
Task IOpenIddictAuthorizationManager.PruneAsync(CancellationToken cancellationToken)
=> PruneAsync(cancellationToken);
Task IOpenIddictAuthorizationManager.RevokeAsync(object authorization, CancellationToken cancellationToken)
=> RevokeAsync((TAuthorization) authorization, cancellationToken);
Task IOpenIddictAuthorizationManager.SetApplicationIdAsync(object authorization, string identifier, CancellationToken cancellationToken)
=> SetApplicationIdAsync((TAuthorization) authorization, identifier, cancellationToken);
Task IOpenIddictAuthorizationManager.UpdateAsync(object authorization, CancellationToken cancellationToken)
=> UpdateAsync((TAuthorization) authorization, cancellationToken);
Task IOpenIddictAuthorizationManager.UpdateAsync(object authorization, OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken)
=> UpdateAsync((TAuthorization) authorization, cancellationToken);
Task<ImmutableArray<ValidationResult>> IOpenIddictAuthorizationManager.ValidateAsync(object authorization, CancellationToken cancellationToken)
=> ValidateAsync((TAuthorization) authorization, cancellationToken);
}
}

78
src/OpenIddict.Core/Managers/OpenIddictScopeManager.cs

@ -22,7 +22,7 @@ namespace OpenIddict.Core
/// Provides methods allowing to manage the scopes stored in the store.
/// </summary>
/// <typeparam name="TScope">The type of the Scope entity.</typeparam>
public class OpenIddictScopeManager<TScope> where TScope : class
public class OpenIddictScopeManager<TScope> : IOpenIddictScopeManager where TScope : class
{
public OpenIddictScopeManager(
[NotNull] IOpenIddictScopeStoreResolver resolver,
@ -58,9 +58,7 @@ namespace OpenIddict.Core
/// whose result returns the number of scopes in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken = default)
{
return Store.CountAsync(cancellationToken);
}
=> Store.CountAsync(cancellationToken);
/// <summary>
/// Determines the number of scopes that match the specified query.
@ -627,5 +625,77 @@ namespace OpenIddict.Core
builder.MoveToImmutable() :
builder.ToImmutable();
}
Task<long> IOpenIddictScopeManager.CountAsync(CancellationToken cancellationToken)
=> CountAsync(cancellationToken);
Task<long> IOpenIddictScopeManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> CountAsync(query, cancellationToken);
async Task<object> IOpenIddictScopeManager.CreateAsync(OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
=> await CreateAsync(descriptor, cancellationToken);
Task IOpenIddictScopeManager.CreateAsync(object scope, CancellationToken cancellationToken)
=> CreateAsync((TScope) scope, cancellationToken);
Task IOpenIddictScopeManager.DeleteAsync(object scope, CancellationToken cancellationToken)
=> DeleteAsync((TScope) scope, cancellationToken);
async Task<object> IOpenIddictScopeManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByIdAsync(identifier, cancellationToken);
async Task<object> IOpenIddictScopeManager.FindByNameAsync(string name, CancellationToken cancellationToken)
=> await FindByNameAsync(name, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictScopeManager.FindByNamesAsync(ImmutableArray<string> names, CancellationToken cancellationToken)
=> (await FindByNamesAsync(names, cancellationToken)).CastArray<object>();
Task<TResult> IOpenIddictScopeManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> GetAsync(query, cancellationToken);
Task<TResult> IOpenIddictScopeManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> GetAsync(query, state, cancellationToken);
ValueTask<string> IOpenIddictScopeManager.GetDescriptionAsync(object scope, CancellationToken cancellationToken)
=> GetDescriptionAsync((TScope) scope, cancellationToken);
ValueTask<string> IOpenIddictScopeManager.GetDisplayNameAsync(object scope, CancellationToken cancellationToken)
=> GetDisplayNameAsync((TScope) scope, cancellationToken);
ValueTask<string> IOpenIddictScopeManager.GetIdAsync(object scope, CancellationToken cancellationToken)
=> GetIdAsync((TScope) scope, cancellationToken);
ValueTask<string> IOpenIddictScopeManager.GetNameAsync(object scope, CancellationToken cancellationToken)
=> GetNameAsync((TScope) scope, cancellationToken);
ValueTask<ImmutableArray<string>> IOpenIddictScopeManager.GetResourcesAsync(object scope, CancellationToken cancellationToken)
=> GetResourcesAsync((TScope) scope, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictScopeManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> (await ListAsync(count, offset, cancellationToken)).CastArray<object>();
Task<ImmutableArray<TResult>> IOpenIddictScopeManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> ListAsync(query, cancellationToken);
Task<ImmutableArray<TResult>> IOpenIddictScopeManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> ListAsync(query, state, cancellationToken);
Task<ImmutableArray<string>> IOpenIddictScopeManager.ListResourcesAsync(ImmutableArray<string> scopes, CancellationToken cancellationToken)
=> ListResourcesAsync(scopes, cancellationToken);
Task IOpenIddictScopeManager.PopulateAsync(OpenIddictScopeDescriptor descriptor, object scope, CancellationToken cancellationToken)
=> PopulateAsync(descriptor, (TScope) scope, cancellationToken);
Task IOpenIddictScopeManager.PopulateAsync(object scope, OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
=> PopulateAsync((TScope) scope, descriptor, cancellationToken);
Task IOpenIddictScopeManager.UpdateAsync(object scope, CancellationToken cancellationToken)
=> UpdateAsync((TScope) scope, cancellationToken);
Task IOpenIddictScopeManager.UpdateAsync(object scope, OpenIddictScopeDescriptor descriptor, CancellationToken cancellationToken)
=> UpdateAsync((TScope) scope, descriptor, cancellationToken);
Task<ImmutableArray<ValidationResult>> IOpenIddictScopeManager.ValidateAsync(object scope, CancellationToken cancellationToken)
=> ValidateAsync((TScope) scope, cancellationToken);
}
}

126
src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs

@ -23,7 +23,7 @@ namespace OpenIddict.Core
/// Provides methods allowing to manage the tokens stored in the store.
/// </summary>
/// <typeparam name="TToken">The type of the Token entity.</typeparam>
public class OpenIddictTokenManager<TToken> where TToken : class
public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TToken : class
{
public OpenIddictTokenManager(
[NotNull] IOpenIddictTokenStoreResolver resolver,
@ -59,9 +59,7 @@ namespace OpenIddict.Core
/// whose result returns the number of tokens in the database.
/// </returns>
public virtual Task<long> CountAsync(CancellationToken cancellationToken = default)
{
return Store.CountAsync(cancellationToken);
}
=> Store.CountAsync(cancellationToken);
/// <summary>
/// Determines the number of tokens that match the specified query.
@ -968,5 +966,125 @@ namespace OpenIddict.Core
builder.MoveToImmutable() :
builder.ToImmutable();
}
Task<long> IOpenIddictTokenManager.CountAsync(CancellationToken cancellationToken)
=> CountAsync(cancellationToken);
Task<long> IOpenIddictTokenManager.CountAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> CountAsync(query, cancellationToken);
async Task<object> IOpenIddictTokenManager.CreateAsync(OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
=> await CreateAsync(descriptor, cancellationToken);
Task IOpenIddictTokenManager.CreateAsync(object token, CancellationToken cancellationToken)
=> CreateAsync((TToken) token, cancellationToken);
Task IOpenIddictTokenManager.DeleteAsync(object token, CancellationToken cancellationToken)
=> DeleteAsync((TToken) token, cancellationToken);
Task IOpenIddictTokenManager.ExtendAsync(object token, DateTimeOffset? date, CancellationToken cancellationToken)
=> ExtendAsync((TToken) token, date, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
=> (await FindByApplicationIdAsync(identifier, cancellationToken)).CastArray<object>();
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken)
=> (await FindByAuthorizationIdAsync(identifier, cancellationToken)).CastArray<object>();
async Task<object> IOpenIddictTokenManager.FindByIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByIdAsync(identifier, cancellationToken);
async Task<object> IOpenIddictTokenManager.FindByReferenceIdAsync(string identifier, CancellationToken cancellationToken)
=> await FindByReferenceIdAsync(identifier, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindBySubjectAsync(string subject, CancellationToken cancellationToken)
=> (await FindBySubjectAsync(subject, cancellationToken)).CastArray<object>();
ValueTask<string> IOpenIddictTokenManager.GetApplicationIdAsync(object token, CancellationToken cancellationToken)
=> GetApplicationIdAsync((TToken) token, cancellationToken);
Task<TResult> IOpenIddictTokenManager.GetAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> GetAsync(query, cancellationToken);
Task<TResult> IOpenIddictTokenManager.GetAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> GetAsync(query, state, cancellationToken);
ValueTask<string> IOpenIddictTokenManager.GetAuthorizationIdAsync(object token, CancellationToken cancellationToken)
=> GetAuthorizationIdAsync((TToken) token, cancellationToken);
ValueTask<DateTimeOffset?> IOpenIddictTokenManager.GetCreationDateAsync(object token, CancellationToken cancellationToken)
=> GetCreationDateAsync((TToken) token, cancellationToken);
ValueTask<DateTimeOffset?> IOpenIddictTokenManager.GetExpirationDateAsync(object token, CancellationToken cancellationToken)
=> GetExpirationDateAsync((TToken) token, cancellationToken);
ValueTask<string> IOpenIddictTokenManager.GetIdAsync(object token, CancellationToken cancellationToken)
=> GetIdAsync((TToken) token, cancellationToken);
ValueTask<string> IOpenIddictTokenManager.GetPayloadAsync(object token, CancellationToken cancellationToken)
=> GetPayloadAsync((TToken) token, cancellationToken);
ValueTask<string> IOpenIddictTokenManager.GetReferenceIdAsync(object token, CancellationToken cancellationToken)
=> GetReferenceIdAsync((TToken) token, cancellationToken);
ValueTask<string> IOpenIddictTokenManager.GetStatusAsync(object token, CancellationToken cancellationToken)
=> GetStatusAsync((TToken) token, cancellationToken);
ValueTask<string> IOpenIddictTokenManager.GetSubjectAsync(object token, CancellationToken cancellationToken)
=> GetSubjectAsync((TToken) token, cancellationToken);
ValueTask<string> IOpenIddictTokenManager.GetTokenTypeAsync(object token, CancellationToken cancellationToken)
=> GetTokenTypeAsync((TToken) token, cancellationToken);
Task<bool> IOpenIddictTokenManager.IsRedeemedAsync(object token, CancellationToken cancellationToken)
=> IsRedeemedAsync((TToken) token, cancellationToken);
Task<bool> IOpenIddictTokenManager.IsRevokedAsync(object token, CancellationToken cancellationToken)
=> IsRevokedAsync((TToken) token, cancellationToken);
Task<bool> IOpenIddictTokenManager.IsValidAsync(object token, CancellationToken cancellationToken)
=> IsValidAsync((TToken) token, cancellationToken);
async Task<ImmutableArray<object>> IOpenIddictTokenManager.ListAsync(int? count, int? offset, CancellationToken cancellationToken)
=> (await ListAsync(count, offset, cancellationToken)).CastArray<object>();
Task<ImmutableArray<TResult>> IOpenIddictTokenManager.ListAsync<TResult>(Func<IQueryable<object>, IQueryable<TResult>> query, CancellationToken cancellationToken)
=> ListAsync(query, cancellationToken);
Task<ImmutableArray<TResult>> IOpenIddictTokenManager.ListAsync<TState, TResult>(Func<IQueryable<object>, TState, IQueryable<TResult>> query, TState state, CancellationToken cancellationToken)
=> ListAsync(query, state, cancellationToken);
Task<string> IOpenIddictTokenManager.ObfuscateReferenceIdAsync(string identifier, CancellationToken cancellationToken)
=> ObfuscateReferenceIdAsync(identifier, cancellationToken);
Task IOpenIddictTokenManager.PopulateAsync(OpenIddictTokenDescriptor descriptor, object token, CancellationToken cancellationToken)
=> PopulateAsync(descriptor, (TToken) token, cancellationToken);
Task IOpenIddictTokenManager.PopulateAsync(object token, OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
=> PopulateAsync((TToken) token, descriptor, cancellationToken);
Task IOpenIddictTokenManager.PruneAsync(CancellationToken cancellationToken)
=> PruneAsync(cancellationToken);
Task IOpenIddictTokenManager.RedeemAsync(object token, CancellationToken cancellationToken)
=> RedeemAsync((TToken) token, cancellationToken);
Task IOpenIddictTokenManager.RevokeAsync(object token, CancellationToken cancellationToken)
=> RevokeAsync((TToken) token, cancellationToken);
Task IOpenIddictTokenManager.SetApplicationIdAsync(object token, string identifier, CancellationToken cancellationToken)
=> SetApplicationIdAsync((TToken) token, identifier, cancellationToken);
Task IOpenIddictTokenManager.SetAuthorizationIdAsync(object token, string identifier, CancellationToken cancellationToken)
=> SetAuthorizationIdAsync((TToken) token, identifier, cancellationToken);
Task IOpenIddictTokenManager.UpdateAsync(object token, CancellationToken cancellationToken)
=> UpdateAsync((TToken) token, cancellationToken);
Task IOpenIddictTokenManager.UpdateAsync(object token, OpenIddictTokenDescriptor descriptor, CancellationToken cancellationToken)
=> UpdateAsync((TToken) token, descriptor, cancellationToken);
Task<ImmutableArray<ValidationResult>> IOpenIddictTokenManager.ValidateAsync(object token, CancellationToken cancellationToken)
=> ValidateAsync((TToken) token, cancellationToken);
}
}

5
src/OpenIddict.Core/OpenIddict.Core.csproj

@ -20,12 +20,7 @@
<PackageReference Include="CryptoHelper" Version="$(CryptoHelperVersion)" />
<PackageReference Include="JetBrains.Annotations" Version="$(JetBrainsVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(JsonNetVersion)" />
<PackageReference Include="System.Collections.Immutable" Version="$(ImmutableCollectionsVersion)" />
<PackageReference Include="System.ComponentModel.Annotations" Version="$(DataAnnotationsVersion)" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="$(TasksExtensionsVersion)" />
</ItemGroup>
</Project>

66
src/OpenIddict.Core/OpenIddictCoreExtensions.cs

@ -5,8 +5,10 @@
*/
using System;
using System.Text;
using JetBrains.Annotations;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
using OpenIddict.Core;
@ -41,6 +43,70 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Services.TryAddScoped<IOpenIddictScopeStoreResolver, OpenIddictScopeStoreResolver>();
builder.Services.TryAddScoped<IOpenIddictTokenStoreResolver, OpenIddictTokenStoreResolver>();
builder.Services.TryAddScoped(provider =>
{
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue;
if (options.DefaultApplicationType == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The default application type must be configured for the non-generic services to work correctly.")
.Append("To configure the entities, use either 'services.AddOpenIddict().AddCore().UseDefaultModels()' ")
.Append("or 'services.AddOpenIddict().AddCore().UseCustomModels()'.")
.ToString());
}
return (IOpenIddictApplicationManager) provider.GetRequiredService(
typeof(OpenIddictApplicationManager<>).MakeGenericType(options.DefaultApplicationType));
});
builder.Services.TryAddScoped(provider =>
{
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue;
if (options.DefaultAuthorizationType == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The default authorization type must be configured for the non-generic services to work correctly.")
.Append("To configure the entities, use either 'services.AddOpenIddict().AddCore().UseDefaultModels()' ")
.Append("or 'services.AddOpenIddict().AddCore().UseCustomModels()'.")
.ToString());
}
return (IOpenIddictAuthorizationManager) provider.GetRequiredService(
typeof(OpenIddictAuthorizationManager<>).MakeGenericType(options.DefaultAuthorizationType));
});
builder.Services.TryAddScoped(provider =>
{
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue;
if (options.DefaultScopeType == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The default scope type must be configured for the non-generic services to work correctly.")
.Append("To configure the entities, use either 'services.AddOpenIddict().AddCore().UseDefaultModels()' ")
.Append("or 'services.AddOpenIddict().AddCore().UseCustomModels()'.")
.ToString());
}
return (IOpenIddictScopeManager) provider.GetRequiredService(
typeof(OpenIddictScopeManager<>).MakeGenericType(options.DefaultScopeType));
});
builder.Services.TryAddScoped(provider =>
{
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictCoreOptions>>().CurrentValue;
if (options.DefaultTokenType == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The default token type must be configured for the non-generic services to work correctly.")
.Append("To configure the entities, use either 'services.AddOpenIddict().AddCore().UseDefaultModels()' ")
.Append("or 'services.AddOpenIddict().AddCore().UseCustomModels()'.")
.ToString());
}
return (IOpenIddictTokenManager) provider.GetRequiredService(
typeof(OpenIddictTokenManager<>).MakeGenericType(options.DefaultTokenType));
});
return new OpenIddictCoreBuilder(builder.Services);
}

12
src/OpenIddict.Core/OpenIddictCoreOptions.cs

@ -11,22 +11,26 @@ namespace OpenIddict.Core
public class OpenIddictCoreOptions
{
/// <summary>
/// Gets or sets the type corresponding to the Application entity.
/// Gets or sets the type corresponding to the default Application entity,
/// used by the non-generic application manager and the server/validation services.
/// </summary>
public Type DefaultApplicationType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Authorization entity.
/// Gets or sets the type corresponding to the default Authorization entity,
/// used by the non-generic authorization manager and the server/validation services.
/// </summary>
public Type DefaultAuthorizationType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Scope entity.
/// Gets or sets the type corresponding to the default Scope entity,
/// used by the non-generic scope manager and the server/validation services.
/// </summary>
public Type DefaultScopeType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Token entity.
/// Gets or sets the type corresponding to the default Token entity,
/// used by the non-generic token manager and the server/validation services.
/// </summary>
public Type DefaultTokenType { get; set; }
}

2
src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs

@ -285,7 +285,7 @@ namespace OpenIddict.EntityFramework
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public override async Task PruneAsync(CancellationToken cancellationToken = default)
public override async Task PruneAsync(CancellationToken cancellationToken)
{
// Note: Entity Framework 6.x doesn't support set-based deletes, which prevents removing
// entities in a single command without having to retrieve and materialize them first.

2
src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs

@ -291,7 +291,7 @@ namespace OpenIddict.EntityFramework
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public override async Task PruneAsync(CancellationToken cancellationToken = default)
public override async Task PruneAsync(CancellationToken cancellationToken)
{
// Note: Entity Framework 6.x doesn't support set-based deletes, which prevents removing
// entities in a single command without having to retrieve and materialize them first.

2
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs

@ -527,7 +527,7 @@ namespace OpenIddict.EntityFrameworkCore
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public override async Task PruneAsync(CancellationToken cancellationToken = default)
public override async Task PruneAsync(CancellationToken cancellationToken)
{
// Note: Entity Framework Core doesn't support set-based deletes, which prevents removing
// entities in a single command without having to retrieve and materialize them first.

2
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs

@ -469,7 +469,7 @@ namespace OpenIddict.EntityFrameworkCore
/// <returns>
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation.
/// </returns>
public override async Task PruneAsync(CancellationToken cancellationToken = default)
public override async Task PruneAsync(CancellationToken cancellationToken)
{
// Note: Entity Framework Core doesn't support set-based deletes, which prevents removing
// entities in a single command without having to retrieve and materialize them first.

26
src/OpenIddict.Server/Internal/OpenIddictServerInitializer.cs

@ -15,7 +15,6 @@ using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Core;
namespace OpenIddict.Server
{
@ -28,19 +27,16 @@ namespace OpenIddict.Server
{
private readonly IDistributedCache _cache;
private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly IOptionsMonitor<OpenIddictCoreOptions> _options;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictServerInitializer"/> class.
/// </summary>
public OpenIddictServerInitializer(
[NotNull] IDistributedCache cache,
[NotNull] IDataProtectionProvider dataProtectionProvider,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options)
[NotNull] IDataProtectionProvider dataProtectionProvider)
{
_cache = cache;
_dataProtectionProvider = dataProtectionProvider;
_options = options;
}
/// <summary>
@ -193,26 +189,6 @@ namespace OpenIddict.Server
{
options.Scopes.Add(OpenIdConnectConstants.Scopes.OfflineAccess);
}
if (options.ApplicationType == null)
{
options.ApplicationType = _options.CurrentValue.DefaultApplicationType;
}
if (options.AuthorizationType == null)
{
options.AuthorizationType = _options.CurrentValue.DefaultAuthorizationType;
}
if (options.ScopeType == null)
{
options.ScopeType = _options.CurrentValue.DefaultScopeType;
}
if (options.TokenType == null)
{
options.TokenType = _options.CurrentValue.DefaultTokenType;
}
}
}
}

109
src/OpenIddict.Server/Internal/OpenIddictServerProvider.Authentication.cs

@ -23,8 +23,7 @@ using OpenIddict.Abstractions;
namespace OpenIddict.Server
{
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
public partial class OpenIddictServerProvider : OpenIdConnectServerProvider
{
public override async Task ExtractAuthorizationRequest([NotNull] ExtractAuthorizationRequestContext context)
{
@ -33,8 +32,8 @@ namespace OpenIddict.Server
// Reject requests using the unsupported request parameter.
if (!string.IsNullOrEmpty(context.Request.Request))
{
Logger.LogError("The authorization request was rejected because it contained " +
"an unsupported parameter: {Parameter}.", "request");
_logger.LogError("The authorization request was rejected because it contained " +
"an unsupported parameter: {Parameter}.", "request");
context.Reject(
error: OpenIdConnectConstants.Errors.RequestNotSupported,
@ -46,8 +45,8 @@ namespace OpenIddict.Server
// Reject requests using the unsupported request_uri parameter.
if (!string.IsNullOrEmpty(context.Request.RequestUri))
{
Logger.LogError("The authorization request was rejected because it contained " +
"an unsupported parameter: {Parameter}.", "request_uri");
_logger.LogError("The authorization request was rejected because it contained " +
"an unsupported parameter: {Parameter}.", "request_uri");
context.Reject(
error: OpenIdConnectConstants.Errors.RequestUriNotSupported,
@ -63,8 +62,8 @@ namespace OpenIddict.Server
// Return an error if request caching support was not enabled.
if (!options.EnableRequestCaching)
{
Logger.LogError("The authorization request was rejected because " +
"request caching support was not enabled.");
_logger.LogError("The authorization request was rejected because " +
"request caching support was not enabled.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -80,8 +79,8 @@ namespace OpenIddict.Server
var payload = await options.Cache.GetAsync(key);
if (payload == null)
{
Logger.LogError("The authorization request was rejected because an unknown " +
"or invalid request_id parameter was specified.");
_logger.LogError("The authorization request was rejected because an unknown " +
"or invalid request_id parameter was specified.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -115,8 +114,8 @@ namespace OpenIddict.Server
// none and custom flows but OpenIddict uses a stricter policy rejecting none and custum flows.
if (!context.Request.IsAuthorizationCodeFlow() && !context.Request.IsHybridFlow() && !context.Request.IsImplicitFlow())
{
Logger.LogError("The authorization request was rejected because the '{ResponseType}' " +
"response type is not supported.", context.Request.ResponseType);
_logger.LogError("The authorization request was rejected because the '{ResponseType}' " +
"response type is not supported.", context.Request.ResponseType);
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedResponseType,
@ -129,8 +128,8 @@ namespace OpenIddict.Server
if (context.Request.IsAuthorizationCodeFlow() &&
!options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode))
{
Logger.LogError("The authorization request was rejected because " +
"the authorization code flow was not enabled.");
_logger.LogError("The authorization request was rejected because " +
"the authorization code flow was not enabled.");
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedResponseType,
@ -142,7 +141,7 @@ namespace OpenIddict.Server
// Reject implicit flow authorization requests if the implicit flow is not enabled.
if (context.Request.IsImplicitFlow() && !options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.Implicit))
{
Logger.LogError("The authorization request was rejected because the implicit flow was not enabled.");
_logger.LogError("The authorization request was rejected because the implicit flow was not enabled.");
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedResponseType,
@ -155,8 +154,8 @@ namespace OpenIddict.Server
if (context.Request.IsHybridFlow() && (!options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.AuthorizationCode) ||
!options.GrantTypes.Contains(OpenIdConnectConstants.GrantTypes.Implicit)))
{
Logger.LogError("The authorization request was rejected because the " +
"authorization code flow or the implicit flow was not enabled.");
_logger.LogError("The authorization request was rejected because the " +
"authorization code flow or the implicit flow was not enabled.");
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedResponseType,
@ -180,10 +179,10 @@ namespace OpenIddict.Server
foreach (var scope in context.Request.GetScopes())
{
if (options.EnableScopeValidation && !options.Scopes.Contains(scope) &&
await Scopes.FindByNameAsync(scope) == null)
await _scopeManager.FindByNameAsync(scope) == null)
{
Logger.LogError("The authorization request was rejected because an " +
"unregistered scope was specified: {Scope}.", scope);
_logger.LogError("The authorization request was rejected because an " +
"unregistered scope was specified: {Scope}.", scope);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -200,8 +199,8 @@ namespace OpenIddict.Server
!context.Request.IsFragmentResponseMode() &&
!context.Request.IsQueryResponseMode())
{
Logger.LogError("The authorization request was rejected because the '{ResponseMode}' " +
"response mode is not supported.", context.Request.ResponseMode);
_logger.LogError("The authorization request was rejected because the '{ResponseMode}' " +
"response mode is not supported.", context.Request.ResponseMode);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -231,8 +230,8 @@ namespace OpenIddict.Server
// reject the authorization request if the code_challenge_method is missing.
if (string.IsNullOrEmpty(context.Request.CodeChallengeMethod))
{
Logger.LogError("The authorization request was rejected because the " +
"required 'code_challenge_method' parameter was missing.");
_logger.LogError("The authorization request was rejected because the " +
"required 'code_challenge_method' parameter was missing.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -245,8 +244,8 @@ namespace OpenIddict.Server
// See https://tools.ietf.org/html/rfc7636#section-7.2 for more information.
if (string.Equals(context.Request.CodeChallengeMethod, OpenIdConnectConstants.CodeChallengeMethods.Plain))
{
Logger.LogError("The authorization request was rejected because the " +
"'code_challenge_method' parameter was set to 'plain'.");
_logger.LogError("The authorization request was rejected because the " +
"'code_challenge_method' parameter was set to 'plain'.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -258,8 +257,8 @@ namespace OpenIddict.Server
// Reject authorization requests that contain response_type=token when a code_challenge is specified.
if (context.Request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Token))
{
Logger.LogError("The authorization request was rejected because the " +
"specified response type was not compatible with PKCE.");
_logger.LogError("The authorization request was rejected because the " +
"specified response type was not compatible with PKCE.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -270,11 +269,11 @@ namespace OpenIddict.Server
}
// Retrieve the application details corresponding to the requested client_id.
var application = await Applications.FindByClientIdAsync(context.ClientId);
var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null)
{
Logger.LogError("The authorization request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
_logger.LogError("The authorization request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -291,7 +290,7 @@ namespace OpenIddict.Server
// from the authorization endpoint are rejected if the client_id corresponds to a confidential application.
// Note: when using the authorization code grant, ValidateTokenRequest is responsible of rejecting
// the token request if the client_id corresponds to an unauthenticated confidential client.
if (await Applications.IsConfidentialAsync(application) &&
if (await _applicationManager.IsConfidentialAsync(application) &&
context.Request.HasResponseType(OpenIdConnectConstants.ResponseTypes.Token))
{
context.Reject(
@ -302,10 +301,10 @@ namespace OpenIddict.Server
}
// Reject the request if the application is not allowed to use the authorization endpoint.
if (!await Applications.HasPermissionAsync(application, OpenIddictConstants.Permissions.Endpoints.Authorization))
if (!await _applicationManager.HasPermissionAsync(application, OpenIddictConstants.Permissions.Endpoints.Authorization))
{
Logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to use the authorization endpoint.", context.ClientId);
_logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to use the authorization endpoint.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.UnauthorizedClient,
@ -315,11 +314,11 @@ namespace OpenIddict.Server
}
// Reject the request if the application is not allowed to use the authorization code flow.
if (context.Request.IsAuthorizationCodeFlow() && !await Applications.HasPermissionAsync(
if (context.Request.IsAuthorizationCodeFlow() && !await _applicationManager.HasPermissionAsync(
application, OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode))
{
Logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to use the authorization code flow.", context.ClientId);
_logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to use the authorization code flow.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.UnauthorizedClient,
@ -329,11 +328,11 @@ namespace OpenIddict.Server
}
// Reject the request if the application is not allowed to use the implicit flow.
if (context.Request.IsImplicitFlow() && !await Applications.HasPermissionAsync(
if (context.Request.IsImplicitFlow() && !await _applicationManager.HasPermissionAsync(
application, OpenIddictConstants.Permissions.GrantTypes.Implicit))
{
Logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to use the implicit flow.", context.ClientId);
_logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to use the implicit flow.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.UnauthorizedClient,
@ -344,15 +343,15 @@ namespace OpenIddict.Server
// Reject the request if the application is not allowed to use the authorization code/implicit flows.
if (context.Request.IsHybridFlow() &&
(!await Applications.HasPermissionAsync(application, OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode) ||
!await Applications.HasPermissionAsync(application, OpenIddictConstants.Permissions.GrantTypes.Implicit)))
(!await _applicationManager.HasPermissionAsync(application, OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode) ||
!await _applicationManager.HasPermissionAsync(application, OpenIddictConstants.Permissions.GrantTypes.Implicit)))
{
Logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to use the hybrid flow.", context.ClientId);
_logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to use the hybrid flow.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.UnauthorizedClient,
description: "The client application is not allowed to use the hybrid flow.");
description: "The client application is not allowed to use the hybrid flow.");
return;
}
@ -360,10 +359,10 @@ namespace OpenIddict.Server
// Reject the request if the offline_access scope was request and if the
// application is not allowed to use the authorization code/implicit flows.
if (context.Request.HasScope(OpenIdConnectConstants.Scopes.OfflineAccess) &&
!await Applications.HasPermissionAsync(application, OpenIddictConstants.Permissions.GrantTypes.RefreshToken))
!await _applicationManager.HasPermissionAsync(application, OpenIddictConstants.Permissions.GrantTypes.RefreshToken))
{
Logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to request the 'offline_access' scope.", context.ClientId);
_logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to request the 'offline_access' scope.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -373,10 +372,10 @@ namespace OpenIddict.Server
}
// Ensure that the specified redirect_uri is valid and is associated with the client application.
if (!await Applications.ValidateRedirectUriAsync(application, context.RedirectUri))
if (!await _applicationManager.ValidateRedirectUriAsync(application, context.RedirectUri))
{
Logger.LogError("The authorization request was rejected because the redirect_uri " +
"was invalid: '{RedirectUri}'.", context.RedirectUri);
_logger.LogError("The authorization request was rejected because the redirect_uri " +
"was invalid: '{RedirectUri}'.", context.RedirectUri);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -395,10 +394,10 @@ namespace OpenIddict.Server
}
// Reject the request if the application is not allowed to use the iterated scope.
if (!await Applications.HasPermissionAsync(application, OpenIddictConstants.Permissions.Prefixes.Scope + scope))
if (!await _applicationManager.HasPermissionAsync(application, OpenIddictConstants.Permissions.Prefixes.Scope + scope))
{
Logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to use the scope {Scope}.", context.ClientId, scope);
_logger.LogError("The authorization request was rejected because the application '{ClientId}' " +
"was not allowed to use the scope {Scope}.", context.ClientId, scope);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,

3
src/OpenIddict.Server/Internal/OpenIddictServerProvider.Discovery.cs

@ -16,8 +16,7 @@ using OpenIddict.Abstractions;
namespace OpenIddict.Server
{
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
public partial class OpenIddictServerProvider : OpenIdConnectServerProvider
{
public override async Task HandleConfigurationRequest([NotNull] HandleConfigurationRequestContext context)
{

83
src/OpenIddict.Server/Internal/OpenIddictServerProvider.Exchange.cs

@ -16,8 +16,7 @@ using OpenIddict.Abstractions;
namespace OpenIddict.Server
{
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
public partial class OpenIddictServerProvider : OpenIdConnectServerProvider
{
public override async Task ValidateTokenRequest([NotNull] ValidateTokenRequestContext context)
{
@ -26,8 +25,8 @@ namespace OpenIddict.Server
// Reject token requests that don't specify a supported grant type.
if (!options.GrantTypes.Contains(context.Request.GrantType))
{
Logger.LogError("The token request was rejected because the '{GrantType}' " +
"grant type is not supported.", context.Request.GrantType);
_logger.LogError("The token request was rejected because the '{GrantType}' " +
"grant type is not supported.", context.Request.GrantType);
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedGrantType,
@ -80,10 +79,10 @@ namespace OpenIddict.Server
foreach (var scope in context.Request.GetScopes())
{
if (options.EnableScopeValidation && !options.Scopes.Contains(scope) &&
await Scopes.FindByNameAsync(scope) == null)
await _scopeManager.FindByNameAsync(scope) == null)
{
Logger.LogError("The token request was rejected because an " +
"unregistered scope was specified: {Scope}.", scope);
_logger.LogError("The token request was rejected because an " +
"unregistered scope was specified: {Scope}.", scope);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -117,8 +116,8 @@ namespace OpenIddict.Server
// Reject the request if client identification is mandatory.
if (options.RequireClientIdentification)
{
Logger.LogError("The token request was rejected becaused the " +
"mandatory client_id parameter was missing or empty.");
_logger.LogError("The token request was rejected becaused the " +
"mandatory client_id parameter was missing or empty.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -127,8 +126,8 @@ namespace OpenIddict.Server
return;
}
Logger.LogDebug("The token request validation process was partially skipped " +
"because the 'client_id' parameter was missing or empty.");
_logger.LogDebug("The token request validation process was partially skipped " +
"because the 'client_id' parameter was missing or empty.");
context.Skip();
@ -136,11 +135,11 @@ namespace OpenIddict.Server
}
// Retrieve the application details corresponding to the requested client_id.
var application = await Applications.FindByClientIdAsync(context.ClientId);
var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null)
{
Logger.LogError("The token request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
_logger.LogError("The token request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -154,10 +153,10 @@ namespace OpenIddict.Server
context.Request.SetProperty($"{OpenIddictConstants.Properties.Application}:{context.ClientId}", application);
// Reject the request if the application is not allowed to use the token endpoint.
if (!await Applications.HasPermissionAsync(application, OpenIddictConstants.Permissions.Endpoints.Token))
if (!await _applicationManager.HasPermissionAsync(application, OpenIddictConstants.Permissions.Endpoints.Token))
{
Logger.LogError("The token request was rejected because the application '{ClientId}' " +
"was not allowed to use the token endpoint.", context.ClientId);
_logger.LogError("The token request was rejected because the application '{ClientId}' " +
"was not allowed to use the token endpoint.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.UnauthorizedClient,
@ -167,11 +166,11 @@ namespace OpenIddict.Server
}
// Reject the request if the application is not allowed to use the specified grant type.
if (!await Applications.HasPermissionAsync(application,
if (!await _applicationManager.HasPermissionAsync(application,
OpenIddictConstants.Permissions.Prefixes.GrantType + context.Request.GrantType))
{
Logger.LogError("The token request was rejected because the application '{ClientId}' was not allowed to " +
"use the specified grant type: {GrantType}.", context.ClientId, context.Request.GrantType);
_logger.LogError("The token request was rejected because the application '{ClientId}' was not allowed to " +
"use the specified grant type: {GrantType}.", context.ClientId, context.Request.GrantType);
context.Reject(
error: OpenIdConnectConstants.Errors.UnauthorizedClient,
@ -180,13 +179,13 @@ namespace OpenIddict.Server
return;
}
if (await Applications.IsPublicAsync(application))
if (await _applicationManager.IsPublicAsync(application))
{
// Note: public applications are not allowed to use the client credentials grant.
if (context.Request.IsClientCredentialsGrantType())
{
Logger.LogError("The token request was rejected because the public client application '{ClientId}' " +
"was not allowed to use the client credentials grant.", context.Request.ClientId);
_logger.LogError("The token request was rejected because the public client application '{ClientId}' " +
"was not allowed to use the client credentials grant.", context.Request.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.UnauthorizedClient,
@ -198,8 +197,8 @@ namespace OpenIddict.Server
// Reject token requests containing a client_secret when the client is a public application.
if (!string.IsNullOrEmpty(context.ClientSecret))
{
Logger.LogError("The token request was rejected because the public application '{ClientId}' " +
"was not allowed to send a client secret.", context.ClientId);
_logger.LogError("The token request was rejected because the public application '{ClientId}' " +
"was not allowed to send a client secret.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -208,8 +207,8 @@ namespace OpenIddict.Server
return;
}
Logger.LogDebug("The token request validation process was not fully validated because " +
"the client '{ClientId}' was a public application.", context.ClientId);
_logger.LogDebug("The token request validation process was not fully validated because " +
"the client '{ClientId}' was a public application.", context.ClientId);
// If client authentication cannot be enforced, call context.Skip() to inform
// the OpenID Connect server middleware that the caller cannot be fully trusted.
@ -222,8 +221,8 @@ namespace OpenIddict.Server
// to protect them from impersonation attacks.
if (string.IsNullOrEmpty(context.ClientSecret))
{
Logger.LogError("The token request was rejected because the confidential or hybrid application " +
"'{ClientId}' didn't specify a client secret.", context.ClientId);
_logger.LogError("The token request was rejected because the confidential or hybrid application " +
"'{ClientId}' didn't specify a client secret.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -232,10 +231,10 @@ namespace OpenIddict.Server
return;
}
if (!await Applications.ValidateClientSecretAsync(application, context.ClientSecret))
if (!await _applicationManager.ValidateClientSecretAsync(application, context.ClientSecret))
{
Logger.LogError("The token request was rejected because the confidential or hybrid application " +
"'{ClientId}' didn't specify valid client credentials.", context.ClientId);
_logger.LogError("The token request was rejected because the confidential or hybrid application " +
"'{ClientId}' didn't specify valid client credentials.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -254,11 +253,11 @@ namespace OpenIddict.Server
}
// Reject the request if the application is not allowed to use the iterated scope.
if (!await Applications.HasPermissionAsync(application,
if (!await _applicationManager.HasPermissionAsync(application,
OpenIddictConstants.Permissions.Prefixes.Scope + scope))
{
Logger.LogError("The token request was rejected because the application '{ClientId}' " +
"was not allowed to use the scope {Scope}.", context.ClientId, scope);
_logger.LogError("The token request was rejected because the application '{ClientId}' " +
"was not allowed to use the scope {Scope}.", context.ClientId, scope);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -298,13 +297,13 @@ namespace OpenIddict.Server
Debug.Assert(!string.IsNullOrEmpty(identifier), "The authentication ticket should contain a token identifier.");
// Retrieve the authorization code/refresh token from the request properties.
var token = context.Request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");
var token = context.Request.GetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}");
Debug.Assert(token != null, "The token shouldn't be null.");
// If the authorization code/refresh token is already marked as redeemed, this may indicate that
// it was compromised. In this case, revoke the authorization and all the associated tokens.
// See https://tools.ietf.org/html/rfc6749#section-10.5 for more information.
if (await Tokens.IsRedeemedAsync(token))
if (await _tokenManager.IsRedeemedAsync(token))
{
// Try to revoke the authorization and the associated tokens.
// If the operation fails, the helpers will automatically log
@ -314,8 +313,8 @@ namespace OpenIddict.Server
await TryRevokeTokensAsync(context.Ticket);
await TryRevokeTokenAsync(token);
Logger.LogError("The token request was rejected because the authorization code " +
"or refresh token '{Identifier}' has already been redeemed.", identifier);
_logger.LogError("The token request was rejected because the authorization code " +
"or refresh token '{Identifier}' has already been redeemed.", identifier);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,
@ -326,10 +325,10 @@ namespace OpenIddict.Server
return;
}
else if (!await Tokens.IsValidAsync(token))
else if (!await _tokenManager.IsValidAsync(token))
{
Logger.LogError("The token request was rejected because the authorization code " +
"or refresh token '{Identifier}' was no longer valid.", identifier);
_logger.LogError("The token request was rejected because the authorization code " +
"or refresh token '{Identifier}' was no longer valid.", identifier);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidGrant,

156
src/OpenIddict.Server/Internal/OpenIddictServerProvider.Helpers.cs

@ -18,12 +18,10 @@ using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json.Linq;
using OpenIddict.Abstractions;
using OpenIddict.Core;
namespace OpenIddict.Server
{
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
public partial class OpenIddictServerProvider : OpenIdConnectServerProvider
{
private async Task CreateAuthorizationAsync([NotNull] AuthenticationTicket ticket,
[NotNull] OpenIddictServerOptions options, [NotNull] OpenIdConnectRequest request)
@ -49,28 +47,28 @@ namespace OpenIddict.Server
// If the client application is known, bind it to the authorization.
if (!string.IsNullOrEmpty(request.ClientId))
{
var application = request.GetProperty<TApplication>($"{OpenIddictConstants.Properties.Application}:{request.ClientId}");
var application = request.GetProperty($"{OpenIddictConstants.Properties.Application}:{request.ClientId}");
Debug.Assert(application != null, "The client application shouldn't be null.");
descriptor.ApplicationId = await Applications.GetIdAsync(application);
descriptor.ApplicationId = await _applicationManager.GetIdAsync(application);
}
var authorization = await Authorizations.CreateAsync(descriptor);
var authorization = await _authorizationManager.CreateAsync(descriptor);
if (authorization != null)
{
var identifier = await Authorizations.GetIdAsync(authorization);
var identifier = await _authorizationManager.GetIdAsync(authorization);
if (string.IsNullOrEmpty(request.ClientId))
{
Logger.LogInformation("An ad hoc authorization was automatically created and " +
"associated with an unknown application: {Identifier}.", identifier);
_logger.LogInformation("An ad hoc authorization was automatically created and " +
"associated with an unknown application: {Identifier}.", identifier);
}
else
{
Logger.LogInformation("An ad hoc authorization was automatically created and " +
"associated with the '{ClientId}' application: {Identifier}.",
request.ClientId, identifier);
_logger.LogInformation("An ad hoc authorization was automatically created and " +
"associated with the '{ClientId}' application: {Identifier}.",
request.ClientId, identifier);
}
// Attach the unique identifier of the ad hoc authorization to the authentication ticket
@ -155,7 +153,7 @@ namespace OpenIddict.Server
result = Base64UrlEncoder.Encode(bytes);
// Obfuscate the reference identifier so it can be safely stored in the databse.
descriptor.ReferenceId = await Tokens.ObfuscateReferenceIdAsync(result);
descriptor.ReferenceId = await _tokenManager.ObfuscateReferenceIdAsync(result);
}
// Otherwise, only create a token metadata entry for authorization codes and refresh tokens.
@ -168,24 +166,24 @@ namespace OpenIddict.Server
// If the client application is known, associate it with the token.
if (!string.IsNullOrEmpty(request.ClientId))
{
var application = request.GetProperty<TApplication>($"{OpenIddictConstants.Properties.Application}:{request.ClientId}");
var application = request.GetProperty($"{OpenIddictConstants.Properties.Application}:{request.ClientId}");
Debug.Assert(application != null, "The client application shouldn't be null.");
descriptor.ApplicationId = await Applications.GetIdAsync(application);
descriptor.ApplicationId = await _applicationManager.GetIdAsync(application);
}
// If a null value was returned by CreateAsync(), return immediately.
// Note: the request cancellation token is deliberately not used here to ensure the caller
// cannot prevent this operation from being executed by resetting the TCP connection.
var token = await Tokens.CreateAsync(descriptor);
var token = await _tokenManager.CreateAsync(descriptor);
if (token == null)
{
return null;
}
// Throw an exception if the token identifier can't be resolved.
var identifier = await Tokens.GetIdAsync(token);
var identifier = await _tokenManager.GetIdAsync(token);
if (string.IsNullOrEmpty(identifier))
{
throw new InvalidOperationException("The unique key associated with a refresh token cannot be null or empty.");
@ -204,9 +202,9 @@ namespace OpenIddict.Server
if (!string.IsNullOrEmpty(result))
{
Logger.LogTrace("A new reference token was successfully generated and persisted " +
"in the database: {Token} ; {Claims} ; {Properties}.",
result, ticket.Principal.Claims, ticket.Properties.Items);
_logger.LogTrace("A new reference token was successfully generated and persisted " +
"in the database: {Token} ; {Claims} ; {Properties}.",
result, ticket.Principal.Claims, ticket.Properties.Items);
}
return result;
@ -228,7 +226,7 @@ namespace OpenIddict.Server
string identifier;
AuthenticationTicket ticket;
TToken token;
object token;
if (options.UseReferenceTokens)
{
@ -239,14 +237,14 @@ namespace OpenIddict.Server
// the property value (that may be null) is used instead of making a database call.
if (request.HasProperty($"{OpenIddictConstants.Properties.ReferenceToken}:{value}"))
{
token = request.GetProperty<TToken>($"{OpenIddictConstants.Properties.ReferenceToken}:{value}");
token = request.GetProperty($"{OpenIddictConstants.Properties.ReferenceToken}:{value}");
}
else
{
// Retrieve the token entry from the database. If it
// cannot be found, assume the token is not valid.
token = await Tokens.FindByReferenceIdAsync(value);
token = await _tokenManager.FindByReferenceIdAsync(value);
// Store the token as a request property so it can be retrieved if this method is called another time.
request.AddProperty($"{OpenIddictConstants.Properties.ReferenceToken}:{value}", token);
@ -254,28 +252,28 @@ namespace OpenIddict.Server
if (token == null)
{
Logger.LogInformation("The reference token corresponding to the '{Identifier}' " +
"reference identifier cannot be found in the database.", value);
_logger.LogInformation("The reference token corresponding to the '{Identifier}' " +
"reference identifier cannot be found in the database.", value);
return null;
}
identifier = await Tokens.GetIdAsync(token);
identifier = await _tokenManager.GetIdAsync(token);
if (string.IsNullOrEmpty(identifier))
{
Logger.LogWarning("The identifier associated with the received token cannot be retrieved. " +
"This may indicate that the token entry is corrupted.");
_logger.LogWarning("The identifier associated with the received token cannot be retrieved. " +
"This may indicate that the token entry is corrupted.");
return null;
}
// Extract the encrypted payload from the token. If it's null or empty,
// assume the token is not a reference token and consider it as invalid.
var payload = await Tokens.GetPayloadAsync(token);
var payload = await _tokenManager.GetPayloadAsync(token);
if (string.IsNullOrEmpty(payload))
{
Logger.LogWarning("The ciphertext associated with the token '{Identifier}' cannot be retrieved. " +
"This may indicate that the token is not a reference token.", identifier);
_logger.LogWarning("The ciphertext associated with the token '{Identifier}' cannot be retrieved. " +
"This may indicate that the token is not a reference token.", identifier);
return null;
}
@ -283,9 +281,9 @@ namespace OpenIddict.Server
ticket = format.Unprotect(payload);
if (ticket == null)
{
Logger.LogWarning("The ciphertext associated with the token '{Identifier}' cannot be decrypted. " +
"This may indicate that the token entry is corrupted or tampered.",
await Tokens.GetIdAsync(token));
_logger.LogWarning("The ciphertext associated with the token '{Identifier}' cannot be decrypted. " +
"This may indicate that the token entry is corrupted or tampered.",
await _tokenManager.GetIdAsync(token));
return null;
}
@ -299,7 +297,7 @@ namespace OpenIddict.Server
ticket = format.Unprotect(value);
if (ticket == null)
{
Logger.LogTrace("The received token was invalid or malformed: {Token}.", value);
_logger.LogTrace("The received token was invalid or malformed: {Token}.", value);
return null;
}
@ -307,8 +305,8 @@ namespace OpenIddict.Server
identifier = ticket.GetTokenId();
if (string.IsNullOrEmpty(identifier))
{
Logger.LogWarning("The identifier associated with the received token cannot be retrieved. " +
"This may indicate that the token entry is corrupted.");
_logger.LogWarning("The identifier associated with the received token cannot be retrieved. " +
"This may indicate that the token entry is corrupted.");
return null;
}
@ -320,14 +318,14 @@ namespace OpenIddict.Server
// the property value (that may be null) is used instead of making a database call.
if (request.HasProperty($"{OpenIddictConstants.Properties.Token}:{identifier}"))
{
token = request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");
token = request.GetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}");
}
// Otherwise, retrieve the authorization code/refresh token entry from the database.
// If it cannot be found, assume the authorization code/refresh token is not valid.
else
{
token = await Tokens.FindByIdAsync(identifier);
token = await _tokenManager.FindByIdAsync(identifier);
// Store the token as a request property so it can be retrieved if this method is called another time.
request.AddProperty($"{OpenIddictConstants.Properties.Token}:{identifier}", token);
@ -335,7 +333,7 @@ namespace OpenIddict.Server
if (token == null)
{
Logger.LogInformation("The token '{Identifier}' cannot be found in the database.", ticket.GetTokenId());
_logger.LogInformation("The token '{Identifier}' cannot be found in the database.", ticket.GetTokenId());
return null;
}
@ -351,16 +349,16 @@ namespace OpenIddict.Server
ticket.SetTokenId(identifier);
// Dynamically set the creation and expiration dates.
ticket.Properties.IssuedUtc = await Tokens.GetCreationDateAsync(token);
ticket.Properties.ExpiresUtc = await Tokens.GetExpirationDateAsync(token);
ticket.Properties.IssuedUtc = await _tokenManager.GetCreationDateAsync(token);
ticket.Properties.ExpiresUtc = await _tokenManager.GetExpirationDateAsync(token);
// Restore the authorization identifier using the identifier attached with the database entry.
ticket.SetProperty(OpenIddictConstants.Properties.AuthorizationId,
await Tokens.GetAuthorizationIdAsync(token));
await _tokenManager.GetAuthorizationIdAsync(token));
Logger.LogTrace("The token '{Identifier}' was successfully decrypted and " +
"retrieved from the database: {Claims} ; {Properties}.",
ticket.GetTokenId(), ticket.Principal.Claims, ticket.Properties.Items);
_logger.LogTrace("The token '{Identifier}' was successfully decrypted and " +
"retrieved from the database: {Claims} ; {Properties}.",
ticket.GetTokenId(), ticket.Principal.Claims, ticket.Properties.Items);
return ticket;
}
@ -376,7 +374,7 @@ namespace OpenIddict.Server
return true;
}
var authorization = await Authorizations.FindByIdAsync(identifier);
var authorization = await _authorizationManager.FindByIdAsync(identifier);
if (authorization == null)
{
return true;
@ -386,42 +384,42 @@ namespace OpenIddict.Server
{
// Note: the request cancellation token is deliberately not used here to ensure the caller
// cannot prevent this operation from being executed by resetting the TCP connection.
await Authorizations.RevokeAsync(authorization);
await _authorizationManager.RevokeAsync(authorization);
Logger.LogInformation("The authorization '{Identifier}' was automatically revoked.", identifier);
_logger.LogInformation("The authorization '{Identifier}' was automatically revoked.", identifier);
return true;
}
catch (Exception exception)
{
Logger.LogDebug(exception, "An exception occurred while trying to revoke the authorization " +
"associated with the token '{Identifier}'.", identifier);
_logger.LogDebug(exception, "An exception occurred while trying to revoke the authorization " +
"associated with the token '{Identifier}'.", identifier);
return false;
}
}
private async Task<bool> TryRevokeTokenAsync([NotNull] TToken token)
private async Task<bool> TryRevokeTokenAsync([NotNull] object token)
{
var identifier = await Tokens.GetIdAsync(token);
var identifier = await _tokenManager.GetIdAsync(token);
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");
try
{
// Note: the request cancellation token is deliberately not used here to ensure the caller
// cannot prevent this operation from being executed by resetting the TCP connection.
await Tokens.RevokeAsync(token);
await _tokenManager.RevokeAsync(token);
Logger.LogInformation("The token '{Identifier}' was automatically revoked.", identifier);
_logger.LogInformation("The token '{Identifier}' was automatically revoked.", identifier);
return true;
}
catch (Exception exception)
{
Logger.LogDebug(exception, "An exception occurred while trying to revoke " +
"the token '{Identifier}'.", identifier);
_logger.LogDebug(exception, "An exception occurred while trying to revoke " +
"the token '{Identifier}'.", identifier);
return false;
}
@ -438,10 +436,10 @@ namespace OpenIddict.Server
var result = true;
foreach (var token in await Tokens.FindByAuthorizationIdAsync(identifier))
foreach (var token in await _tokenManager.FindByAuthorizationIdAsync(identifier))
{
// Don't change the status of the token used in the token request.
if (string.Equals(ticket.GetTokenId(), await Tokens.GetIdAsync(token), StringComparison.Ordinal))
if (string.Equals(ticket.GetTokenId(), await _tokenManager.GetIdAsync(token), StringComparison.Ordinal))
{
continue;
}
@ -452,33 +450,33 @@ namespace OpenIddict.Server
return result;
}
private async Task<bool> TryRedeemTokenAsync([NotNull] TToken token)
private async Task<bool> TryRedeemTokenAsync([NotNull] object token)
{
var identifier = await Tokens.GetIdAsync(token);
var identifier = await _tokenManager.GetIdAsync(token);
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");
try
{
// Note: the request cancellation token is deliberately not used here to ensure the caller
// cannot prevent this operation from being executed by resetting the TCP connection.
await Tokens.RedeemAsync(token);
await _tokenManager.RedeemAsync(token);
Logger.LogInformation("The token '{Identifier}' was automatically marked as redeemed.", identifier);
_logger.LogInformation("The token '{Identifier}' was automatically marked as redeemed.", identifier);
return true;
}
catch (Exception exception)
{
Logger.LogDebug(exception, "An exception occurred while trying to " +
"redeem the token '{Identifier}'.", identifier);
_logger.LogDebug(exception, "An exception occurred while trying to " +
"redeem the token '{Identifier}'.", identifier);
return false;
}
}
private async Task<bool> TryExtendTokenAsync(
[NotNull] TToken token, [NotNull] AuthenticationTicket ticket, [NotNull] OpenIddictServerOptions options)
[NotNull] object token, [NotNull] AuthenticationTicket ticket, [NotNull] OpenIddictServerOptions options)
{
var identifier = ticket.GetTokenId();
Debug.Assert(!string.IsNullOrEmpty(identifier), "The token identifier shouldn't be null or empty.");
@ -491,18 +489,18 @@ namespace OpenIddict.Server
// Note: the request cancellation token is deliberately not used here to ensure the caller
// cannot prevent this operation from being executed by resetting the TCP connection.
await Tokens.ExtendAsync(token, date);
await _tokenManager.ExtendAsync(token, date);
Logger.LogInformation("The expiration date of the refresh token '{Identifier}' " +
"was automatically updated: {Date}.", identifier, date);
_logger.LogInformation("The expiration date of the refresh token '{Identifier}' " +
"was automatically updated: {Date}.", identifier, date);
return true;
}
catch (Exception exception)
{
Logger.LogDebug(exception, "An exception occurred while trying to update the " +
"expiration date of the token '{Identifier}'.", identifier);
_logger.LogDebug(exception, "An exception occurred while trying to update the " +
"expiration date of the token '{Identifier}'.", identifier);
return false;
}
@ -544,8 +542,8 @@ namespace OpenIddict.Server
catch (Exception exception)
{
Logger.LogWarning(exception, "An error occurred while parsing the public property " +
"'{Name}' from the authentication ticket.", name);
_logger.LogWarning(exception, "An error occurred while parsing the public property " +
"'{Name}' from the authentication ticket.", name);
continue;
}
@ -568,8 +566,8 @@ namespace OpenIddict.Server
catch (Exception exception)
{
Logger.LogWarning(exception, "An error occurred while parsing the public property " +
"'{Name}' from the authentication ticket.", name);
_logger.LogWarning(exception, "An error occurred while parsing the public property " +
"'{Name}' from the authentication ticket.", name);
continue;
}
@ -585,8 +583,8 @@ namespace OpenIddict.Server
if (request.IsAuthorizationRequest() || request.IsLogoutRequest())
{
Logger.LogWarning("The JSON property '{Name}' was excluded as it was not " +
"compatible with the OpenID Connect response type.", name);
_logger.LogWarning("The JSON property '{Name}' was excluded as it was not " +
"compatible with the OpenID Connect response type.", name);
continue;
}
@ -600,8 +598,8 @@ namespace OpenIddict.Server
catch (Exception exception)
{
Logger.LogWarning(exception, "An error occurred while deserializing the public JSON " +
"property '{Name}' from the authentication ticket.", name);
_logger.LogWarning(exception, "An error occurred while deserializing the public JSON " +
"property '{Name}' from the authentication ticket.", name);
continue;
}

47
src/OpenIddict.Server/Internal/OpenIddictServerProvider.Introspection.cs

@ -16,8 +16,7 @@ using OpenIddict.Abstractions;
namespace OpenIddict.Server
{
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
public partial class OpenIddictServerProvider : OpenIdConnectServerProvider
{
public override Task ExtractIntrospectionRequest([NotNull] ExtractIntrospectionRequestContext context)
{
@ -51,11 +50,11 @@ namespace OpenIddict.Server
}
// Retrieve the application details corresponding to the requested client_id.
var application = await Applications.FindByClientIdAsync(context.ClientId);
var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null)
{
Logger.LogError("The introspection request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
_logger.LogError("The introspection request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -69,10 +68,10 @@ namespace OpenIddict.Server
context.Request.SetProperty($"{OpenIddictConstants.Properties.Application}:{context.ClientId}", application);
// Reject the request if the application is not allowed to use the introspection endpoint.
if (!await Applications.HasPermissionAsync(application, OpenIddictConstants.Permissions.Endpoints.Introspection))
if (!await _applicationManager.HasPermissionAsync(application, OpenIddictConstants.Permissions.Endpoints.Introspection))
{
Logger.LogError("The introspection request was rejected because the application '{ClientId}' " +
"was not allowed to use the introspection endpoint.", context.ClientId);
_logger.LogError("The introspection request was rejected because the application '{ClientId}' " +
"was not allowed to use the introspection endpoint.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.UnauthorizedClient,
@ -82,10 +81,10 @@ namespace OpenIddict.Server
}
// Reject introspection requests sent by public applications.
if (await Applications.IsPublicAsync(application))
if (await _applicationManager.IsPublicAsync(application))
{
Logger.LogError("The introspection request was rejected because the public application " +
"'{ClientId}' was not allowed to use this endpoint.", context.ClientId);
_logger.LogError("The introspection request was rejected because the public application " +
"'{ClientId}' was not allowed to use this endpoint.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -95,10 +94,10 @@ namespace OpenIddict.Server
}
// Validate the client credentials.
if (!await Applications.ValidateClientSecretAsync(application, context.ClientSecret))
if (!await _applicationManager.ValidateClientSecretAsync(application, context.ClientSecret))
{
Logger.LogError("The introspection request was rejected because the confidential or hybrid application " +
"'{ClientId}' didn't specify valid client credentials.", context.ClientId);
_logger.LogError("The introspection request was rejected because the confidential or hybrid application " +
"'{ClientId}' didn't specify valid client credentials.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -122,7 +121,7 @@ namespace OpenIddict.Server
if (!context.Ticket.IsAccessToken())
{
Logger.LogError("The token '{Identifier}' is not an access token and thus cannot be introspected.", identifier);
_logger.LogError("The token '{Identifier}' is not an access token and thus cannot be introspected.", identifier);
context.Active = false;
@ -134,9 +133,9 @@ namespace OpenIddict.Server
// For that, an error is automatically returned if no explicit audience is attached to the authentication ticket.
if (!context.Ticket.HasAudience())
{
Logger.LogError("The token '{Identifier}' doesn't have any audience attached " +
"and cannot be introspected. To add an audience, use the " +
"'ticket.SetResources(...)' extension when creating the ticket.", identifier);
_logger.LogError("The token '{Identifier}' doesn't have any audience attached " +
"and cannot be introspected. To add an audience, use the " +
"'ticket.SetResources(...)' extension when creating the ticket.", identifier);
context.Active = false;
@ -145,9 +144,9 @@ namespace OpenIddict.Server
if (!context.Ticket.HasAudience(context.Request.ClientId))
{
Logger.LogError("The client application '{ClientId}' is not allowed to introspect the access " +
"token '{Identifier}' because it's not listed as a valid audience.",
context.Request.ClientId, identifier);
_logger.LogError("The client application '{ClientId}' is not allowed to introspect the access " +
"token '{Identifier}' because it's not listed as a valid audience.",
context.Request.ClientId, identifier);
context.Active = false;
@ -162,12 +161,12 @@ namespace OpenIddict.Server
}
// Retrieve the token from the request properties. If it's marked as invalid, return active = false.
var token = context.Request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");
var token = context.Request.GetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}");
Debug.Assert(token != null, "The token shouldn't be null.");
if (!await Tokens.IsValidAsync(token))
if (!await _tokenManager.IsValidAsync(token))
{
Logger.LogInformation("The token '{Identifier}' was declared as inactive because it was revoked.", identifier);
_logger.LogInformation("The token '{Identifier}' was declared as inactive because it was revoked.", identifier);
context.Active = false;

63
src/OpenIddict.Server/Internal/OpenIddictServerProvider.Revocation.cs

@ -16,8 +16,7 @@ using OpenIddict.Abstractions;
namespace OpenIddict.Server
{
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
public partial class OpenIddictServerProvider : OpenIdConnectServerProvider
{
public override async Task ValidateRevocationRequest([NotNull] ValidateRevocationRequestContext context)
{
@ -58,8 +57,8 @@ namespace OpenIddict.Server
// Reject the request if client identification is mandatory.
if (options.RequireClientIdentification)
{
Logger.LogError("The revocation request was rejected becaused the " +
"mandatory client_id parameter was missing or empty.");
_logger.LogError("The revocation request was rejected becaused the " +
"mandatory client_id parameter was missing or empty.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -68,8 +67,8 @@ namespace OpenIddict.Server
return;
}
Logger.LogDebug("The revocation request validation process was skipped " +
"because the client_id parameter was missing or empty.");
_logger.LogDebug("The revocation request validation process was skipped " +
"because the client_id parameter was missing or empty.");
context.Skip();
@ -77,11 +76,11 @@ namespace OpenIddict.Server
}
// Retrieve the application details corresponding to the requested client_id.
var application = await Applications.FindByClientIdAsync(context.ClientId);
var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
if (application == null)
{
Logger.LogError("The revocation request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
_logger.LogError("The revocation request was rejected because the client " +
"application was not found: '{ClientId}'.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -95,10 +94,10 @@ namespace OpenIddict.Server
context.Request.SetProperty($"{OpenIddictConstants.Properties.Application}:{context.ClientId}", application);
// Reject the request if the application is not allowed to use the revocation endpoint.
if (!await Applications.HasPermissionAsync(application, OpenIddictConstants.Permissions.Endpoints.Revocation))
if (!await _applicationManager.HasPermissionAsync(application, OpenIddictConstants.Permissions.Endpoints.Revocation))
{
Logger.LogError("The revocation request was rejected because the application '{ClientId}' " +
"was not allowed to use the revocation endpoint.", context.ClientId);
_logger.LogError("The revocation request was rejected because the application '{ClientId}' " +
"was not allowed to use the revocation endpoint.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.UnauthorizedClient,
@ -108,12 +107,12 @@ namespace OpenIddict.Server
}
// Reject revocation requests containing a client_secret if the application is a public client.
if (await Applications.IsPublicAsync(application))
if (await _applicationManager.IsPublicAsync(application))
{
if (!string.IsNullOrEmpty(context.ClientSecret))
{
Logger.LogError("The revocation request was rejected because the public application " +
"'{ClientId}' was not allowed to use this endpoint.", context.ClientId);
_logger.LogError("The revocation request was rejected because the public application " +
"'{ClientId}' was not allowed to use this endpoint.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -122,8 +121,8 @@ namespace OpenIddict.Server
return;
}
Logger.LogDebug("The revocation request validation process was not fully validated because " +
"the client '{ClientId}' was a public application.", context.ClientId);
_logger.LogDebug("The revocation request validation process was not fully validated because " +
"the client '{ClientId}' was a public application.", context.ClientId);
// If client authentication cannot be enforced, call context.Skip() to inform
// the OpenID Connect server middleware that the caller cannot be fully trusted.
@ -136,8 +135,8 @@ namespace OpenIddict.Server
// to protect them from impersonation attacks.
if (string.IsNullOrEmpty(context.ClientSecret))
{
Logger.LogError("The revocation request was rejected because the confidential or hybrid application " +
"'{ClientId}' didn't specify a client secret.", context.ClientId);
_logger.LogError("The revocation request was rejected because the confidential or hybrid application " +
"'{ClientId}' didn't specify a client secret.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -146,10 +145,10 @@ namespace OpenIddict.Server
return;
}
if (!await Applications.ValidateClientSecretAsync(application, context.ClientSecret))
if (!await _applicationManager.ValidateClientSecretAsync(application, context.ClientSecret))
{
Logger.LogError("The revocation request was rejected because the confidential or hybrid application " +
"'{ClientId}' didn't specify valid client credentials.", context.ClientId);
_logger.LogError("The revocation request was rejected because the confidential or hybrid application " +
"'{ClientId}' didn't specify valid client credentials.", context.ClientId);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidClient,
@ -171,7 +170,7 @@ namespace OpenIddict.Server
// return an error to indicate that the token cannot be revoked.
if (context.Ticket.IsIdentityToken())
{
Logger.LogError("The revocation request was rejected because identity tokens are not revocable.");
_logger.LogError("The revocation request was rejected because identity tokens are not revocable.");
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedTokenType,
@ -183,7 +182,7 @@ namespace OpenIddict.Server
// If the received token is an access token, return an error if reference tokens are not enabled.
if (!options.UseReferenceTokens && context.Ticket.IsAccessToken())
{
Logger.LogError("The revocation request was rejected because the access token was not revocable.");
_logger.LogError("The revocation request was rejected because the access token was not revocable.");
context.Reject(
error: OpenIdConnectConstants.Errors.UnsupportedTokenType,
@ -197,13 +196,13 @@ namespace OpenIddict.Server
Debug.Assert(!string.IsNullOrEmpty(identifier), "The authentication ticket should contain a token identifier.");
// Retrieve the token from the request properties. If it's already marked as revoked, directly return a 200 response.
var token = context.Request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{identifier}");
var token = context.Request.GetProperty($"{OpenIddictConstants.Properties.Token}:{identifier}");
Debug.Assert(token != null, "The token shouldn't be null.");
if (await Tokens.IsRevokedAsync(token))
if (await _tokenManager.IsRevokedAsync(token))
{
Logger.LogInformation("The token '{Identifier}' was not revoked because " +
"it was already marked as invalid.", identifier);
_logger.LogInformation("The token '{Identifier}' was not revoked because " +
"it was already marked as invalid.", identifier);
context.Revoked = true;
@ -215,18 +214,18 @@ namespace OpenIddict.Server
// will be returned to the client application.
try
{
await Tokens.RevokeAsync(token);
await _tokenManager.RevokeAsync(token);
}
catch (Exception exception)
{
Logger.LogWarning(exception, "An exception occurred while trying to revoke the authorization " +
"associated with the token '{Identifier}'.", identifier);
_logger.LogWarning(exception, "An exception occurred while trying to revoke the authorization " +
"associated with the token '{Identifier}'.", identifier);
return;
}
Logger.LogInformation("The token '{Identifier}' was successfully revoked.", identifier);
_logger.LogInformation("The token '{Identifier}' was successfully revoked.", identifier);
context.Revoked = true;
}

3
src/OpenIddict.Server/Internal/OpenIddictServerProvider.Serialization.cs

@ -12,8 +12,7 @@ using JetBrains.Annotations;
namespace OpenIddict.Server
{
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
public partial class OpenIddictServerProvider : OpenIdConnectServerProvider
{
public override async Task DeserializeAccessToken([NotNull] DeserializeAccessTokenContext context)
{

24
src/OpenIddict.Server/Internal/OpenIddictServerProvider.Session.cs

@ -22,8 +22,7 @@ using OpenIddict.Abstractions;
namespace OpenIddict.Server
{
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
public partial class OpenIddictServerProvider : OpenIdConnectServerProvider
{
public override async Task ExtractLogoutRequest([NotNull] ExtractLogoutRequestContext context)
{
@ -36,8 +35,7 @@ namespace OpenIddict.Server
// Return an error if request caching support was not enabled.
if (!options.EnableRequestCaching)
{
Logger.LogError("The logout request was rejected because " +
"request caching support was not enabled.");
_logger.LogError("The logout request was rejected because request caching support was not enabled.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -53,8 +51,8 @@ namespace OpenIddict.Server
var payload = await options.Cache.GetAsync(key);
if (payload == null)
{
Logger.LogError("The logout request was rejected because an unknown " +
"or invalid request_id parameter was specified.");
_logger.LogError("The logout request was rejected because an unknown " +
"or invalid request_id parameter was specified.");
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -87,8 +85,8 @@ namespace OpenIddict.Server
{
if (!Uri.TryCreate(context.PostLogoutRedirectUri, UriKind.Absolute, out Uri uri) || !uri.IsWellFormedOriginalString())
{
Logger.LogError("The logout request was rejected because the specified post_logout_redirect_uri was not " +
"a valid absolute URL: {PostLogoutRedirectUri}.", context.PostLogoutRedirectUri);
_logger.LogError("The logout request was rejected because the specified post_logout_redirect_uri was not " +
"a valid absolute URL: {PostLogoutRedirectUri}.", context.PostLogoutRedirectUri);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -99,8 +97,8 @@ namespace OpenIddict.Server
if (!string.IsNullOrEmpty(uri.Fragment))
{
Logger.LogError("The logout request was rejected because the 'post_logout_redirect_uri' contained " +
"a URL fragment: {PostLogoutRedirectUri}.", context.PostLogoutRedirectUri);
_logger.LogError("The logout request was rejected because the 'post_logout_redirect_uri' contained " +
"a URL fragment: {PostLogoutRedirectUri}.", context.PostLogoutRedirectUri);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,
@ -109,10 +107,10 @@ namespace OpenIddict.Server
return;
}
if (!await Applications.ValidatePostLogoutRedirectUriAsync(context.PostLogoutRedirectUri))
if (!await _applicationManager.ValidatePostLogoutRedirectUriAsync(context.PostLogoutRedirectUri))
{
Logger.LogError("The logout request was rejected because the specified post_logout_redirect_uri " +
"was unknown: {PostLogoutRedirectUri}.", context.PostLogoutRedirectUri);
_logger.LogError("The logout request was rejected because the specified post_logout_redirect_uri " +
"was unknown: {PostLogoutRedirectUri}.", context.PostLogoutRedirectUri);
context.Reject(
error: OpenIdConnectConstants.Errors.InvalidRequest,

3
src/OpenIddict.Server/Internal/OpenIddictServerProvider.Userinfo.cs

@ -10,8 +10,7 @@ using JetBrains.Annotations;
namespace OpenIddict.Server
{
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
public partial class OpenIddictServerProvider : OpenIdConnectServerProvider
{
public override Task ExtractUserinfoRequest([NotNull] ExtractUserinfoRequestContext context)
{

60
src/OpenIddict.Server/Internal/OpenIddictServerProvider.cs

@ -15,7 +15,6 @@ using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;
using OpenIddict.Abstractions;
using OpenIddict.Core;
namespace OpenIddict.Server
{
@ -23,51 +22,28 @@ namespace OpenIddict.Server
/// Provides the logic necessary to extract, validate and handle OpenID Connect requests.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
public partial class OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken> : OpenIdConnectServerProvider
where TApplication : class where TAuthorization : class where TScope : class where TToken : class
public partial class OpenIddictServerProvider : OpenIdConnectServerProvider
{
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictServerProvider{TApplication, TAuthorization, TScope, TToken}"/> class.
/// </summary>
public readonly ILogger _logger;
public readonly IOpenIddictApplicationManager _applicationManager;
public readonly IOpenIddictAuthorizationManager _authorizationManager;
public readonly IOpenIddictScopeManager _scopeManager;
public readonly IOpenIddictTokenManager _tokenManager;
public OpenIddictServerProvider(
[NotNull] ILogger<OpenIddictServerProvider<TApplication, TAuthorization, TScope, TToken>> logger,
[NotNull] OpenIddictApplicationManager<TApplication> applications,
[NotNull] OpenIddictAuthorizationManager<TAuthorization> authorizations,
[NotNull] OpenIddictScopeManager<TScope> scopes,
[NotNull] OpenIddictTokenManager<TToken> tokens)
[NotNull] ILogger<OpenIddictServerProvider> logger,
[NotNull] IOpenIddictApplicationManager applicationManager,
[NotNull] IOpenIddictAuthorizationManager authorizationManager,
[NotNull] IOpenIddictScopeManager scopeManager,
[NotNull] IOpenIddictTokenManager tokenManager)
{
Applications = applications;
Authorizations = authorizations;
Logger = logger;
Scopes = scopes;
Tokens = tokens;
_logger = logger;
_applicationManager = applicationManager;
_authorizationManager = authorizationManager;
_scopeManager = scopeManager;
_tokenManager = tokenManager;
}
/// <summary>
/// Gets the applications manager.
/// </summary>
public OpenIddictApplicationManager<TApplication> Applications { get; }
/// <summary>
/// Gets the authorizations manager.
/// </summary>
public OpenIddictAuthorizationManager<TAuthorization> Authorizations { get; }
/// <summary>
/// Gets the logger associated with the current class.
/// </summary>
public ILogger Logger { get; }
/// <summary>
/// Gets the scopes manager.
/// </summary>
public OpenIddictScopeManager<TScope> Scopes { get; }
/// <summary>
/// Gets the tokens manager.
/// </summary>
public OpenIddictTokenManager<TToken> Tokens { get; }
public override Task ProcessChallengeResponse([NotNull] ProcessChallengeResponseContext context)
{
Debug.Assert(context.Request.IsAuthorizationRequest() ||
@ -148,7 +124,7 @@ namespace OpenIddict.Server
return;
}
var token = context.Request.GetProperty<TToken>($"{OpenIddictConstants.Properties.Token}:{context.Ticket.GetTokenId()}");
var token = context.Request.GetProperty($"{OpenIddictConstants.Properties.Token}:{context.Ticket.GetTokenId()}");
Debug.Assert(token != null, "The token shouldn't be null.");
// If rolling tokens are enabled or if the request is a grant_type=authorization_code request,

3
src/OpenIddict.Server/OpenIddict.Server.csproj

@ -13,13 +13,14 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OpenIddict.Core\OpenIddict.Core.csproj" />
<ProjectReference Include="..\OpenIddict.Abstractions\OpenIddict.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="AspNet.Security.OpenIdConnect.Server" Version="$(AspNetContribOpenIdServerVersion)" />
<PackageReference Include="JetBrains.Annotations" Version="$(JetBrainsVersion)" PrivateAssets="All" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.Abstractions" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="$(AspNetCoreVersion)" />
<PackageReference Include="Newtonsoft.Json.Bson" Version="$(JsonNetBsonVersion)" />
</ItemGroup>

5
src/OpenIddict.Server/OpenIddictServerBuilder.cs

@ -12,13 +12,11 @@ using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using AspNet.Security.OpenIdConnect.Primitives;
using JetBrains.Annotations;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Core;
using OpenIddict.Server;
namespace Microsoft.Extensions.DependencyInjection
@ -453,8 +451,7 @@ namespace Microsoft.Extensions.DependencyInjection
/// <summary>
/// Rejects authorization and token requests that specify scopes that have not been
/// registered using <see cref="RegisterScopes(string[])"/> or
/// <see cref="OpenIddictScopeManager{TScope}.CreateAsync(TScope, CancellationToken)"/>.
/// registered using <see cref="RegisterScopes(string[])"/> or the scope manager.
/// </summary>
/// <returns>The <see cref="OpenIddictServerBuilder"/>.</returns>
public OpenIddictServerBuilder EnableScopeValidation()

42
src/OpenIddict.Server/OpenIddictServerExtensions.cs

@ -5,7 +5,6 @@
*/
using System;
using System.Text;
using AspNet.Security.OpenIdConnect.Server;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
@ -32,46 +31,15 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Services.AddAuthentication();
builder.Services.TryAddScoped<OpenIddictServerHandler>();
builder.Services.TryAddScoped<OpenIddictServerProvider>();
// Register the options initializers used by the OpenID Connect server handler and OpenIddict.
// Note: TryAddEnumerable() is used here to ensure the initializers are only registered once.
builder.Services.TryAddEnumerable(new[]
{
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictServerOptions>,
OpenIddictServerInitializer>(),
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictServerOptions>,
OpenIdConnectServerInitializer>()
});
// Register the OpenIddict handler/provider.
builder.Services.TryAddScoped(typeof(OpenIddictServerProvider<,,,>));
builder.Services.TryAddScoped<OpenIddictServerHandler>();
builder.Services.TryAddScoped(provider =>
{
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictServerOptions>>()
.Get(OpenIddictServerDefaults.AuthenticationScheme);
if (options == null)
{
throw new InvalidOperationException("The OpenIddict validation options cannot be resolved.");
}
if (options.ApplicationType == null || options.AuthorizationType == null ||
options.ScopeType == null || options.TokenType == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The entity types must be configured for the token server services to work correctly.")
.Append("To configure the entities, use either 'services.AddOpenIddict().AddCore().UseDefaultModels()' ")
.Append("or 'services.AddOpenIddict().AddCore().UseCustomModels()'.")
.ToString());
}
var type = typeof(OpenIddictServerProvider<,,,>).MakeGenericType(
/* TApplication: */ options.ApplicationType,
/* TAuthorization: */ options.AuthorizationType,
/* TScope: */ options.ScopeType,
/* TToken: */ options.TokenType);
return (OpenIdConnectServerProvider) provider.GetRequiredService(type);
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictServerOptions>, OpenIddictServerInitializer>(),
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictServerOptions>, OpenIdConnectServerInitializer>()
});
// Register the OpenID Connect server handler in the authentication options,

26
src/OpenIddict.Server/OpenIddictServerOptions.cs

@ -14,7 +14,7 @@ using Microsoft.Extensions.Caching.Distributed;
namespace OpenIddict.Server
{
/// <summary>
/// Provides various settings needed to configure OpenIddict.
/// Provides various settings needed to configure the OpenIddict server handler.
/// </summary>
public class OpenIddictServerOptions : OpenIdConnectServerOptions
{
@ -23,22 +23,10 @@ namespace OpenIddict.Server
/// </summary>
public OpenIddictServerOptions()
{
// Note: OpenIdConnectServerProvider is automatically mapped
// to the generic OpenIddictProvider class by the DI container.
Provider = null;
ProviderType = typeof(OpenIdConnectServerProvider);
ProviderType = typeof(OpenIddictServerProvider);
}
/// <summary>
/// Gets or sets the type corresponding to the Application entity.
/// </summary>
public Type ApplicationType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Authorization entity.
/// </summary>
public Type AuthorizationType { get; set; }
/// <summary>
/// Gets or sets the distributed cache used by OpenIddict. If no cache is explicitly
/// provided, the cache registered in the dependency injection container is used.
@ -103,16 +91,6 @@ namespace OpenIddict.Server
OpenIdConnectConstants.Scopes.OpenId
};
/// <summary>
/// Gets or sets the type corresponding to the Scope entity.
/// </summary>
public Type ScopeType { get; set; }
/// <summary>
/// Gets or sets the type corresponding to the Token entity.
/// </summary>
public Type TokenType { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether reference tokens should be used.
/// When set to <c>true</c>, authorization codes, access tokens and refresh tokens

31
src/OpenIddict.Validation/Internal/OpenIddictValidationHandler.cs

@ -7,6 +7,7 @@
using System;
using System.ComponentModel;
using System.Security.Claims;
using System.Text;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
using AspNet.Security.OAuth.Validation;
@ -18,25 +19,11 @@ using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json.Linq;
using OpenIddict.Abstractions;
using OpenIddict.Core;
namespace OpenIddict.Validation
{
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictValidationHandler : OAuthValidationHandler
{
public OpenIddictValidationHandler(
[NotNull] IOptionsMonitor<OpenIddictValidationOptions> options,
[NotNull] ILoggerFactory logger,
[NotNull] UrlEncoder encoder,
[NotNull] ISystemClock clock)
: base(options, logger, encoder, clock)
{
}
}
[EditorBrowsable(EditorBrowsableState.Never)]
public class OpenIddictValidationHandler<TToken> : OpenIddictValidationHandler where TToken : class
{
public OpenIddictValidationHandler(
[NotNull] IOptionsMonitor<OpenIddictValidationOptions> options,
@ -49,6 +36,11 @@ namespace OpenIddict.Validation
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Options.UseReferenceTokens)
{
return await base.HandleAuthenticateAsync();
}
var context = new RetrieveTokenContext(Context, Scheme, Options);
await Events.RetrieveToken(context);
@ -197,10 +189,15 @@ namespace OpenIddict.Validation
private async Task<AuthenticateResult> CreateTicketAsync(string payload)
{
var manager = Context.RequestServices.GetService<OpenIddictTokenManager<TToken>>();
// Note: the token manager is deliberately not injected using constructor injection
// to allow using the validation handler without having to register the core services.
var manager = Context.RequestServices.GetService<IOpenIddictTokenManager>();
if (manager == null)
{
throw new InvalidOperationException("The token manager was not correctly registered.");
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The core services must be registered when enabling reference tokens support.")
.Append("To register the OpenIddict core services, use 'services.AddOpenIddict().AddCore()'.")
.ToString());
}
// Retrieve the token entry from the database. If it
@ -282,5 +279,7 @@ namespace OpenIddict.Validation
}
private new OAuthValidationEvents Events => (OAuthValidationEvents) base.Events;
private new OpenIddictValidationOptions Options => (OpenIddictValidationOptions) base.Options;
}
}

12
src/OpenIddict.Validation/Internal/OpenIddictValidationInitializer.cs

@ -11,7 +11,6 @@ using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Options;
using OpenIddict.Core;
namespace OpenIddict.Validation
{
@ -23,17 +22,13 @@ namespace OpenIddict.Validation
public class OpenIddictValidationInitializer : IPostConfigureOptions<OpenIddictValidationOptions>
{
private readonly IDataProtectionProvider _dataProtectionProvider;
private readonly IOptionsMonitor<OpenIddictCoreOptions> _options;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictValidationInitializer"/> class.
/// </summary>
public OpenIddictValidationInitializer(
[NotNull] IDataProtectionProvider dataProtectionProvider,
[NotNull] IOptionsMonitor<OpenIddictCoreOptions> options)
public OpenIddictValidationInitializer([NotNull] IDataProtectionProvider dataProtectionProvider)
{
_dataProtectionProvider = dataProtectionProvider;
_options = options;
}
/// <summary>
@ -73,11 +68,6 @@ namespace OpenIddict.Validation
options.AccessTokenFormat = new TicketDataFormat(protector);
}
if (options.TokenType == null)
{
options.TokenType = _options.CurrentValue.DefaultTokenType;
}
}
}
}

2
src/OpenIddict.Validation/OpenIddict.Validation.csproj

@ -13,7 +13,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OpenIddict.Core\OpenIddict.Core.csproj" />
<ProjectReference Include="..\OpenIddict.Abstractions\OpenIddict.Abstractions.csproj" />
</ItemGroup>
<ItemGroup>

48
src/OpenIddict.Validation/OpenIddictValidationExtensions.cs

@ -5,13 +5,10 @@
*/
using System;
using System.Text;
using System.Text.Encodings.Web;
using AspNet.Security.OAuth.Validation;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OpenIddict.Validation;
@ -34,52 +31,15 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Services.AddAuthentication();
builder.Services.TryAddScoped<OpenIddictValidationHandler>();
// Note: TryAddEnumerable() is used here to ensure the initializer is only registered once.
builder.Services.TryAddEnumerable(new[]
{
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictValidationOptions>,
OpenIddictValidationInitializer>(),
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictValidationOptions>,
OAuthValidationInitializer>()
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictValidationOptions>, OpenIddictValidationInitializer>(),
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictValidationOptions>, OAuthValidationInitializer>()
});
builder.Services.TryAddScoped(typeof(OpenIddictValidationHandler<>));
builder.Services.TryAddScoped(provider =>
{
var options = provider.GetRequiredService<IOptionsMonitor<OpenIddictValidationOptions>>()
.Get(OpenIddictValidationDefaults.AuthenticationScheme);
if (options == null)
{
throw new InvalidOperationException("The OpenIddict validation options cannot be resolved.");
}
if (options.UseReferenceTokens)
{
if (options.TokenType == null)
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The entity types must be configured for the token validation services to work correctly.")
.Append("To configure the entities, use either 'services.AddOpenIddict().AddCore().UseDefaultModels()' ")
.Append("or 'services.AddOpenIddict().AddCore().UseCustomModels()'.")
.ToString());
}
var type = typeof(OpenIddictValidationHandler<>).MakeGenericType(options.TokenType);
return (OpenIddictValidationHandler) provider.GetService(type);
}
return new OpenIddictValidationHandler(
provider.GetRequiredService<IOptionsMonitor<OpenIddictValidationOptions>>(),
provider.GetRequiredService<ILoggerFactory>(),
provider.GetRequiredService<UrlEncoder>(),
provider.GetRequiredService<ISystemClock>());
});
builder.Services.TryAddEnumerable(
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictValidationOptions>,
OAuthValidationInitializer>());
// Register the OpenIddict validation handler in the authentication options,
// so it can be discovered by the default authentication handler provider.
builder.Services.Configure<AuthenticationOptions>(options =>

6
src/OpenIddict.Validation/OpenIddictValidationOptions.cs

@ -4,18 +4,12 @@
* the license and the contributors participating to this project.
*/
using System;
using AspNet.Security.OAuth.Validation;
namespace OpenIddict.Validation
{
public class OpenIddictValidationOptions : OAuthValidationOptions
{
/// <summary>
/// Gets or sets the type corresponding to the Token entity.
/// </summary>
public Type TokenType { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether reference tokens are used.
/// </summary>

1
src/OpenIddict/OpenIddict.csproj

@ -13,6 +13,7 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\OpenIddict.Core\OpenIddict.Core.csproj" />
<ProjectReference Include="..\OpenIddict.Models\OpenIddict.Models.csproj" />
<ProjectReference Include="..\OpenIddict.Server\OpenIddict.Server.csproj" />
<ProjectReference Include="..\OpenIddict.Validation\OpenIddict.Validation.csproj" />

Loading…
Cancel
Save