diff --git a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs index 60b0765d..bbd62009 100644 --- a/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs +++ b/src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs @@ -190,6 +190,35 @@ namespace OpenIddict.Core return Store.FindAsync(subject, client, cancellationToken); } + /// + /// Retrieves the authorizations corresponding to the specified subject, associated with + /// the application identifier and for which the specified scopes have been granted. + /// + /// The subject associated with the authorization. + /// The client associated with the authorization. + /// The minimal scopes associated with the authorization. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, whose result + /// returns the authorizations corresponding to the specified subject/client/scopes. + /// + public virtual Task> FindAsync( + [NotNull] string subject, [NotNull] string client, + ImmutableArray scopes, CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(subject)) + { + throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); + } + + if (string.IsNullOrEmpty(client)) + { + throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); + } + + return Store.FindAsync(subject, client, scopes, cancellationToken); + } + /// /// Retrieves an authorization using its unique identifier. /// diff --git a/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs index 639b62c1..94e0146b 100644 --- a/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.Core/Stores/IOpenIddictAuthorizationStore.cs @@ -75,6 +75,22 @@ namespace OpenIddict.Core /// Task> FindAsync([NotNull] string subject, [NotNull] string client, CancellationToken cancellationToken); + /// + /// Retrieves the authorizations corresponding to the specified subject, associated with + /// the application identifier and for which the specified scopes have been granted. + /// + /// The subject associated with the authorization. + /// The client associated with the authorization. + /// The minimal scopes associated with the authorization. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, whose result + /// returns the authorizations corresponding to the specified subject/client/scopes. + /// + Task> FindAsync( + [NotNull] string subject, [NotNull] string client, + ImmutableArray scopes, CancellationToken cancellationToken); + /// /// Retrieves an authorization using its unique identifier. /// diff --git a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs index 520053ba..acdd7e25 100644 --- a/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs +++ b/src/OpenIddict.Core/Stores/OpenIddictAuthorizationStore.cs @@ -5,6 +5,7 @@ */ using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.ComponentModel; using System.Linq; @@ -111,6 +112,46 @@ namespace OpenIddict.Core (key: ConvertIdentifierFromString(client), principal: subject), cancellationToken); } + /// + /// Retrieves the authorizations corresponding to the specified subject, associated with + /// the application identifier and for which the specified scopes have been granted. + /// + /// The subject associated with the authorization. + /// The client associated with the authorization. + /// The minimal scopes associated with the authorization. + /// The that can be used to abort the operation. + /// + /// A that can be used to monitor the asynchronous operation, whose result + /// returns the authorizations corresponding to the specified subject/client/scopes. + /// + public virtual async Task> FindAsync( + [NotNull] string subject, [NotNull] string client, + ImmutableArray scopes, CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(subject)) + { + throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); + } + + if (string.IsNullOrEmpty(client)) + { + throw new ArgumentException("The client cannot be null or empty.", nameof(client)); + } + + var builder = ImmutableArray.CreateBuilder(); + + foreach (var authorization in await FindAsync(subject, client, cancellationToken)) + { + var set = new HashSet(await GetScopesAsync(authorization, cancellationToken), StringComparer.Ordinal); + if (set.IsSupersetOf(scopes)) + { + builder.Add(authorization); + } + } + + return builder.ToImmutable(); + } + /// /// Retrieves an authorization using its unique identifier. ///