Browse Source

Merge the FindAsync()/RevokeAsync() methods into a single API with nullable parameters

pull/2216/head
Kévin Chalet 2 years ago
parent
commit
6f68ef7806
  1. 47
      src/OpenIddict.Abstractions/Caches/IOpenIddictAuthorizationCache.cs
  2. 32
      src/OpenIddict.Abstractions/Caches/IOpenIddictTokenCache.cs
  3. 79
      src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs
  4. 65
      src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs
  5. 85
      src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs
  6. 64
      src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs
  7. 226
      src/OpenIddict.Core/Caches/OpenIddictAuthorizationCache.cs
  8. 186
      src/OpenIddict.Core/Caches/OpenIddictTokenCache.cs
  9. 316
      src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
  10. 242
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  11. 276
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs
  12. 224
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs
  13. 372
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs
  14. 323
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs
  15. 231
      src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs
  16. 184
      src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs

47
src/OpenIddict.Abstractions/Caches/IOpenIddictAuthorizationCache.cs

@ -22,52 +22,19 @@ public interface IOpenIddictAuthorizationCache<TAuthorization> where TAuthorizat
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns> /// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask AddAsync(TAuthorization authorization, CancellationToken cancellationToken); ValueTask AddAsync(TAuthorization authorization, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the authorizations corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The authorizations corresponding to the subject/client.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(string subject, string client, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Retrieves the authorizations matching the specified parameters. /// Retrieves the authorizations matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the authorization.</param> /// <param name="subject">The subject associated with the authorization, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the authorization.</param> /// <param name="client">The client associated with the authorization, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The authorization status.</param> /// <param name="status">The authorization status, or <see langword="null"/> not to filter out specific authorization statuses.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="type">The authorization type, or <see langword="null"/> not to filter out specific authorization types.</param>
/// <returns>The authorizations corresponding to the criteria.</returns> /// <param name="scopes">The minimal scopes associated with the authorization, or <see langword="null"/> not to filter out scopes.</param>
IAsyncEnumerable<TAuthorization> FindAsync(string subject, string client, 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>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, string status,
string type, 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="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> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The authorizations corresponding to the criteria.</returns> /// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync( IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, string status, string? subject, string? client, string? status,
string type, ImmutableArray<string> scopes, CancellationToken cancellationToken); string? type, ImmutableArray<string>? scopes, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Retrieves the list of authorizations corresponding to the specified application identifier. /// Retrieves the list of authorizations corresponding to the specified application identifier.

32
src/OpenIddict.Abstractions/Caches/IOpenIddictTokenCache.cs

@ -20,38 +20,18 @@ public interface IOpenIddictTokenCache<TToken> where TToken : class
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns> /// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask AddAsync(TToken token, CancellationToken cancellationToken); ValueTask AddAsync(TToken token, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the subject/client.</returns>
IAsyncEnumerable<TToken> FindAsync(string subject, string client, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<TToken> FindAsync(string subject, string client, string status, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Retrieves the tokens matching the specified parameters. /// Retrieves the tokens matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the token.</param> /// <param name="subject">The subject associated with the token, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the token.</param> /// <param name="client">The client associated with the token, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The token status.</param> /// <param name="status">The token status, or <see langword="null"/> not to filter out specific token statuses.</param>
/// <param name="type">The token type.</param> /// <param name="type">The token type, or <see langword="null"/> not to filter out specific token types.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the criteria.</returns> /// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<TToken> FindAsync( IAsyncEnumerable<TToken> FindAsync(
string subject, string client, string? subject, string? client,
string status, string type, CancellationToken cancellationToken); string? status, string? type, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Retrieves the list of tokens corresponding to the specified application identifier. /// Retrieves the list of tokens corresponding to the specified application identifier.

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

@ -106,54 +106,19 @@ public interface IOpenIddictAuthorizationManager
/// </returns> /// </returns>
ValueTask DeleteAsync(object authorization, CancellationToken cancellationToken = default); ValueTask DeleteAsync(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>The authorizations corresponding to the subject/client.</returns>
IAsyncEnumerable<object> FindAsync(string subject, 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>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync(
string subject, string client,
string status, 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="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Retrieves the authorizations matching the specified parameters. /// Retrieves the authorizations matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the authorization.</param> /// <param name="subject">The subject associated with the authorization, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the authorization.</param> /// <param name="client">The client associated with the authorization, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The authorization status.</param> /// <param name="status">The authorization status, or <see langword="null"/> not to filter out specific authorization statuses.</param>
/// <param name="type">The authorization type.</param> /// <param name="type">The authorization type, or <see langword="null"/> not to filter out specific authorization types.</param>
/// <param name="scopes">The minimal scopes associated with the authorization.</param> /// <param name="scopes">The minimal scopes associated with the authorization, or <see langword="null"/> not to filter out scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The authorizations corresponding to the criteria.</returns> /// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync( IAsyncEnumerable<object> FindAsync(
string subject, string client, string status, string? subject, string? client, string? status,
string type, ImmutableArray<string> scopes, CancellationToken cancellationToken = default); string? type, ImmutableArray<string>? scopes, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Retrieves the list of authorizations corresponding to the specified application identifier. /// Retrieves the list of authorizations corresponding to the specified application identifier.
@ -394,36 +359,16 @@ public interface IOpenIddictAuthorizationManager
/// <returns>The number of authorizations that were removed.</returns> /// <returns>The number of authorizations that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default); ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all 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>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all 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>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Revokes all the authorizations matching the specified parameters. /// Revokes all the authorizations matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the authorization.</param> /// <param name="subject">The subject associated with the authorization, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the authorization.</param> /// <param name="client">The client associated with the authorization, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The authorization status.</param> /// <param name="status">The authorization status, or <see langword="null"/> not to filter out specific authorization statuses.</param>
/// <param name="type">The authorization type.</param> /// <param name="type">The authorization type, or <see langword="null"/> not to filter out specific authorization types.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns> /// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken = default); ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Revokes all the authorizations associated with the specified application identifier. /// Revokes all the authorizations associated with the specified application identifier.

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

@ -72,41 +72,18 @@ public interface IOpenIddictTokenManager
/// </returns> /// </returns>
ValueTask DeleteAsync(object token, CancellationToken cancellationToken = default); ValueTask DeleteAsync(object token, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the subject/client.</returns>
IAsyncEnumerable<object> FindAsync(string subject,
string client, CancellationToken cancellationToken = default);
/// <summary>
/// Retrieves the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Retrieves the tokens matching the specified parameters. /// Retrieves the tokens matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the token.</param> /// <param name="subject">The subject associated with the token, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the token.</param> /// <param name="client">The client associated with the token, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The token status.</param> /// <param name="status">The token status, or <see langword="null"/> not to filter out specific token statuses.</param>
/// <param name="type">The token type.</param> /// <param name="type">The token type, or <see langword="null"/> not to filter out specific token types.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the criteria.</returns> /// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync( IAsyncEnumerable<object> FindAsync(
string subject, string client, string? subject, string? client,
string status, string type, CancellationToken cancellationToken = default); string? status, string? type, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Retrieves the list of tokens corresponding to the specified application identifier. /// Retrieves the list of tokens corresponding to the specified application identifier.
@ -409,36 +386,16 @@ public interface IOpenIddictTokenManager
/// <returns>The number of tokens that were removed.</returns> /// <returns>The number of tokens that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default); ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Revokes all the tokens matching the specified parameters. /// Revokes all the tokens matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the token.</param> /// <param name="subject">The subject associated with the token, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the token.</param> /// <param name="client">The client associated with the token, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The token status.</param> /// <param name="status">The token status, or <see langword="null"/> not to filter out specific token statuses.</param>
/// <param name="type">The token type.</param> /// <param name="type">The token type, or <see langword="null"/> not to filter out specific token types.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns> /// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken = default); ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken = default);
/// <summary> /// <summary>
/// Revokes all the tokens associated with the specified application identifier. /// Revokes all the tokens associated with the specified application identifier.

85
src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs

@ -53,55 +53,20 @@ public interface IOpenIddictAuthorizationStore<TAuthorization> where TAuthorizat
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns> /// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask DeleteAsync(TAuthorization authorization, CancellationToken cancellationToken); ValueTask DeleteAsync(TAuthorization authorization, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the authorizations corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The authorizations corresponding to the subject/client.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(string subject, string client, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Retrieves the authorizations matching the specified parameters. /// Retrieves the authorizations matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the authorization.</param> /// <param name="subject">The subject associated with the authorization, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the authorization.</param> /// <param name="client">The client associated with the authorization, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The authorization status.</param> /// <param name="status">The authorization status, or <see langword="null"/> not to filter out specific authorization statuses.</param>
/// <param name="type">The authorization type, or <see langword="null"/> not to filter out specific authorization types.</param>
/// <param name="scopes">The minimal scopes associated with the authorization, or <see langword="null"/> not to filter out scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The authorizations corresponding to the criteria.</returns> /// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync( IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, string? subject, string? client,
string status, CancellationToken cancellationToken); string? status, string? type,
ImmutableArray<string>? scopes, 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>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type, 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="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>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Retrieves the list of authorizations corresponding to the specified application identifier. /// Retrieves the list of authorizations corresponding to the specified application identifier.
@ -279,36 +244,16 @@ public interface IOpenIddictAuthorizationStore<TAuthorization> where TAuthorizat
/// <returns>The number of authorizations that were removed.</returns> /// <returns>The number of authorizations that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken); ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken);
/// <summary>
/// Revokes all 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>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Revokes all the authorizations matching the specified parameters. /// Revokes all the authorizations matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the authorization.</param> /// <param name="subject">The subject associated with the authorization, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the authorization.</param> /// <param name="client">The client associated with the authorization, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The authorization status.</param> /// <param name="status">The authorization status, or <see langword="null"/> not to filter out specific authorization statuses.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="type">The authorization type, or <see langword="null"/> not to filter out specific authorization types.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken);
/// <summary>
/// Revokes all 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> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns> /// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken); ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Revokes all the authorizations associated with the specified application identifier. /// Revokes all the authorizations associated with the specified application identifier.
@ -316,7 +261,7 @@ public interface IOpenIddictAuthorizationStore<TAuthorization> where TAuthorizat
/// <param name="identifier">The application identifier associated with the authorizations.</param> /// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations associated with the specified application that were marked as revoked.</returns> /// <returns>The number of authorizations associated with the specified application that were marked as revoked.</returns>
ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken = default); ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Revokes all the authorizations associated with the specified subject. /// Revokes all the authorizations associated with the specified subject.
@ -324,7 +269,7 @@ public interface IOpenIddictAuthorizationStore<TAuthorization> where TAuthorizat
/// <param name="subject">The subject associated with the authorizations.</param> /// <param name="subject">The subject associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations associated with the specified subject that were marked as revoked.</returns> /// <returns>The number of authorizations associated with the specified subject that were marked as revoked.</returns>
ValueTask<long> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken = default); ValueTask<long> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Sets the application identifier associated with an authorization. /// Sets the application identifier associated with an authorization.

