Skip to content

Commit

Permalink
Introduce new RevokeByApplicationIdAsync()/RevokeBySubjectAsync() API…
Browse files Browse the repository at this point in the history
…s in the authorization/token managers/stores
  • Loading branch information
kevinchalet committed Oct 4, 2024
1 parent 38711c1 commit fcc0ddd
Show file tree
Hide file tree
Showing 12 changed files with 636 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,22 @@ IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
/// <returns>The number of authorizations that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default);

/// <summary>
/// Revokes all the authorizations associated with the specified application identifier.
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations associated with the specified application that were marked as revoked.</returns>
ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken = default);

/// <summary>
/// Revokes all the authorizations associated with the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations associated with the specified subject that were marked as revoked.</returns>
ValueTask<long> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken = default);

/// <summary>
/// Tries to revoke an authorization.
/// </summary>
Expand Down
16 changes: 16 additions & 0 deletions src/OpenIddict.Abstractions/Managers/IOpenIddictTokenManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,14 @@ IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
/// <returns>The number of tokens that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default);

/// <summary>
/// Revokes all the tokens associated with the specified application identifier.
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens associated with the specified application that were marked as revoked.</returns>
ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken = default);

/// <summary>
/// Revokes all the tokens associated with the specified authorization identifier.
/// </summary>
Expand All @@ -417,6 +425,14 @@ IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
/// <returns>The number of tokens associated with the specified authorization that were marked as revoked.</returns>
ValueTask<long> RevokeByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken = default);

/// <summary>
/// Revokes all the tokens associated with the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens associated with the specified subject that were marked as revoked.</returns>
ValueTask<long> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken = default);

/// <summary>
/// Tries to redeem a token.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,22 @@ IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
/// <returns>The number of authorizations that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken);

/// <summary>
/// Revokes all the authorizations associated with the specified application identifier.
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations associated with the specified application that were marked as revoked.</returns>
ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken = default);

/// <summary>
/// Revokes all the authorizations associated with the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations associated with the specified subject that were marked as revoked.</returns>
ValueTask<long> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken = default);

/// <summary>
/// Sets the application identifier associated with an authorization.
/// </summary>
Expand Down
16 changes: 16 additions & 0 deletions src/OpenIddict.Abstractions/Stores/IOpenIddictTokenStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,14 @@ IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
/// <returns>The number of tokens that were removed.</returns>
ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken);

/// <summary>
/// Revokes all the tokens associated with the specified application identifier.
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens associated with the specified application that were marked as revoked.</returns>
ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken = default);

/// <summary>
/// Revokes all the tokens associated with the specified authorization identifier.
/// </summary>
Expand All @@ -334,6 +342,14 @@ IAsyncEnumerable<TResult> ListAsync<TState, TResult>(
/// <returns>The number of tokens associated with the specified authorization that were marked as revoked.</returns>
ValueTask<long> RevokeByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken);

/// <summary>
/// Revokes all the tokens associated with the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens associated with the specified subject that were marked as revoked.</returns>
ValueTask<long> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken = default);

/// <summary>
/// Sets the application identifier associated with a token.
/// </summary>
Expand Down
40 changes: 40 additions & 0 deletions src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,38 @@ public virtual async ValueTask PopulateAsync(
public virtual ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default)
=> Store.PruneAsync(threshold, cancellationToken);

/// <summary>
/// Revokes all the authorizations associated with the specified application identifier.
/// </summary>
/// <param name="identifier">The application identifier associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations associated with the specified application that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0195), nameof(identifier));
}

return Store.RevokeByApplicationIdAsync(identifier, cancellationToken);
}

/// <summary>
/// Revokes all the authorizations associated with the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the authorizations.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of authorizations associated with the specified subject that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0195), nameof(subject));
}

return Store.RevokeBySubjectAsync(subject, cancellationToken);
}

