|
|
@ -179,6 +179,171 @@ namespace OpenIddict.Core |
|
|
await UpdateAsync(token, cancellationToken); |
|
|
await UpdateAsync(token, cancellationToken); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Retrieves 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>
|
|
|
|
|
|
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
|
|
|
|
/// whose result returns the tokens corresponding to the subject/client.
|
|
|
|
|
|
/// </returns>
|
|
|
|
|
|
public virtual async Task<ImmutableArray<TToken>> FindAsync([NotNull] string subject, |
|
|
|
|
|
[NotNull] string client, CancellationToken cancellationToken = default) |
|
|
|
|
|
{ |
|
|
|
|
|
if (string.IsNullOrEmpty(subject)) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(client)) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
|
|
var tokens = await Store.FindAsync(subject, client, cancellationToken); |
|
|
|
|
|
if (tokens.IsEmpty) |
|
|
|
|
|
{ |
|
|
|
|
|
return ImmutableArray.Create<TToken>(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var builder = ImmutableArray.CreateBuilder<TToken>(tokens.Length); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var token in tokens) |
|
|
|
|
|
{ |
|
|
|
|
|
if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal)) |
|
|
|
|
|
{ |
|
|
|
|
|
builder.Add(token); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return builder.Count == builder.Capacity ? |
|
|
|
|
|
builder.MoveToImmutable() : |
|
|
|
|
|
builder.ToImmutable(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Retrieves 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>
|
|
|
|
|
|
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
|
|
|
|
/// whose result returns the tokens corresponding to the criteria.
|
|
|
|
|
|
/// </returns>
|
|
|
|
|
|
public virtual async Task<ImmutableArray<TToken>> FindAsync( |
|
|
|
|
|
[NotNull] string subject, [NotNull] string client, |
|
|
|
|
|
[NotNull] string status, CancellationToken cancellationToken = default) |
|
|
|
|
|
{ |
|
|
|
|
|
if (string.IsNullOrEmpty(subject)) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(client)) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(status)) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
|
|
var tokens = await Store.FindAsync(subject, client, status, cancellationToken); |
|
|
|
|
|
if (tokens.IsEmpty) |
|
|
|
|
|
{ |
|
|
|
|
|
return ImmutableArray.Create<TToken>(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var builder = ImmutableArray.CreateBuilder<TToken>(tokens.Length); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var token in tokens) |
|
|
|
|
|
{ |
|
|
|
|
|
if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal)) |
|
|
|
|
|
{ |
|
|
|
|
|
builder.Add(token); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return builder.Count == builder.Capacity ? |
|
|
|
|
|
builder.MoveToImmutable() : |
|
|
|
|
|
builder.ToImmutable(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Retrieves 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>
|
|
|
|
|
|
/// A <see cref="Task"/> that can be used to monitor the asynchronous operation,
|
|
|
|
|
|
/// whose result returns the tokens corresponding to the criteria.
|
|
|
|
|
|
/// </returns>
|
|
|
|
|
|
public virtual async Task<ImmutableArray<TToken>> FindAsync( |
|
|
|
|
|
[NotNull] string subject, [NotNull] string client, |
|
|
|
|
|
[NotNull] string status, [NotNull] string type, CancellationToken cancellationToken = default) |
|
|
|
|
|
{ |
|
|
|
|
|
if (string.IsNullOrEmpty(subject)) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new ArgumentException("The subject cannot be null or empty.", nameof(subject)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(client)) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new ArgumentException("The client identifier cannot be null or empty.", nameof(client)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(status)) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new ArgumentException("The status cannot be null or empty.", nameof(status)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(type)) |
|
|
|
|
|
{ |
|
|
|
|
|
throw new ArgumentException("The type cannot be null or empty.", nameof(type)); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
|
|
var tokens = await Store.FindAsync(subject, client, status, type, cancellationToken); |
|
|
|
|
|
if (tokens.IsEmpty) |
|
|
|
|
|
{ |
|
|
|
|
|
return ImmutableArray.Create<TToken>(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
var builder = ImmutableArray.CreateBuilder<TToken>(tokens.Length); |
|
|
|
|
|
|
|
|
|
|
|
foreach (var token in tokens) |
|
|
|
|
|
{ |
|
|
|
|
|
if (string.Equals(await Store.GetSubjectAsync(token, cancellationToken), subject, StringComparison.Ordinal)) |
|
|
|
|
|
{ |
|
|
|
|
|
builder.Add(token); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return builder.Count == builder.Capacity ? |
|
|
|
|
|
builder.MoveToImmutable() : |
|
|
|
|
|
builder.ToImmutable(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// Retrieves the list of tokens corresponding to the specified application identifier.
|
|
|
/// Retrieves the list of tokens corresponding to the specified application identifier.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
@ -985,6 +1150,15 @@ namespace OpenIddict.Core |
|
|
Task IOpenIddictTokenManager.ExtendAsync(object token, DateTimeOffset? date, CancellationToken cancellationToken) |
|
|
Task IOpenIddictTokenManager.ExtendAsync(object token, DateTimeOffset? date, CancellationToken cancellationToken) |
|
|
=> ExtendAsync((TToken) token, date, cancellationToken); |
|
|
=> ExtendAsync((TToken) token, date, cancellationToken); |
|
|
|
|
|
|
|
|
|
|
|
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindAsync(string subject, string client, CancellationToken cancellationToken) |
|
|
|
|
|
=> (await FindAsync(subject, client, cancellationToken)).CastArray<object>(); |
|
|
|
|
|
|
|
|
|
|
|
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindAsync(string subject, string client, string status, CancellationToken cancellationToken) |
|
|
|
|
|
=> (await FindAsync(subject, client, status, cancellationToken)).CastArray<object>(); |
|
|
|
|
|
|
|
|
|
|
|
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindAsync(string subject, string client, string status, string type, CancellationToken cancellationToken) |
|
|
|
|
|
=> (await FindAsync(subject, client, status, type, cancellationToken)).CastArray<object>(); |
|
|
|
|
|
|
|
|
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindByApplicationIdAsync(string identifier, CancellationToken cancellationToken) |
|
|
async Task<ImmutableArray<object>> IOpenIddictTokenManager.FindByApplicationIdAsync(string identifier, CancellationToken cancellationToken) |
|
|
=> (await FindByApplicationIdAsync(identifier, cancellationToken)).CastArray<object>(); |
|
|
=> (await FindByApplicationIdAsync(identifier, cancellationToken)).CastArray<object>(); |
|
|
|
|
|
|
|
|
|