diff --git a/Directory.Build.targets b/Directory.Build.targets
index fb986cc61..46dfd60bb 100644
--- a/Directory.Build.targets
+++ b/Directory.Build.targets
@@ -24,17 +24,17 @@
12.0
+ $([MSBuild]::VersionGreaterThanOrEquals($(TargetPlatformVersion), '12.2'))) ">12.2
13.1
+ $([MSBuild]::VersionGreaterThanOrEquals($(TargetPlatformVersion), '15.0'))) ">15.0
10.15
+ $([MSBuild]::VersionGreaterThanOrEquals($(TargetPlatformVersion), '12.0'))) ">12.0
-
+
@@ -103,7 +103,7 @@
-
+
@@ -160,7 +160,7 @@
-
+
@@ -206,7 +206,7 @@
-
+
@@ -228,31 +228,31 @@
-
-
-
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
+
+
@@ -274,32 +274,32 @@
-
+
-
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
-
+
@@ -321,57 +321,57 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
+
+
--------------
diff --git a/WorkloadRollback.json b/WorkloadRollback.json
index 53eb2e595..9fa723978 100644
--- a/WorkloadRollback.json
+++ b/WorkloadRollback.json
@@ -1,17 +1,17 @@
{
- "microsoft.net.sdk.android": "35.0.0-rc.2.152/9.0.100-rc.2",
- "microsoft.net.sdk.ios": "18.0.9600-net9-rc2/9.0.100-rc.2",
- "microsoft.net.sdk.maccatalyst": "18.0.9600-net9-rc2/9.0.100-rc.2",
- "microsoft.net.sdk.macos": "15.0.9600-net9-rc2/9.0.100-rc.2",
- "microsoft.net.sdk.maui": "9.0.0-rc.2.24503.2/9.0.100-rc.2",
- "microsoft.net.sdk.tvos": "18.0.9600-net9-rc2/9.0.100-rc.2",
- "microsoft.net.workload.mono.toolchain.current": "9.0.0-rc.2.24473.5/9.0.100-rc.2",
- "microsoft.net.workload.emscripten.current": "9.0.0-rc.2.24468.8/9.0.100-rc.2",
- "microsoft.net.workload.emscripten.net6": "9.0.0-rc.2.24468.8/9.0.100-rc.2",
- "microsoft.net.workload.emscripten.net7": "9.0.0-rc.2.24468.8/9.0.100-rc.2",
- "microsoft.net.workload.emscripten.net8": "9.0.0-rc.2.24468.8/9.0.100-rc.2",
- "microsoft.net.workload.mono.toolchain.net6": "9.0.0-rc.2.24473.5/9.0.100-rc.2",
- "microsoft.net.workload.mono.toolchain.net7": "9.0.0-rc.2.24473.5/9.0.100-rc.2",
- "microsoft.net.workload.mono.toolchain.net8": "9.0.0-rc.2.24473.5/9.0.100-rc.2",
- "microsoft.net.sdk.aspire": "8.2.0/8.0.100"
+ "microsoft.net.sdk.android": "35.0.7/9.0.100",
+ "microsoft.net.sdk.ios": "18.0.9617/9.0.100",
+ "microsoft.net.sdk.maccatalyst": "18.0.9617/9.0.100",
+ "microsoft.net.sdk.macos": "15.0.9617/9.0.100",
+ "microsoft.net.sdk.maui": "9.0.0/9.0.100",
+ "microsoft.net.sdk.tvos": "18.0.9617/9.0.100",
+ "microsoft.net.workload.mono.toolchain.current": "9.0.0/9.0.100",
+ "microsoft.net.workload.emscripten.current": "9.0.0/9.0.100",
+ "microsoft.net.workload.emscripten.net6": "9.0.0/9.0.100",
+ "microsoft.net.workload.emscripten.net7": "9.0.0/9.0.100",
+ "microsoft.net.workload.emscripten.net8": "9.0.0/9.0.100",
+ "microsoft.net.workload.mono.toolchain.net6": "9.0.0/9.0.100",
+ "microsoft.net.workload.mono.toolchain.net7": "9.0.0/9.0.100",
+ "microsoft.net.workload.mono.toolchain.net8": "9.0.0/9.0.100",
+ "microsoft.net.sdk.aspire": "8.2.2/8.0.100"
}
diff --git a/eng/Versions.props b/eng/Versions.props
index 7f7aa0e4e..a00cc94a0 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -5,9 +5,9 @@
0
0
$(MajorVersion).$(MinorVersion).$(PatchVersion)
- preview3
+ preview5
- Preview 3
+ Preview 5
false
release
true
diff --git a/global.json b/global.json
index a58515918..4f305b4ae 100644
--- a/global.json
+++ b/global.json
@@ -1,17 +1,17 @@
{
"sdk": {
- "version": "9.0.100-rc.2.24474.11",
+ "version": "9.0.100",
"allowPrerelease": true,
"rollForward": "major"
},
"tools": {
- "dotnet": "9.0.100-rc.2.24474.11",
+ "dotnet": "9.0.100",
"runtimes": {
"aspnetcore": [
- "6.0.35",
- "8.0.10"
+ "6.0.36",
+ "8.0.11"
]
}
},
diff --git a/sandbox/OpenIddict.Sandbox.AspNet.Server/Startup.cs b/sandbox/OpenIddict.Sandbox.AspNet.Server/Startup.cs
index 287bfc7cd..ad53f9781 100644
--- a/sandbox/OpenIddict.Sandbox.AspNet.Server/Startup.cs
+++ b/sandbox/OpenIddict.Sandbox.AspNet.Server/Startup.cs
@@ -201,7 +201,7 @@ await manager.CreateAsync(new OpenIddictApplicationDescriptor
ClientId = "mvc",
ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
ClientType = ClientTypes.Confidential,
- ConsentType = ConsentTypes.Explicit,
+ ConsentType = ConsentTypes.Systematic,
DisplayName = "MVC client application",
RedirectUris =
{
diff --git a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
index 6ad635fcf..f4d44f2fa 100644
--- a/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
+++ b/sandbox/OpenIddict.Sandbox.AspNetCore.Server/Worker.cs
@@ -152,7 +152,7 @@ await manager.CreateAsync(new OpenIddictApplicationDescriptor
ClientId = "mvc",
ClientSecret = "901564A5-E7FE-42CB-B10D-61EF6A8F3654",
ClientType = ClientTypes.Confidential,
- ConsentType = ConsentTypes.Explicit,
+ ConsentType = ConsentTypes.Systematic,
DisplayName = "MVC client application",
DisplayNames =
{
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/OpenIddictResources.resx b/src/OpenIddict.Abstractions/OpenIddictResources.resx
index 0ab3e2479..4e260d063 100644
--- a/src/OpenIddict.Abstractions/OpenIddictResources.resx
+++ b/src/OpenIddict.Abstractions/OpenIddictResources.resx
@@ -1701,6 +1701,12 @@ To apply post-logout redirection responses, create a class implementing 'IOpenId
The '{0}' parameter cannot contain null or empty values.
+
+ A token must be specified when using introspection.
+
+
+ A token must be specified when using revocation.
+
The security token is missing.
diff --git a/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs b/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs
index 039d64cb7..d6be1a7e5 100644
--- a/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs
+++ b/src/OpenIddict.Abstractions/Primitives/OpenIddictParameter.cs
@@ -200,7 +200,7 @@ public bool Equals(OpenIddictParameter other)
(string left, string right) => string.Equals(left, right, StringComparison.Ordinal),
// If the two parameters are string arrays, use SequenceEqual().
- (string?[] left, string?[] right) => left.SequenceEqual(right),
+ (string?[] left, string?[] right) => Enumerable.SequenceEqual(left, right),
// If one of the two parameters is an undefined JsonElement, treat it
// as a null value and return true if the other parameter is null too.
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.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs
index 1e0df7e7d..67148aa41 100644
--- a/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs
+++ b/src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs
@@ -156,17 +156,24 @@ protected override async Task HandleAuthenticateAsync()
return AuthenticateResult.NoResult();
}
- var properties = new AuthenticationProperties(new Dictionary
- {
- [Properties.Error] = context.Error,
- [Properties.ErrorDescription] = context.ErrorDescription,
- [Properties.ErrorUri] = context.ErrorUri
- });
+ var properties = CreateAuthenticationProperties();
+ properties.Items[Properties.Error] = context.Error;
+ properties.Items[Properties.ErrorDescription] = context.ErrorDescription;
+ properties.Items[Properties.ErrorUri] = context.ErrorUri;
return AuthenticateResult.Fail(SR.GetResourceString(SR.ID0113), properties);
}
else
+ {
+ var properties = CreateAuthenticationProperties();
+
+ return AuthenticateResult.Success(new AuthenticationTicket(
+ context.MergedPrincipal ?? new ClaimsPrincipal(new ClaimsIdentity()), properties,
+ OpenIddictClientAspNetCoreDefaults.AuthenticationScheme));
+ }
+
+ AuthenticationProperties CreateAuthenticationProperties()
{
var properties = new AuthenticationProperties
{
@@ -336,9 +343,7 @@ protected override async Task HandleAuthenticateAsync()
properties.SetParameter(Properties.UserInfoTokenPrincipal, context.UserInfoTokenPrincipal);
}
- return AuthenticateResult.Success(new AuthenticationTicket(
- context.MergedPrincipal ?? new ClaimsPrincipal(new ClaimsIdentity()), properties,
- OpenIddictClientAspNetCoreDefaults.AuthenticationScheme));
+ return properties;
}
}
diff --git a/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandler.cs b/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandler.cs
index b6c480d7b..8f7f44a31 100644
--- a/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandler.cs
+++ b/src/OpenIddict.Client.Owin/OpenIddictClientOwinHandler.cs
@@ -155,17 +155,22 @@ public override async Task InvokeAsync()
return null;
}
- var properties = new AuthenticationProperties(new Dictionary
- {
- [Properties.Error] = context.Error,
- [Properties.ErrorDescription] = context.ErrorDescription,
- [Properties.ErrorUri] = context.ErrorUri
- });
+ var properties = CreateAuthenticationProperties();
+ properties.Dictionary[Properties.Error] = context.Error;
+ properties.Dictionary[Properties.ErrorDescription] = context.ErrorDescription;
+ properties.Dictionary[Properties.ErrorUri] = context.ErrorUri;
- return new AuthenticationTicket(null, properties);
+ return new AuthenticationTicket(new ClaimsIdentity(), properties);
}
else
+ {
+ var properties = CreateAuthenticationProperties();
+
+ return new AuthenticationTicket(context.MergedPrincipal?.Identity as ClaimsIdentity ?? new ClaimsIdentity(), properties);
+ }
+
+ AuthenticationProperties CreateAuthenticationProperties()
{
var properties = new AuthenticationProperties
{
@@ -240,7 +245,7 @@ public override async Task InvokeAsync()
properties.Dictionary[Tokens.UserInfoToken] = context.UserInfoToken;
}
- return new AuthenticationTicket(context.MergedPrincipal?.Identity as ClaimsIdentity, properties);
+ return properties;
}
}
diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationConfiguration.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationConfiguration.cs
index 85d5b74e5..b1bc3e0c9 100644
--- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationConfiguration.cs
+++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationConfiguration.cs
@@ -5,7 +5,10 @@
*/
using System.ComponentModel;
+using System.Security.Cryptography.X509Certificates;
using Microsoft.Extensions.Options;
+using OpenIddict.Client.SystemNetHttp;
+using static OpenIddict.Client.WebIntegration.OpenIddictClientWebIntegrationConstants;
namespace OpenIddict.Client.WebIntegration;
@@ -14,7 +17,8 @@ namespace OpenIddict.Client.WebIntegration;
///
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed partial class OpenIddictClientWebIntegrationConfiguration : IConfigureOptions,
- IPostConfigureOptions
+ IPostConfigureOptions,
+ IPostConfigureOptions
{
///
public void Configure(OpenIddictClientOptions options)
@@ -47,6 +51,38 @@ public void PostConfigure(string? name, OpenIddictClientOptions options)
});
}
+ ///
+ public void PostConfigure(string? name, OpenIddictClientSystemNetHttpOptions options)
+ {
+ if (options is null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ // Override the default/user-defined selectors to support attaching TLS client
+ // certificates that don't meet the requirements enforced by default by OpenIddict.
+ options.SelfSignedTlsClientAuthenticationCertificateSelector = CreateSelector(options.SelfSignedTlsClientAuthenticationCertificateSelector);
+ options.TlsClientAuthenticationCertificateSelector = CreateSelector(options.TlsClientAuthenticationCertificateSelector);
+
+ static Func CreateSelector(Func selector)
+ => registration =>
+ {
+ var certificate = registration.ProviderType switch
+ {
+ ProviderTypes.ProSantéConnect => registration.GetProSantéConnectSettings().SigningCertificate,
+
+ _ => null
+ };
+
+ if (certificate is not null)
+ {
+ return certificate;
+ }
+
+ return selector(registration);
+ };
+ }
+
///
/// Amends the registration with the provider-specific configuration logic.
///
diff --git a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationExtensions.cs b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationExtensions.cs
index 3b78e5d0e..1ad218023 100644
--- a/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationExtensions.cs
+++ b/src/OpenIddict.Client.WebIntegration/OpenIddictClientWebIntegrationExtensions.cs
@@ -7,6 +7,7 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using OpenIddict.Client;
+using OpenIddict.Client.SystemNetHttp;
using OpenIddict.Client.WebIntegration;
namespace Microsoft.Extensions.DependencyInjection;
@@ -40,6 +41,8 @@ public static OpenIddictClientWebIntegrationBuilder UseWebProviders(this OpenIdd
// Note: TryAddEnumerable() is used here to ensure the initializers are registered only once.
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
IConfigureOptions, OpenIddictClientWebIntegrationConfiguration>());
+ builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
+ IPostConfigureOptions, OpenIddictClientWebIntegrationConfiguration>());
// Note: the IPostConfigureOptions service responsible for populating
// the client registrations MUST be registered before OpenIddictClientConfiguration to ensure
diff --git a/src/OpenIddict.Client/OpenIddictClientHandlers.cs b/src/OpenIddict.Client/OpenIddictClientHandlers.cs
index f327891d2..5de69eb74 100644
--- a/src/OpenIddict.Client/OpenIddictClientHandlers.cs
+++ b/src/OpenIddict.Client/OpenIddictClientHandlers.cs
@@ -6171,6 +6171,11 @@ public ValueTask HandleAsync(ProcessIntrospectionContext context)
throw new ArgumentNullException(nameof(context));
}
+ if (string.IsNullOrEmpty(context.Token))
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0458));
+ }
+
if (context.Registration is null && string.IsNullOrEmpty(context.RegistrationId) &&
context.Issuer is null && string.IsNullOrEmpty(context.ProviderName) &&
context.Options.Registrations.Count is not 1)
@@ -6841,6 +6846,11 @@ public ValueTask HandleAsync(ProcessRevocationContext context)
throw new ArgumentNullException(nameof(context));
}
+ if (string.IsNullOrEmpty(context.Token))
+ {
+ throw new InvalidOperationException(SR.GetResourceString(SR.ID0459));
+ }
+
if (context.Registration is null && string.IsNullOrEmpty(context.RegistrationId) &&
context.Issuer is null && string.IsNullOrEmpty(context.ProviderName) &&
context.Options.Registrations.Count is not 1)
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;
- }
-
- ///