Browse Source

Update IOpenIddictAuthorizationStore.PruneAsync() to also take expired tokens into account

pull/662/head
Kévin Chalet 8 years ago
parent
commit
ddbe7aed38
  1. 2
      src/OpenIddict.Abstractions/Managers/IOpenIddictAuthorizationManager.cs
  2. 2
      src/OpenIddict.Abstractions/Stores/IOpenIddictAuthorizationStore.cs
  3. 2
      src/OpenIddict.Core/Managers/OpenIddictAuthorizationManager.cs
  4. 5
      src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs
  5. 8
      src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs
  6. 5
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs
  7. 8
      src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs
  8. 48
      src/OpenIddict.MongoDb/Stores/OpenIddictAuthorizationStore.cs
  9. 4
      src/OpenIddict.MongoDb/Stores/OpenIddictTokenStore.cs

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

@ -357,7 +357,7 @@ namespace OpenIddict.Abstractions
Task PopulateAsync([NotNull] object authorization, [NotNull] OpenIddictAuthorizationDescriptor descriptor, CancellationToken cancellationToken = default);
/// <summary>
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid token attached.
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>

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

@ -279,7 +279,7 @@ namespace OpenIddict.Abstractions
[CanBeNull] TState state, CancellationToken cancellationToken);
/// <summary>
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid token attached.
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>

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

@ -887,7 +887,7 @@ namespace OpenIddict.Core
}
/// <summary>
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid token attached.
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>

5
src/OpenIddict.EntityFramework/Stores/OpenIddictAuthorizationStore.cs

@ -691,7 +691,7 @@ namespace OpenIddict.EntityFramework
}
/// <summary>
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid token attached.
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
@ -735,7 +735,8 @@ namespace OpenIddict.EntityFramework
await (from authorization in Authorizations.Include(authorization => authorization.Tokens)
where authorization.Status != OpenIddictConstants.Statuses.Valid ||
(authorization.Type == OpenIddictConstants.AuthorizationTypes.AdHoc &&
!authorization.Tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid))
!authorization.Tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid &&
token.ExpirationDate > DateTimeOffset.UtcNow))
orderby authorization.Id
select authorization).Skip(offset).Take(1_000).ToListAsync(cancellationToken);

8
src/OpenIddict.EntityFramework/Stores/OpenIddictTokenStore.cs

@ -810,7 +810,9 @@ namespace OpenIddict.EntityFramework
}
}
for (var offset = 0; offset < 100_000; offset = offset + 1_000)
// Note: to avoid sending too many queries, the maximum number of elements
// that can be removed by a single call to PruneAsync() is limited to 50000.
for (var offset = 0; offset < 50_000; offset = offset + 1_000)
{
cancellationToken.ThrowIfCancellationRequested();
@ -822,8 +824,8 @@ namespace OpenIddict.EntityFramework
{
var tokens =
await (from token in Tokens
where token.ExpirationDate < DateTimeOffset.UtcNow ||
token.Status != OpenIddictConstants.Statuses.Valid
where token.Status != OpenIddictConstants.Statuses.Valid ||
token.ExpirationDate < DateTimeOffset.UtcNow
orderby token.Id
select token).Skip(offset).Take(1_000).ToListAsync(cancellationToken);

5
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictAuthorizationStore.cs

@ -780,7 +780,7 @@ namespace OpenIddict.EntityFrameworkCore
}
/// <summary>
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid token attached.
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
@ -834,7 +834,8 @@ namespace OpenIddict.EntityFrameworkCore
await (from authorization in Authorizations.Include(authorization => authorization.Tokens).AsTracking()
where authorization.Status != OpenIddictConstants.Statuses.Valid ||
(authorization.Type == OpenIddictConstants.AuthorizationTypes.AdHoc &&
!authorization.Tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid))
!authorization.Tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid &&
token.ExpirationDate > DateTimeOffset.UtcNow))
orderby authorization.Id
select authorization).Skip(offset).Take(1_000).ToListAsync(cancellationToken);

8
src/OpenIddict.EntityFrameworkCore/Stores/OpenIddictTokenStore.cs