64
src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs

@ -53,40 +53,18 @@ public interface IOpenIddictTokenStore<TToken> where TToken : class
/// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns> /// <returns>A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.</returns>
ValueTask DeleteAsync(TToken token, CancellationToken cancellationToken); ValueTask DeleteAsync(TToken token, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the subject/client.</returns>
IAsyncEnumerable<TToken> FindAsync(string subject, string client, CancellationToken cancellationToken);
/// <summary>
/// Retrieves the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Retrieves the tokens matching the specified parameters. /// Retrieves the tokens matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the token.</param> /// <param name="subject">The subject associated with the token, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the token.</param> /// <param name="client">The client associated with the token, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The token status.</param> /// <param name="status">The token status, or <see langword="null"/> not to filter out specific token statuses.</param>
/// <param name="type">The token type.</param> /// <param name="type">The token type, or <see langword="null"/> not to filter out specific token types.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the criteria.</returns> /// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<TToken> FindAsync( IAsyncEnumerable<TToken> FindAsync(
string subject, string client, string? subject, string? client,
string status, string type, CancellationToken cancellationToken); string? status, string? type, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Retrieves the list of tokens corresponding to the specified application identifier. /// Retrieves the list of tokens corresponding to the specified application identifier.
@ -326,36 +304,16 @@ public interface IOpenIddictTokenStore<TToken> where TToken : class
/// <returns>The number of tokens that were removed.</returns> /// <returns>The number of tokens that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken); ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken);
/// <summary>
/// Revokes all the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken);
/// <summary>
/// Revokes all the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Revokes all the tokens matching the specified parameters. /// Revokes all the tokens matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the token.</param> /// <param name="subject">The subject associated with the token, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the token.</param> /// <param name="client">The client associated with the token, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The token status.</param> /// <param name="status">The token status, or <see langword="null"/> not to filter out specific token statuses.</param>
/// <param name="type">The token type.</param> /// <param name="type">The token type, or <see langword="null"/> not to filter out specific token types.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns> /// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken); ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Revokes all the tokens associated with the specified application identifier. /// Revokes all the tokens associated with the specified application identifier.

226
src/OpenIddict.Core/Caches/OpenIddictAuthorizationCache.cs

@ -44,30 +44,6 @@ public sealed class OpenIddictAuthorizationCache<TAuthorization> : IOpenIddictAu
throw new ArgumentNullException(nameof(authorization)); throw new ArgumentNullException(nameof(authorization));
} }
_cache.Remove(new
{
Method = nameof(FindAsync),
Subject = await _store.GetSubjectAsync(authorization, cancellationToken),
Client = await _store.GetApplicationIdAsync(authorization, cancellationToken)
});
_cache.Remove(new
{
Method = nameof(FindAsync),
Subject = await _store.GetSubjectAsync(authorization, cancellationToken),
Client = await _store.GetApplicationIdAsync(authorization, cancellationToken),
Status = await _store.GetStatusAsync(authorization, cancellationToken)
});
_cache.Remove(new
{
Method = nameof(FindAsync),
Subject = await _store.GetSubjectAsync(authorization, cancellationToken),
Client = await _store.GetApplicationIdAsync(authorization, cancellationToken),
Status = await _store.GetStatusAsync(authorization, cancellationToken),
Type = await _store.GetTypeAsync(authorization, cancellationToken)
});
_cache.Remove(new _cache.Remove(new
{ {
Method = nameof(FindByApplicationIdAsync), Method = nameof(FindByApplicationIdAsync),
@ -105,206 +81,18 @@ public sealed class OpenIddictAuthorizationCache<TAuthorization> : IOpenIddictAu
} }
/// <inheritdoc/> /// <inheritdoc/>
public IAsyncEnumerable<TAuthorization> FindAsync(string subject, string client, CancellationToken cancellationToken) public async IAsyncEnumerable<TAuthorization> FindAsync(
{ string? subject, string? client,
if (string.IsNullOrEmpty(subject)) string? status, string? type,
{ ImmutableArray<string>? scopes, [EnumeratorCancellation] CancellationToken cancellationToken)
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var parameters = new
{
Method = nameof(FindAsync),
Subject = subject,
Client = client
};
if (!_cache.TryGetValue(parameters, out ImmutableArray<TAuthorization> authorizations))
{
var builder = ImmutableArray.CreateBuilder<TAuthorization>();
await foreach (var authorization in _store.FindAsync(subject, client, cancellationToken))
{
builder.Add(authorization);
await AddAsync(authorization, cancellationToken);
}
authorizations = builder.ToImmutable();
await CreateEntryAsync(parameters, authorizations, cancellationToken);
}
foreach (var authorization in authorizations)
{
yield return authorization;
}
}
}
/// <inheritdoc/>
public IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var parameters = new
{
Method = nameof(FindAsync),
Subject = subject,
Client = client,
Status = status
};
if (!_cache.TryGetValue(parameters, out ImmutableArray<TAuthorization> authorizations))
{
var builder = ImmutableArray.CreateBuilder<TAuthorization>();
await foreach (var authorization in _store.FindAsync(subject, client, status, cancellationToken))
{
builder.Add(authorization);
await AddAsync(authorization, cancellationToken);
}
authorizations = builder.ToImmutable();
await CreateEntryAsync(parameters, authorizations, cancellationToken);
}
foreach (var authorization in authorizations)
{
yield return authorization;
}
}
}
/// <inheritdoc/>
public IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var parameters = new
{
Method = nameof(FindAsync),
Subject = subject,
Client = client,
Status = status,
Type = type
};
if (!_cache.TryGetValue(parameters, out ImmutableArray<TAuthorization> authorizations))
{
var builder = ImmutableArray.CreateBuilder<TAuthorization>();
await foreach (var authorization in _store.FindAsync(subject, client, status, type, cancellationToken))
{
builder.Add(authorization);
await AddAsync(authorization, cancellationToken);
}
authorizations = builder.ToImmutable();
await CreateEntryAsync(parameters, authorizations, cancellationToken);
}
foreach (var authorization in authorizations)
{
yield return authorization;
}
}
}
/// <inheritdoc/>
public IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
// Note: this method is only partially cached. // Note: this method is only partially cached.
return ExecuteAsync(cancellationToken); await foreach (var authorization in _store.FindAsync(subject, client, status, type, scopes, cancellationToken))
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{ {
await foreach (var authorization in _store.FindAsync(subject, client, status, type, scopes, cancellationToken)) await AddAsync(authorization, cancellationToken);
{
await AddAsync(authorization, cancellationToken);
yield return authorization; yield return authorization;
}
} }
} }