/// <summary>
/// Tries to revoke an authorization.
/// </summary>
Expand Down Expand Up @@ -1337,6 +1369,14 @@ ValueTask IOpenIddictAuthorizationManager.PopulateAsync(object authorization, Op
ValueTask<long> IOpenIddictAuthorizationManager.PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
=> PruneAsync(threshold, cancellationToken);

/// <inheritdoc/>
ValueTask<long> IOpenIddictAuthorizationManager.RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
=> RevokeByApplicationIdAsync(identifier, cancellationToken);

/// <inheritdoc/>
ValueTask<long> IOpenIddictAuthorizationManager.RevokeBySubjectAsync(string subject, CancellationToken cancellationToken)
=> RevokeBySubjectAsync(subject, cancellationToken);

/// <inheritdoc/>
ValueTask<bool> IOpenIddictAuthorizationManager.TryRevokeAsync(object authorization, CancellationToken cancellationToken)
=> TryRevokeAsync((TAuthorization) authorization, cancellationToken);
Expand Down
40 changes: 40 additions & 0 deletions src/OpenIddict.Core/Managers/OpenIddictTokenManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1055,6 +1055,22 @@ public virtual async ValueTask PopulateAsync(
public virtual ValueTask<long> PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken = default)
=> Store.PruneAsync(threshold, cancellationToken);

/// <summary>
/// Revokes all the tokens associated with the specified application identifier.
/// </summary>
/// <param name="identifier">The application identifier associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens associated with the specified application that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0195), nameof(identifier));
}

return Store.RevokeByApplicationIdAsync(identifier, cancellationToken);
}

/// <summary>
/// Revokes all the tokens associated with the specified authorization identifier.
/// </summary>
Expand All @@ -1071,6 +1087,22 @@ public virtual ValueTask<long> RevokeByAuthorizationIdAsync(string identifier, C
return Store.RevokeByAuthorizationIdAsync(identifier, cancellationToken);
}

/// <summary>
/// Revokes all the tokens associated with the specified subject.
/// </summary>
/// <param name="subject">The subject associated with the tokens.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The number of tokens associated with the specified subject that were marked as revoked.</returns>
public virtual ValueTask<long> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0195), nameof(subject));
}

return Store.RevokeBySubjectAsync(subject, cancellationToken);
}

/// <summary>
/// Tries to redeem a token.
/// </summary>
Expand Down Expand Up @@ -1501,10 +1533,18 @@ ValueTask IOpenIddictTokenManager.PopulateAsync(object token, OpenIddictTokenDes
ValueTask<long> IOpenIddictTokenManager.PruneAsync(DateTimeOffset threshold, CancellationToken cancellationToken)
=> PruneAsync(threshold, cancellationToken);

/// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
=> RevokeByApplicationIdAsync(identifier, cancellationToken);

/// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeByAuthorizationIdAsync(string identifier, CancellationToken cancellationToken)
=> RevokeByAuthorizationIdAsync(identifier, cancellationToken);

/// <inheritdoc/>
ValueTask<long> IOpenIddictTokenManager.RevokeBySubjectAsync(string subject, CancellationToken cancellationToken)
=> RevokeBySubjectAsync(subject, cancellationToken);

/// <inheritdoc/>
ValueTask<bool> IOpenIddictTokenManager.TryRedeemAsync(object token, CancellationToken cancellationToken)
=> TryRedeemAsync((TToken) token, cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,98 @@ orderby authorization.Id
return result;
}

/// <inheritdoc/>
public virtual async ValueTask<long> RevokeByApplicationIdAsync(string identifier, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(identifier))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0195), nameof(identifier));
}

var key = ConvertIdentifierFromString(identifier);

List<Exception>? exceptions = null;

var result = 0L;

foreach (var authorization in await (from authorization in Authorizations
where authorization.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> RevokeBySubjectAsync(string subject, CancellationToken cancellationToken)
{
if (string.IsNullOrEmpty(subject))
{
throw new ArgumentException(SR.GetResourceString(SR.ID0195), nameof(subject));
}

List<Exception>? exceptions = null;

var result = 0L;

foreach (var authorization in await (from authorization in Authorizations
where 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 SetApplicationIdAsync(TAuthorization authorization,
string? identifier, CancellationToken cancellationToken)
Expand Down
Loading

0 comments on commit fcc0ddd

Please sign in to comment.