Browse Source

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

pull/2216/head
Kévin Chalet 1 year 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>
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>
/// 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<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="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, or <see langword="null"/> not to filter out specific clients.</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>
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, string status,
string type, ImmutableArray<string> scopes, CancellationToken cancellationToken);
string? subject, string? client, string? status,
string? type, ImmutableArray<string>? scopes, CancellationToken cancellationToken);
/// <summary>
/// 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>
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>
/// 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="type">The token type.</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, or <see langword="null"/> not to filter out specific clients.</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, 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>
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken);
string? subject, string? client,
string? status, string? type, CancellationToken cancellationToken);
/// <summary>
/// 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>
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>
/// 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="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, or <see langword="null"/> not to filter out specific clients.</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>
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync(
string subject, string client, string status,
string type, ImmutableArray<string> scopes, CancellationToken cancellationToken = default);
string? subject, string? client, string? status,
string? type, ImmutableArray<string>? scopes, CancellationToken cancellationToken = default);
/// <summary>
/// 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>
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>
/// 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="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, or <see langword="null"/> not to filter out specific clients.</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>
/// <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>
/// 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>
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>
/// 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="type">The token type.</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, or <see langword="null"/> not to filter out specific clients.</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, 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>
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<object> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken = default);
string? subject, string? client,
string? status, string? type, CancellationToken cancellationToken = default);
/// <summary>
/// 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>
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>
/// 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="type">The token type.</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, or <see langword="null"/> not to filter out specific clients.</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, 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>
/// <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>
/// 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>
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>
/// 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="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, or <see langword="null"/> not to filter out specific clients.</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>
/// <returns>The authorizations corresponding to the criteria.</returns>
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>
/// <returns>The authorizations corresponding to the criteria.</returns>
IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type,
ImmutableArray<string> scopes, CancellationToken cancellationToken);
string? subject, string? client,
string? status, string? type,
ImmutableArray<string>? scopes, CancellationToken cancellationToken);
/// <summary>
/// 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>
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>
/// 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);
/// <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="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, or <see langword="null"/> not to filter out specific clients.</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>
/// <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>
/// 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="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>
ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken = default);
ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken);
/// <summary>
/// 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="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>
ValueTask<long> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken = default);
ValueTask<long> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken);
/// <summary>
/// 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>
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>
/// 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="type">The token type.</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, or <see langword="null"/> not to filter out specific clients.</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, 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>
/// <returns>The tokens corresponding to the criteria.</returns>
IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken);
string? subject, string? client,
string? status, string? type, CancellationToken cancellationToken);
/// <summary>
/// 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>
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>
/// 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="type">The token type.</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, or <see langword="null"/> not to filter out specific clients.</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, 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>
/// <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>
/// 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));
}
_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
{
Method = nameof(FindByApplicationIdAsync),
@ -105,206 +81,18 @@ public sealed class OpenIddictAuthorizationCache<TAuthorization> : IOpenIddictAu
}
/// <inheritdoc/>
public IAsyncEnumerable<TAuthorization> 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));
}
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)
public async IAsyncEnumerable<TAuthorization> FindAsync(
string? subject, string? client,
string? status, string? type,
ImmutableArray<string>? scopes, [EnumeratorCancellation] 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.
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
await foreach (var authorization in _store.FindAsync(subject, client, status, type, scopes, 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));
}
_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
{
Method = nameof(FindByApplicationIdAsync),
@ -123,165 +99,17 @@ public sealed class OpenIddictTokenCache<TToken> : IOpenIddictTokenCache<TToken>
}
/// <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))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
// Note: this method is only partially cached.
return ExecuteAsync(cancellationToken);
async IAsyncEnumerable<TToken> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
await foreach (var token in _store.FindAsync(subject, client, status, type, cancellationToken))
{
var parameters = new
{
Method = nameof(FindAsync),
Subject = subject,
Client = client
};
await AddAsync(token, cancellationToken);
if (!_cache.TryGetValue(parameters, out ImmutableArray<TToken> tokens))
{
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;
}
yield return token;
}
}

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