186
src/OpenIddict.Core/Caches/OpenIddictTokenCache.cs

@ -44,30 +44,6 @@ public sealed class OpenIddictTokenCache<TToken> : IOpenIddictTokenCache<TToken>
throw new ArgumentNullException(nameof(token)); throw new ArgumentNullException(nameof(token));
} }
_cache.Remove(new
{
Method = nameof(FindAsync),
Subject = await _store.GetSubjectAsync(token, cancellationToken),
Client = await _store.GetApplicationIdAsync(token, cancellationToken)
});
_cache.Remove(new
{
Method = nameof(FindAsync),
Subject = await _store.GetSubjectAsync(token, cancellationToken),
Client = await _store.GetApplicationIdAsync(token, cancellationToken),
Status = await _store.GetStatusAsync(token, cancellationToken)
});
_cache.Remove(new
{
Method = nameof(FindAsync),
Subject = await _store.GetSubjectAsync(token, cancellationToken),
Client = await _store.GetApplicationIdAsync(token, cancellationToken),
Status = await _store.GetStatusAsync(token, cancellationToken),
Type = await _store.GetTypeAsync(token, cancellationToken)
});
_cache.Remove(new _cache.Remove(new
{ {
Method = nameof(FindByApplicationIdAsync), Method = nameof(FindByApplicationIdAsync),
@ -123,165 +99,17 @@ public sealed class OpenIddictTokenCache<TToken> : IOpenIddictTokenCache<TToken>
} }
/// <inheritdoc/> /// <inheritdoc/>
public IAsyncEnumerable<TToken> FindAsync(string subject, string client, CancellationToken cancellationToken) public async IAsyncEnumerable<TToken> FindAsync(
string? subject, string? client,
string? status, string? type, [EnumeratorCancellation] CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) // Note: this method is only partially cached.
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
return ExecuteAsync(cancellationToken); await foreach (var token in _store.FindAsync(subject, client, status, type, cancellationToken))
async IAsyncEnumerable<TToken> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{ {
var parameters = new await AddAsync(token, cancellationToken);
{
Method = nameof(FindAsync),
Subject = subject,
Client = client
};
if (!_cache.TryGetValue(parameters, out ImmutableArray<TToken> tokens)) yield return token;
{
var builder = ImmutableArray.CreateBuilder<TToken>();
await foreach (var token in _store.FindAsync(subject, client, cancellationToken))
{
builder.Add(token);
await AddAsync(token, cancellationToken);
}
tokens = builder.ToImmutable();
await CreateEntryAsync(parameters, tokens, cancellationToken);
}
foreach (var token in tokens)
{
yield return token;
}
}
}
/// <inheritdoc/>
public IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TToken> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var parameters = new
{
Method = nameof(FindAsync),
Subject = subject,
Client = client,
Status = status
};
if (!_cache.TryGetValue(parameters, out ImmutableArray<TToken> tokens))
{
var builder = ImmutableArray.CreateBuilder<TToken>();
await foreach (var token in _store.FindAsync(subject, client, status, cancellationToken))
{
builder.Add(token);
await AddAsync(token, cancellationToken);
}
tokens = builder.ToImmutable();
await CreateEntryAsync(parameters, tokens, cancellationToken);
}
foreach (var token in tokens)
{
yield return token;
}
}
}
/// <inheritdoc/>
public IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TToken> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var parameters = new
{
Method = nameof(FindAsync),
Subject = subject,
Client = client,
Status = status,
Type = type
};
if (!_cache.TryGetValue(parameters, out ImmutableArray<TToken> tokens))
{
var builder = ImmutableArray.CreateBuilder<TToken>();
await foreach (var token in _store.FindAsync(subject, client, status, type, cancellationToken))
{
builder.Add(token);
await AddAsync(token, cancellationToken);
}
tokens = builder.ToImmutable();
await CreateEntryAsync(parameters, tokens, cancellationToken);
}
foreach (var token in tokens)
{
yield return token;
}
} }
} }

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

