diff --git a/src/OpenIddict.Abstractions/Caches/IOpenIddictAuthorizationCache.cs b/src/OpenIddict.Abstractions/Caches/IOpenIddictAuthorizationCache.cs index a397ef6d2..f87fcefd7 100644 --- a/src/OpenIddict.Abstractions/Caches/IOpenIddictAuthorizationCache.cs +++ b/src/OpenIddict.Abstractions/Caches/IOpenIddictAuthorizationCache.cs @@ -22,52 +22,19 @@ public interface IOpenIddictAuthorizationCache where TAuthorizat /// A that can be used to monitor the asynchronous operation. ValueTask AddAsync(TAuthorization authorization, CancellationToken cancellationToken); - /// - /// Retrieves the authorizations corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the subject/client. - IAsyncEnumerable FindAsync(string subject, string client, CancellationToken cancellationToken); - /// /// Retrieves the authorizations matching the specified parameters. /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the criteria. - IAsyncEnumerable FindAsync(string subject, string client, string status, CancellationToken cancellationToken); - - /// - /// Retrieves the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the criteria. - IAsyncEnumerable FindAsync( - string subject, string client, string status, - string type, CancellationToken cancellationToken); - - /// - /// Retrieves the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. - /// The minimal scopes associated with the authorization. + /// The subject associated with the authorization, or not to filter out specific subjects. + /// The client associated with the authorization, or not to filter out specific clients. + /// The authorization status, or not to filter out specific authorization statuses. + /// The authorization type, or not to filter out specific authorization types. + /// The minimal scopes associated with the authorization, or not to filter out scopes. /// The that can be used to abort the operation. /// The authorizations corresponding to the criteria. IAsyncEnumerable FindAsync( - string subject, string client, string status, - string type, ImmutableArray scopes, CancellationToken cancellationToken); + string? subject, string? client, string? status, + string? type, ImmutableArray? scopes, CancellationToken cancellationToken); /// /// Retrieves the list of authorizations corresponding to the specified application identifier. diff --git a/src/OpenIddict.Abstractions/Caches/IOpenIddictTokenCache.cs b/src/OpenIddict.Abstractions/Caches/IOpenIddictTokenCache.cs index 7bba6bc31..bf3364f09 100644 --- a/src/OpenIddict.Abstractions/Caches/IOpenIddictTokenCache.cs +++ b/src/OpenIddict.Abstractions/Caches/IOpenIddictTokenCache.cs @@ -20,38 +20,18 @@ public interface IOpenIddictTokenCache where TToken : class /// A that can be used to monitor the asynchronous operation. ValueTask AddAsync(TToken token, CancellationToken cancellationToken); - /// - /// Retrieves the tokens corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The that can be used to abort the operation. - /// The tokens corresponding to the subject/client. - IAsyncEnumerable FindAsync(string subject, string client, CancellationToken cancellationToken); - - /// - /// Retrieves the tokens matching the specified parameters. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The that can be used to abort the operation. - /// The tokens corresponding to the criteria. - IAsyncEnumerable FindAsync(string subject, string client, string status, CancellationToken cancellationToken); - /// /// Retrieves the tokens matching the specified parameters. /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The token type. + /// The subject associated with the token, or not to filter out specific subjects. + /// The client associated with the token, or not to filter out specific clients. + /// The token status, or not to filter out specific token statuses. + /// The token type, or not to filter out specific token types. /// The that can be used to abort the operation. /// The tokens corresponding to the criteria. IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, CancellationToken cancellationToken); + string? subject, string? client, + string? status, string? type, CancellationToken cancellationToken); /// /// Retrieves the list of tokens corresponding to the specified application identifier. diff --git a/src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs b/src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs index 7a9e41b2b..a72ace979 100644 --- a/src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs +++ b/src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs @@ -106,54 +106,19 @@ ValueTask CreateAsync( /// ValueTask DeleteAsync(object authorization, CancellationToken cancellationToken = default); - /// - /// Retrieves the authorizations corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the subject/client. - IAsyncEnumerable FindAsync(string subject, string client, CancellationToken cancellationToken = default); - - /// - /// Retrieves the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the criteria. - IAsyncEnumerable FindAsync( - string subject, string client, - string status, CancellationToken cancellationToken = default); - - /// - /// Retrieves the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the criteria. - IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, CancellationToken cancellationToken = default); - /// /// Retrieves the authorizations matching the specified parameters. /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. - /// The minimal scopes associated with the authorization. + /// The subject associated with the authorization, or not to filter out specific subjects. + /// The client associated with the authorization, or not to filter out specific clients. + /// The authorization status, or not to filter out specific authorization statuses. + /// The authorization type, or not to filter out specific authorization types. + /// The minimal scopes associated with the authorization, or not to filter out scopes. /// The that can be used to abort the operation. /// The authorizations corresponding to the criteria. IAsyncEnumerable FindAsync( - string subject, string client, string status, - string type, ImmutableArray scopes, CancellationToken cancellationToken = default); + string? subject, string? client, string? status, + string? type, ImmutableArray? scopes, CancellationToken cancellationToken = default); /// /// Retrieves the list of authorizations corresponding to the specified application identifier. @@ -394,36 +359,16 @@ IAsyncEnumerable ListAsync( /// The number of authorizations that were removed. ValueTask PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default); - /// - /// Revokes all the authorizations corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The that can be used to abort the operation. - /// The number of authorizations corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, CancellationToken cancellationToken = default); - - /// - /// Revokes all the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The that can be used to abort the operation. - /// The number of authorizations corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken = default); - /// /// Revokes all the authorizations matching the specified parameters. /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. + /// The subject associated with the authorization, or not to filter out specific subjects. + /// The client associated with the authorization, or not to filter out specific clients. + /// The authorization status, or not to filter out specific authorization statuses. + /// The authorization type, or not to filter out specific authorization types. /// The that can be used to abort the operation. /// The number of authorizations corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken = default); + ValueTask RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken = default); /// /// Revokes all the authorizations associated with the specified application identifier. diff --git a/src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs b/src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs index 3ddcfde7f..3773e7021 100644 --- a/src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs +++ b/src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs @@ -72,41 +72,18 @@ public interface IOpenIddictTokenManager /// ValueTask DeleteAsync(object token, CancellationToken cancellationToken = default); - /// - /// Retrieves the tokens corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The that can be used to abort the operation. - /// The tokens corresponding to the subject/client. - IAsyncEnumerable FindAsync(string subject, - string client, CancellationToken cancellationToken = default); - - /// - /// Retrieves the tokens matching the specified parameters. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The that can be used to abort the operation. - /// The tokens corresponding to the criteria. - IAsyncEnumerable FindAsync( - string subject, string client, - string status, CancellationToken cancellationToken = default); - /// /// Retrieves the tokens matching the specified parameters. /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The token type. + /// The subject associated with the token, or not to filter out specific subjects. + /// The client associated with the token, or not to filter out specific clients. + /// The token status, or not to filter out specific token statuses. + /// The token type, or not to filter out specific token types. /// The that can be used to abort the operation. /// The tokens corresponding to the criteria. IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, CancellationToken cancellationToken = default); + string? subject, string? client, + string? status, string? type, CancellationToken cancellationToken = default); /// /// Retrieves the list of tokens corresponding to the specified application identifier. @@ -409,36 +386,16 @@ IAsyncEnumerable ListAsync( /// The number of tokens that were removed. ValueTask PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default); - /// - /// Revokes all the tokens corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The that can be used to abort the operation. - /// The number of tokens corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, CancellationToken cancellationToken = default); - - /// - /// Revokes all the tokens matching the specified parameters. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The that can be used to abort the operation. - /// The number of tokens corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken = default); - /// /// Revokes all the tokens matching the specified parameters. /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The token type. + /// The subject associated with the token, or not to filter out specific subjects. + /// The client associated with the token, or not to filter out specific clients. + /// The token status, or not to filter out specific token statuses. + /// The token type, or not to filter out specific token types. /// The that can be used to abort the operation. /// The number of tokens corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken = default); + ValueTask RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken = default); /// /// Revokes all the tokens associated with the specified application identifier. diff --git a/src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs b/src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs index cac2c2970..b1526fd41 100644 --- a/src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs @@ -53,55 +53,20 @@ public interface IOpenIddictAuthorizationStore where TAuthorizat /// A that can be used to monitor the asynchronous operation. ValueTask DeleteAsync(TAuthorization authorization, CancellationToken cancellationToken); - /// - /// Retrieves the authorizations corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the subject/client. - IAsyncEnumerable FindAsync(string subject, string client, CancellationToken cancellationToken); - /// /// Retrieves the authorizations matching the specified parameters. /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. + /// The subject associated with the authorization, or not to filter out specific subjects. + /// The client associated with the authorization, or not to filter out specific clients. + /// The authorization status, or not to filter out specific authorization statuses. + /// The authorization type, or not to filter out specific authorization types. + /// The minimal scopes associated with the authorization, or not to filter out scopes. /// The that can be used to abort the operation. /// The authorizations corresponding to the criteria. IAsyncEnumerable FindAsync( - string subject, string client, - string status, CancellationToken cancellationToken); - - /// - /// Retrieves the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the criteria. - IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, CancellationToken cancellationToken); - - /// - /// Retrieves the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. - /// The minimal scopes associated with the authorization. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the criteria. - IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, - ImmutableArray scopes, CancellationToken cancellationToken); + string? subject, string? client, + string? status, string? type, + ImmutableArray? scopes, CancellationToken cancellationToken); /// /// Retrieves the list of authorizations corresponding to the specified application identifier. @@ -279,36 +244,16 @@ IAsyncEnumerable ListAsync( /// The number of authorizations that were removed. ValueTask PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken); - /// - /// Revokes all the authorizations corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The that can be used to abort the operation. - /// The number of authorizations corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, CancellationToken cancellationToken); - /// /// Revokes all the authorizations matching the specified parameters. /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The that can be used to abort the operation. - /// The number of authorizations corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken); - - /// - /// Revokes all the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. + /// The subject associated with the authorization, or not to filter out specific subjects. + /// The client associated with the authorization, or not to filter out specific clients. + /// The authorization status, or not to filter out specific authorization statuses. + /// The authorization type, or not to filter out specific authorization types. /// The that can be used to abort the operation. /// The number of authorizations corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken); + ValueTask RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken); /// /// Revokes all the authorizations associated with the specified application identifier. @@ -316,7 +261,7 @@ IAsyncEnumerable ListAsync( /// The application identifier associated with the authorizations. /// The that can be used to abort the operation. /// The number of authorizations associated with the specified application that were marked as revoked. - ValueTask RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken = default); + ValueTask RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken); /// /// Revokes all the authorizations associated with the specified subject. @@ -324,7 +269,7 @@ IAsyncEnumerable ListAsync( /// The subject associated with the authorizations. /// The that can be used to abort the operation. /// The number of authorizations associated with the specified subject that were marked as revoked. - ValueTask RevokeBySubjectAsync(string subject, CancellationToken cancellationToken = default); + ValueTask RevokeBySubjectAsync(string subject, CancellationToken cancellationToken); /// /// Sets the application identifier associated with an authorization. diff --git a/src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs b/src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs index b2cde75da..9f7856ab0 100644 --- a/src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs +++ b/src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs @@ -53,40 +53,18 @@ public interface IOpenIddictTokenStore where TToken : class /// A that can be used to monitor the asynchronous operation. ValueTask DeleteAsync(TToken token, CancellationToken cancellationToken); - /// - /// Retrieves the tokens corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The that can be used to abort the operation. - /// The tokens corresponding to the subject/client. - IAsyncEnumerable FindAsync(string subject, string client, CancellationToken cancellationToken); - - /// - /// Retrieves the tokens matching the specified parameters. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The that can be used to abort the operation. - /// The tokens corresponding to the criteria. - IAsyncEnumerable FindAsync( - string subject, string client, - string status, CancellationToken cancellationToken); - /// /// Retrieves the tokens matching the specified parameters. /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The token type. + /// The subject associated with the token, or not to filter out specific subjects. + /// The client associated with the token, or not to filter out specific clients. + /// The token status, or not to filter out specific token statuses. + /// The token type, or not to filter out specific token types. /// The that can be used to abort the operation. /// The tokens corresponding to the criteria. IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, CancellationToken cancellationToken); + string? subject, string? client, + string? status, string? type, CancellationToken cancellationToken); /// /// Retrieves the list of tokens corresponding to the specified application identifier. @@ -326,36 +304,16 @@ IAsyncEnumerable ListAsync( /// The number of tokens that were removed. ValueTask PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken); - /// - /// Revokes all the tokens corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The that can be used to abort the operation. - /// The number of tokens corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, CancellationToken cancellationToken); - - /// - /// Revokes all the tokens matching the specified parameters. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The that can be used to abort the operation. - /// The number of tokens corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken); - /// /// Revokes all the tokens matching the specified parameters. /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The token type. + /// The subject associated with the token, or not to filter out specific subjects. + /// The client associated with the token, or not to filter out specific clients. + /// The token status, or not to filter out specific token statuses. + /// The token type, or not to filter out specific token types. /// The that can be used to abort the operation. /// The number of tokens corresponding to the criteria that were marked as revoked. - ValueTask RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken); + ValueTask RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken); /// /// Revokes all the tokens associated with the specified application identifier. diff --git a/src/OpenIddict.Core/Caches/OpenIddictAuthorizationCache.cs b/src/OpenIddict.Core/Caches/OpenIddictAuthorizationCache.cs index 631205bc7..17b79006c 100644 --- a/src/OpenIddict.Core/Caches/OpenIddictAuthorizationCache.cs +++ b/src/OpenIddict.Core/Caches/OpenIddictAuthorizationCache.cs @@ -44,30 +44,6 @@ public async ValueTask AddAsync(TAuthorization authorization, CancellationToken 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 void Dispose() } /// - public IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - var parameters = new - { - Method = nameof(FindAsync), - Subject = subject, - Client = client - }; - - if (!_cache.TryGetValue(parameters, out ImmutableArray authorizations)) - { - var builder = ImmutableArray.CreateBuilder(); - - 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; - } - } - } - - /// - public IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - var parameters = new - { - Method = nameof(FindAsync), - Subject = subject, - Client = client, - Status = status - }; - - if (!_cache.TryGetValue(parameters, out ImmutableArray authorizations)) - { - var builder = ImmutableArray.CreateBuilder(); - - 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; - } - } - } - - /// - public IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, CancellationToken cancellationToken) + public async IAsyncEnumerable FindAsync( + string? subject, string? client, + string? status, string? type, + ImmutableArray? 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - var parameters = new - { - Method = nameof(FindAsync), - Subject = subject, - Client = client, - Status = status, - Type = type - }; - - if (!_cache.TryGetValue(parameters, out ImmutableArray authorizations)) - { - var builder = ImmutableArray.CreateBuilder(); - - 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; - } - } - } - - /// - public IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, - ImmutableArray 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 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; } } diff --git a/src/OpenIddict.Core/Caches/OpenIddictTokenCache.cs b/src/OpenIddict.Core/Caches/OpenIddictTokenCache.cs index 7d3108670..f1f34d5cf 100644 --- a/src/OpenIddict.Core/Caches/OpenIddictTokenCache.cs +++ b/src/OpenIddict.Core/Caches/OpenIddictTokenCache.cs @@ -44,30 +44,6 @@ public async ValueTask AddAsync(TToken token, CancellationToken cancellationToke 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 void Dispose() } /// - public IAsyncEnumerable FindAsync(string subject, string client, CancellationToken cancellationToken) + public async IAsyncEnumerable 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 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 tokens)) - { - var builder = ImmutableArray.CreateBuilder(); - - 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; - } - } - } - - /// - public IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - var parameters = new - { - Method = nameof(FindAsync), - Subject = subject, - Client = client, - Status = status - }; - - if (!_cache.TryGetValue(parameters, out ImmutableArray tokens)) - { - var builder = ImmutableArray.CreateBuilder(); - - 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; - } - } - } - - /// - public IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - var parameters = new - { - Method = nameof(FindAsync), - Subject = subject, - Client = client, - Status = status, - Type = type - }; - - if (!_cache.TryGetValue(parameters, out ImmutableArray tokens)) - { - var builder = ImmutableArray.CreateBuilder(); - - 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; } } diff --git a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs index e2c4b556d..4b085e04a 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs @@ -271,207 +271,21 @@ public virtual async ValueTask DeleteAsync(TAuthorization authorization, Cancell await Store.DeleteAsync(authorization, cancellationToken); } - /// - /// Retrieves the authorizations corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the subject/client. - public virtual IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - await foreach (var authorization in authorizations) - { - if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal)) - { - yield return authorization; - } - } - } - } - - /// - /// Retrieves the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the criteria. - public virtual IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - await foreach (var authorization in authorizations) - { - if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal)) - { - yield return authorization; - } - } - } - } - /// /// Retrieves the authorizations matching the specified parameters. /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. + /// The subject associated with the authorization, or not to filter out specific subjects. + /// The client associated with the authorization, or not to filter out specific clients. + /// The authorization status, or not to filter out specific authorization statuses. + /// The authorization type, or not to filter out specific authorization types. + /// The minimal scopes associated with the authorization, or not to filter out scopes. /// The that can be used to abort the operation. /// The authorizations corresponding to the criteria. public virtual IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, CancellationToken cancellationToken = default) + string? subject, string? client, + string? status, string? type, + ImmutableArray? 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - await foreach (var authorization in authorizations) - { - if (string.Equals(await Store.GetSubjectAsync(authorization, cancellationToken), subject, StringComparison.Ordinal)) - { - yield return authorization; - } - } - } - } - - /// - /// Retrieves the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. - /// The minimal scopes associated with the authorization. - /// The that can be used to abort the operation. - /// The authorizations corresponding to the criteria. - public virtual IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, - ImmutableArray 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 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Can { 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 virtual async ValueTask PopulateAsync( public virtual ValueTask PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default) => Store.PruneAsync(threshold, cancellationToken); - /// - /// Revokes all the authorizations corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The that can be used to abort the operation. - /// The number of authorizations corresponding to the criteria that were marked as revoked. - public virtual ValueTask 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); - } - /// /// Revokes all the authorizations matching the specified parameters. /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. + /// The subject associated with the authorization, or not to filter out specific subjects. + /// The client associated with the authorization, or not to filter out specific clients. + /// The authorization status, or not to filter out specific authorization statuses. + /// The authorization type, or not to filter out specific authorization types. /// The that can be used to abort the operation. /// The number of authorizations corresponding to the criteria that were marked as revoked. - public virtual ValueTask 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); - } - - /// - /// Revokes all the authorizations matching the specified parameters. - /// - /// The subject associated with the authorization. - /// The client associated with the authorization. - /// The authorization status. - /// The authorization type. - /// The that can be used to abort the operation. - /// The number of authorizations corresponding to the criteria that were marked as revoked. - public virtual ValueTask 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 RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken = default) + => Store.RevokeAsync(subject, client, status, type, cancellationToken); /// /// Revokes all the authorizations associated with the specified application identifier. @@ -1352,19 +1094,7 @@ ValueTask IOpenIddictAuthorizationManager.DeleteAsync(object authorization, Canc => DeleteAsync((TAuthorization) authorization, cancellationToken); /// - IAsyncEnumerable IOpenIddictAuthorizationManager.FindAsync(string subject, string client, CancellationToken cancellationToken) - => FindAsync(subject, client, cancellationToken); - - /// - IAsyncEnumerable IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, CancellationToken cancellationToken) - => FindAsync(subject, client, status, cancellationToken); - - /// - IAsyncEnumerable IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, string type, CancellationToken cancellationToken) - => FindAsync(subject, client, status, type, cancellationToken); - - /// - IAsyncEnumerable IOpenIddictAuthorizationManager.FindAsync(string subject, string client, string status, string type, ImmutableArray scopes, CancellationToken cancellationToken) + IAsyncEnumerable IOpenIddictAuthorizationManager.FindAsync(string? subject, string? client, string? status, string? type, ImmutableArray? scopes, CancellationToken cancellationToken) => FindAsync(subject, client, status, type, scopes, cancellationToken); /// @@ -1455,15 +1185,7 @@ ValueTask IOpenIddictAuthorizationManager.PruneAsync(DateTimeOffset thresh => PruneAsync(threshold, cancellationToken); /// - ValueTask IOpenIddictAuthorizationManager.RevokeAsync(string subject, string client, CancellationToken cancellationToken) - => RevokeAsync(subject, client, cancellationToken); - - /// - ValueTask IOpenIddictAuthorizationManager.RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken) - => RevokeAsync(subject, client, status, cancellationToken); - - /// - ValueTask IOpenIddictAuthorizationManager.RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken) + ValueTask IOpenIddictAuthorizationManager.RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken) => RevokeAsync(subject, client, status, type, cancellationToken); /// diff --git a/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs b/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs index c16ba7269..54529e759 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs @@ -205,141 +205,19 @@ public virtual async ValueTask DeleteAsync(TToken token, CancellationToken cance await Store.DeleteAsync(token, cancellationToken); } - /// - /// Retrieves the tokens corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The that can be used to abort the operation. - /// The tokens corresponding to the subject/client. - public virtual IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - await foreach (var token in tokens) - { - if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal)) - { - yield return token; - } - } - } - } - - /// - /// Retrieves the tokens matching the specified parameters. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The that can be used to abort the operation. - /// The tokens corresponding to the criteria. - public virtual IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - await foreach (var token in tokens) - { - if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal)) - { - yield return token; - } - } - } - } - /// /// Retrieves the tokens matching the specified parameters. /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The token type. + /// The subject associated with the token, or not to filter out specific subjects. + /// The client associated with the token, or not to filter out specific clients. + /// The token status, or not to filter out specific token statuses. + /// The token type, or not to filter out specific token types. /// The that can be used to abort the operation. /// Tokens corresponding to the criteria. public virtual IAsyncEnumerable 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 @@ async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] Cancellatio { 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 virtual async ValueTask PopulateAsync( public virtual ValueTask PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default) => Store.PruneAsync(threshold, cancellationToken); - /// - /// Revokes all the tokens corresponding to the specified - /// subject and associated with the application identifier. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The that can be used to abort the operation. - /// The number of tokens corresponding to the criteria that were marked as revoked. - public virtual ValueTask 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); - } - - /// - /// Revokes all the tokens matching the specified parameters. - /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The that can be used to abort the operation. - /// The number of tokens corresponding to the criteria that were marked as revoked. - public virtual ValueTask 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); - } - /// /// Revokes all the tokens matching the specified parameters. /// - /// The subject associated with the token. - /// The client associated with the token. - /// The token status. - /// The token type. + /// The subject associated with the token, or not to filter out specific subjects. + /// The client associated with the token, or not to filter out specific clients. + /// The token status, or not to filter out specific token statuses. + /// The token type, or not to filter out specific token types. /// The that can be used to abort the operation. /// The number of tokens corresponding to the criteria that were marked as revoked. - public virtual ValueTask 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 RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken = default) + => Store.RevokeAsync(subject, client, status, type, cancellationToken); /// /// Revokes all the tokens associated with the specified application identifier. @@ -1495,15 +1301,7 @@ ValueTask IOpenIddictTokenManager.DeleteAsync(object token, CancellationToken ca => DeleteAsync((TToken) token, cancellationToken); /// - IAsyncEnumerable IOpenIddictTokenManager.FindAsync(string subject, string client, CancellationToken cancellationToken) - => FindAsync(subject, client, cancellationToken); - - /// - IAsyncEnumerable IOpenIddictTokenManager.FindAsync(string subject, string client, string status, CancellationToken cancellationToken) - => FindAsync(subject, client, status, cancellationToken); - - /// - IAsyncEnumerable IOpenIddictTokenManager.FindAsync(string subject, string client, string status, string type, CancellationToken cancellationToken) + IAsyncEnumerable IOpenIddictTokenManager.FindAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken) => FindAsync(subject, client, status, type, cancellationToken); /// @@ -1619,15 +1417,7 @@ ValueTask IOpenIddictTokenManager.PruneAsync(DateTimeOffset threshold, Can => PruneAsync(threshold, cancellationToken); /// - ValueTask IOpenIddictTokenManager.RevokeAsync(string subject, string client, CancellationToken cancellationToken) - => RevokeAsync(subject, client, cancellationToken); - - /// - ValueTask IOpenIddictTokenManager.RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken) - => RevokeAsync(subject, client, status, cancellationToken); - - /// - ValueTask IOpenIddictTokenManager.RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken) + ValueTask IOpenIddictTokenManager.RevokeAsync(string? subject, string? client, string? status, string? type, CancellationToken cancellationToken) => RevokeAsync(subject, client, status, type, cancellationToken); /// diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs index b0ba2e067..434fe2119 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs @@ -170,138 +170,42 @@ Task> ListTokensAsync() } /// - public virtual IAsyncEnumerable FindAsync( - string subject, string client, CancellationToken cancellationToken) + public virtual async IAsyncEnumerable FindAsync( + string? subject, string? client, + string? status, string? type, + ImmutableArray? 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); - } - - /// - public virtual IAsyncEnumerable 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); - } - - /// - public virtual IAsyncEnumerable 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 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); - } - - /// - public virtual IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, - ImmutableArray 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 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 @@ orderby authorization.Id } /// - public virtual async ValueTask 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? 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; - } - - /// - public virtual async ValueTask RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken) + public virtual async ValueTask 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? 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 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; - } - - /// - public virtual async ValueTask 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? 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 virtual async ValueTask RevokeByApplicationIdAsync(string identifie 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 virtual async ValueTask RevokeBySubjectAsync(string subject, Cancel 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)) { diff --git a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs index 56edf7bb3..44cbe134b 100644 --- a/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs +++ b/src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs @@ -145,90 +145,36 @@ public virtual async ValueTask DeleteAsync(TToken token, CancellationToken cance } } - /// - public virtual IAsyncEnumerable 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); - } - /// public virtual IAsyncEnumerable 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 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); - } - - /// - public virtual IAsyncEnumerable 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); } /// @@ -660,151 +606,37 @@ orderby token.Id } /// - public virtual async ValueTask RevokeAsync(string subject, string client, CancellationToken cancellationToken) + public virtual async ValueTask 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 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? 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; - } - - /// - public virtual async ValueTask 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? 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; - } - - /// - public virtual async ValueTask 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? 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 virtual async ValueTask RevokeByApplicationIdAsync(string identifie 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 virtual async ValueTask RevokeByAuthorizationIdAsync(string identif 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 virtual async ValueTask RevokeBySubjectAsync(string subject, Cancel 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)) { diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs index 71bb8d541..c4eb5a47a 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs @@ -241,165 +241,50 @@ await strategy.ExecuteAsync(async () => } /// - public virtual IAsyncEnumerable FindAsync( - string subject, string client, CancellationToken cancellationToken) + public virtual async IAsyncEnumerable FindAsync( + string? subject, string? client, + string? status, string? type, + ImmutableArray? 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); - } - - /// - public virtual IAsyncEnumerable 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 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); - } - - /// - public virtual IAsyncEnumerable 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); - } - - /// - public virtual IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, - ImmutableArray 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 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 @@ orderby authorization.Id } /// - public virtual async ValueTask RevokeAsync(string subject, string client, CancellationToken cancellationToken) + public virtual async ValueTask 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 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? 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; - } - - /// - public virtual async ValueTask 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? 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; - } - - /// - public virtual async ValueTask 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 @@ from authorization in Authorizations // // 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 @@ from authorization in Authorizations // // 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 @@ from authorization in Authorizations 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)) { diff --git a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs index 8c67c192e..a9ff14943 100644 --- a/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs +++ b/src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs @@ -165,110 +165,44 @@ public virtual async ValueTask DeleteAsync(TToken token, CancellationToken cance } } - /// - public virtual IAsyncEnumerable 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); - } - /// public virtual IAsyncEnumerable 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 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); - } - - /// - public virtual IAsyncEnumerable 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); } /// @@ -754,192 +688,47 @@ orderby token.Id } /// - public virtual async ValueTask RevokeAsync(string subject, string client, CancellationToken cancellationToken) + public virtual async ValueTask 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 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? 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; - } - - /// - public virtual async ValueTask 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? 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; - } - - /// - public virtual async ValueTask 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 @@ from token in Tokens 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 @@ from token in Tokens // // 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 @@ from token in Tokens // // 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 @@ from token in Tokens 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)) { diff --git a/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs b/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs index 142dafcfd..7f58382c0 100644 --- a/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs +++ b/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs @@ -103,159 +103,46 @@ await database.GetCollection(Options.CurrentValue.Tokens } /// - public virtual IAsyncEnumerable FindAsync( - string subject, string client, CancellationToken cancellationToken) + public virtual async IAsyncEnumerable FindAsync( + string? subject, string? client, + string? status, string? type, + ImmutableArray? 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - var database = await Context.GetDatabaseAsync(cancellationToken); - var collection = database.GetCollection(Options.CurrentValue.AuthorizationsCollectionName); - - await foreach (var authorization in collection.Find(authorization => - authorization.ApplicationId == ObjectId.Parse(client) && - authorization.Subject == subject).ToAsyncEnumerable(cancellationToken)) - { - yield return authorization; - } - } - } - - /// - public virtual IAsyncEnumerable 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(Options.CurrentValue.AuthorizationsCollectionName); - return ExecuteAsync(cancellationToken); + IQueryable query = collection.AsQueryable(); - async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) + if (!string.IsNullOrEmpty(subject)) { - var database = await Context.GetDatabaseAsync(cancellationToken); - var collection = database.GetCollection(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); } - } - /// - public virtual IAsyncEnumerable 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 values) { - throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type)); - } - - return ExecuteAsync(cancellationToken); - - async IAsyncEnumerable ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - var database = await Context.GetDatabaseAsync(cancellationToken); - var collection = database.GetCollection(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; - } - } - } - - /// - public virtual IAsyncEnumerable FindAsync( - string subject, string client, - string status, string type, - ImmutableArray 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - var database = await Context.GetDatabaseAsync(cancellationToken); - var collection = database.GetCollection(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 @@ where authorization.CreationDate < threshold.UtcDateTime } /// - public virtual async ValueTask RevokeAsync(string subject, string client, CancellationToken cancellationToken) + public virtual async ValueTask 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(Options.CurrentValue.AuthorizationsCollectionName); - return (await collection.UpdateManyAsync( - filter : authorization => authorization.Subject == subject && authorization.ApplicationId == ObjectId.Parse(client), - update : Builders.Update.Set(authorization => authorization.Status, Statuses.Revoked), - options : null, - cancellationToken: cancellationToken)).MatchedCount; - } - - /// - public virtual async ValueTask 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.Filter.Empty; - var database = await Context.GetDatabaseAsync(cancellationToken); - var collection = database.GetCollection(Options.CurrentValue.AuthorizationsCollectionName); - - return (await collection.UpdateManyAsync( - filter : authorization => authorization.ApplicationId == ObjectId.Parse(client) && - authorization.Subject == subject && - authorization.Status == status, - update : Builders.Update.Set(authorization => authorization.Status, Statuses.Revoked), - options : null, - cancellationToken: cancellationToken)).MatchedCount; - } - - /// - public virtual async ValueTask 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.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.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.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.Filter.Where(authorization => authorization.Type == type); } - var database = await Context.GetDatabaseAsync(cancellationToken); - var collection = database.GetCollection(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.Update.Set(authorization => authorization.Status, Statuses.Revoked), options : null, cancellationToken: cancellationToken)).MatchedCount; diff --git a/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs b/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs index f14bd5ac6..ddead28ae 100644 --- a/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs +++ b/src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs @@ -99,112 +99,38 @@ public virtual async ValueTask DeleteAsync(TToken token, CancellationToken cance } /// - public virtual IAsyncEnumerable FindAsync(string subject, - string client, CancellationToken cancellationToken) + public virtual async IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - var database = await Context.GetDatabaseAsync(cancellationToken); - var collection = database.GetCollection(Options.CurrentValue.TokensCollectionName); - - await foreach (var token in collection.Find(token => - token.ApplicationId == ObjectId.Parse(client) && - token.Subject == subject).ToAsyncEnumerable(cancellationToken)) - { - yield return token; - } - } - } - - /// - public virtual IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) - { - var database = await Context.GetDatabaseAsync(cancellationToken); - var collection = database.GetCollection(Options.CurrentValue.TokensCollectionName); + var database = await Context.GetDatabaseAsync(cancellationToken); + var collection = database.GetCollection(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 query = collection.AsQueryable(); - /// - public virtual IAsyncEnumerable 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 ExecuteAsync([EnumeratorCancellation] CancellationToken cancellationToken) + await foreach (var token in query.ToAsyncEnumerable(cancellationToken)) { - var database = await Context.GetDatabaseAsync(cancellationToken); - var collection = database.GetCollection(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 @@ on token.AuthorizationId equals authorization.Id into authorizations 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 @@ where token.CreationDate < threshold.UtcDateTime } /// - public virtual async ValueTask RevokeAsync(string subject, string client, CancellationToken cancellationToken) + public virtual async ValueTask 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(Options.CurrentValue.TokensCollectionName); - return (await collection.UpdateManyAsync( - filter : token => token.ApplicationId == ObjectId.Parse(client) && token.Subject == subject, - update : Builders.Update.Set(token => token.Status, Statuses.Revoked), - options : null, - cancellationToken: cancellationToken)).MatchedCount; - } + var filter = Builders.Filter.Empty; - /// - public virtual async ValueTask 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(Options.CurrentValue.TokensCollectionName); - - return (await collection.UpdateManyAsync( - filter : token => token.ApplicationId == ObjectId.Parse(client) && - token.Subject == subject && - token.Status == status, - update : Builders.Update.Set(token => token.Status, Statuses.Revoked), - options : null, - cancellationToken: cancellationToken)).MatchedCount; - } - - /// - public virtual async ValueTask 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.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.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.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.Filter.Where(token => token.Type == type); } - var database = await Context.GetDatabaseAsync(cancellationToken); - var collection = database.GetCollection(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.Update.Set(token => token.Status, Statuses.Revoked), options : null, cancellationToken: cancellationToken)).MatchedCount;