Browse Source

Add new RevokeAsync() methods to the authorization and token stores

pull/2215/head
Kévin Chalet 1 year ago
parent
commit
bda3bee913
  1. 31
      src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs
  2. 31
      src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs
  3. 31
      src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs
  4. 31
      src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs
  5. 97
      src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
  6. 97
      src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
  7. 176
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkAuthorizationStore.cs
  8. 176
      src/OpenIddict.EntityFramework/Stores/OpenIddictEntityFrameworkTokenStore.cs
  9. 287
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreAuthorizationStore.cs
  10. 296
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictEntityFrameworkCoreTokenStore.cs
  11. 99
      src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbAuthorizationStore.cs
  12. 89
      src/OpenIddict.MongoDb/Stores/OpenIddictMongoDbTokenStore.cs

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

@ -394,6 +394,37 @@ public interface IOpenIddictAuthorizationManager
/// <returns>The number of authorizations that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all the authorizations corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all the authorizations associated with the specified application identifier.
/// </summary>

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

@ -409,6 +409,37 @@ public interface IOpenIddictTokenManager
/// <returns>The number of tokens that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken = default);
/// <summary>
/// Revokes all the tokens associated with the specified application identifier.
/// </summary>

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

@ -279,6 +279,37 @@ public interface IOpenIddictAuthorizationStore<TAuthorization> where TAuthorizat
/// <returns>The number of authorizations that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken);
/// <summary>
/// Revokes all the authorizations corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken);
/// <summary>
/// Revokes all the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken);
/// <summary>
/// Revokes all the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken);
/// <summary>
/// Revokes all the authorizations associated with the specified application identifier.
/// </summary>

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

@ -326,6 +326,37 @@ public interface IOpenIddictTokenStore<TToken> where TToken : class
/// <returns>The number of tokens that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken);
/// <summary>
/// Revokes all the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken);
/// <summary>
/// Revokes all the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken);
/// <summary>
/// Revokes all the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken);
/// <summary>
/// Revokes all the tokens associated with the specified application identifier.
/// </summary>

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