@ -271,207 +271,21 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
await Store.DeleteAsync(authorization, cancellationToken); await Store.DeleteAsync(authorization, cancellationToken);
} }
/// <summary>
/// Retrieves the authorizations corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The authorizations corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var authorizations = Options.CurrentValue.DisableEntityCaching ?
Store.FindAsync(subject, client, cancellationToken) :
Cache.FindAsync(subject, client, cancellationToken);
// SQL engines like Microsoft SQL Server or MySQL are known to use case-insensitive lookups by default.
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
if (Options.CurrentValue.DisableAdditionalFiltering)
{
return authorizations;
}
// SQL engines like Microsoft SQL Server or MySQL are known to use case-insensitive lookups by default.
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
await foreach (var authorization in authorizations)
{
if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal))
{
yield return authorization;
}
}
}
}
/// <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>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var authorizations = Options.CurrentValue.DisableEntityCaching ?
Store.FindAsync(subject, client, status, cancellationToken) :
Cache.FindAsync(subject, client, status, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
return authorizations;
}
// SQL engines like Microsoft SQL Server or MySQL are known to use case-insensitive lookups by default.
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
await foreach (var authorization in authorizations)
{
if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal))
{
yield return authorization;
}
}
}
}
/// <summary> /// <summary>
/// Retrieves the authorizations matching the specified parameters. /// Retrieves the authorizations matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the authorization.</param> /// <param name="subject">The subject associated with the authorization, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the authorization.</param> /// <param name="client">The client associated with the authorization, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The authorization status.</param> /// <param name="status">The authorization status, or <see langword="null"/> not to filter out specific authorization statuses.</param>
/// <param name="type">The authorization type.</param> /// <param name="type">The authorization type, or <see langword="null"/> not to filter out specific authorization types.</param>
/// <param name="scopes">The minimal scopes associated with the authorization, or <see langword="null"/> not to filter out scopes.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The authorizations corresponding to the criteria.</returns> /// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync( public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, string? subject, string? client,
string status, string type, CancellationToken cancellationToken = default) string? status, string? type,
ImmutableArray<string>? scopes, CancellationToken cancellationToken = default)
{ {
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
var authorizations = Options.CurrentValue.DisableEntityCaching ?
Store.FindAsync(subject, client, status, type, cancellationToken) :
Cache.FindAsync(subject, client, status, type, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
return authorizations;
}
// SQL engines like Microsoft SQL Server or MySQL are known to use case-insensitive lookups by default.
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
await foreach (var authorization in authorizations)
{
if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal))
{
yield return authorization;
}
}
}
}
/// <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>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
var authorizations = Options.CurrentValue.DisableEntityCaching ? var authorizations = Options.CurrentValue.DisableEntityCaching ?
Store.FindAsync(subject, client, status, type, scopes, cancellationToken) : Store.FindAsync(subject, client, status, type, scopes, cancellationToken) :
Cache.FindAsync(subject, client, status, type, scopes, cancellationToken); Cache.FindAsync(subject, client, status, type, scopes, cancellationToken);
@ -491,12 +305,13 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
{ {
await foreach (var authorization in authorizations) await foreach (var authorization in authorizations)
{ {
if (!string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal)) if (!string.IsNullOrEmpty(subject) &&
!string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal))
{ {
continue; continue;
} }
if (!await HasScopesAsync(authorization, scopes, cancellationToken)) if (scopes is not null && !await HasScopesAsync(authorization, scopes.Value, cancellationToken))
{ {
continue; continue;
} }
@ -1028,90 +843,17 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
public virtual ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default) public virtual ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default)
=> Store.PruneAsync(threshold, cancellationToken); => Store.PruneAsync(threshold, cancellationToken);
/// <summary>
/// Revokes all 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>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
return Store.RevokeAsync(subject, client, cancellationToken);
}
/// <summary> /// <summary>
/// Revokes all the authorizations matching the specified parameters. /// Revokes all the authorizations matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the authorization.</param> /// <param name="subject">The subject associated with the authorization, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the authorization.</param> /// <param name="client">The client associated with the authorization, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The authorization status.</param> /// <param name="status">The authorization status, or <see langword="null"/> not to filter out specific authorization statuses.</param>
/// <param name="type">The authorization type, or <see langword="null"/> not to filter out specific authorization types.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns> /// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken = default) public virtual ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken = default)
{ => Store.RevokeAsync(subject, client, status, type, cancellationToken);
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
return Store.RevokeAsync(subject, client, status, cancellationToken);
}
/// <summary>
/// Revokes all 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>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
return Store.RevokeAsync(subject, client, status, type, cancellationToken);
}
/// <summary> /// <summary>
/// Revokes all the authorizations associated with the specified application identifier. /// Revokes all the authorizations associated with the specified application identifier.
@ -1352,19 +1094,7 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
=> DeleteAsync((TAuthorization) authorization, cancellationToken); => DeleteAsync((TAuthorization) authorization, cancellationToken);
/// <inheritdoc/> /// <inheritdoc/>
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, CancellationToken cancellationToken) IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string? subject, string? client, string? status, string? type, ImmutableArray<string>? scopes, CancellationToken cancellationToken)
=> FindAsync(subject, client, cancellationToken);
/// <inheritdoc/>
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, cancellationToken);
/// <inheritdoc/>
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, type, cancellationToken);
/// <inheritdoc/>
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, string type, ImmutableArray<string> scopes, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, type, scopes, cancellationToken); => FindAsync(subject, client, status, type, scopes, cancellationToken);
/// <inheritdoc/> /// <inheritdoc/>
@ -1455,15 +1185,7 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
=> PruneAsync(threshold, cancellationToken); => PruneAsync(threshold, cancellationToken);
/// <inheritdoc/> /// <inheritdoc/>
ValueTask<long> IOpenIddictAuthorizationManager.RevokeAsync(string subject, string client, CancellationToken cancellationToken) ValueTask<long> IOpenIddictAuthorizationManager.RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictAuthorizationManager.RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, status, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictAuthorizationManager.RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, status, type, cancellationToken); => RevokeAsync(subject, client, status, type, cancellationToken);
/// <inheritdoc/> /// <inheritdoc/>

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

@ -205,141 +205,19 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
await Store.DeleteAsync(token, cancellationToken); await Store.DeleteAsync(token, cancellationToken);
} }
/// <summary>
/// Retrieves the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the subject/client.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(string subject,
string client, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var tokens = Options.CurrentValue.DisableEntityCaching ?
Store.FindAsync(subject, client, cancellationToken) :
Cache.FindAsync(subject, client, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
return tokens;
}
// SQL engines like Microsoft SQL Server or MySQL are known to use case-insensitive lookups by default.
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TToken> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
await foreach (var token in tokens)
{
if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal))
{
yield return token;
}
}
}
}
/// <summary>
/// Retrieves the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var tokens = Options.CurrentValue.DisableEntityCaching ?
Store.FindAsync(subject, client, status, cancellationToken) :
Cache.FindAsync(subject, client, status, cancellationToken);
if (Options.CurrentValue.DisableAdditionalFiltering)
{
return tokens;
}
// SQL engines like Microsoft SQL Server or MySQL are known to use case-insensitive lookups by default.
// To ensure a case-sensitive comparison is enforced independently of the database/table/query collation
// used by the store, a second pass using string.Equals(StringComparison.Ordinal) is manually made here.
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TToken> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
await foreach (var token in tokens)
{
if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal))
{
yield return token;
}
}
}
}
/// <summary> /// <summary>
/// Retrieves the tokens matching the specified parameters. /// Retrieves the tokens matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the token.</param> /// <param name="subject">The subject associated with the token, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the token.</param> /// <param name="client">The client associated with the token, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The token status.</param> /// <param name="status">The token status, or <see langword="null"/> not to filter out specific token statuses.</param>
/// <param name="type">The token type.</param> /// <param name="type">The token type, or <see langword="null"/> not to filter out specific token types.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>Tokens corresponding to the criteria.</returns> /// <returns>Tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync( public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client, string? subject, string? client,
string status, string type, CancellationToken cancellationToken = default) string? status, string? type, CancellationToken cancellationToken = default)
{ {
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
var tokens = Options.CurrentValue.DisableEntityCaching ? var tokens = Options.CurrentValue.DisableEntityCaching ?
Store.FindAsync(subject, client, status, type, cancellationToken) : Store.FindAsync(subject, client, status, type, cancellationToken) :
Cache.FindAsync(subject, client, status, type, cancellationToken); Cache.FindAsync(subject, client, status, type, cancellationToken);
@ -359,7 +237,8 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
{ {
await foreach (var token in tokens) await foreach (var token in tokens)
{ {
if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal)) if (string.IsNullOrEmpty(subject) ||
string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal))
{ {
yield return token; yield return token;
} }
@ -1055,90 +934,17 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
public virtual ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default) public virtual ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default)
=> Store.PruneAsync(threshold, cancellationToken); => Store.PruneAsync(threshold, cancellationToken);
/// <summary>
/// Revokes all the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
return Store.RevokeAsync(subject, client, cancellationToken);
}
/// <summary>
/// Revokes all the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
return Store.RevokeAsync(subject, client, status, cancellationToken);
}
/// <summary> /// <summary>
/// Revokes all the tokens matching the specified parameters. /// Revokes all the tokens matching the specified parameters.
/// </summary> /// </summary>
/// <param name="subject">The subject associated with the token.</param> /// <param name="subject">The subject associated with the token, or <see langword="null"/> not to filter out specific subjects.</param>
/// <param name="client">The client associated with the token.</param> /// <param name="client">The client associated with the token, or <see langword="null"/> not to filter out specific clients.</param>
/// <param name="status">The token status.</param> /// <param name="status">The token status, or <see langword="null"/> not to filter out specific token statuses.</param>
/// <param name="type">The token type.</param> /// <param name="type">The token type, or <see langword="null"/> not to filter out specific token types.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param> /// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns> /// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken = default) public virtual ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken = default)
{ => Store.RevokeAsync(subject, client, status, type, cancellationToken);
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
return Store.RevokeAsync(subject, client, status, type, cancellationToken);
}
/// <summary> /// <summary>
/// Revokes all the tokens associated with the specified application identifier. /// Revokes all the tokens associated with the specified application identifier.
@ -1495,15 +1301,7 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
=> DeleteAsync((TToken) token, cancellationToken); => DeleteAsync((TToken) token, cancellationToken);
/// <inheritdoc/> /// <inheritdoc/>
IAsyncEnumerable<object> IOpenIddictTokenManager.FindAsync(string subject, string client, CancellationToken cancellationToken) IAsyncEnumerable<object> IOpenIddictTokenManager.FindAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
=> FindAsync(subject, client, cancellationToken);
/// <inheritdoc/>
IAsyncEnumerable<object> IOpenIddictTokenManager.FindAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, cancellationToken);
/// <inheritdoc/>
IAsyncEnumerable<object> IOpenIddictTokenManager.FindAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, type, cancellationToken); => FindAsync(subject, client, status, type, cancellationToken);
/// <inheritdoc/> /// <inheritdoc/>
@ -1619,15 +1417,7 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
=> PruneAsync(threshold, cancellationToken); => PruneAsync(threshold, cancellationToken);
/// <inheritdoc/> /// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeAsync(string subject, string client, CancellationToken cancellationToken) ValueTask<long> IOpenIddictTokenManager.RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, status, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, status, type, cancellationToken); => RevokeAsync(subject, client, status, type, cancellationToken);
/// <inheritdoc/> /// <inheritdoc/>