@ -271,207 +271,21 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
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>
/// 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="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, or <see langword="null"/> not to filter out specific clients.</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>
/// <returns>The authorizations corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken = default)
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 ?
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 ?
Store.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)
{
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;
}
if (!await HasScopesAsync(authorization, scopes, cancellationToken))
if (scopes is not null && !await HasScopesAsync(authorization, scopes.Value, cancellationToken))
{
continue;
}
@ -1028,90 +843,17 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
public virtual ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default)
=> 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>
/// 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="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, or <see langword="null"/> not to filter out specific clients.</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>
/// <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)
{
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);
}
public virtual ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken = default)
=> Store.RevokeAsync(subject, client, status, type, cancellationToken);
/// <summary>
/// Revokes all the authorizations associated with the specified application identifier.
@ -1352,19 +1094,7 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
=> DeleteAsync((TAuthorization) authorization, cancellationToken);
/// <inheritdoc/>
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string subject, string client, 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)
IAsyncEnumerable<object> IOpenIddictAuthorizationManager.FindAsync(string? subject, string? client, string? status, string? type, ImmutableArray<string>? scopes, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, type, scopes, cancellationToken);
/// <inheritdoc/>
@ -1455,15 +1185,7 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
=> PruneAsync(threshold, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictAuthorizationManager.RevokeAsync(string subject, string client, 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)
ValueTask<long> IOpenIddictAuthorizationManager.RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, status, type, cancellationToken);
/// <inheritdoc/>

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

@ -205,141 +205,19 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
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>
/// 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="type">The token type.</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, or <see langword="null"/> not to filter out specific clients.</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, 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>
/// <returns>Tokens corresponding to the criteria.</returns>
public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken = default)
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));
}
var tokens = Options.CurrentValue.DisableEntityCaching ?
Store.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)
{
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;
}
@ -1055,90 +934,17 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
public virtual ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default)
=> 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>
/// 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="type">The token type.</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, or <see langword="null"/> not to filter out specific clients.</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, 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>
/// <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)
{
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);
}
public virtual ValueTask<long> RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken = default)
=> Store.RevokeAsync(subject, client, status, type, cancellationToken);
/// <summary>
/// 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);
/// <inheritdoc/>
IAsyncEnumerable<object> IOpenIddictTokenManager.FindAsync(string subject, string client, 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)
IAsyncEnumerable<object> IOpenIddictTokenManager.FindAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
=> FindAsync(subject, client, status, type, cancellationToken);
/// <inheritdoc/>
@ -1619,15 +1417,7 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
=> PruneAsync(threshold, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeAsync(string subject, string client, 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)
ValueTask<long> IOpenIddictTokenManager.RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, status, type, cancellationToken);
/// <inheritdoc/>

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