@ -1028,6 +1028,91 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
public virtual ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default)
=> Store.PruneAsync(threshold, cancellationToken);
/// <summary>
/// Revokes all the authorizations corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
return Store.RevokeAsync(subject, client, cancellationToken);
}
/// <summary>
/// Revokes all the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
return Store.RevokeAsync(subject, client, status, cancellationToken);
}
/// <summary>
/// Revokes all the authorizations matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the authorization.</param>
/// <param name="client">The client associated with the authorization.</param>
/// <param name="status">The authorization status.</param>
/// <param name="type">The authorization type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
return Store.RevokeAsync(subject, client, status, type, cancellationToken);
}
/// <summary>
/// Revokes all the authorizations associated with the specified application identifier.
/// </summary>
@ -1369,6 +1454,18 @@ public class OpenIddictAuthorizationManager<TAuthorization> : IOpenIddictAuthori
ValueTask<long> IOpenIddictAuthorizationManager.PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
=> PruneAsync(threshold, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictAuthorizationManager.RevokeAsync(string subject, string client, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictAuthorizationManager.RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, status, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictAuthorizationManager.RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, status, type, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictAuthorizationManager.RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
=> RevokeByApplicationIdAsync(identifier, cancellationToken);

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

@ -1055,6 +1055,91 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
public virtual ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default)
=> Store.PruneAsync(threshold, cancellationToken);
/// <summary>
/// Revokes all the tokens corresponding to the specified
/// subject and associated with the application identifier.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
return Store.RevokeAsync(subject, client, cancellationToken);
}
/// <summary>
/// Revokes all the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
return Store.RevokeAsync(subject, client, status, cancellationToken);
}
/// <summary>
/// Revokes all the tokens matching the specified parameters.
/// </summary>
/// <param name="subject">The subject associated with the token.</param>
/// <param name="client">The client associated with the token.</param>
/// <param name="status">The token status.</param>
/// <param name="type">The token type.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens corresponding to the criteria that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
return Store.RevokeAsync(subject, client, status, type, cancellationToken);
}
/// <summary>
/// Revokes all the tokens associated with the specified application identifier.
/// </summary>
@ -1533,6 +1618,18 @@ public class OpenIddictTokenManager<TToken> : IOpenIddictTokenManager where TTok
ValueTask<long> IOpenIddictTokenManager.PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
=> PruneAsync(threshold, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeAsync(string subject, string client, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, status, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
=> RevokeAsync(subject, client, status, type, cancellationToken);
/// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
=> RevokeByApplicationIdAsync(identifier, cancellationToken);

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

@ -658,6 +658,182 @@ public class OpenIddictEntityFrameworkAuthorizationStore<TAuthorization, TApplic
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null;
var result = 0L;
foreach (var authorization in await (from authorization in Authorizations
where authorization.Application!.Id!.Equals(key) && authorization.Subject == subject
select authorization).ToListAsync(cancellationToken))
{
authorization.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null;
var result = 0L;
foreach (var authorization in await (from authorization in Authorizations
where authorization.Application!.Id!.Equals(key) &&
authorization.Subject == subject &&
authorization.Status == status
select authorization).ToListAsync(cancellationToken))
{
authorization.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null;
var result = 0L;
foreach (var 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))
{
authorization.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
{

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

@ -659,6 +659,182 @@ public class OpenIddictEntityFrameworkTokenStore<TToken, TApplication, TAuthoriz
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null;
var result = 0L;
foreach (var token in await (from token in Tokens
where token.Application!.Id!.Equals(key) && token.Subject == subject
select token).ToListAsync(cancellationToken))
{
token.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null;
var result = 0L;
foreach (var token in await (from token in Tokens
where token.Application!.Id!.Equals(key) &&
token.Subject == subject &&
token.Status == status
select token).ToListAsync(cancellationToken))
{
token.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
var key = ConvertIdentifierFromString(client);
List<Exception>? exceptions = null;
var result = 0L;
foreach (var token in await (from token in Tokens
where token.Application!.Id!.Equals(key) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type
select token).ToListAsync(cancellationToken))
{
token.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
{

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

@ -254,9 +254,10 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
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 method is overridden to use an explicit join before applying the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// 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);
@ -288,9 +289,10 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
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 method is overridden to use an explicit join before applying the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// 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);
@ -327,9 +329,10 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
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 method is overridden to use an explicit join before applying the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// 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);
@ -373,9 +376,10 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
async IAsyncEnumerable<TAuthorization> ExecuteAsync([EnumeratorCancellation] CancellationToken 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 method is overridden to use an explicit join before applying the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// 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);
@ -409,9 +413,10 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
throw new ArgumentException(SR.GetResourceString(SR.ID0195), nameof(identifier));
}
// 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 method is overridden to use an explicit join before applying the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// 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(identifier);
@ -799,6 +804,245 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var key = ConvertIdentifierFromString(client);
#if SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations)
{
return await (
from authorization in Authorizations
where authorization.Subject == subject && authorization.Application!.Id!.Equals(key)
select authorization).ExecuteUpdateAsync(entity => entity.SetProperty(
authorization => authorization.Status, Statuses.Revoked), cancellationToken);
// Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately.
}
#endif
List<Exception>? exceptions = null;
var result = 0L;
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var authorization in await (from authorization in Authorizations.AsTracking()
where authorization.Subject == subject
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).ToListAsync(cancellationToken))
{
authorization.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var key = ConvertIdentifierFromString(client);
#if SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations)
{
return await (
from authorization in Authorizations
where authorization.Subject == subject &&
authorization.Status == status &&
authorization.Application!.Id!.Equals(key)
select authorization).ExecuteUpdateAsync(entity => entity.SetProperty(
authorization => authorization.Status, Statuses.Revoked), cancellationToken);
// Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately.
}
#endif
List<Exception>? exceptions = null;
var result = 0L;
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var authorization in await (from authorization in Authorizations.AsTracking()
where authorization.Subject == subject && authorization.Status == status
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).ToListAsync(cancellationToken))
{
authorization.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
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 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);
// Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately.
}
#endif
List<Exception>? exceptions = null;
var result = 0L;
// Note: due to a bug in Entity Framework Core's query visitor, the authorizations
// can't be filtered using authorization.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var authorization in await (from authorization in Authorizations.AsTracking()
where authorization.Subject == subject && authorization.Status == status && authorization.Type == type
join application in Applications.AsTracking() on authorization.Application!.Id equals application.Id
where application.Id!.Equals(key)
select authorization).ToListAsync(cancellationToken))
{
authorization.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(authorization).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
{
@ -826,8 +1070,15 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
var result = 0L;
foreach (var authorization in await (from authorization in Authorizations
where authorization.Application!.Id!.Equals(key)
// 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()
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;
@ -884,7 +1135,7 @@ public class OpenIddictEntityFrameworkCoreAuthorizationStore<TAuthorization, TAp
var result = 0L;
foreach (var authorization in await (from authorization in Authorizations
foreach (var authorization in await (from authorization in Authorizations.AsTracking()
where authorization.Subject == subject
select authorization).ToListAsync(cancellationToken))
{

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

@ -178,9 +178,10 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
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 token.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// 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);
@ -212,9 +213,10 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
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 token.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// 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);
@ -252,9 +254,10 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
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 token.Application.Id.Equals(key). To work around this issue,
// this compiled query uses an explicit join before applying the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// 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);
@ -276,9 +279,10 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
throw new ArgumentException(SR.GetResourceString(SR.ID0195), nameof(identifier));
}
// 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 method is overridden to use an explicit join before applying the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// 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(identifier);
@ -297,9 +301,10 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
throw new ArgumentException(SR.GetResourceString(SR.ID0195), nameof(identifier));
}
// Note: due to a bug in Entity Framework Core's query visitor, the tokens can't be
// filtered using token.Authorization.Id.Equals(key). To work around this issue,
// this method is overridden to use an explicit join before applying the equality check.
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Authorization.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(identifier);
@ -748,6 +753,243 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var key = ConvertIdentifierFromString(client);
#if SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations)
{
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: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately.
}
#endif
List<Exception>? exceptions = null;
var result = 0L;
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var token in await (from token in Tokens.AsTracking()
where token.Subject == subject
join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id!.Equals(key)
select token).ToListAsync(cancellationToken))
{
token.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var key = ConvertIdentifierFromString(client);
#if SUPPORTS_BULK_DBSET_OPERATIONS
if (!Options.CurrentValue.DisableBulkOperations)
{
return await (
from token in Tokens
where token.Subject == subject && token.Status == status && token.Application!.Id!.Equals(key)
select token).ExecuteUpdateAsync(entity => entity.SetProperty(
token => token.Status, Statuses.Revoked), cancellationToken);
// Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately.
}
#endif
List<Exception>? exceptions = null;
var result = 0L;
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var token in await (from token in Tokens.AsTracking()
where token.Subject == subject && token.Status == status
join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id!.Equals(key)
select token).ToListAsync(cancellationToken))
{
token.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
if (string.IsNullOrEmpty(type))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0200), nameof(type));
}
var key = ConvertIdentifierFromString(client);
#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);
// Note: calling DbContext.SaveChangesAsync() is not necessary
// with bulk update operations as they are executed immediately.
}
#endif
List<Exception>? exceptions = null;
var result = 0L;
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Application.Id.Equals(key). To work around
// this issue, this query uses use an explicit join to apply the equality check.
//
// See https://github.com/openiddict/openiddict-core/issues/499 for more information.
foreach (var token in await (from token in Tokens.AsTracking()
where token.Subject == subject && token.Status == status && token.Type == type
join application in Applications.AsTracking() on token.Application!.Id equals application.Id
where application.Id!.Equals(key)
select token).ToListAsync(cancellationToken))
{
token.Status = Statuses.Revoked;
try
{
await Context.SaveChangesAsync(cancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
// Reset the state of the entity to prevents future calls to SaveChangesAsync() from failing.
Context.Entry(token).State = EntityState.Unchanged;
exceptions ??= [];
exceptions.Add(exception);
continue;
}
result++;
}
if (exceptions is not null)
{
throw new AggregateException(SR.GetResourceString(SR.ID0249), exceptions);
}
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
{
@ -775,8 +1017,15 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
var result = 0L;
foreach (var token in await (from token in Tokens
where token.Application!.Id!.Equals(key)
// 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()
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;
@ -835,8 +1084,15 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
var result = 0L;
foreach (var token in await (from token in Tokens
where token.Authorization!.Id!.Equals(key)
// Note: due to a bug in Entity Framework Core's query visitor, the tokens
// can't be filtered using token.Authorization.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()
join authorization in Authorizations.AsTracking() on token.Authorization!.Id equals authorization.Id
where authorization.Id!.Equals(key)
select token).ToListAsync(cancellationToken))
{
token.Status = Statuses.Revoked;
@ -893,7 +1149,7 @@ public class OpenIddictEntityFrameworkCoreTokenStore<TToken, TApplication, TAuth
var result = 0L;
foreach (var token in await (from token in Tokens
foreach (var token in await (from token in Tokens.AsTracking()
where token.Subject == subject
select token).ToListAsync(cancellationToken))
{

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

@ -124,8 +124,8 @@ public class OpenIddictMongoDbAuthorizationStore<TAuthorization> : IOpenIddictAu
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
await foreach (var authorization in collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client)).ToAsyncEnumerable(cancellationToken))
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
}
@ -160,8 +160,8 @@ public class OpenIddictMongoDbAuthorizationStore<TAuthorization> : IOpenIddictAu
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
await foreach (var authorization in collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject &&
authorization.Status == status).ToAsyncEnumerable(cancellationToken))
{
yield return authorization;
@ -202,8 +202,8 @@ public class OpenIddictMongoDbAuthorizationStore<TAuthorization> : IOpenIddictAu
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
await foreach (var authorization in collection.Find(authorization =>
authorization.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type).ToAsyncEnumerable(cancellationToken))
{
@ -248,8 +248,8 @@ public class OpenIddictMongoDbAuthorizationStore<TAuthorization> : IOpenIddictAu
// 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.Subject == subject &&
authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type &&
Enumerable.All(scopes, scope => authorization.Scopes!.Contains(scope))).ToAsyncEnumerable(cancellationToken))
@ -549,6 +549,95 @@ public class OpenIddictMongoDbAuthorizationStore<TAuthorization> : IOpenIddictAu
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return (await collection.UpdateManyAsync(
filter : authorization => authorization.Subject == subject && authorization.ApplicationId == ObjectId.Parse(client),
update : Builders<TAuthorization>.Update.Set(authorization => authorization.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return (await collection.UpdateManyAsync(
filter : authorization => authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject &&
authorization.Status == status,
update : Builders<TAuthorization>.Update.Set(authorization => authorization.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
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 database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
return (await collection.UpdateManyAsync(
filter : authorization => authorization.ApplicationId == ObjectId.Parse(client) &&
authorization.Subject == subject &&
authorization.Status == status &&
authorization.Type == type,
update : Builders<TAuthorization>.Update.Set(authorization => authorization.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
{

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

@ -586,6 +586,95 @@ public class OpenIddictMongoDbTokenStore<TToken> : IOpenIddictTokenStore<TToken>
return result;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return (await collection.UpdateManyAsync(
filter : token => token.ApplicationId == ObjectId.Parse(client) && token.Subject == subject,
update : Builders<TToken>.Update.Set(token => token.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0124), nameof(client));
}
if (string.IsNullOrEmpty(status))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0199), nameof(status));
}
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return (await collection.UpdateManyAsync(
filter : token => token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject &&
token.Status == status,
update : Builders<TToken>.Update.Set(token => token.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeAsync(string subject, string client, string status, string type, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0198), nameof(subject));
}
if (string.IsNullOrEmpty(client))
{
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 database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
return (await collection.UpdateManyAsync(
filter : token => token.ApplicationId == ObjectId.Parse(client) &&
token.Subject == subject &&
token.Status == status &&
token.Type == type,
update : Builders<TToken>.Update.Set(token => token.Status, Statuses.Revoked),
options : null,
cancellationToken: cancellationToken)).MatchedCount;
}
/// <inheritdoc/>
public virtual async ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
{

Loading…
Cancel
Save