276
src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs

@ -170,138 +170,42 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
} }
/// <inheritdoc/> /// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync( public virtual async IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, CancellationToken cancellationToken) string? subject, string? client,
string? status, string? type,
ImmutableArray<string>? scopes, [EnumeratorCancellation] CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) IQueryable<TAuthorization> query = Authorizations.Include(authorization => authorization.Application);
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var key = ConvertIdentifierFromString(client);
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application!.Id!.Equals(key) &&
authorization.Subject == subject
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var key = ConvertIdentifierFromString(client);
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application!.Id!.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); query = query.Where(authorization => authorization.Subject == subject);
} }
if (string.IsNullOrEmpty(type)) if (!string.IsNullOrEmpty(client))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); var key = ConvertIdentifierFromString(client);
}
var key = ConvertIdentifierFromString(client);
return (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application!.Id!.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client)) query = query.Where(authorization => authorization.Application!.Id!.Equals(key));
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); query = query.Where(authorization => authorization.Status == status);
} }
if (string.IsNullOrEmpty(type)) if (!string.IsNullOrEmpty(type))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); query = query.Where(authorization => authorization.Type == type);
} }
return ExecuteAsync(cancellationToken); await foreach (var authorization in query.AsAsyncEnumerable(cancellationToken))
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{ {
var key = ConvertIdentifierFromString(client); if (scopes is null || (await GetScopesAsync(authorization, cancellationToken))
.ToHashSet(StringComparer.Ordinal)
var authorizations = (from authorization in Authorizations.Include(authorization => authorization.Application) .IsSupersetOf(scopes))
where authorization.Application!.Id!.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
select authorization).AsAsyncEnumerable(cancellationToken);
await foreach (var authorization in authorizations)
{ {
if ((await GetScopesAsync(authorization, cancellationToken)) yield return authorization;
.ToHashSet(StringComparer.Ordinal)
.IsSupersetOf(scopes))
{
yield return authorization;
}
} }
} }
} }
@ -659,151 +563,37 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
} }
/// <inheritdoc/> /// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken) public virtual async ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null;
var result = 0L;
foreach (var authorization in await (from authorization in Authorizations
where authorization.Application!.Id!.Equals(key) && authorization.Subject == subject
select authorization).ToListAsync(cancellationToken))
{
authorization.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) IQueryable<TAuthorization> query = Authorizations.Include(authorization => authorization.Application);
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null;
var result = 0L;
foreach (var authorization in await (from authorization in Authorizations
where authorization.Application!.Id!.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status
select authorization).ToListAsync(cancellationToken))
{
authorization.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue; if (!string.IsNullOrEmpty(subject))
}
result++;
}
if (exceptions is not null)
{ {
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions); query = query.Where(authorization => authorization.Subject == subject);
} }
return result; if (!string.IsNullOrEmpty(client))
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject)); var key = ConvertIdentifierFromString(client);
}
if (string.IsNullOrEmpty(client)) query = query.Where(authorization => authorization.Application!.Id!.Equals(key));
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); query = query.Where(authorization => authorization.Status == status);
} }
if (string.IsNullOrEmpty(type)) if (!string.IsNullOrEmpty(type))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); query = query.Where(authorization => authorization.Type == type);
} }
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null; List<Exception>? exceptions = null;
var result = 0L; var result = 0L;
foreach (var authorization in await (from authorization in Authorizations foreach (var authorization in await query.ToListAsync(cancellationToken))
where authorization.Application!.Id!.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
select authorization).ToListAsync(cancellationToken))
{ {
authorization.Status = Statuses.Revoked; authorization.Status = Statuses.Revoked;
@ -848,7 +638,7 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
var result = 0L; var result = 0L;
foreach (var authorization in await (from authorization in Authorizations foreach (var authorization in await (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Application!.Id!.Equals(key) where authorization.Application!.Id!.Equals(key)
select authorization).ToListAsync(cancellationToken)) select authorization).ToListAsync(cancellationToken))
{ {
@ -893,7 +683,7 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
var result = 0L; var result = 0L;
foreach (var authorization in await (from authorization in Authorizations foreach (var authorization in await (from authorization in Authorizations.Include(authorization => authorization.Application)
where authorization.Subject == subject where authorization.Subject == subject
select authorization).ToListAsync(cancellationToken)) select authorization).ToListAsync(cancellationToken))
{ {

224
src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs

@ -145,90 +145,36 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
} }
} }
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(string subject,
string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var key = ConvertIdentifierFromString(client);
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application!.Id!.Equals(key) &&
token.Subject == subject
select token).AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/> /// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync( public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client, string? subject, string? client,
string status, CancellationToken cancellationToken) string? status, string? type, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) IQueryable<TToken> query = Tokens.Include(token => token.Application).Include(token => token.Authorization);
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client)) if (!string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); query = query.Where(token => token.Subject == subject);
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(client))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); var key = ConvertIdentifierFromString(client);
}
var key = ConvertIdentifierFromString(client); query = query.Where(token => token.Application!.Id!.Equals(key));
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application!.Id!.Equals(key) &&
token.Subject == subject &&
token.Status == status
select token).AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); query = query.Where(token => token.Status == status);
} }
if (string.IsNullOrEmpty(type)) if (!string.IsNullOrEmpty(type))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); query = query.Where(token => token.Type == type);
} }
var key = ConvertIdentifierFromString(client); return query.AsAsyncEnumerable(cancellationToken);
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application!.Id!.Equals(key) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type
select token).AsAsyncEnumerable(cancellationToken);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -660,151 +606,37 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
} }
/// <inheritdoc/> /// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken) public virtual async ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) IQueryable<TToken> query = Tokens.Include(token => token.Application).Include(token => token.Authorization);
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client)) if (!string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); query = query.Where(token => token.Subject == subject);
} }
var key = ConvertIdentifierFromString(client); if (!string.IsNullOrEmpty(client))
List<Exception>? exceptions = null;
var result = 0L;
foreach (var token in await (from token in Tokens
where token.Application!.Id!.Equals(key) && token.Subject == subject
select token).ToListAsync(cancellationToken))
{ {
token.Status = Statuses.Revoked; var key = ConvertIdentifierFromString(client);
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception)) query = query.Where(token => token.Application!.Id!.Equals(key));
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
} }
if (exceptions is not null) if (!string.IsNullOrEmpty(status))
{ {
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions); query = query.Where(token => token.Status == status);
} }
return result; if (!string.IsNullOrEmpty(type))
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject)); query = query.Where(token => token.Type == type);
} }
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null; List<Exception>? exceptions = null;
var result = 0L; var result = 0L;
foreach (var token in await (from token in Tokens foreach (var token in await query.ToListAsync(cancellationToken))
where token.Application!.Id!.Equals(key) &&
token.Subject == subject &&
token.Status == status
select token).ToListAsync(cancellationToken))
{
token.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null;
var result = 0L;
foreach (var token in await (from token in Tokens
where token.Application!.Id!.Equals(key) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type
select token).ToListAsync(cancellationToken))
{ {
token.Status = Statuses.Revoked; token.Status = Statuses.Revoked;
@ -849,7 +681,7 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
var result = 0L; var result = 0L;
foreach (var token in await (from token in Tokens foreach (var token in await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Application!.Id!.Equals(key) where token.Application!.Id!.Equals(key)
select token).ToListAsync(cancellationToken)) select token).ToListAsync(cancellationToken))
{ {
@ -896,7 +728,7 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
var result = 0L; var result = 0L;
foreach (var token in await (from token in Tokens foreach (var token in await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Authorization!.Id!.Equals(key) where token.Authorization!.Id!.Equals(key)
select token).ToListAsync(cancellationToken)) select token).ToListAsync(cancellationToken))
{ {
@ -941,7 +773,7 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
var result = 0L; var result = 0L;
foreach (var token in await (from token in Tokens foreach (var token in await (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization)
where token.Subject == subject where token.Subject == subject
select token).ToListAsync(cancellationToken)) select token).ToListAsync(cancellationToken))
{ {

372
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs

@ -241,165 +241,50 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
} }
/// <inheritdoc/> /// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync( public virtual async IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, CancellationToken cancellationToken) string? subject, string? client,
string? status, string? type,
ImmutableArray<string>? scopes, [EnumeratorCancellation] CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) IQueryable<TAuthorization> query = Authorizations.Include(authorization => authorization.Application).AsTracking();
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
var key = ConvertIdentifierFromString(client);
return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
var key = ConvertIdentifierFromString(client); if (!string.IsNullOrEmpty(subject))
return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject && authorization.Status == status
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); query = query.Where(authorization => authorization.Subject == subject);
} }
if (string.IsNullOrEmpty(type)) if (!string.IsNullOrEmpty(client))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); // Note: due to a bug in Entity Framework Core's query visitor, the authorizations
} // can't be filtered using authorization.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations //
// can't be filtered using authorization.Application.Id.Equals(key). To work around // See https://github.com/openiddict/openiddict-core/issues/499 for more information.
// this issue, this query uses use an explicit join to apply the equality check. var key = ConvertIdentifierFromString(client);
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
var key = ConvertIdentifierFromString(client);
return (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client)) query = from authorization in query
{ join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); where application.Id!.Equals(key)
select authorization;
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); query = query.Where(authorization => authorization.Status == status);
} }
if (string.IsNullOrEmpty(type)) if (!string.IsNullOrEmpty(type))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); query = query.Where(authorization => authorization.Type == type);
} }
return ExecuteAsync(cancellationToken); await foreach (var authorization in query.AsAsyncEnumerable(cancellationToken))
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{ {
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations if (scopes is null || (await GetScopesAsync(authorization, cancellationToken))
// can't be filtered using authorization.Application.Id.Equals(key). To work around .ToHashSet(StringComparer.Ordinal)
// this issue, this query uses use an explicit join to apply the equality check. .IsSupersetOf(scopes))
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
var key = ConvertIdentifierFromString(client);
var authorizations = (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).AsAsyncEnumerable(cancellationToken);
await foreach (var authorization in authorizations)
{ {
if ((await GetScopesAsync(authorization, cancellationToken)) yield return authorization;
.ToHashSet(StringComparer.Ordinal)
.IsSupersetOf(scopes))
{
yield return authorization;
}
} }
} }
} }
@ -805,194 +690,47 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
} }
/// <inheritdoc/> /// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken) public virtual async ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) IQueryable<TAuthorization> query = Options.CurrentValue.DisableBulkOperations ?
{ Authorizations.Include(authorization => authorization.Application).AsTracking() :
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject)); Authorizations;
}
if (string.IsNullOrEmpty(client)) if (!string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); query = query.Where(authorization => authorization.Subject == subject);
} }
var key = ConvertIdentifierFromString(client); if (!string.IsNullOrEmpty(client))
#if SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations)
{ {
return await ( // Note: due to a bug in Entity Framework Core's query visitor, the authorizations
from authorization in Authorizations // can't be filtered using authorization.Application.Id.Equals(key). To work around
where authorization.Subject == subject && authorization.Application!.Id!.Equals(key) // this issue, this query uses use an explicit join to apply the equality check.
select authorization).ExecuteUpdateAsync(entity => entity.SetProperty( //
authorization => authorization.Status, Statuses.Revoked), cancellationToken); // See https://github.com/openiddict/openiddict-core/issues/499 for more information.
var key = ConvertIdentifierFromString(client);
// Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately.
}
#endif
List<Exception>? exceptions = null;
var result = 0L;
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var authorization in await (from authorization in Authorizations.AsTracking()
where authorization.Subject == subject
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).ToListAsync(cancellationToken))
{
authorization.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var key = ConvertIdentifierFromString(client);
#if SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations)
{
return await (
from authorization in Authorizations
where authorization.Subject == subject &&
authorization.Status == status &&
authorization.Application!.Id!.Equals(key)
select authorization).ExecuteUpdateAsync(entity => entity.SetProperty(
authorization => authorization.Status, Statuses.Revoked), cancellationToken);
// Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately.
}
#endif
List<Exception>? exceptions = null;
var result = 0L;
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var authorization in await (from authorization in Authorizations.AsTracking()
where authorization.Subject == subject && authorization.Status == status
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).ToListAsync(cancellationToken))
{
authorization.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client)) query = from authorization in query
{ join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); where application.Id!.Equals(key)
select authorization;
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); query = query.Where(authorization => authorization.Status == status);
} }
if (string.IsNullOrEmpty(type)) if (!string.IsNullOrEmpty(type))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); query = query.Where(authorization => authorization.Type == type);
} }
var key = ConvertIdentifierFromString(client);
#if SUPPORTS_BULK_DBSET_OPERATIONS #if SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations) if (!Options.CurrentValue.DisableBulkOperations)
{ {
return await ( return await query.ExecuteUpdateAsync(entity => entity.SetProperty(
from authorization in Authorizations authorization => authorization.Status, Statuses.Revoked), cancellationToken);
where authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type &&
authorization.Application!.Id!.Equals(key)
select authorization).ExecuteUpdateAsync(entity => entity.SetProperty(
authorization => authorization.Status, Statuses.Revoked), cancellationToken);
// Note: calling DbContext.SaveChangesAsync() is not necessary // Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately. // with bulk update operations as they are executed immediately.
@ -1008,11 +746,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
// //
// See https://github.com/openiddict/openiddict-core/issues/499 for more information. // See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var authorization in await (from authorization in Authorizations.AsTracking() foreach (var authorization in await query.ToListAsync(cancellationToken))
where authorization.Subject == subject && authorization.Status == status && authorization.Type == type
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).ToListAsync(cancellationToken))
{ {
authorization.Status = Statuses.Revoked; authorization.Status = Statuses.Revoked;
@ -1076,7 +810,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
// //
// See https://github.com/openiddict/openiddict-core/issues/499 for more information. // See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var authorization in await (from authorization in Authorizations.AsTracking() foreach (var authorization in await (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key) where application.Id!.Equals(key)
select authorization).ToListAsync(cancellationToken)) select authorization).ToListAsync(cancellationToken))
@ -1135,7 +869,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
var result = 0L; var result = 0L;
foreach (var authorization in await (from authorization in Authorizations.AsTracking() foreach (var authorization in await (from authorization in Authorizations.Include(authorization => authorization.Application).AsTracking()
where authorization.Subject == subject where authorization.Subject == subject
select authorization).ToListAsync(cancellationToken)) select authorization).ToListAsync(cancellationToken))
{ {

323
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs

@ -165,110 +165,44 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
} }
} }
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(string subject, string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
var key = ConvertIdentifierFromString(client);
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.Subject == subject
join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id!.Equals(key)
select token).AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/> /// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync( public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client, string? subject, string? client,
string status, CancellationToken cancellationToken) string? status, string? type, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) IQueryable<TToken> query = Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking();
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client)) if (!string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); query = query.Where(token => token.Subject == subject);
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(client))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); // Note: due to a bug in Entity Framework Core's query visitor, the authorizations
} // can't be filtered using authorization.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the tokens //
// can't be filtered using token.Application.Id.Equals(key). To work around // See https://github.com/openiddict/openiddict-core/issues/499 for more information.
// this issue, this query uses use an explicit join to apply the equality check. var key = ConvertIdentifierFromString(client);
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
var key = ConvertIdentifierFromString(client);
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() query = from authorization in query
where token.Subject == subject && join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
token.Status == status where application.Id!.Equals(key)
join application in Applications.AsTracking() on token.Application!.Id equals application.Id select authorization;
where application.Id!.Equals(key)
select token).AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (!string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); query = query.Where(token => token.Status == status);
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(type))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); query = query.Where(token => token.Type == type);
} }
if (string.IsNullOrEmpty(type)) return query.AsAsyncEnumerable(cancellationToken);
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
var key = ConvertIdentifierFromString(client);
return (from token in Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking()
where token.Subject == subject &&
token.Status == status &&
token.Type == type
join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id!.Equals(key)
select token).AsAsyncEnumerable(cancellationToken);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -754,192 +688,47 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
} }
/// <inheritdoc/> /// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken) public virtual async ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string ?type, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) IQueryable<TToken> query = Options.CurrentValue.DisableBulkOperations ?
{ Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() :
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject)); Tokens;
}
if (string.IsNullOrEmpty(client)) if (!string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); query = query.Where(token => token.Subject == subject);
} }
var key = ConvertIdentifierFromString(client); if (!string.IsNullOrEmpty(client))
#if SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations)
{ {
return await ( // Note: due to a bug in Entity Framework Core's query visitor, the authorizations
from token in Tokens // can't be filtered using authorization.Application.Id.Equals(key). To work around
where token.Subject == subject && token.Application!.Id!.Equals(key) // this issue, this query uses use an explicit join to apply the equality check.
select token).ExecuteUpdateAsync(entity => entity.SetProperty( //
token => token.Status, Statuses.Revoked), cancellationToken); // See https://github.com/openiddict/openiddict-core/issues/499 for more information.
var key = ConvertIdentifierFromString(client);
// Note: calling DbContext.SaveChangesAsync() is not necessary query = from authorization in query
// with bulk update operations as they are executed immediately. join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization;
} }
#endif
List<Exception>? exceptions = null;
var result = 0L; if (!string.IsNullOrEmpty(status))
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var token in await (from token in Tokens.AsTracking()
where token.Subject == subject
join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id!.Equals(key)
select token).ToListAsync(cancellationToken))
{ {
token.Status = Statuses.Revoked; query = query.Where(token => token.Status == status);
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var key = ConvertIdentifierFromString(client);
#if SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations)
{
return await (
from token in Tokens
where token.Subject == subject && token.Status == status && token.Application!.Id!.Equals(key)
select token).ExecuteUpdateAsync(entity => entity.SetProperty(
token => token.Status, Statuses.Revoked), cancellationToken);
// Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately.
}
#endif
List<Exception>? exceptions = null;
var result = 0L;
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var token in await (from token in Tokens.AsTracking()
where token.Subject == subject && token.Status == status
join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id!.Equals(key)
select token).ToListAsync(cancellationToken))
{
token.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
} }
if (exceptions is not null) if (!string.IsNullOrEmpty(type))
{ {
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions); query = query.Where(token => token.Type == type);
} }
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
var key = ConvertIdentifierFromString(client);
#if SUPPORTS_BULK_DBSET_OPERATIONS #if SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations) if (!Options.CurrentValue.DisableBulkOperations)
{ {
return await ( return await query.ExecuteUpdateAsync(entity => entity.SetProperty(
from token in Tokens token => token.Status, Statuses.Revoked), cancellationToken);
where token.Subject == subject &&
token.Status == status &&
token.Type == type &&
token.Application!.Id!.Equals(key)
select token).ExecuteUpdateAsync(entity => entity.SetProperty(
token => token.Status, Statuses.Revoked), cancellationToken);
// Note: calling DbContext.SaveChangesAsync() is not necessary // Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately. // with bulk update operations as they are executed immediately.
@ -949,17 +738,7 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
var result = 0L; var result = 0L;
// Note: due to a bug in Entity Framework Core's query visitor, the tokens foreach (var token in await query.ToListAsync(cancellationToken))
// can't be filtered using token.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var token in await (from token in Tokens.AsTracking()
where token.Subject == subject && token.Status == status && token.Type == type
join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id!.Equals(key)
select token).ToListAsync(cancellationToken))
{ {
token.Status = Statuses.Revoked; token.Status = Statuses.Revoked;
@ -1023,7 +802,9 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
// //
// See https://github.com/openiddict/openiddict-core/issues/499 for more information. // See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var token in await (from token in Tokens.AsTracking() foreach (var token in await (from token in Tokens.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
join application in Applications.AsTracking() on token.Application!.Id equals application.Id join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id!.Equals(key) where application.Id!.Equals(key)
select token).ToListAsync(cancellationToken)) select token).ToListAsync(cancellationToken))
@ -1090,7 +871,9 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
// //
// See https://github.com/openiddict/openiddict-core/issues/499 for more information. // See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var token in await (from token in Tokens.AsTracking() foreach (var token in await (from token in Tokens.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
join authorization in Authorizations.AsTracking() on token.Authorization!.Id equals authorization.Id join authorization in Authorizations.AsTracking() on token.Authorization!.Id equals authorization.Id
where authorization.Id!.Equals(key) where authorization.Id!.Equals(key)
select token).ToListAsync(cancellationToken)) select token).ToListAsync(cancellationToken))
@ -1149,7 +932,9 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
var result = 0L; var result = 0L;
foreach (var token in await (from token in Tokens.AsTracking() foreach (var token in await (from token in Tokens.Include(token => token.Application)
.Include(token => token.Authorization)
.AsTracking()
where token.Subject == subject where token.Subject == subject
select token).ToListAsync(cancellationToken)) select token).ToListAsync(cancellationToken))
{ {

231
src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs

@ -103,159 +103,46 @@ public class OpenIddictMongoDbAuthorizationStore<TAuthorization> : IOpenIddictAu
} }
/// <inheritdoc/> /// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync( public virtual async IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, CancellationToken cancellationToken) string? subject, string? client,
string? status, string? type,
ImmutableArray<string>? scopes, [EnumeratorCancellation] CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) var database = await Context.GetDatabaseAsync(cancellationToken);
{ var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
await foreach (var authorization in collection.Find(authorization =>
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
return ExecuteAsync(cancellationToken); IQueryable<TAuthorization> query = collection.AsQueryable();
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) if (!string.IsNullOrEmpty(subject))
{ {
var database = await Context.GetDatabaseAsync(cancellationToken); query = query.Where(authorization => authorization.Subject == subject);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
await foreach (var authorization in collection.Find(authorization =>
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject &&
authorization.Status == status).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
} }
}
/// <inheritdoc/> if (!string.IsNullOrEmpty(client))
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject)); query = query.Where(authorization => authorization.ApplicationId == ObjectId.Parse(client));
} }
if (string.IsNullOrEmpty(client)) if (!string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); query = query.Where(authorization => authorization.Status == status);
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(type))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); query = query.Where(authorization => authorization.Type == type);
} }
if (string.IsNullOrEmpty(type)) if (scopes is ImmutableArray<string> values)
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); // Note: Enumerable.All() is deliberately used without the extension method syntax to ensure
} // ImmutableArrayExtensions.All() (which is not supported by MongoDB) is not used instead.
query = query.Where(authorization => Enumerable.All(values, scope => authorization.Scopes!.Contains(scope)));
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
await foreach (var authorization in collection.Find(authorization =>
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
}
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
} }
if (string.IsNullOrEmpty(type)) await foreach (var authorization in query.ToAsyncEnumerable(cancellationToken))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); yield return authorization;
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
// Note: Enumerable.All() is deliberately used without the extension method syntax to ensure
// ImmutableArrayExtensions.All() (which is not supported by MongoDB) is not used instead.
await foreach (var authorization in collection.Find(authorization =>
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type &&
Enumerable.All(scopes, scope => authorization.Scopes!.Contains(scope))).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
} }
} }
@ -550,89 +437,35 @@ public class OpenIddictMongoDbAuthorizationStore<TAuthorization> : IOpenIddictAu
} }
/// <inheritdoc/> /// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken) public virtual async ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var database = await Context.GetDatabaseAsync(cancellationToken); var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName); var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return (await collection.UpdateManyAsync( var filter = Builders<TAuthorization>.Filter.Empty;
filter : authorization => authorization.Subject == subject && authorization.ApplicationId == ObjectId.Parse(client),
update : Builders<TAuthorization>.Update.Set(authorization => authorization.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var database = await Context.GetDatabaseAsync(cancellationToken); if (!string.IsNullOrEmpty(subject))
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return (await collection.UpdateManyAsync(
filter : authorization => authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject &&
authorization.Status == status,
update : Builders<TAuthorization>.Update.Set(authorization => authorization.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject)); filter &= Builders<TAuthorization>.Filter.Where(authorization => authorization.Subject == subject);
} }
if (string.IsNullOrEmpty(client)) if (!string.IsNullOrEmpty(client))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); filter &= Builders<TAuthorization>.Filter.Where(authorization => authorization.ApplicationId == ObjectId.Parse(client));
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); filter &= Builders<TAuthorization>.Filter.Where(authorization => authorization.Status == status);
} }
if (string.IsNullOrEmpty(type)) if (!string.IsNullOrEmpty(type))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); filter &= Builders<TAuthorization>.Filter.Where(authorization => authorization.Type == type);
} }
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return (await collection.UpdateManyAsync( return (await collection.UpdateManyAsync(
filter : authorization => authorization.ApplicationId == ObjectId.Parse(client) && filter : filter,
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type,
update : Builders<TAuthorization>.Update.Set(authorization => authorization.Status, Statuses.Revoked), update : Builders<TAuthorization>.Update.Set(authorization => authorization.Status, Statuses.Revoked),
options : null, options : null,
cancellationToken: cancellationToken)).MatchedCount; cancellationToken: cancellationToken)).MatchedCount;