@ -170,138 +170,42 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, CancellationToken cancellationToken)
public virtual async IAsyncEnumerable<TAuthorization> FindAsync(
string? subject, string? client,
string? status, string? type,
ImmutableArray<string>? scopes, [EnumeratorCancellation] 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 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));
}
IQueryable<TAuthorization> query = Authorizations.Include(authorization => authorization.Application);
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);
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));
}
var key = ConvertIdentifierFromString(client);
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
query = query.Where(authorization => authorization.Application!.Id!.Equals(key));
}
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);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
await foreach (var authorization in query.AsAsyncEnumerable(cancellationToken))
{
var key = ConvertIdentifierFromString(client);
var authorizations = (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);
await foreach (var authorization in authorizations)
if (scopes is null || (await GetScopesAsync(authorization, cancellationToken))
.ToHashSet(StringComparer.Ordinal)
.IsSupersetOf(scopes))
{
if ((await GetScopesAsync(authorization, cancellationToken))
.ToHashSet(StringComparer.Ordinal)
.IsSupersetOf(scopes))
{
yield return authorization;
}
yield return authorization;
}
}
}
@ -659,151 +563,37 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(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);
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)
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));
}
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);
IQueryable<TAuthorization> query = Authorizations.Include(authorization => authorization.Application);
continue;
}
result++;
}
if (exceptions is not null)
if (!string.IsNullOrEmpty(subject))
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
query = query.Where(authorization => authorization.Subject == subject);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
if (!string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
var key = ConvertIdentifierFromString(client);
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
query = query.Where(authorization => authorization.Application!.Id!.Equals(key));
}
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;
var result = 0L;
foreach (var authorization in await (from authorization in Authorizations
where authorization.Application!.Id!.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type
select authorization).ToListAsync(cancellationToken))
foreach (var authorization in await query.ToListAsync(cancellationToken))
{
authorization.Status = Statuses.Revoked;
@ -848,7 +638,7 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
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)
select authorization).ToListAsync(cancellationToken))
{
@ -893,7 +683,7 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
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
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/>
public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken)
string? subject, string? client,
string? status, string? type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
IQueryable<TToken> query = Tokens.Include(token => token.Application).Include(token => token.Authorization);
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);
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));
query = query.Where(token => token.Application!.Id!.Equals(key));
}
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 (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);
return query.AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/>
@ -660,151 +606,37 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
}
/// <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));
}
IQueryable<TToken> query = Tokens.Include(token => token.Application).Include(token => token.Authorization);
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);
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))
if (!string.IsNullOrEmpty(client))
{
token.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
var key = ConvertIdentifierFromString(client);
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++;
query = query.Where(token => token.Application!.Id!.Equals(key));
}
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;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
if (!string.IsNullOrEmpty(type))
{
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;
var result = 0L;
foreach (var token in await (from token in Tokens
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))
foreach (var token in await query.ToListAsync(cancellationToken))
{
token.Status = Statuses.Revoked;
@ -849,7 +681,7 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
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)
select token).ToListAsync(cancellationToken))
{
@ -896,7 +728,7 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
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)
select token).ToListAsync(cancellationToken))
{
@ -941,7 +773,7 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
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
select token).ToListAsync(cancellationToken))
{

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

@ -241,165 +241,50 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, CancellationToken cancellationToken)
public virtual async IAsyncEnumerable<TAuthorization> FindAsync(
string? subject, string? client,
string? status, string? type,
ImmutableArray<string>? scopes, [EnumeratorCancellation] 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 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.
IQueryable<TAuthorization> query = Authorizations.Include(authorization => authorization.Application).AsTracking();
var key = ConvertIdentifierFromString(client);
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))
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));
}
// 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 &&
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));
}
// 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(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
query = from authorization in query
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
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);
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
await foreach (var authorization in query.AsAsyncEnumerable(cancellationToken))
{
// 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);
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 (scopes is null || (await GetScopesAsync(authorization, cancellationToken))
.ToHashSet(StringComparer.Ordinal)
.IsSupersetOf(scopes))
{
if ((await GetScopesAsync(authorization, cancellationToken))
.ToHashSet(StringComparer.Ordinal)
.IsSupersetOf(scopes))
{
yield return authorization;
}
yield return authorization;
}
}
}
@ -805,194 +690,47 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
}
/// <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));
}
IQueryable<TAuthorization> query = Options.CurrentValue.DisableBulkOperations ?
Authorizations.Include(authorization => authorization.Application).AsTracking() :
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 SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations)
if (!string.IsNullOrEmpty(client))
{
return await (
from authorization in Authorizations
where authorization.Subject == subject && 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
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));
}
// 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(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
query = from authorization in query
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
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 (!Options.CurrentValue.DisableBulkOperations)
{
return await (
from authorization in Authorizations
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);
return await query.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.
@ -1008,11 +746,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
//
// 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 && authorization.Type == type
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).ToListAsync(cancellationToken))
foreach (var authorization in await query.ToListAsync(cancellationToken))
{
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.
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
where application.Id!.Equals(key)
select authorization).ToListAsync(cancellationToken))
@ -1135,7 +869,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
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
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/>
public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, CancellationToken cancellationToken)
string? subject, string? client,
string? status, string? type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
IQueryable<TToken> query = Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking();
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 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);
// 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 token in Tokens.Include(token => token.Application).Include(token => token.Authorization).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).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));
query = from authorization in query
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization;
}
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))
{
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);
return query.AsAsyncEnumerable(cancellationToken);
}
/// <inheritdoc/>
@ -754,192 +688,47 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
}
/// <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));
}
IQueryable<TToken> query = Options.CurrentValue.DisableBulkOperations ?
Tokens.Include(token => token.Application).Include(token => token.Authorization).AsTracking() :
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 SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations)
if (!string.IsNullOrEmpty(client))
{
return await (
from token in Tokens
where token.Subject == subject && token.Application!.Id!.Equals(key)
select token).ExecuteUpdateAsync(entity => entity.SetProperty(
token => token.Status, Statuses.Revoked), cancellationToken);
// 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);
// Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately.
query = from authorization in query
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;
// 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))
if (!string.IsNullOrEmpty(status))
{
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, 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++;
query = query.Where(token => token.Status == status);
}
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 (!Options.CurrentValue.DisableBulkOperations)
{
return await (
from token in Tokens
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);
return await query.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.
@ -949,17 +738,7 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
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 && token.Type == type
join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id!.Equals(key)
select token).ToListAsync(cancellationToken))
foreach (var token in await query.ToListAsync(cancellationToken))
{
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.
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
where application.Id!.Equals(key)
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.
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
where authorization.Id!.Equals(key)
select token).ToListAsync(cancellationToken))
@ -1149,7 +932,9 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
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
select token).ToListAsync(cancellationToken))
{

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

@ -103,159 +103,46 @@ public class OpenIddictMongoDbAuthorizationStore<TAuthorization> : IOpenIddictAu
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client, CancellationToken cancellationToken)
public virtual async IAsyncEnumerable<TAuthorization> FindAsync(
string? subject, string? client,
string? status, string? type,
ImmutableArray<string>? scopes, [EnumeratorCancellation] 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));
}
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));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
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);
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;
}
query = query.Where(authorization => authorization.Subject == subject);
}
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TAuthorization> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
if (!string.IsNullOrEmpty(client))
{
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));
}
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));
// 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)));
}
if (string.IsNullOrEmpty(type))
await foreach (var authorization in query.ToAsyncEnumerable(cancellationToken))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
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;
}
yield return authorization;
}
}
@ -550,89 +437,35 @@ public class OpenIddictMongoDbAuthorizationStore<TAuthorization> : IOpenIddictAu
}
/// <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 collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return (await collection.UpdateManyAsync(
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 filter = Builders<TAuthorization>.Filter.Empty;
var database = await Context.GetDatabaseAsync(cancellationToken);
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))
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(
filter : authorization => authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type,
filter : filter,
update : Builders<TAuthorization>.Update.Set(authorization => authorization.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;

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

@ -99,112 +99,38 @@ public class OpenIddictMongoDbTokenStore<TToken> : IOpenIddictTokenStore<TToken>
}
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(string subject,
string client, CancellationToken cancellationToken)
public virtual async IAsyncEnumerable<TToken> FindAsync(
string? subject, string? client,
string? status, string? type, [EnumeratorCancellation] 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));
}
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);
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 &&
token.Status == status).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
}
}
IQueryable<TToken> query = collection.AsQueryable();
/// <inheritdoc/>
public virtual IAsyncEnumerable<TToken> FindAsync(
string subject, string client,
string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
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);
async IAsyncEnumerable<TToken> ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken)
await foreach (var token in query.ToAsyncEnumerable(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 &&
token.Status == status &&
token.Type == type).ToAsyncEnumerable(cancellationToken))
{
yield return token;
}
yield return token;
}
}
@ -573,7 +499,7 @@ public class OpenIddictMongoDbTokenStore<TToken> : IOpenIddictTokenStore<TToken>
where token.CreationDate < threshold.UtcDateTime
where (token.Status != Statuses.Inactive && token.Status != Statuses.Valid) ||
token.ExpirationDate < DateTime.UtcNow ||
authorizations.Any(authorization => authorization.Status != Statuses.Valid)
authorizations.Any(token => token.Status != Statuses.Valid)
select token.Id).ToListAsync(cancellationToken);
// 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/>
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 collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return (await collection.UpdateManyAsync(
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;
}
var filter = Builders<TToken>.Filter.Empty;
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
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);
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));
filter &= Builders<TToken>.Filter.Where(token => token.Subject == 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(
filter : token => token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type,
filter : filter,
update : Builders<TToken>.Update.Set(token => token.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;

Loading…
Cancel
Save