@ -935,7 +935,9 @@ namespace OpenIddict.EntityFrameworkCore
return null;
}
for (var offset = 0; offset < 100_000; offset = offset + 1_000)
// Note: to avoid sending too many queries, the maximum number of elements
// that can be removed by a single call to PruneAsync() is limited to 50000.
for (var offset = 0; offset < 50_000; offset = offset + 1_000)
{
cancellationToken.ThrowIfCancellationRequested();
@ -947,8 +949,8 @@ namespace OpenIddict.EntityFrameworkCore
{
var tokens =
await (from token in Tokens.AsTracking()
where token.ExpirationDate < DateTimeOffset.UtcNow ||
token.Status != OpenIddictConstants.Statuses.Valid
where token.Status != OpenIddictConstants.Statuses.Valid ||
token.ExpirationDate < DateTimeOffset.UtcNow
orderby token.Id
select token).Skip(offset).Take(1_000).ToListAsync(cancellationToken);

48
src/OpenIddict.MongoDb/Stores/OpenIddictAuthorizationStore.cs

@ -615,7 +615,7 @@ namespace OpenIddict.MongoDb
}
/// <summary>
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid token attached.
/// Removes the ad-hoc authorizations that are marked as invalid or have no valid/nonexpired token attached.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>
@ -626,17 +626,57 @@ namespace OpenIddict.MongoDb
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TAuthorization>(Options.CurrentValue.AuthorizationsCollectionName);
// Note: directly deleting the resulting set of an aggregate query is not supported by MongoDB.
// To work around this limitation, the authorization identifiers are stored in an intermediate
// list and delete requests are sent to remove the documents corresponding to these identifiers.
var identifiers =
await (from authorization in collection.AsQueryable()
join token in database.GetCollection<OpenIddictToken>(Options.CurrentValue.TokensCollectionName).AsQueryable()
on authorization.Id equals token.AuthorizationId into tokens
where authorization.Status != OpenIddictConstants.Statuses.Valid ||
(authorization.Type == OpenIddictConstants.AuthorizationTypes.AdHoc &&
!tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid))
orderby authorization.Id
!tokens.Any(token => token.Status == OpenIddictConstants.Statuses.Valid &&
token.ExpirationDate > DateTime.UtcNow))
select authorization.Id).ToListAsync(cancellationToken);
await collection.DeleteManyAsync(authorization => identifiers.Contains(authorization.Id));
// Note: to avoid generating delete requests with very large filters, a buffer is used here and the
// maximum number of elements that can be removed by a single call to PruneAsync() is limited to 50000.
foreach (var buffer in Buffer(identifiers.Take(50_000), 1_000))
{
await collection.DeleteManyAsync(authorization => buffer.Contains(authorization.Id));
// Delete the tokens associated with the pruned authorizations.
await database.GetCollection<OpenIddictToken>(Options.CurrentValue.TokensCollectionName)
.DeleteManyAsync(token => buffer.Contains(token.AuthorizationId), cancellationToken);
}
IEnumerable<IList<TSource>> Buffer<TSource>(IEnumerable<TSource> source, int count)
{
List<TSource> buffer = null;
foreach (var element in source)
{
if (buffer == null)
{
buffer = new List<TSource>();
}
buffer.Add(element);
if (buffer.Count == count)
{
yield return buffer;
buffer = null;
}
}
if (buffer != null)
{
yield return buffer;
}
}
}
/// <summary>

4
src/OpenIddict.MongoDb/Stores/OpenIddictTokenStore.cs

@ -712,8 +712,8 @@ namespace OpenIddict.MongoDb
var database = await Context.GetDatabaseAsync(cancellationToken);
var collection = database.GetCollection<TToken>(Options.CurrentValue.TokensCollectionName);
await collection.DeleteManyAsync(token => token.ExpirationDate < DateTimeOffset.UtcNow ||
token.Status != OpenIddictConstants.Statuses.Valid, cancellationToken);
await collection.DeleteManyAsync(token => token.Status != OpenIddictConstants.Statuses.Valid ||
token.ExpirationDate < DateTime.UtcNow, cancellationToken);
}
/// <summary>

Loading…
Cancel
Save