184
src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs

@ -99,112 +99,38 @@ public class OpenIddictMongoDbTokenStore<TToken> : IOpenIddictTokenStore<TToken>
} }
/// <inheritdoc/> /// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(string subject, public virtual async IAsyncEnumerable<TToken> FindAsync(
string client, CancellationToken cancellationToken) string? subject, string? client,
string? status, string? type, [EnumeratorCancellation] CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject)) var database = await Context.GetDatabaseAsync(cancellationToken);
{ var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TToken> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
await foreach (var token in collection.Find(token =>
token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TToken> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
await foreach (var token in collection.Find(token => IQueryable<TToken> query = collection.AsQueryable();
token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject &&
token.Status == status).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
/// <inheritdoc/> if (!string.IsNullOrEmpty(subject))
public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject)); query = query.Where(token => token.Subject == subject);
} }
if (string.IsNullOrEmpty(client)) if (!string.IsNullOrEmpty(client))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); query = query.Where(token => token.ApplicationId == ObjectId.Parse(client));
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); query = query.Where(token => token.Status == status);
} }
if (string.IsNullOrEmpty(type)) if (!string.IsNullOrEmpty(type))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); query = query.Where(token => token.Type == type);
} }
return ExecuteAsync(cancellationToken); await foreach (var token in query.ToAsyncEnumerable(cancellationToken))
async IAsyncEnumerable<TToken> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
{ {
var database = await Context.GetDatabaseAsync(cancellationToken); yield return token;
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
await foreach (var token in collection.Find(token =>
token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
} }
} }
@ -573,7 +499,7 @@ public class OpenIddictMongoDbTokenStore<TToken> : IOpenIddictTokenStore<TToken>
where token.CreationDate < threshold.UtcDateTime where token.CreationDate < threshold.UtcDateTime
where (token.Status != Statuses.Inactive && token.Status != Statuses.Valid) || where (token.Status != Statuses.Inactive && token.Status != Statuses.Valid) ||
token.ExpirationDate < DateTime.UtcNow || token.ExpirationDate < DateTime.UtcNow ||
authorizations.Any(authorization => authorization.Status != Statuses.Valid) authorizations.Any(token => token.Status != Statuses.Valid)
select token.Id).ToListAsync(cancellationToken); select token.Id).ToListAsync(cancellationToken);
// Note: to avoid generating delete requests with very large filters, a buffer is used here and the // Note: to avoid generating delete requests with very large filters, a buffer is used here and the
@ -587,89 +513,35 @@ public class OpenIddictMongoDbTokenStore<TToken> : IOpenIddictTokenStore<TToken>
} }
/// <inheritdoc/> /// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken) public virtual async ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
{ {
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var database = await Context.GetDatabaseAsync(cancellationToken); var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName); var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return (await collection.UpdateManyAsync( var filter = Builders<TToken>.Filter.Empty;
filter : token => token.ApplicationId == ObjectId.Parse(client) && token.Subject == subject,
update : Builders<TToken>.Update.Set(token => token.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;
}
/// <inheritdoc/> if (!string.IsNullOrEmpty(subject))
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject)); filter &= Builders<TToken>.Filter.Where(token => token.Subject == subject);
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return (await collection.UpdateManyAsync(
filter : token => token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject &&
token.Status == status,
update : Builders<TToken>.Update.Set(token => token.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
} }
if (string.IsNullOrEmpty(client)) if (!string.IsNullOrEmpty(client))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client)); filter &= Builders<TToken>.Filter.Where(token => token.ApplicationId == ObjectId.Parse(client));
} }
if (string.IsNullOrEmpty(status)) if (!string.IsNullOrEmpty(status))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status)); filter &= Builders<TToken>.Filter.Where(token => token.Status == status);
} }
if (string.IsNullOrEmpty(type)) if (!string.IsNullOrEmpty(type))
{ {
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); filter &= Builders<TToken>.Filter.Where(token => token.Type == type);
} }
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return (await collection.UpdateManyAsync( return (await collection.UpdateManyAsync(
filter : token => token.ApplicationId == ObjectId.Parse(client) && filter : filter,
token.Subject == subject &&
token.Status == status &&
token.Type == type,
update : Builders<TToken>.Update.Set(token => token.Status, Statuses.Revoked), update : Builders<TToken>.Update.Set(token => token.Status, Statuses.Revoked),
options : null, options : null,
cancellationToken: cancellationToken)).MatchedCount; cancellationToken: cancellationToken)).MatchedCount;

Loading…
Cancel
Save