Browse Source

Update the client/server/validation stacks to always use the CancellationToken attached to the context

pull/2517/head
Kévin Chalet 2 months ago
parent
commit
e9d5a1c64f
  1. 2
      sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/HomeController.cs
  2. 2
      sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/HomeController.cs
  3. 28
      src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs
  4. 28
      src/OpenIddict.Client.Owin/OpenIddictClientOwinHandler.cs
  5. 4
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs
  6. 4
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs
  7. 2
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.cs
  8. 9
      src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs
  9. 2
      src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.Userinfo.cs
  10. 14
      src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs
  11. 6
      src/OpenIddict.Client/IOpenIddictClientFactory.cs
  12. 16
      src/OpenIddict.Client/OpenIddictClientConfiguration.cs
  13. 2
      src/OpenIddict.Client/OpenIddictClientDispatcher.cs
  14. 14
      src/OpenIddict.Client/OpenIddictClientEvents.cs
  15. 12
      src/OpenIddict.Client/OpenIddictClientFactory.cs
  16. 40
      src/OpenIddict.Client/OpenIddictClientHandlers.Protection.cs
  17. 8
      src/OpenIddict.Client/OpenIddictClientHandlers.cs
  18. 84
      src/OpenIddict.Client/OpenIddictClientService.cs
  19. 8
      src/OpenIddict.Client/OpenIddictClientTransaction.cs
  20. 29
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs
  21. 2
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs
  22. 30
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs
  23. 8
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs
  24. 6
      src/OpenIddict.Server/IOpenIddictServerFactory.cs
  25. 6
      src/OpenIddict.Server/OpenIddictServerConfiguration.cs
  26. 2
      src/OpenIddict.Server/OpenIddictServerDispatcher.cs
  27. 14
      src/OpenIddict.Server/OpenIddictServerEvents.cs
  28. 12
      src/OpenIddict.Server/OpenIddictServerFactory.cs
  29. 104
      src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs
  30. 20
      src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs
  31. 34
      src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs
  32. 8
      src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs
  33. 64
      src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs
  34. 8
      src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs
  35. 36
      src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs
  36. 98
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  37. 8
      src/OpenIddict.Server/OpenIddictServerTransaction.cs
  38. 26
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandler.cs
  39. 2
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
  40. 26
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandler.cs
  41. 8
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
  42. 14
      src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs
  43. 6
      src/OpenIddict.Validation/IOpenIddictValidationFactory.cs
  44. 2
      src/OpenIddict.Validation/OpenIddictValidationDispatcher.cs
  45. 14
      src/OpenIddict.Validation/OpenIddictValidationEvents.cs
  46. 12
      src/OpenIddict.Validation/OpenIddictValidationFactory.cs
  47. 34
      src/OpenIddict.Validation/OpenIddictValidationHandlers.Protection.cs
  48. 12
      src/OpenIddict.Validation/OpenIddictValidationService.cs
  49. 8
      src/OpenIddict.Validation/OpenIddictValidationTransaction.cs

2
sandbox/OpenIddict.Sandbox.AspNet.Client/Controllers/HomeController.cs

@ -43,7 +43,7 @@ public class HomeController([FromKeyedServices("ApiClient")] HttpClient client,
return View("Index", new IndexViewModel
{
Message = await response.Content.ReadAsStringAsync(),
Message = await response.Content.ReadAsStringAsync(cancellationToken),
Providers = from registration in await service.GetClientRegistrationsAsync(cancellationToken)
where !string.IsNullOrEmpty(registration.ProviderName)
where !string.IsNullOrEmpty(registration.ProviderDisplayName)

2
sandbox/OpenIddict.Sandbox.AspNetCore.Client/Controllers/HomeController.cs

@ -35,7 +35,7 @@ public class HomeController([FromKeyedServices("ApiClient")] HttpClient client,
return View("Index", new IndexViewModel
{
Message = await response.Content.ReadAsStringAsync(),
Message = await response.Content.ReadAsStringAsync(cancellationToken),
Providers = from registration in await service.GetClientRegistrationsAsync(cancellationToken)
where !string.IsNullOrEmpty(registration.ProviderName)
where !string.IsNullOrEmpty(registration.ProviderDisplayName)

28
src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs

@ -44,13 +44,23 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Au
/// <inheritdoc/>
public async Task<bool> HandleRequestAsync()
{
// Note: to ensure internal operations are not immediately cancelled when the request is aborted
// (which may represent a security risk if sensitive operations are in progress), an ad-hoc token
// source is always created and configured to be triggered 5 seconds after the request is aborted.
var source = new CancellationTokenSource();
var registration = Context.RequestAborted.Register(static state =>
((CancellationTokenSource) state!).CancelAfter(TimeSpan.FromSeconds(5)), source);
Response.RegisterForDispose(source);
Response.RegisterForDispose(registration);
// Note: the transaction may be already attached when replaying an ASP.NET Core request
// (e.g when using the built-in status code pages middleware with the re-execute mode).
var transaction = Context.Features.Get<OpenIddictClientAspNetCoreFeature>()?.Transaction;
if (transaction is null)
{
// Create a new transaction and attach the HTTP request to make it available to the ASP.NET Core handlers.
transaction = await _factory.CreateTransactionAsync();
transaction = await _factory.CreateTransactionAsync(source.Token);
transaction.Properties[typeof(HttpRequest).FullName!] = new WeakReference<HttpRequest>(Request);
// Attach the OpenIddict client transaction to the ASP.NET Core features
@ -58,11 +68,7 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Au
Context.Features.Set(new OpenIddictClientAspNetCoreFeature { Transaction = transaction });
}
var context = new ProcessRequestContext(transaction)
{
CancellationToken = Context.RequestAborted
};
var context = new ProcessRequestContext(transaction);
await _dispatcher.DispatchAsync(context);
if (context.IsRequestHandled)
@ -79,7 +85,6 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Au
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Context.RequestAborted,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -116,10 +121,7 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Au
var context = transaction.GetProperty<ProcessAuthenticationContext>(typeof(ProcessAuthenticationContext).FullName!);
if (context is null)
{
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = Context.RequestAborted
});
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction));
// Store the context object in the transaction so it can be later retrieved by handlers
// that want to access the authentication result without triggering a new authentication flow.
@ -377,7 +379,6 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Au
var context = new ProcessChallengeContext(transaction)
{
CancellationToken = Context.RequestAborted,
Principal = new ClaimsPrincipal(new ClaimsIdentity()),
Request = new OpenIddictRequest()
};
@ -393,7 +394,6 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Au
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Context.RequestAborted,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -423,7 +423,6 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Au
var context = new ProcessSignOutContext(transaction)
{
CancellationToken = Context.RequestAborted,
Principal = new ClaimsPrincipal(new ClaimsIdentity()),
Request = new OpenIddictRequest()
};
@ -441,7 +440,6 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Au
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Context.RequestAborted,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,

28
src/OpenIddict.Client.Owin/OpenIddictClientOwinHandler.cs

@ -46,13 +46,23 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<Authenti
/// <inheritdoc/>
protected override async Task InitializeCoreAsync()
{
// Note: to ensure internal operations are not immediately cancelled when the request is aborted
// (which may represent a security risk if sensitive operations are in progress), an ad-hoc token
// source is always created and configured to be triggered 5 seconds after the request is aborted.
var source = new CancellationTokenSource();
var registration = Request.CallCancelled.Register(static state =>
((CancellationTokenSource) state!).CancelAfter(TimeSpan.FromSeconds(5)), source);
Response.OnSendingHeaders(static state => ((CancellationTokenSource) state!).Dispose(), source);
Response.OnSendingHeaders(static state => ((CancellationTokenRegistration) state!).Dispose(), registration);
// Note: the transaction may be already attached when replaying an OWIN request
// (e.g when using a status code pages middleware re-invoking the OWIN pipeline).
var transaction = Context.Get<OpenIddictClientTransaction>(typeof(OpenIddictClientTransaction).FullName);
if (transaction is null)
{
// Create a new transaction and attach the OWIN request to make it available to the OWIN handlers.
transaction = await _factory.CreateTransactionAsync();
transaction = await _factory.CreateTransactionAsync(source.Token);
transaction.Properties[typeof(IOwinRequest).FullName!] = new WeakReference<IOwinRequest>(Request);
// Attach the OpenIddict client transaction to the OWIN shared dictionary
@ -60,11 +70,7 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<Authenti
Context.Set(typeof(OpenIddictClientTransaction).FullName, transaction);
}
var context = new ProcessRequestContext(transaction)
{
CancellationToken = Request.CallCancelled
};
var context = new ProcessRequestContext(transaction);
await _dispatcher.DispatchAsync(context);
// Store the context in the transaction so that it can be retrieved from InvokeAsync().
@ -98,7 +104,6 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<Authenti
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Request.CallCancelled,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -135,10 +140,7 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<Authenti
var context = transaction.GetProperty<ProcessAuthenticationContext>(typeof(ProcessAuthenticationContext).FullName!);
if (context is null)
{
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = Request.CallCancelled
});
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction));
// Store the context object in the transaction so it can be later retrieved by handlers
// that want to access the authentication result without triggering a new authentication flow.
@ -302,7 +304,6 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<Authenti
var context = new ProcessChallengeContext(transaction)
{
CancellationToken = Request.CallCancelled,
Principal = new ClaimsPrincipal(new ClaimsIdentity()),
Request = new OpenIddictRequest()
};
@ -318,7 +319,6 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<Authenti
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Request.CallCancelled,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -348,7 +348,6 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<Authenti
var context = new ProcessSignOutContext(transaction)
{
CancellationToken = Request.CallCancelled,
Principal = new ClaimsPrincipal(new ClaimsIdentity()),
Request = new OpenIddictRequest()
};
@ -364,7 +363,6 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<Authenti
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Request.CallCancelled,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,

4
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Authentication.cs

@ -646,8 +646,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
_ => "Authentication failed. Please return to the application."
});
await response.OutputStream.WriteAsync(buffer);
await response.OutputStream.FlushAsync();
await response.OutputStream.WriteAsync(buffer.AsMemory(), context.CancellationToken);
await response.OutputStream.FlushAsync(context.CancellationToken);
context.HandleRequest();
}

4
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.Session.cs

@ -646,8 +646,8 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
_ => "Logout failed. Please return to the application."
});
await response.OutputStream.WriteAsync(buffer);
await response.OutputStream.FlushAsync();
await response.OutputStream.WriteAsync(buffer.AsMemory(), context.CancellationToken);
await response.OutputStream.FlushAsync(context.CancellationToken);
context.HandleRequest();
}

2
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationHandlers.cs

@ -457,7 +457,7 @@ public static partial class OpenIddictClientSystemIntegrationHandlers
context.Transaction.Request = new OpenIddictRequest(await OpenIddictHelpers.ParseFormAsync(
stream : request.InputStream,
encoding : GetEncoding(type) is { CodePage: not 65000 } encoding ? encoding : Encoding.UTF8,
cancellationToken: CancellationToken.None));
cancellationToken: context.CancellationToken));
}
else

9
src/OpenIddict.Client.SystemIntegration/OpenIddictClientSystemIntegrationService.cs

@ -147,21 +147,16 @@ public sealed class OpenIddictClientSystemIntegrationService
// Create a client transaction and store the specified instance so
// it can be retrieved by the event handlers that need to access it.
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
transaction.SetProperty(typeof(TProperty).FullName!, property);
var context = new ProcessRequestContext(transaction)
{
CancellationToken = cancellationToken
};
var context = new ProcessRequestContext(transaction);
await dispatcher.DispatchAsync(context);
if (context.IsRejected)
{
await dispatcher.DispatchAsync(new ProcessErrorContext(transaction)
{
CancellationToken = cancellationToken,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,

2
src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.Userinfo.cs

@ -127,7 +127,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
MediaTypes.JsonWebToken, StringComparison.OrdinalIgnoreCase))
{
context.Response = new OpenIddictResponse();
context.UserInfoToken = await response.Content.ReadAsStringAsync();
context.UserInfoToken = await response.Content.ReadAsStringAsync(context.CancellationToken);
return;
}

14
src/OpenIddict.Client.SystemNetHttp/OpenIddictClientSystemNetHttpHandlers.cs

@ -611,7 +611,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
else if (string.Equals(encoding, ContentEncodings.Gzip, StringComparison.OrdinalIgnoreCase))
{
stream ??= await response.Content.ReadAsStreamAsync();
stream ??= await response.Content.ReadAsStreamAsync().WaitAsync(context.CancellationToken);
stream = new GZipStream(stream, CompressionMode.Decompress);
}
@ -625,13 +625,13 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
// For more information, read https://www.rfc-editor.org/rfc/rfc9110.html#name-deflate-coding.
else if (string.Equals(encoding, ContentEncodings.Deflate, StringComparison.OrdinalIgnoreCase))
{
stream ??= await response.Content.ReadAsStreamAsync();
stream ??= await response.Content.ReadAsStreamAsync().WaitAsync(context.CancellationToken);
stream = new ZLibStream(stream, CompressionMode.Decompress);
}
else if (string.Equals(encoding, ContentEncodings.Brotli, StringComparison.OrdinalIgnoreCase))
{
stream ??= await response.Content.ReadAsStreamAsync();
stream ??= await response.Content.ReadAsStreamAsync().WaitAsync(context.CancellationToken);
stream = new BrotliStream(stream, CompressionMode.Decompress);
}
#endif
@ -655,7 +655,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
// (e.g if the JSON deserialization process fails, the stream is read as a string
// during a second pass a second time for logging/debuggability purposes).
var content = new StreamContent(stream);
await content.LoadIntoBufferAsync();
await content.LoadIntoBufferAsync(context.CancellationToken);
// Copy the headers from the original content to the new instance.
foreach (var header in response.Content.Headers)
@ -728,7 +728,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Logger.LogError(6183, exception, SR.GetResourceString(SR.ID6183),
await response.Content.ReadAsStringAsync());
await response.Content.ReadAsStringAsync(context.CancellationToken));
context.Reject(
error: Errors.ServerError,
@ -949,7 +949,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
if (!response.IsSuccessStatusCode && string.IsNullOrEmpty(context.Transaction.Response?.Error))
{
context.Logger.LogError(6184, SR.GetResourceString(SR.ID6184), response.StatusCode,
await response.Content.ReadAsStringAsync());
await response.Content.ReadAsStringAsync(context.CancellationToken));
context.Reject(
error: (int) response.StatusCode switch
@ -973,7 +973,7 @@ public static partial class OpenIddictClientSystemNetHttpHandlers
if (context.Transaction.Response is null)
{
context.Logger.LogError(6185, SR.GetResourceString(SR.ID6185), response.StatusCode,
response.Content.Headers.ContentType, await response.Content.ReadAsStringAsync());
response.Content.Headers.ContentType, await response.Content.ReadAsStringAsync(context.CancellationToken));
context.Reject(
error: Errors.ServerError,

6
src/OpenIddict.Client/IOpenIddictClientFactory.cs

@ -18,9 +18,13 @@ public interface IOpenIddictClientFactory
/// Creates a new <see cref="OpenIddictClientTransaction"/> that is used as a
/// way to store per-request data needed to process the requested operation.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <remarks>
/// Note: the specified <see cref="CancellationToken"/> is automatically attached to the returned transaction.
/// </remarks>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous
/// operation, whose result returns the created transaction.
/// </returns>
ValueTask<OpenIddictClientTransaction> CreateTransactionAsync();
ValueTask<OpenIddictClientTransaction> CreateTransactionAsync(CancellationToken cancellationToken);
}

16
src/OpenIddict.Client/OpenIddictClientConfiguration.cs

@ -88,8 +88,8 @@ public sealed class OpenIddictClientConfiguration : IPostConfigureOptions<OpenId
// Implicitly add the redirect_uri attached to the client registrations
// to the list of redirection endpoints URIs if they haven't been added.
options.RedirectionEndpointUris.AddRange(options.Registrations
.Where(registration => registration.RedirectUri is not null)
.Select(registration => registration.RedirectUri!)
.Where(static registration => registration.RedirectUri is not null)
.Select(static registration => registration.RedirectUri!)
.Where(uri => !options.RedirectionEndpointUris.Contains(uri))
.Distinct()
.ToList());
@ -97,8 +97,8 @@ public sealed class OpenIddictClientConfiguration : IPostConfigureOptions<OpenId
// Implicitly add the post_logout_redirect_uri attached to the client registrations
// to the list of post-logout redirection endpoints URIs if they haven't been added.
options.PostLogoutRedirectionEndpointUris.AddRange(options.Registrations
.Where(registration => registration.PostLogoutRedirectUri is not null)
.Select(registration => registration.PostLogoutRedirectUri!)
.Where(static registration => registration.PostLogoutRedirectUri is not null)
.Select(static registration => registration.PostLogoutRedirectUri!)
.Where(uri => !options.PostLogoutRedirectionEndpointUris.Contains(uri))
.Distinct()
.ToList());
@ -113,9 +113,9 @@ public sealed class OpenIddictClientConfiguration : IPostConfigureOptions<OpenId
options.SigningCredentials.Sort((left, right) => Compare(left.Key, right.Key, now));
// Generate a key identifier for the encryption/signing keys that don't already have one.
foreach (var key in options.EncryptionCredentials.Select(credentials => credentials.Key)
.Concat(options.SigningCredentials.Select(credentials => credentials.Key))
.Where(key => string.IsNullOrEmpty(key.KeyId)))
foreach (var key in options.EncryptionCredentials.Select(static credentials => credentials.Key)
.Concat(options.SigningCredentials.Select(static credentials => credentials.Key))
.Where(static key => string.IsNullOrEmpty(key.KeyId)))
{
key.KeyId = GetKeyIdentifier(key);
}
@ -354,7 +354,7 @@ public sealed class OpenIddictClientConfiguration : IPostConfigureOptions<OpenId
//
// Note: a string comparer ignoring casing is deliberately used to prevent two
// registrations using the same identifier with a different casing from being added.
if (options.Registrations.Count != options.Registrations.Select(registration => registration.RegistrationId)
if (options.Registrations.Count != options.Registrations.Select(static registration => registration.RegistrationId)
.Distinct(StringComparer.OrdinalIgnoreCase)
.Count())
{

2
src/OpenIddict.Client/OpenIddictClientDispatcher.cs

@ -40,6 +40,8 @@ public sealed class OpenIddictClientDispatcher : IOpenIddictClientDispatcher
await foreach (var handler in GetHandlersAsync())
{
context.CancellationToken.ThrowIfCancellationRequested();
try
{
await handler.HandleAsync(context);

14
src/OpenIddict.Client/OpenIddictClientEvents.cs

@ -32,19 +32,9 @@ public static partial class OpenIddictClientEvents
public OpenIddictClientTransaction Transaction { get; }
/// <summary>
/// Gets or sets the cancellation token that will be
/// used to determine if the operation was aborted.
/// Gets the cancellation token used to determine if the operation was aborted.
/// </summary>
/// <remarks>
/// Note: for security reasons, this property shouldn't be used by event
/// handlers to abort security-sensitive operations. As such, it is
/// recommended to use this property only for user-dependent operations.
/// </remarks>
public CancellationToken CancellationToken
{
get => Transaction.CancellationToken;
set => Transaction.CancellationToken = value;
}
public CancellationToken CancellationToken => Transaction.CancellationToken;
/// <summary>
/// Gets or sets the endpoint type that handled the request, if applicable.

12
src/OpenIddict.Client/OpenIddictClientFactory.cs

@ -31,10 +31,18 @@ public sealed class OpenIddictClientFactory : IOpenIddictClientFactory
}
/// <inheritdoc/>
public ValueTask<OpenIddictClientTransaction> CreateTransactionAsync()
=> new(new OpenIddictClientTransaction
public ValueTask<OpenIddictClientTransaction> CreateTransactionAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new(Task.FromCanceled<OpenIddictClientTransaction>(cancellationToken));
}
return new(new OpenIddictClientTransaction
{
CancellationToken = cancellationToken,
Logger = _logger,
Options = _options.CurrentValue
});
}
}

40
src/OpenIddict.Client/OpenIddictClientHandlers.Protection.cs

@ -274,7 +274,7 @@ public static partial class OpenIddictClientHandlers
}
// If the reference token cannot be found, don't return an error to allow another handler to validate it.
var token = await _tokenManager.FindByReferenceIdAsync(context.Token);
var token = await _tokenManager.FindByReferenceIdAsync(context.Token, context.CancellationToken);
if (token is null)
{
return;
@ -284,8 +284,8 @@ public static partial class OpenIddictClientHandlers
if (!(context.ValidTokenTypes.Count switch
{
0 => true, // If no specific token type is expected, accept all token types at this stage.
1 => await _tokenManager.HasTypeAsync(token, context.ValidTokenTypes.ElementAt(0)),
_ => await _tokenManager.HasTypeAsync(token, [.. context.ValidTokenTypes])
1 => await _tokenManager.HasTypeAsync(token, context.ValidTokenTypes.ElementAt(0), context.CancellationToken),
_ => await _tokenManager.HasTypeAsync(token, [.. context.ValidTokenTypes], context.CancellationToken)
}))
{
context.Reject(
@ -296,7 +296,7 @@ public static partial class OpenIddictClientHandlers
return;
}
var payload = await _tokenManager.GetPayloadAsync(token);
var payload = await _tokenManager.GetPayloadAsync(token, context.CancellationToken);
if (string.IsNullOrEmpty(payload))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0026));
@ -307,7 +307,7 @@ public static partial class OpenIddictClientHandlers
// used to restore the properties associated with the token.
context.IsReferenceToken = true;
context.Token = payload;
context.TokenId = await _tokenManager.GetIdAsync(token);
context.TokenId = await _tokenManager.GetIdAsync(token, context.CancellationToken);
}
}
@ -575,7 +575,7 @@ public static partial class OpenIddictClientHandlers
}
// If the token entry cannot be found, return a generic error.
var token = await _tokenManager.FindByIdAsync(identifier);
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken);
if (token is null)
{
context.Reject(
@ -589,9 +589,9 @@ public static partial class OpenIddictClientHandlers
// If the token was not validated as a reference token but has a reference identifier attached, this
// may indicate that the payload stored in the database has leaked and is being used as a regular,
// non-reference token. To prevent this, reject the token if the reference identifier is not null.
if (!context.IsReferenceToken && !string.IsNullOrEmpty(await _tokenManager.GetReferenceIdAsync(token)))
if (!context.IsReferenceToken && !string.IsNullOrEmpty(await _tokenManager.GetReferenceIdAsync(token, context.CancellationToken)))
{
context.Logger.LogWarning(6292, SR.GetResourceString(SR.ID6292), await _tokenManager.GetIdAsync(token));
context.Logger.LogWarning(6292, SR.GetResourceString(SR.ID6292), await _tokenManager.GetIdAsync(token, context.CancellationToken));
context.Reject(
error: Errors.InvalidToken,
@ -603,10 +603,10 @@ public static partial class OpenIddictClientHandlers
// Restore the creation/expiration dates/identifiers from the token entry metadata.
context.Principal
.SetCreationDate(await _tokenManager.GetCreationDateAsync(token))
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token))
.SetTokenId(context.TokenId = await _tokenManager.GetIdAsync(token))
.SetTokenType(await _tokenManager.GetTypeAsync(token));
.SetCreationDate(await _tokenManager.GetCreationDateAsync(token, context.CancellationToken))
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token, context.CancellationToken))
.SetTokenId(context.TokenId = await _tokenManager.GetIdAsync(token, context.CancellationToken))
.SetTokenType(await _tokenManager.GetTypeAsync(token, context.CancellationToken));
}
}
@ -851,10 +851,10 @@ public static partial class OpenIddictClientHandlers
Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
Debug.Assert(!string.IsNullOrEmpty(context.TokenId), SR.GetResourceString(SR.ID4017));
var token = await _tokenManager.FindByIdAsync(context.TokenId)
var token = await _tokenManager.FindByIdAsync(context.TokenId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0021));
if (await _tokenManager.HasStatusAsync(token, Statuses.Redeemed))
if (await _tokenManager.HasStatusAsync(token, Statuses.Redeemed, context.CancellationToken))
{
context.Logger.LogInformation(6002, SR.GetResourceString(SR.ID6002), context.TokenId);
@ -876,7 +876,7 @@ public static partial class OpenIddictClientHandlers
return;
}
if (!await _tokenManager.HasStatusAsync(token, Statuses.Valid))
if (!await _tokenManager.HasStatusAsync(token, Statuses.Valid, context.CancellationToken))
{
context.Logger.LogInformation(6005, SR.GetResourceString(SR.ID6005), context.TokenId);
@ -980,10 +980,10 @@ public static partial class OpenIddictClientHandlers
// Tokens produced by the client stack cannot have an application attached.
var token = await _tokenManager.CreateAsync(descriptor)
var token = await _tokenManager.CreateAsync(descriptor, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0019));
var identifier = await _tokenManager.GetIdAsync(token);
var identifier = await _tokenManager.GetIdAsync(token, context.CancellationToken);
// Attach the token identifier to the principal so that it can be stored in the token.
context.Principal.SetTokenId(identifier);
@ -1172,11 +1172,11 @@ public static partial class OpenIddictClientHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0009));
}
var token = await _tokenManager.FindByIdAsync(identifier)
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0021));
var descriptor = new OpenIddictTokenDescriptor();
await _tokenManager.PopulateAsync(descriptor, token);
await _tokenManager.PopulateAsync(descriptor, token, context.CancellationToken);
// Attach the generated token to the token entry.
descriptor.Payload = context.Token;
@ -1187,7 +1187,7 @@ public static partial class OpenIddictClientHandlers
descriptor.ReferenceId = Base64Url.EncodeToString(RandomNumberGenerator.GetBytes(count: 256 / 8));
}
await _tokenManager.UpdateAsync(token, descriptor);
await _tokenManager.UpdateAsync(token, descriptor, context.CancellationToken);
context.Logger.LogTrace(6014, SR.GetResourceString(SR.ID6014), context.Token, identifier, context.TokenType);

8
src/OpenIddict.Client/OpenIddictClientHandlers.cs

@ -7,7 +7,9 @@
using System.Collections.Immutable;
using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Buffers.Text;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
@ -18,8 +20,6 @@ using Microsoft.Extensions.Primitives;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;
using static OpenIddict.Abstractions.OpenIddictExceptions;
using System.Runtime.CompilerServices;
using System.Buffers.Text;
#if !NET
using Org.BouncyCastle.Crypto.Digests;
@ -857,8 +857,8 @@ public static partial class OpenIddictClientHandlers
}
// Mark the token as redeemed to prevent future reuses.
var token = await _tokenManager.FindByIdAsync(identifier);
if (token is not null && !await _tokenManager.TryRedeemAsync(token))
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken);
if (token is not null && !await _tokenManager.TryRedeemAsync(token, context.CancellationToken))
{
context.Reject(
error: Errors.InvalidToken,

84
src/OpenIddict.Client/OpenIddictClientService.cs

@ -266,11 +266,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = request.CancellationToken,
Nonce = request.Nonce,
Request = new(),
TokenEndpointClientCertificate = request.TokenBindingCertificate,
@ -340,11 +339,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessChallengeContext(transaction)
{
CancellationToken = request.CancellationToken,
CodeChallengeMethod = request.CodeChallengeMethod,
GrantType = request.GrantType,
IdentityTokenHint = request.IdentityTokenHint,
@ -422,11 +420,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = request.CancellationToken,
GrantType = GrantTypes.ClientCredentials,
Issuer = request.Issuer,
ProviderName = request.ProviderName,
@ -513,11 +510,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = request.CancellationToken,
DisableUserInfoRetrieval = request.DisableUserInfo,
DisableUserInfoValidation = request.DisableUserInfo,
GrantType = request.GrantType,
@ -607,11 +603,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = source.Token,
DeviceCode = request.DeviceCode,
DisableUserInfoRetrieval = request.DisableUserInfo,
DisableUserInfoValidation = request.DisableUserInfo,
@ -714,11 +709,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessChallengeContext(transaction)
{
CancellationToken = request.CancellationToken,
DeviceAuthorizationRequest = request.AdditionalDeviceAuthorizationRequestParameters
is Dictionary<string, OpenIddictParameter> parameters ? new(parameters) : new(),
GrantType = GrantTypes.DeviceCode,
@ -793,11 +787,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = request.CancellationToken,
DisableUserInfoRetrieval = request.DisableUserInfo,
DisableUserInfoValidation = request.DisableUserInfo,
GrantType = GrantTypes.Password,
@ -881,13 +874,12 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessAuthenticationContext(transaction)
{
ActorToken = request.ActorToken,
ActorTokenType = request.ActorTokenType,
CancellationToken = request.CancellationToken,
DisableUserInfoRetrieval = request.DisableUserInfo,
DisableUserInfoValidation = request.DisableUserInfo,
GrantType = GrantTypes.TokenExchange,
@ -969,11 +961,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = request.CancellationToken,
DisableUserInfoRetrieval = request.DisableUserInfo,
DisableUserInfoValidation = request.DisableUserInfo,
GrantType = GrantTypes.RefreshToken,
@ -1055,11 +1046,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessIntrospectionContext(transaction)
{
CancellationToken = request.CancellationToken,
IntrospectionRequest = request.AdditionalIntrospectionRequestParameters
is Dictionary<string, OpenIddictParameter> parameters ? new(parameters) : new(),
Issuer = request.Issuer,
@ -1115,11 +1105,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessRevocationContext(transaction)
{
CancellationToken = request.CancellationToken,
Issuer = request.Issuer,
ProviderName = request.ProviderName,
RegistrationId = request.RegistrationId,
@ -1183,7 +1172,7 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
var request = new OpenIddictRequest();
request = await PrepareConfigurationRequestAsync();
@ -1197,7 +1186,6 @@ public class OpenIddictClientService
{
var context = new PrepareConfigurationRequestContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Registration = registration,
Request = request
@ -1219,7 +1207,6 @@ public class OpenIddictClientService
{
var context = new ApplyConfigurationRequestContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Registration = registration,
Request = request
@ -1243,7 +1230,6 @@ public class OpenIddictClientService
{
var context = new ExtractConfigurationResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Registration = registration,
Request = request
@ -1269,7 +1255,6 @@ public class OpenIddictClientService
{
var context = new HandleConfigurationResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Registration = registration,
Request = request,
@ -1308,11 +1293,10 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(request.CancellationToken);
var context = new ProcessSignOutContext(transaction)
{
CancellationToken = request.CancellationToken,
IdentityTokenHint = request.IdentityTokenHint,
Issuer = request.Issuer,
LoginHint = request.LoginHint,
@ -1379,7 +1363,7 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
var request = new OpenIddictRequest();
request = await PrepareJsonWebKeySetRequestAsync();
@ -1394,7 +1378,6 @@ public class OpenIddictClientService
{
var context = new PrepareJsonWebKeySetRequestContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Registration = registration,
Request = request
@ -1416,7 +1399,6 @@ public class OpenIddictClientService
{
var context = new ApplyJsonWebKeySetRequestContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Registration = registration,
Request = request
@ -1440,7 +1422,6 @@ public class OpenIddictClientService
{
var context = new ExtractJsonWebKeySetResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Registration = registration,
Request = request
@ -1466,7 +1447,6 @@ public class OpenIddictClientService
{
var context = new HandleJsonWebKeySetResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Registration = registration,
Request = request,
@ -1521,7 +1501,7 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
request = await PrepareDeviceAuthorizationRequestAsync();
request = await ApplyDeviceAuthorizationRequestAsync();
@ -1534,7 +1514,6 @@ public class OpenIddictClientService
{
var context = new PrepareDeviceAuthorizationRequestContext(transaction)
{
CancellationToken = cancellationToken,
ClientAuthenticationMethod = method,
Configuration = configuration,
RemoteUri = uri,
@ -1559,7 +1538,6 @@ public class OpenIddictClientService
{
var context = new ApplyDeviceAuthorizationRequestContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Configuration = configuration,
Registration = registration,
@ -1584,7 +1562,6 @@ public class OpenIddictClientService
{
var context = new ExtractDeviceAuthorizationResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Configuration = configuration,
Registration = registration,
@ -1611,7 +1588,6 @@ public class OpenIddictClientService
{
var context = new HandleDeviceAuthorizationResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Configuration = configuration,
Registration = registration,
@ -1666,7 +1642,7 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
request = await PrepareIntrospectionRequestAsync();
request = await ApplyIntrospectionRequestAsync();
@ -1679,7 +1655,6 @@ public class OpenIddictClientService
{
var context = new PrepareIntrospectionRequestContext(transaction)
{
CancellationToken = cancellationToken,
ClientAuthenticationMethod = method,
Configuration = configuration,
Registration = registration,
@ -1704,7 +1679,6 @@ public class OpenIddictClientService
{
var context = new ApplyIntrospectionRequestContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
Registration = registration,
RemoteUri = uri,
@ -1729,7 +1703,6 @@ public class OpenIddictClientService
{
var context = new ExtractIntrospectionResponseContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
Registration = registration,
RemoteUri = uri,
@ -1756,7 +1729,6 @@ public class OpenIddictClientService
{
var context = new HandleIntrospectionResponseContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
Registration = registration,
RemoteUri = uri,
@ -1814,7 +1786,7 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
request = await PreparePushedAuthorizationRequestAsync();
request = await ApplyPushedAuthorizationRequestAsync();
@ -1827,7 +1799,6 @@ public class OpenIddictClientService
{
var context = new PreparePushedAuthorizationRequestContext(transaction)
{
CancellationToken = cancellationToken,
ClientAuthenticationMethod = method,
RemoteUri = uri,
Configuration = configuration,
@ -1852,7 +1823,6 @@ public class OpenIddictClientService
{
var context = new ApplyPushedAuthorizationRequestContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Configuration = configuration,
Registration = registration,
@ -1877,7 +1847,6 @@ public class OpenIddictClientService
{
var context = new ExtractPushedAuthorizationResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Configuration = configuration,
Registration = registration,
@ -1904,7 +1873,6 @@ public class OpenIddictClientService
{
var context = new HandlePushedAuthorizationResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Configuration = configuration,
Registration = registration,
@ -1959,7 +1927,7 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
request = await PrepareRevocationRequestAsync();
request = await ApplyRevocationRequestAsync();
@ -1972,7 +1940,6 @@ public class OpenIddictClientService
{
var context = new PrepareRevocationRequestContext(transaction)
{
CancellationToken = cancellationToken,
ClientAuthenticationMethod = method,
Configuration = configuration,
Registration = registration,
@ -1997,7 +1964,6 @@ public class OpenIddictClientService
{
var context = new ApplyRevocationRequestContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
Registration = registration,
RemoteUri = uri,
@ -2022,7 +1988,6 @@ public class OpenIddictClientService
{
var context = new ExtractRevocationResponseContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
Registration = registration,
RemoteUri = uri,
@ -2049,7 +2014,6 @@ public class OpenIddictClientService
{
var context = new HandleRevocationResponseContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
Registration = registration,
RemoteUri = uri,
@ -2105,7 +2069,7 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
request = await PrepareTokenRequestAsync();
request = await ApplyTokenRequestAsync();
@ -2118,7 +2082,6 @@ public class OpenIddictClientService
{
var context = new PrepareTokenRequestContext(transaction)
{
CancellationToken = cancellationToken,
ClientAuthenticationMethod = method,
Configuration = configuration,
Registration = registration,
@ -2143,7 +2106,6 @@ public class OpenIddictClientService
{
var context = new ApplyTokenRequestContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
Registration = registration,
RemoteUri = uri,
@ -2169,7 +2131,6 @@ public class OpenIddictClientService
{
var context = new ExtractTokenResponseContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
Registration = registration,
RemoteUri = uri,
@ -2197,7 +2158,6 @@ public class OpenIddictClientService
{
var context = new HandleTokenResponseContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
Registration = registration,
RemoteUri = uri,
@ -2252,7 +2212,7 @@ public class OpenIddictClientService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictClientDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictClientFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
request = await PrepareUserInfoRequestAsync();
request = await ApplyUserInfoRequestAsync();
@ -2265,7 +2225,6 @@ public class OpenIddictClientService
{
var context = new PrepareUserInfoRequestContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
RemoteUri = uri,
Registration = registration,
@ -2289,7 +2248,6 @@ public class OpenIddictClientService
{
var context = new ApplyUserInfoRequestContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
RemoteUri = uri,
Registration = registration,
@ -2314,7 +2272,6 @@ public class OpenIddictClientService
{
var context = new ExtractUserInfoResponseContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
RemoteUri = uri,
Registration = registration,
@ -2341,7 +2298,6 @@ public class OpenIddictClientService
{
var context = new HandleUserInfoResponseContext(transaction)
{
CancellationToken = cancellationToken,
Configuration = configuration,
Registration = registration,
RemoteUri = uri,

8
src/OpenIddict.Client/OpenIddictClientTransaction.cs

@ -16,14 +16,8 @@ namespace OpenIddict.Client;
public sealed class OpenIddictClientTransaction
{
/// <summary>
/// Gets or sets the cancellation token that will be
/// used to determine if the operation was aborted.
/// Gets or sets the cancellation token used to determine if the operation was aborted.
/// </summary>
/// <remarks>
/// Note: for security reasons, this property shouldn't be used by event
/// handlers to abort security-sensitive operations. As such, it is
/// recommended to use this property only for user-dependent operations.
/// </remarks>
public CancellationToken CancellationToken { get; set; }
/// <summary>

29
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs

@ -44,13 +44,23 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Au
/// <inheritdoc/>
public async Task<bool> HandleRequestAsync()
{
// Note: to ensure internal operations are not immediately cancelled when the request is aborted
// (which may represent a security risk if sensitive operations are in progress), an ad-hoc token
// source is always created and configured to be triggered 5 seconds after the request is aborted.
var source = new CancellationTokenSource();
var registration = Context.RequestAborted.Register(static state =>
((CancellationTokenSource) state!).CancelAfter(TimeSpan.FromSeconds(5)), source);
Response.RegisterForDispose(source);
Response.RegisterForDispose(registration);
// Note: the transaction may be already attached when replaying an ASP.NET Core request
// (e.g when using the built-in status code pages middleware with the re-execute mode).
var transaction = Context.Features.Get<OpenIddictServerAspNetCoreFeature>()?.Transaction;
if (transaction is null)
{
// Create a new transaction and attach the HTTP request to make it available to the ASP.NET Core handlers.
transaction = await _factory.CreateTransactionAsync();
transaction = await _factory.CreateTransactionAsync(source.Token);
transaction.Properties[typeof(HttpRequest).FullName!] = new WeakReference<HttpRequest>(Request);
// Attach the OpenIddict server transaction to the ASP.NET Core features
@ -58,11 +68,7 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Au
Context.Features.Set(new OpenIddictServerAspNetCoreFeature { Transaction = transaction });
}
var context = new ProcessRequestContext(transaction)
{
CancellationToken = Context.RequestAborted
};
var context = new ProcessRequestContext(transaction);
await _dispatcher.DispatchAsync(context);
if (context.IsRequestHandled)
@ -79,7 +85,6 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Au
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Context.RequestAborted,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -116,10 +121,7 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Au
var context = transaction.GetProperty<ProcessAuthenticationContext>(typeof(ProcessAuthenticationContext).FullName!);
if (context is null)
{
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = Context.RequestAborted
});
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction));
// Store the context object in the transaction so it can be later retrieved by handlers
// that want to access the authentication result without triggering a new authentication flow.
@ -393,7 +395,6 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Au
var context = new ProcessChallengeContext(transaction)
{
CancellationToken = Context.RequestAborted,
Response = new OpenIddictResponse()
};
@ -408,7 +409,6 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Au
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Context.RequestAborted,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -442,7 +442,6 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Au
var context = new ProcessSignInContext(transaction)
{
CancellationToken = Context.RequestAborted,
Principal = user,
Response = new OpenIddictResponse()
};
@ -483,7 +482,6 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Au
var context = new ProcessSignOutContext(transaction)
{
CancellationToken = Context.RequestAborted,
Response = new OpenIddictResponse()
};
@ -500,7 +498,6 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Au
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Context.RequestAborted,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,

2
src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandlers.cs

@ -705,7 +705,7 @@ public static partial class OpenIddictServerAspNetCoreHandlers
// If a client certificate was used during the TLS handshake, attach it to the context.
if (request.IsHttps && await request.HttpContext.Connection.GetClientCertificateAsync(
request.HttpContext.RequestAborted) is X509Certificate2 certificate)
context.CancellationToken) is X509Certificate2 certificate)
{
context.Transaction.RemoteCertificate = certificate;
}

30
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs

@ -37,13 +37,23 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<Authenti
/// <inheritdoc/>
protected override async Task InitializeCoreAsync()
{
// Note: to ensure internal operations are not immediately cancelled when the request is aborted
// (which may represent a security risk if sensitive operations are in progress), an ad-hoc token
// source is always created and configured to be triggered 5 seconds after the request is aborted.
var source = new CancellationTokenSource();
var registration = Request.CallCancelled.Register(static state =>
((CancellationTokenSource) state!).CancelAfter(TimeSpan.FromSeconds(5)), source);
Response.OnSendingHeaders(static state => ((CancellationTokenSource) state!).Dispose(), source);
Response.OnSendingHeaders(static state => ((CancellationTokenRegistration) state!).Dispose(), registration);
// Note: the transaction may be already attached when replaying an OWIN request
// (e.g when using a status code pages middleware re-invoking the OWIN pipeline).
var transaction = Context.Get<OpenIddictServerTransaction>(typeof(OpenIddictServerTransaction).FullName);
if (transaction is null)
{
// Create a new transaction and attach the OWIN request to make it available to the OWIN handlers.
transaction = await _factory.CreateTransactionAsync();
transaction = await _factory.CreateTransactionAsync(source.Token);
transaction.Properties[typeof(IOwinRequest).FullName!] = new WeakReference<IOwinRequest>(Request);
// Attach the OpenIddict server transaction to the OWIN shared dictionary
@ -51,11 +61,7 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<Authenti
Context.Set(typeof(OpenIddictServerTransaction).FullName, transaction);
}
var context = new ProcessRequestContext(transaction)
{
CancellationToken = Request.CallCancelled
};
var context = new ProcessRequestContext(transaction);
await _dispatcher.DispatchAsync(context);
// Store the context in the transaction so that it can be retrieved from InvokeAsync().
@ -89,7 +95,6 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<Authenti
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Request.CallCancelled,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -126,10 +131,7 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<Authenti
var context = transaction.GetProperty<ProcessAuthenticationContext>(typeof(ProcessAuthenticationContext).FullName!);
if (context is null)
{
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = Request.CallCancelled
});
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction));
// Store the context object in the transaction so it can be later retrieved by handlers
// that want to access the authentication result without triggering a new authentication flow.
@ -290,7 +292,6 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<Authenti
var context = new ProcessChallengeContext(transaction)
{
CancellationToken = Request.CallCancelled,
Response = new OpenIddictResponse()
};
@ -305,7 +306,6 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<Authenti
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Request.CallCancelled,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -333,7 +333,6 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<Authenti
var context = new ProcessSignInContext(transaction)
{
CancellationToken = Request.CallCancelled,
Principal = signin.Principal,
Response = new OpenIddictResponse()
};
@ -349,7 +348,6 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<Authenti
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Request.CallCancelled,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -377,7 +375,6 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<Authenti
var context = new ProcessSignOutContext(transaction)
{
CancellationToken = Request.CallCancelled,
Response = new OpenIddictResponse()
};
@ -392,7 +389,6 @@ public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<Authenti
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Request.CallCancelled,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,

8
src/OpenIddict.Server.Owin/OpenIddictServerOwinHandlers.cs

@ -766,18 +766,20 @@ public static partial class OpenIddictServerOwinHandlers
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0120));
// If a client certificate was used during the TLS handshake, attach it to the context.
if (request.IsSecure && await GetClientCertificateAsync(request.Context) is X509Certificate2 certificate)
if (request.IsSecure && await GetClientCertificateAsync(request.Context,
context.CancellationToken) is X509Certificate2 certificate)
{
context.Transaction.RemoteCertificate = certificate;
}
static async ValueTask<X509Certificate2?> GetClientCertificateAsync(IOwinContext context)
static async ValueTask<X509Certificate2?> GetClientCertificateAsync(
IOwinContext context, CancellationToken cancellationToken)
{
// If a loading function was provided by the OWIN host, always invoke it before trying
// to resolve the certificate to ensure it is present in the environment dictionary.
if (context.Get<Func<Task>>("ssl.LoadClientCertAsync") is Func<Task> loader)
{
await loader();
await loader().WaitAsync(cancellationToken);
}
return context.Get<X509Certificate>("ssl.ClientCertificate") is X509Certificate certificate

6
src/OpenIddict.Server/IOpenIddictServerFactory.cs

@ -18,9 +18,13 @@ public interface IOpenIddictServerFactory
/// Creates a new <see cref="OpenIddictServerTransaction"/> that is used as a
/// way to store per-request data needed to process the requested operation.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <remarks>
/// Note: the specified <see cref="CancellationToken"/> is automatically attached to the returned transaction.
/// </remarks>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous
/// operation, whose result returns the created transaction.
/// </returns>
ValueTask<OpenIddictServerTransaction> CreateTransactionAsync();
ValueTask<OpenIddictServerTransaction> CreateTransactionAsync(CancellationToken cancellationToken);
}

6
src/OpenIddict.Server/OpenIddictServerConfiguration.cs

@ -77,9 +77,9 @@ public sealed class OpenIddictServerConfiguration : IPostConfigureOptions<OpenId
options.SigningCredentials.Sort((left, right) => Compare(left.Key, right.Key, now));
// Generate a key identifier for the encryption/signing keys that don't already have one.
foreach (var key in options.EncryptionCredentials.Select(credentials => credentials.Key)
.Concat(options.SigningCredentials.Select(credentials => credentials.Key))
.Where(key => string.IsNullOrEmpty(key.KeyId)))
foreach (var key in options.EncryptionCredentials.Select(static credentials => credentials.Key)
.Concat(options.SigningCredentials.Select(static credentials => credentials.Key))
.Where(static key => string.IsNullOrEmpty(key.KeyId)))
{
key.KeyId = GetKeyIdentifier(key);
}

2
src/OpenIddict.Server/OpenIddictServerDispatcher.cs

@ -40,6 +40,8 @@ public sealed class OpenIddictServerDispatcher : IOpenIddictServerDispatcher
await foreach (var handler in GetHandlersAsync())
{
context.CancellationToken.ThrowIfCancellationRequested();
try
{
await handler.HandleAsync(context);

14
src/OpenIddict.Server/OpenIddictServerEvents.cs

@ -30,19 +30,9 @@ public static partial class OpenIddictServerEvents
public OpenIddictServerTransaction Transaction { get; }
/// <summary>
/// Gets or sets the cancellation token that will be
/// used to determine if the operation was aborted.
/// Gets the cancellation token used to determine if the operation was aborted.
/// </summary>
/// <remarks>
/// Note: for security reasons, this property shouldn't be used by event
/// handlers to abort security-sensitive operations. As such, it is
/// recommended to use this property only for user-dependent operations.
/// </remarks>
public CancellationToken CancellationToken
{
get => Transaction.CancellationToken;
set => Transaction.CancellationToken = value;
}
public CancellationToken CancellationToken => Transaction.CancellationToken;
/// <summary>
/// Gets or sets the endpoint type that handled the request, if applicable.

12
src/OpenIddict.Server/OpenIddictServerFactory.cs

@ -31,10 +31,18 @@ public sealed class OpenIddictServerFactory : IOpenIddictServerFactory
}
/// <inheritdoc/>
public ValueTask<OpenIddictServerTransaction> CreateTransactionAsync()
=> new(new OpenIddictServerTransaction
public ValueTask<OpenIddictServerTransaction> CreateTransactionAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new(Task.FromCanceled<OpenIddictServerTransaction>(cancellationToken));
}
return new(new OpenIddictServerTransaction
{
CancellationToken = cancellationToken,
Logger = _logger,
Options = _options.CurrentValue
});
}
}

104
src/OpenIddict.Server/OpenIddictServerHandlers.Authentication.cs

@ -1396,14 +1396,14 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// To prevent downgrade attacks, ensure that authorization requests returning
// an access token directly from the authorization endpoint are rejected if
// the client_id corresponds to a confidential application.
if (context.Request.HasResponseType(ResponseTypes.Token) &&
await _applicationManager.HasClientTypeAsync(application, ClientTypes.Confidential))
await _applicationManager.HasClientTypeAsync(application, ClientTypes.Confidential, context.CancellationToken))
{
context.Logger.LogInformation(6045, SR.GetResourceString(SR.ID6045), context.ClientId);
@ -1449,14 +1449,14 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// If no explicit redirect_uri was specified, retrieve the URI associated with the
// client and ensure exactly one redirect_uri was attached to the client definition.
if (string.IsNullOrEmpty(context.RedirectUri))
{
var uris = await _applicationManager.GetRedirectUrisAsync(application);
var uris = await _applicationManager.GetRedirectUrisAsync(application, context.CancellationToken);
if (uris.Length is not 1)
{
context.Logger.LogInformation(6033, SR.GetResourceString(SR.ID6033), Parameters.RedirectUri);
@ -1475,7 +1475,7 @@ public static partial class OpenIddictServerHandlers
}
// Otherwise, ensure that the specified redirect_uri is valid and is associated with the client application.
if (!await _applicationManager.ValidateRedirectUriAsync(application, context.RedirectUri))
if (!await _applicationManager.ValidateRedirectUriAsync(application, context.RedirectUri, context.CancellationToken))
{
context.Logger.LogInformation(6046, SR.GetResourceString(SR.ID6046), context.RedirectUri);
@ -1540,9 +1540,9 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
await foreach (var scope in _scopeManager.FindByNamesAsync([.. scopes]))
await foreach (var scope in _scopeManager.FindByNamesAsync([.. scopes], context.CancellationToken))
{
var name = await _scopeManager.GetNameAsync(scope);
var name = await _scopeManager.GetNameAsync(scope, context.CancellationToken);
if (!string.IsNullOrEmpty(name))
{
scopes.Remove(name);
@ -1615,9 +1615,9 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
await foreach (var resource in _resourceManager.FindByNamesAsync([.. resources]))
await foreach (var resource in _resourceManager.FindByNamesAsync([.. resources], context.CancellationToken))
{
var name = await _resourceManager.GetNameAsync(resource);
var name = await _resourceManager.GetNameAsync(resource, context.CancellationToken);
if (!string.IsNullOrEmpty(name))
{
resources.Remove(name);
@ -1672,11 +1672,11 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the authorization endpoint.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Authorization))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Authorization, context.CancellationToken))
{
context.Logger.LogInformation(6048, SR.GetResourceString(SR.ID6048), context.ClientId);
@ -1722,12 +1722,12 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the authorization code grant.
if (context.Request.IsAuthorizationCodeFlow() &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.AuthorizationCode))
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.AuthorizationCode, context.CancellationToken))
{
context.Logger.LogInformation(6049, SR.GetResourceString(SR.ID6049), context.ClientId);
@ -1741,7 +1741,7 @@ public static partial class OpenIddictServerHandlers
// Reject the request if the application is not allowed to use the implicit grant.
if (context.Request.IsImplicitFlow() &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.Implicit))
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.Implicit, context.CancellationToken))
{
context.Logger.LogInformation(6050, SR.GetResourceString(SR.ID6050), context.ClientId);
@ -1755,8 +1755,8 @@ public static partial class OpenIddictServerHandlers
// Reject the request if the application is not allowed to use the authorization code/implicit grants.
if (context.Request.IsHybridFlow() &&
(!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.AuthorizationCode) ||
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.Implicit)))
(!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.AuthorizationCode, context.CancellationToken) ||
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.Implicit, context.CancellationToken)))
{
context.Logger.LogInformation(6051, SR.GetResourceString(SR.ID6051), context.ClientId);
@ -1771,7 +1771,7 @@ public static partial class OpenIddictServerHandlers
// Reject the request if the offline_access scope was request and
// if the application is not allowed to use the refresh token grant.
if (context.Request.HasScope(Scopes.OfflineAccess) &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.RefreshToken))
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.RefreshToken, context.CancellationToken))
{
context.Logger.LogInformation(6052, SR.GetResourceString(SR.ID6052), context.ClientId, Scopes.OfflineAccess);
@ -1817,7 +1817,7 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject requests that specify a response_type for which no permission was granted.
@ -1838,7 +1838,7 @@ public static partial class OpenIddictServerHandlers
// Note: response type permissions are always prefixed with "rst:".
const string prefix = Permissions.Prefixes.ResponseType;
foreach (var permission in await _applicationManager.GetPermissionsAsync(application))
foreach (var permission in await _applicationManager.GetPermissionsAsync(application, context.CancellationToken))
{
// Ignore permissions that are not response type permissions.
if (!permission.StartsWith(prefix, StringComparison.Ordinal))
@ -1892,7 +1892,7 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
foreach (var scope in context.Request.GetScopes())
@ -1905,7 +1905,7 @@ public static partial class OpenIddictServerHandlers
}
// Reject the request if the application is not allowed to use the iterated scope.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Scope + scope))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Scope + scope, context.CancellationToken))
{
context.Logger.LogInformation(6052, SR.GetResourceString(SR.ID6052), context.ClientId, scope);
@ -1953,13 +1953,13 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
foreach (var resource in context.Request.GetResources())
{
// Reject the request if the application is not allowed to use the iterated resource.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Resource + resource))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Resource + resource, context.CancellationToken))
{
context.Logger.LogInformation(6281, SR.GetResourceString(SR.ID6278), context.ClientId, resource);
@ -2014,10 +2014,10 @@ public static partial class OpenIddictServerHandlers
return;
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.PushedAuthorizationRequests))
if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.PushedAuthorizationRequests, context.CancellationToken))
{
if (string.IsNullOrEmpty(context.Request.RequestUri))
{
@ -2080,10 +2080,10 @@ public static partial class OpenIddictServerHandlers
return;
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.ProofKeyForCodeExchange))
if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.ProofKeyForCodeExchange, context.CancellationToken))
{
context.Logger.LogInformation(6033, SR.GetResourceString(SR.ID6033), Parameters.CodeChallenge);
@ -3483,14 +3483,14 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// To prevent downgrade attacks, ensure that pushed authorization requests returning
// an access token directly from the authorization endpoint are rejected if
// the client_id corresponds to a confidential application.
if (context.Request.HasResponseType(ResponseTypes.Token) &&
await _applicationManager.HasClientTypeAsync(application, ClientTypes.Confidential))
await _applicationManager.HasClientTypeAsync(application, ClientTypes.Confidential, context.CancellationToken))
{
context.Logger.LogInformation(6251, SR.GetResourceString(SR.ID6251), context.ClientId);
@ -3536,14 +3536,14 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// If no explicit redirect_uri was specified, retrieve the URI associated with the
// client and ensure exactly one redirect_uri was attached to the client definition.
if (string.IsNullOrEmpty(context.RedirectUri))
{
var uris = await _applicationManager.GetRedirectUrisAsync(application);
var uris = await _applicationManager.GetRedirectUrisAsync(application, context.CancellationToken);
if (uris.Length is not 1)
{
context.Logger.LogInformation(6240, SR.GetResourceString(SR.ID6240), Parameters.RedirectUri);
@ -3562,7 +3562,7 @@ public static partial class OpenIddictServerHandlers
}
// Otherwise, ensure that the specified redirect_uri is valid and is associated with the client application.
if (!await _applicationManager.ValidateRedirectUriAsync(application, context.RedirectUri))
if (!await _applicationManager.ValidateRedirectUriAsync(application, context.RedirectUri, context.CancellationToken))
{
context.Logger.LogInformation(6252, SR.GetResourceString(SR.ID6252), context.RedirectUri);
@ -3627,9 +3627,9 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
await foreach (var scope in _scopeManager.FindByNamesAsync([.. scopes]))
await foreach (var scope in _scopeManager.FindByNamesAsync([.. scopes], context.CancellationToken))
{
var name = await _scopeManager.GetNameAsync(scope);
var name = await _scopeManager.GetNameAsync(scope, context.CancellationToken);
if (!string.IsNullOrEmpty(name))
{
scopes.Remove(name);
@ -3702,9 +3702,9 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
await foreach (var resource in _resourceManager.FindByNamesAsync([.. resources]))
await foreach (var resource in _resourceManager.FindByNamesAsync([.. resources], context.CancellationToken))
{
var name = await _resourceManager.GetNameAsync(resource);
var name = await _resourceManager.GetNameAsync(resource, context.CancellationToken);
if (!string.IsNullOrEmpty(name))
{
resources.Remove(name);
@ -3759,11 +3759,11 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the pushed authorization endpoint.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.PushedAuthorization))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.PushedAuthorization, context.CancellationToken))
{
context.Logger.LogInformation(6254, SR.GetResourceString(SR.ID6254), context.ClientId);
@ -3809,12 +3809,12 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the authorization code grant.
if (context.Request.IsAuthorizationCodeFlow() &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.AuthorizationCode))
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.AuthorizationCode, context.CancellationToken))
{
context.Logger.LogInformation(6255, SR.GetResourceString(SR.ID6255), context.ClientId);
@ -3828,7 +3828,7 @@ public static partial class OpenIddictServerHandlers
// Reject the request if the application is not allowed to use the implicit grant.
if (context.Request.IsImplicitFlow() &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.Implicit))
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.Implicit, context.CancellationToken))
{
context.Logger.LogInformation(6256, SR.GetResourceString(SR.ID6256), context.ClientId);
@ -3842,8 +3842,8 @@ public static partial class OpenIddictServerHandlers
// Reject the request if the application is not allowed to use the authorization code/implicit grants.
if (context.Request.IsHybridFlow() &&
(!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.AuthorizationCode) ||
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.Implicit)))
(!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.AuthorizationCode, context.CancellationToken) ||
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.Implicit, context.CancellationToken)))
{
context.Logger.LogInformation(6257, SR.GetResourceString(SR.ID6257), context.ClientId);
@ -3858,7 +3858,7 @@ public static partial class OpenIddictServerHandlers
// Reject the request if the offline_access scope was request and
// if the application is not allowed to use the refresh token grant.
if (context.Request.HasScope(Scopes.OfflineAccess) &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.RefreshToken))
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.RefreshToken, context.CancellationToken))
{
context.Logger.LogInformation(6258, SR.GetResourceString(SR.ID6258), context.ClientId, Scopes.OfflineAccess);
@ -3904,7 +3904,7 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject requests that specify a response_type for which no permission was granted.
@ -3925,7 +3925,7 @@ public static partial class OpenIddictServerHandlers
// Note: response type permissions are always prefixed with "rst:".
const string prefix = Permissions.Prefixes.ResponseType;
foreach (var permission in await _applicationManager.GetPermissionsAsync(application))
foreach (var permission in await _applicationManager.GetPermissionsAsync(application, context.CancellationToken))
{
// Ignore permissions that are not response type permissions.
if (!permission.StartsWith(prefix, StringComparison.Ordinal))
@ -3979,7 +3979,7 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
foreach (var scope in context.Request.GetScopes())
@ -3992,7 +3992,7 @@ public static partial class OpenIddictServerHandlers
}
// Reject the request if the application is not allowed to use the iterated scope.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Scope + scope))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Scope + scope, context.CancellationToken))
{
context.Logger.LogInformation(6258, SR.GetResourceString(SR.ID6258), context.ClientId, scope);
@ -4040,13 +4040,13 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
foreach (var resource in context.Request.GetResources())
{
// Reject the request if the application is not allowed to use the iterated resource.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Resource + resource))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Resource + resource, context.CancellationToken))
{
context.Logger.LogInformation(6283, SR.GetResourceString(SR.ID6279), context.ClientId, resource);
@ -4100,10 +4100,10 @@ public static partial class OpenIddictServerHandlers
return;
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.ProofKeyForCodeExchange))
if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.ProofKeyForCodeExchange, context.CancellationToken))
{
context.Logger.LogInformation(6240, SR.GetResourceString(SR.ID6240), Parameters.CodeChallenge);

20
src/OpenIddict.Server/OpenIddictServerHandlers.Device.cs

@ -481,9 +481,9 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
await foreach (var scope in _scopeManager.FindByNamesAsync([.. scopes]))
await foreach (var scope in _scopeManager.FindByNamesAsync([.. scopes], context.CancellationToken))
{
var name = await _scopeManager.GetNameAsync(scope);
var name = await _scopeManager.GetNameAsync(scope, context.CancellationToken);
if (!string.IsNullOrEmpty(name))
{
scopes.Remove(name);
@ -595,14 +595,14 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the device authorization endpoint.
//
// Note: the legacy "ept:device" permission is still allowed for backward compatibility.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.DeviceAuthorization) &&
!await _applicationManager.HasPermissionAsync(application, "ept:device"))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.DeviceAuthorization, context.CancellationToken) &&
!await _applicationManager.HasPermissionAsync(application, "ept:device", context.CancellationToken))
{
context.Logger.LogInformation(6062, SR.GetResourceString(SR.ID6062), context.ClientId);
@ -648,11 +648,11 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the device code grant.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.DeviceCode))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.DeviceCode, context.CancellationToken))
{
context.Logger.LogInformation(6118, SR.GetResourceString(SR.ID6118), context.ClientId);
@ -667,7 +667,7 @@ public static partial class OpenIddictServerHandlers
// Reject the request if the offline_access scope was request and
// if the application is not allowed to use the refresh token grant.
if (context.Request.HasScope(Scopes.OfflineAccess) &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.RefreshToken))
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.RefreshToken, context.CancellationToken))
{
context.Logger.LogInformation(6120, SR.GetResourceString(SR.ID6120), context.ClientId, Scopes.OfflineAccess);
@ -715,7 +715,7 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
foreach (var scope in context.Request.GetScopes())
@ -728,7 +728,7 @@ public static partial class OpenIddictServerHandlers
}
// Reject the request if the application is not allowed to use the iterated scope.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Scope + scope))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Scope + scope, context.CancellationToken))
{
context.Logger.LogInformation(6063, SR.GetResourceString(SR.ID6063), context.ClientId, scope);

34
src/OpenIddict.Server/OpenIddictServerHandlers.Exchange.cs

@ -1047,9 +1047,9 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
await foreach (var scope in _scopeManager.FindByNamesAsync([.. scopes]))
await foreach (var scope in _scopeManager.FindByNamesAsync([.. scopes], context.CancellationToken))
{
var name = await _scopeManager.GetNameAsync(scope);
var name = await _scopeManager.GetNameAsync(scope, context.CancellationToken);
if (!string.IsNullOrEmpty(name))
{
scopes.Remove(name);
@ -1163,9 +1163,9 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
await foreach (var resource in _resourceManager.FindByNamesAsync([.. resources]))
await foreach (var resource in _resourceManager.FindByNamesAsync([.. resources], context.CancellationToken))
{
var name = await _resourceManager.GetNameAsync(resource);
var name = await _resourceManager.GetNameAsync(resource, context.CancellationToken);
if (!string.IsNullOrEmpty(name))
{
resources.Remove(name);
@ -1284,11 +1284,11 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the token endpoint.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Token))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Token, context.CancellationToken))
{
context.Logger.LogInformation(6086, SR.GetResourceString(SR.ID6086), context.ClientId);
@ -1336,11 +1336,11 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the specified grant type.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.GrantType + context.Request.GrantType))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.GrantType + context.Request.GrantType, context.CancellationToken))
{
context.Logger.LogInformation(6087, SR.GetResourceString(SR.ID6087), context.ClientId, context.Request.GrantType);
@ -1355,7 +1355,7 @@ public static partial class OpenIddictServerHandlers
// Reject the request if the offline_access scope was request and if
// the application is not allowed to use the refresh token grant type.
if (context.Request.HasScope(Scopes.OfflineAccess) &&
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.RefreshToken))
!await _applicationManager.HasPermissionAsync(application, Permissions.GrantTypes.RefreshToken, context.CancellationToken))
{
context.Logger.LogInformation(6088, SR.GetResourceString(SR.ID6088), context.ClientId, Scopes.OfflineAccess);
@ -1403,7 +1403,7 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
foreach (var scope in context.Request.GetScopes())
@ -1416,7 +1416,7 @@ public static partial class OpenIddictServerHandlers
}
// Reject the request if the application is not allowed to use the iterated scope.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Scope + scope))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Scope + scope, context.CancellationToken))
{
context.Logger.LogInformation(6089, SR.GetResourceString(SR.ID6089), context.ClientId, scope);
@ -1465,13 +1465,13 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
foreach (var audience in context.Request.GetAudiences())
{
// Reject the request if the application is not allowed to use the iterated audience.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Audience + audience))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Audience + audience, context.CancellationToken))
{
context.Logger.LogInformation(6278, SR.GetResourceString(SR.ID6276), context.ClientId, audience);
@ -1520,13 +1520,13 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
foreach (var resource in context.Request.GetResources())
{
// Reject the request if the application is not allowed to use the iterated resource.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Resource + resource))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Prefixes.Resource + resource, context.CancellationToken))
{
context.Logger.LogInformation(6279, SR.GetResourceString(SR.ID6277), context.ClientId, resource);
@ -1586,10 +1586,10 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.ProofKeyForCodeExchange))
if (await _applicationManager.HasRequirementAsync(application, Requirements.Features.ProofKeyForCodeExchange, context.CancellationToken))
{
context.Logger.LogInformation(6077, SR.GetResourceString(SR.ID6077), Parameters.CodeVerifier);

8
src/OpenIddict.Server/OpenIddictServerHandlers.Introspection.cs

@ -528,11 +528,11 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the introspection endpoint.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Introspection))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Introspection, context.CancellationToken))
{
context.Logger.LogInformation(6103, SR.GetResourceString(SR.ID6103), context.ClientId);
@ -816,11 +816,11 @@ public static partial class OpenIddictServerHandlers
return;
}
var application = await _applicationManager.FindByClientIdAsync(context.Request.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.Request.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Public clients are not allowed to access sensitive claims as authentication cannot be enforced.
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public, context.CancellationToken))
{
context.Logger.LogInformation(6107, SR.GetResourceString(SR.ID6107), context.Request.ClientId);

64
src/OpenIddict.Server/OpenIddictServerHandlers.Protection.cs

@ -173,8 +173,8 @@ public static partial class OpenIddictServerHandlers
// the signing keys from the JSON Web Key set attached to the client application.
//
// Important: at this stage, the issuer isn't guaranteed to be valid or legitimate.
var application = await _applicationManager.FindByClientIdAsync(token.Issuer);
if (application is not null && await _applicationManager.GetJsonWebKeySetAsync(application)
var application = await _applicationManager.FindByClientIdAsync(token.Issuer, context.CancellationToken);
if (application is not null && await _applicationManager.GetJsonWebKeySetAsync(application, context.CancellationToken)
is JsonWebKeySet set)
{
return set.GetSigningKeys();
@ -359,7 +359,7 @@ public static partial class OpenIddictServerHandlers
}
// If the reference token cannot be found, don't return an error to allow another handler to validate it.
var token = await _tokenManager.FindByReferenceIdAsync(context.Token);
var token = await _tokenManager.FindByReferenceIdAsync(context.Token, context.CancellationToken);
if (token is null)
{
return;
@ -369,8 +369,8 @@ public static partial class OpenIddictServerHandlers
if (!(context.ValidTokenTypes.Count switch
{
0 => true, // If no specific token type is expected, accept all token types at this stage.
1 => await _tokenManager.HasTypeAsync(token, context.ValidTokenTypes.ElementAt(0)),
_ => await _tokenManager.HasTypeAsync(token, [.. context.ValidTokenTypes])
1 => await _tokenManager.HasTypeAsync(token, context.ValidTokenTypes.ElementAt(0), context.CancellationToken),
_ => await _tokenManager.HasTypeAsync(token, [.. context.ValidTokenTypes], context.CancellationToken)
}))
{
context.Reject(
@ -407,7 +407,7 @@ public static partial class OpenIddictServerHandlers
return;
}
var payload = await _tokenManager.GetPayloadAsync(token);
var payload = await _tokenManager.GetPayloadAsync(token, context.CancellationToken);
if (string.IsNullOrEmpty(payload))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0026));
@ -418,7 +418,7 @@ public static partial class OpenIddictServerHandlers
// used to restore the properties associated with the token.
context.IsReferenceToken = true;
context.Token = payload;
context.TokenId = await _tokenManager.GetIdAsync(token);
context.TokenId = await _tokenManager.GetIdAsync(token, context.CancellationToken);
}
}
@ -799,7 +799,7 @@ public static partial class OpenIddictServerHandlers
}
// If the token entry cannot be found, return a generic error.
var token = await _tokenManager.FindByIdAsync(identifier);
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken);
if (token is null)
{
context.Reject(
@ -827,9 +827,9 @@ public static partial class OpenIddictServerHandlers
// If the token was not validated as a reference token but has a reference identifier attached, this
// may indicate that the payload stored in the database has leaked and is being used as a regular,
// non-reference token. To prevent this, reject the token if the reference identifier is not null.
if (!context.IsReferenceToken && !string.IsNullOrEmpty(await _tokenManager.GetReferenceIdAsync(token)))
if (!context.IsReferenceToken && !string.IsNullOrEmpty(await _tokenManager.GetReferenceIdAsync(token, context.CancellationToken)))
{
context.Logger.LogWarning(6292, SR.GetResourceString(SR.ID6292), await _tokenManager.GetIdAsync(token));
context.Logger.LogWarning(6292, SR.GetResourceString(SR.ID6292), await _tokenManager.GetIdAsync(token, context.CancellationToken));
context.Reject(
error: Errors.InvalidToken,
@ -855,11 +855,11 @@ public static partial class OpenIddictServerHandlers
// Restore the creation/expiration dates/identifiers from the token entry metadata.
context.Principal
.SetCreationDate(await _tokenManager.GetCreationDateAsync(token))
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token))
.SetAuthorizationId(context.AuthorizationId = await _tokenManager.GetAuthorizationIdAsync(token))
.SetTokenId(context.TokenId = await _tokenManager.GetIdAsync(token))
.SetTokenType(await _tokenManager.GetTypeAsync(token));
.SetCreationDate(await _tokenManager.GetCreationDateAsync(token, context.CancellationToken))
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token, context.CancellationToken))
.SetAuthorizationId(context.AuthorizationId = await _tokenManager.GetAuthorizationIdAsync(token, context.CancellationToken))
.SetTokenId(context.TokenId = await _tokenManager.GetIdAsync(token, context.CancellationToken))
.SetTokenType(await _tokenManager.GetTypeAsync(token, context.CancellationToken));
}
}
@ -1236,7 +1236,7 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
Debug.Assert(!string.IsNullOrEmpty(context.TokenId), SR.GetResourceString(SR.ID4017));
var token = await _tokenManager.FindByIdAsync(context.TokenId)
var token = await _tokenManager.FindByIdAsync(context.TokenId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0021));
// If the token is already marked as redeemed, this may indicate that it was compromised.
@ -1245,7 +1245,7 @@ public static partial class OpenIddictServerHandlers
// Special logic is used to avoid revoking refresh tokens already marked as redeemed to allow for a small leeway.
// Note: the authorization itself is not revoked to allow the legitimate client to start a new flow.
// See https://tools.ietf.org/html/rfc6749#section-10.5 for more information.
if (await _tokenManager.HasStatusAsync(token, Statuses.Redeemed))
if (await _tokenManager.HasStatusAsync(token, Statuses.Redeemed, context.CancellationToken))
{
if (!context.Principal.HasTokenType(TokenTypeIdentifiers.RefreshToken) || !await IsReusableAsync(token))
{
@ -1255,7 +1255,7 @@ public static partial class OpenIddictServerHandlers
try
{
count = await _tokenManager.RevokeByAuthorizationIdAsync(context.AuthorizationId);
count = await _tokenManager.RevokeByAuthorizationIdAsync(context.AuthorizationId, context.CancellationToken);
}
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
@ -1302,7 +1302,7 @@ public static partial class OpenIddictServerHandlers
}
// If the token is not marked as valid yet, return an authorization_pending error.
if (await _tokenManager.HasStatusAsync(token, Statuses.Inactive))
if (await _tokenManager.HasStatusAsync(token, Statuses.Inactive, context.CancellationToken))
{
context.Logger.LogInformation(6003, SR.GetResourceString(SR.ID6003), context.TokenId);
@ -1315,7 +1315,7 @@ public static partial class OpenIddictServerHandlers
}
// If the token is marked as rejected, return an access_denied error.
if (await _tokenManager.HasStatusAsync(token, Statuses.Rejected))
if (await _tokenManager.HasStatusAsync(token, Statuses.Rejected, context.CancellationToken))
{
context.Logger.LogInformation(6004, SR.GetResourceString(SR.ID6004), context.TokenId);
@ -1327,7 +1327,7 @@ public static partial class OpenIddictServerHandlers
return;
}
if (!await _tokenManager.HasStatusAsync(token, Statuses.Valid))
if (!await _tokenManager.HasStatusAsync(token, Statuses.Valid, context.CancellationToken))
{
context.Logger.LogInformation(6005, SR.GetResourceString(SR.ID6005), context.TokenId);
@ -1367,7 +1367,7 @@ public static partial class OpenIddictServerHandlers
return false;
}
var date = await _tokenManager.GetRedemptionDateAsync(token);
var date = await _tokenManager.GetRedemptionDateAsync(token, context.CancellationToken);
if (date is null || context.Options.TimeProvider.GetUtcNow() <
date + context.Options.RefreshTokenReuseLeeway)
{
@ -1413,8 +1413,8 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
Debug.Assert(!string.IsNullOrEmpty(context.AuthorizationId), SR.GetResourceString(SR.ID4018));
var authorization = await _authorizationManager.FindByIdAsync(context.AuthorizationId);
if (authorization is null || !await _authorizationManager.HasStatusAsync(authorization, Statuses.Valid))
var authorization = await _authorizationManager.FindByIdAsync(context.AuthorizationId, context.CancellationToken);
if (authorization is null || !await _authorizationManager.HasStatusAsync(authorization, Statuses.Valid, context.CancellationToken))
{
context.Logger.LogInformation(6006, SR.GetResourceString(SR.ID6006), context.AuthorizationId);
@ -1562,16 +1562,16 @@ public static partial class OpenIddictServerHandlers
// If the client application is known, associate it with the token.
if (!string.IsNullOrEmpty(context.ClientId))
{
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
descriptor.ApplicationId = await _applicationManager.GetIdAsync(application);
descriptor.ApplicationId = await _applicationManager.GetIdAsync(application, context.CancellationToken);
}
var token = await _tokenManager.CreateAsync(descriptor)
var token = await _tokenManager.CreateAsync(descriptor, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0019));
var identifier = await _tokenManager.GetIdAsync(token);
var identifier = await _tokenManager.GetIdAsync(token, context.CancellationToken);
// Attach the token identifier to the principal so that it can be stored in the token payload.
context.Principal.SetTokenId(identifier);
@ -1815,11 +1815,11 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0009));
}
var token = await _tokenManager.FindByIdAsync(identifier)
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0021));
var descriptor = new OpenIddictTokenDescriptor();
await _tokenManager.PopulateAsync(descriptor, token);
await _tokenManager.PopulateAsync(descriptor, token, context.CancellationToken);
// Attach the generated token to the token entry.
descriptor.Payload = context.Token;
@ -1839,7 +1839,7 @@ public static partial class OpenIddictServerHandlers
// User codes are generally short. To help reduce the risks of collisions with
// existing entries, a database check is performed here before updating the entry.
while (await _tokenManager.FindByReferenceIdAsync(descriptor.ReferenceId) is not null);
while (await _tokenManager.FindByReferenceIdAsync(descriptor.ReferenceId, context.CancellationToken) is not null);
}
else
@ -1849,7 +1849,7 @@ public static partial class OpenIddictServerHandlers
}
}
await _tokenManager.UpdateAsync(token, descriptor);
await _tokenManager.UpdateAsync(token, descriptor, context.CancellationToken);
context.Logger.LogTrace(6014, SR.GetResourceString(SR.ID6014), context.Token, identifier, context.TokenType);

8
src/OpenIddict.Server/OpenIddictServerHandlers.Revocation.cs

@ -469,11 +469,11 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the revocation endpoint.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Revocation))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.Revocation, context.CancellationToken))
{
context.Logger.LogInformation(6116, SR.GetResourceString(SR.ID6116), context.ClientId);
@ -671,7 +671,7 @@ public static partial class OpenIddictServerHandlers
return;
}
var token = await _tokenManager.FindByIdAsync(identifier);
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken);
if (token is null)
{
context.Logger.LogInformation(6123, SR.GetResourceString(SR.ID6123), identifier);
@ -685,7 +685,7 @@ public static partial class OpenIddictServerHandlers
}
// Try to revoke the token. If an error occurs, return an error.
if (!await _tokenManager.TryRevokeAsync(token))
if (!await _tokenManager.TryRevokeAsync(token, context.CancellationToken))
{
context.Reject(
error: Errors.UnsupportedTokenType,

36
src/OpenIddict.Server/OpenIddictServerHandlers.Session.cs

@ -599,10 +599,10 @@ public static partial class OpenIddictServerHandlers
if (!string.IsNullOrEmpty(context.ClientId))
{
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
if (!await _applicationManager.ValidatePostLogoutRedirectUriAsync(application, context.PostLogoutRedirectUri))
if (!await _applicationManager.ValidatePostLogoutRedirectUriAsync(application, context.PostLogoutRedirectUri, context.CancellationToken))
{
context.Logger.LogInformation(6128, SR.GetResourceString(SR.ID6128), context.PostLogoutRedirectUri);
@ -634,17 +634,17 @@ public static partial class OpenIddictServerHandlers
// To be considered valid, a post_logout_redirect_uri must correspond to an existing client application
// that was granted the ept:logout permission, unless endpoint permissions checking was explicitly disabled.
await foreach (var application in _applicationManager.FindByPostLogoutRedirectUriAsync(uri))
await foreach (var application in _applicationManager.FindByPostLogoutRedirectUriAsync(uri, context.CancellationToken))
{
// Note: the legacy "ept:logout" permission is still allowed for backward compatibility.
if (!context.Options.IgnoreEndpointPermissions &&
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout"))
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession, context.CancellationToken) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout", context.CancellationToken))
{
continue;
}
if (await _applicationManager.ValidatePostLogoutRedirectUriAsync(application, uri))
if (await _applicationManager.ValidatePostLogoutRedirectUriAsync(application, uri, context.CancellationToken))
{
return true;
}
@ -667,18 +667,18 @@ public static partial class OpenIddictServerHandlers
string.Equals(value.Scheme, Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase)))
{
await foreach (var application in _applicationManager.FindByPostLogoutRedirectUriAsync(
uri: new UriBuilder(value) { Port = -1 }.Uri.AbsoluteUri))
uri: new UriBuilder(value) { Port = -1 }.Uri.AbsoluteUri, context.CancellationToken))
{
// Note: the legacy "ept:logout" permission is still allowed for backward compatibility.
if (!context.Options.IgnoreEndpointPermissions &&
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout"))
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession, context.CancellationToken) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout", context.CancellationToken))
{
continue;
}
if (await _applicationManager.HasApplicationTypeAsync(application, ApplicationTypes.Native) &&
await _applicationManager.ValidatePostLogoutRedirectUriAsync(application, uri))
if (await _applicationManager.HasApplicationTypeAsync(application, ApplicationTypes.Native, context.CancellationToken) &&
await _applicationManager.ValidatePostLogoutRedirectUriAsync(application, uri, context.CancellationToken))
{
return true;
}
@ -729,14 +729,14 @@ public static partial class OpenIddictServerHandlers
Debug.Assert(!string.IsNullOrEmpty(context.ClientId), SR.FormatID4000(Parameters.ClientId));
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Reject the request if the application is not allowed to use the end session endpoint.
//
// Note: the legacy "ept:logout" permission is still allowed for backward compatibility.
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout"))
if (!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession, context.CancellationToken) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout", context.CancellationToken))
{
context.Logger.LogInformation(6048, SR.GetResourceString(SR.ID6048), context.ClientId);
@ -858,7 +858,7 @@ public static partial class OpenIddictServerHandlers
foreach (var identifier in identifiers)
{
var application = await _applicationManager.FindByClientIdAsync(identifier);
var application = await _applicationManager.FindByClientIdAsync(identifier, context.CancellationToken);
if (application is null)
{
continue;
@ -866,13 +866,13 @@ public static partial class OpenIddictServerHandlers
// Note: the legacy "ept:logout" permission is still allowed for backward compatibility.
if (!context.Options.IgnoreEndpointPermissions &&
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout"))
!await _applicationManager.HasPermissionAsync(application, Permissions.Endpoints.EndSession, context.CancellationToken) &&
!await _applicationManager.HasPermissionAsync(application, "ept:logout", context.CancellationToken))
{
continue;
}
if (await _applicationManager.ValidatePostLogoutRedirectUriAsync(application, uri))
if (await _applicationManager.ValidatePostLogoutRedirectUriAsync(application, uri, context.CancellationToken))
{
return true;
}

98
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -1046,7 +1046,7 @@ public static partial class OpenIddictServerHandlers
// Retrieve the application details corresponding to the requested client_id.
// If no entity can be found, this likely indicates that the client_id is invalid.
var application = await _applicationManager.FindByClientIdAsync(context.ClientId);
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken);
if (application is null)
{
context.Logger.LogInformation(6221, SR.GetResourceString(SR.ID6221), context.ClientId);
@ -1113,10 +1113,10 @@ public static partial class OpenIddictServerHandlers
return;
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public, context.CancellationToken))
{
// Reject grant_type=client_credentials token requests if the application is a public client.
if (context.EndpointType is OpenIddictServerEndpointType.Token &&
@ -1224,16 +1224,16 @@ public static partial class OpenIddictServerHandlers
return;
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// If the application is a public client, don't validate the client secret.
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public, context.CancellationToken))
{
return;
}
if (!await _applicationManager.ValidateClientSecretAsync(application, context.ClientSecret))
if (!await _applicationManager.ValidateClientSecretAsync(application, context.ClientSecret, context.CancellationToken))
{
context.Logger.LogInformation(6225, SR.GetResourceString(SR.ID6225), context.ClientId);
@ -1398,7 +1398,7 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0032));
// Note: to avoid building and introspecting a X.509 certificate chain and reduce the cost
@ -1421,7 +1421,7 @@ public static partial class OpenIddictServerHandlers
}
if (await _applicationManager.GetSelfSignedTlsClientAuthenticationPolicyAsync(
application, context.Options.SelfSignedTlsClientAuthenticationPolicy) is not X509ChainPolicy policy)
application, context.Options.SelfSignedTlsClientAuthenticationPolicy, context.CancellationToken) is not X509ChainPolicy policy)
{
context.Logger.LogInformation(6283, SR.GetResourceString(SR.ID6283), context.ClientId);
@ -1442,7 +1442,7 @@ public static partial class OpenIddictServerHandlers
// To allow validating such certificates, the chain policy is amended to consider the specified
// self-signed certificate as a trusted root and basically disable chain validation while still
// validating the other aspects of the certificate (e.g expiration date, key usage, etc).
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public, context.CancellationToken))
{
// Always clone the X.509 chain policy to ensure the original instance is never mutated.
policy = policy.Clone();
@ -1455,7 +1455,7 @@ public static partial class OpenIddictServerHandlers
}
if (!await _applicationManager.ValidateSelfSignedTlsClientCertificateAsync(
application, context.Transaction.RemoteCertificate, policy))
application, context.Transaction.RemoteCertificate, policy, context.CancellationToken))
{
context.Logger.LogInformation(6283, SR.GetResourceString(SR.ID6283), context.ClientId);
@ -1481,9 +1481,9 @@ public static partial class OpenIddictServerHandlers
}
if (await _applicationManager.GetPublicKeyInfrastructureTlsClientAuthenticationPolicyAsync(
application, context.Options.PublicKeyInfrastructureTlsClientAuthenticationPolicy) is not X509ChainPolicy policy ||
application, context.Options.PublicKeyInfrastructureTlsClientAuthenticationPolicy, context.CancellationToken) is not X509ChainPolicy policy ||
!await _applicationManager.ValidatePublicKeyInfrastructureTlsClientCertificateAsync(
application, context.Transaction.RemoteCertificate, policy))
application, context.Transaction.RemoteCertificate, policy, context.CancellationToken))
{
context.Logger.LogInformation(6284, SR.GetResourceString(SR.ID6284), context.ClientId);
@ -2663,10 +2663,10 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0008));
}
var token = await _tokenManager.FindByIdAsync(identifier);
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken);
if (token is not null)
{
await _tokenManager.TryRejectAsync(token);
await _tokenManager.TryRejectAsync(token, context.CancellationToken);
}
}
}
@ -2719,10 +2719,10 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0009));
}
var token = await _tokenManager.FindByIdAsync(identifier);
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken);
if (token is not null)
{
await _tokenManager.TryRejectAsync(token);
await _tokenManager.TryRejectAsync(token, context.CancellationToken);
}
}
}
@ -2988,7 +2988,7 @@ public static partial class OpenIddictServerHandlers
return;
}
var token = await _tokenManager.FindByIdAsync(identifier);
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken);
if (token is null)
{
return;
@ -2998,10 +2998,10 @@ public static partial class OpenIddictServerHandlers
// errors returned while trying to mark the entry as redeemed (that may be caused by concurrent requests).
if (context.EndpointType is OpenIddictServerEndpointType.Token && context.Request.IsRefreshTokenGrantType())
{
await _tokenManager.TryRedeemAsync(token);
await _tokenManager.TryRedeemAsync(token, context.CancellationToken);
}
else if (!await _tokenManager.TryRedeemAsync(token))
else if (!await _tokenManager.TryRedeemAsync(token, context.CancellationToken))
{
context.Reject(
error: Errors.InvalidToken,
@ -3483,16 +3483,16 @@ public static partial class OpenIddictServerHandlers
// If the client application is known, associate it to the authorization.
if (!string.IsNullOrEmpty(context.Request.ClientId))
{
var application = await _applicationManager.FindByClientIdAsync(context.Request.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.Request.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
descriptor.ApplicationId = await _applicationManager.GetIdAsync(application);
descriptor.ApplicationId = await _applicationManager.GetIdAsync(application, context.CancellationToken);
}
var authorization = await _authorizationManager.CreateAsync(descriptor)
var authorization = await _authorizationManager.CreateAsync(descriptor, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0018));
var identifier = await _authorizationManager.GetIdAsync(authorization);
var identifier = await _authorizationManager.GetIdAsync(authorization, context.CancellationToken);
if (string.IsNullOrEmpty(context.Request.ClientId))
{
@ -3610,10 +3610,10 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
var settings = await _applicationManager.GetSettingsAsync(application);
var settings = await _applicationManager.GetSettingsAsync(application, context.CancellationToken);
if (settings.TryGetValue(Settings.TokenLifetimes.AccessToken, out string? setting) &&
TimeSpan.TryParse(setting, CultureInfo.InvariantCulture, out var value))
{
@ -3744,10 +3744,10 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
var settings = await _applicationManager.GetSettingsAsync(application);
var settings = await _applicationManager.GetSettingsAsync(application, context.CancellationToken);
if (settings.TryGetValue(Settings.TokenLifetimes.AuthorizationCode, out string? setting) &&
TimeSpan.TryParse(setting, CultureInfo.InvariantCulture, out var value))
{
@ -3868,10 +3868,10 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
var settings = await _applicationManager.GetSettingsAsync(application);
var settings = await _applicationManager.GetSettingsAsync(application, context.CancellationToken);
if (settings.TryGetValue(Settings.TokenLifetimes.DeviceCode, out string? setting) &&
TimeSpan.TryParse(setting, CultureInfo.InvariantCulture, out var value))
{
@ -4084,7 +4084,7 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
var name = context.IssuedTokenType switch
@ -4096,7 +4096,7 @@ public static partial class OpenIddictServerHandlers
_ => Settings.TokenLifetimes.IssuedToken
};
var settings = await _applicationManager.GetSettingsAsync(application);
var settings = await _applicationManager.GetSettingsAsync(application, context.CancellationToken);
if (settings.TryGetValue(name, out string? setting) &&
TimeSpan.TryParse(setting, CultureInfo.InvariantCulture, out var value))
{
@ -4178,7 +4178,7 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
// Note: refresh tokens are only bound to the provided certificate when the client
@ -4186,7 +4186,7 @@ public static partial class OpenIddictServerHandlers
// are already sender-constrained via standard client authentication, which is more
// flexible than certificate-based token binding, as rotating client credentials is
// easier in that case (specially when using PKI-based mTLS client authentication).
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public, context.CancellationToken))
{
principal.SetClaim(Claims.Confirmation, CreateConfirmationClaim(certificate));
}
@ -4274,10 +4274,10 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
var settings = await _applicationManager.GetSettingsAsync(application);
var settings = await _applicationManager.GetSettingsAsync(application, context.CancellationToken);
if (settings.TryGetValue(Settings.TokenLifetimes.RequestToken, out string? setting) &&
TimeSpan.TryParse(setting, CultureInfo.InvariantCulture, out var value))
{
@ -4419,10 +4419,10 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
var settings = await _applicationManager.GetSettingsAsync(application);
var settings = await _applicationManager.GetSettingsAsync(application, context.CancellationToken);
if (settings.TryGetValue(Settings.TokenLifetimes.RefreshToken, out string? setting) &&
TimeSpan.TryParse(setting, CultureInfo.InvariantCulture, out var value))
{
@ -4472,7 +4472,7 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
// Note: refresh tokens are only bound to the provided certificate when the client
@ -4480,7 +4480,7 @@ public static partial class OpenIddictServerHandlers
// are already sender-constrained via standard client authentication, which is more
// flexible than certificate-based token binding, as rotating client credentials is
// easier in that case (specially when using PKI-based mTLS client authentication).
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public))
if (await _applicationManager.HasClientTypeAsync(application, ClientTypes.Public, context.CancellationToken))
{
principal.SetClaim(Claims.Confirmation, CreateConfirmationClaim(certificate));
}
@ -4594,10 +4594,10 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
var settings = await _applicationManager.GetSettingsAsync(application);
var settings = await _applicationManager.GetSettingsAsync(application, context.CancellationToken);
if (settings.TryGetValue(Settings.TokenLifetimes.IdentityToken, out string? setting) &&
TimeSpan.TryParse(setting, CultureInfo.InvariantCulture, out var value))
{
@ -4718,10 +4718,10 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0016));
}
var application = await _applicationManager.FindByClientIdAsync(context.ClientId)
var application = await _applicationManager.FindByClientIdAsync(context.ClientId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0017));
var settings = await _applicationManager.GetSettingsAsync(application);
var settings = await _applicationManager.GetSettingsAsync(application, context.CancellationToken);
if (settings.TryGetValue(Settings.TokenLifetimes.UserCode, out string? setting) &&
TimeSpan.TryParse(setting, CultureInfo.InvariantCulture, out var value))
{
@ -5255,13 +5255,13 @@ public static partial class OpenIddictServerHandlers
throw new InvalidOperationException(SR.GetResourceString(SR.ID0008));
}
var token = await _tokenManager.FindByIdAsync(identifier)
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0265));
// Replace the device code details by the payload derived from the new device code principal,
// that includes all the user claims populated by the application after authenticating the user.
var descriptor = new OpenIddictTokenDescriptor();
await _tokenManager.PopulateAsync(descriptor, token);
await _tokenManager.PopulateAsync(descriptor, token, context.CancellationToken);
// Note: the lifetime is deliberately extended to give more time to the client to redeem the code.
descriptor.ExpirationDate = context.DeviceCodePrincipal.GetExpirationDate();
@ -5270,9 +5270,9 @@ public static partial class OpenIddictServerHandlers
descriptor.Status = Statuses.Valid;
descriptor.Subject = context.DeviceCodePrincipal.GetClaim(Claims.Subject);
await _tokenManager.UpdateAsync(token, descriptor);
await _tokenManager.UpdateAsync(token, descriptor, context.CancellationToken);
context.Logger.LogTrace(6021, SR.GetResourceString(SR.ID6021), await _tokenManager.GetIdAsync(token));
context.Logger.LogTrace(6021, SR.GetResourceString(SR.ID6021), await _tokenManager.GetIdAsync(token, context.CancellationToken));
}
}
@ -5850,14 +5850,14 @@ public static partial class OpenIddictServerHandlers
return;
}
var token = await _tokenManager.FindByIdAsync(identifier);
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken);
if (token is null)
{
return;
}
// Mark the token as redeemed to prevent future reuses.
await _tokenManager.TryRedeemAsync(token);
await _tokenManager.TryRedeemAsync(token, context.CancellationToken);
}
}

8
src/OpenIddict.Server/OpenIddictServerTransaction.cs

@ -17,14 +17,8 @@ namespace OpenIddict.Server;
public sealed class OpenIddictServerTransaction
{
/// <summary>
/// Gets or sets the cancellation token that will be
/// used to determine if the operation was aborted.
/// Gets or sets the cancellation token used to determine if the operation was aborted.
/// </summary>
/// <remarks>
/// Note: for security reasons, this property shouldn't be used by event
/// handlers to abort security-sensitive operations. As such, it is
/// recommended to use this property only for user-dependent operations.
/// </remarks>
public CancellationToken CancellationToken { get; set; }
/// <summary>

26
src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandler.cs

@ -42,13 +42,23 @@ public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandle
/// <inheritdoc/>
public async Task<bool> HandleRequestAsync()
{
// Note: to ensure internal operations are not immediately cancelled when the request is aborted
// (which may represent a security risk if sensitive operations are in progress), an ad-hoc token
// source is always created and configured to be triggered 5 seconds after the request is aborted.
var source = new CancellationTokenSource();
var registration = Context.RequestAborted.Register(static state =>
((CancellationTokenSource) state!).CancelAfter(TimeSpan.FromSeconds(5)), source);
Response.RegisterForDispose(source);
Response.RegisterForDispose(registration);
// Note: the transaction may be already attached when replaying an ASP.NET Core request
// (e.g when using the built-in status code pages middleware with the re-execute mode).
var transaction = Context.Features.Get<OpenIddictValidationAspNetCoreFeature>()?.Transaction;
if (transaction is null)
{
// Create a new transaction and attach the HTTP request to make it available to the ASP.NET Core handlers.
transaction = await _factory.CreateTransactionAsync();
transaction = await _factory.CreateTransactionAsync(source.Token);
transaction.Properties[typeof(HttpRequest).FullName!] = new WeakReference<HttpRequest>(Request);
// Attach the OpenIddict validation transaction to the ASP.NET Core features
@ -56,11 +66,7 @@ public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandle
Context.Features.Set(new OpenIddictValidationAspNetCoreFeature { Transaction = transaction });
}
var context = new ProcessRequestContext(transaction)
{
CancellationToken = Context.RequestAborted
};
var context = new ProcessRequestContext(transaction);
await _dispatcher.DispatchAsync(context);
if (context.IsRequestHandled)
@ -77,7 +83,6 @@ public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandle
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Context.RequestAborted,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -114,10 +119,7 @@ public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandle
var context = transaction.GetProperty<ProcessAuthenticationContext>(typeof(ProcessAuthenticationContext).FullName!);
if (context is null)
{
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = Context.RequestAborted
});
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction));
// Store the context object in the transaction so it can be later retrieved by handlers
// that want to access the authentication result without triggering a new authentication flow.
@ -214,7 +216,6 @@ public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandle
var context = new ProcessChallengeContext(transaction)
{
CancellationToken = Context.RequestAborted,
Response = new OpenIddictResponse()
};
@ -229,7 +230,6 @@ public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandle
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Context.RequestAborted,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,

2
src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs

@ -332,7 +332,7 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
// If a client certificate was used during the TLS handshake, attach it to the context.
if (request.IsHttps && await request.HttpContext.Connection.GetClientCertificateAsync(
request.HttpContext.RequestAborted) is X509Certificate2 certificate)
context.CancellationToken) is X509Certificate2 certificate)
{
context.Transaction.RemoteCertificate = certificate;
}

26
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandler.cs

@ -37,13 +37,23 @@ public sealed class OpenIddictValidationOwinHandler : AuthenticationHandler<Auth
/// <inheritdoc/>
protected override async Task InitializeCoreAsync()
{
// Note: to ensure internal operations are not immediately cancelled when the request is aborted
// (which may represent a security risk if sensitive operations are in progress), an ad-hoc token
// source is always created and configured to be triggered 5 seconds after the request is aborted.
var source = new CancellationTokenSource();
var registration = Request.CallCancelled.Register(static state =>
((CancellationTokenSource) state!).CancelAfter(TimeSpan.FromSeconds(5)), source);
Response.OnSendingHeaders(static state => ((CancellationTokenSource) state!).Dispose(), source);
Response.OnSendingHeaders(static state => ((CancellationTokenRegistration) state!).Dispose(), registration);
// Note: the transaction may be already attached when replaying an OWIN request
// (e.g when using a status code pages middleware re-invoking the OWIN pipeline).
var transaction = Context.Get<OpenIddictValidationTransaction>(typeof(OpenIddictValidationTransaction).FullName);
if (transaction is null)
{
// Create a new transaction and attach the OWIN request to make it available to the OWIN handlers.
transaction = await _factory.CreateTransactionAsync();
transaction = await _factory.CreateTransactionAsync(source.Token);
transaction.Properties[typeof(IOwinRequest).FullName!] = new WeakReference<IOwinRequest>(Request);
// Attach the OpenIddict validation transaction to the OWIN shared dictionary
@ -51,11 +61,7 @@ public sealed class OpenIddictValidationOwinHandler : AuthenticationHandler<Auth
Context.Set(typeof(OpenIddictValidationTransaction).FullName, transaction);
}
var context = new ProcessRequestContext(transaction)
{
CancellationToken = Request.CallCancelled
};
var context = new ProcessRequestContext(transaction);
await _dispatcher.DispatchAsync(context);
// Store the context in the transaction so that it can be retrieved from InvokeAsync().
@ -89,7 +95,6 @@ public sealed class OpenIddictValidationOwinHandler : AuthenticationHandler<Auth
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Request.CallCancelled,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,
@ -126,10 +131,7 @@ public sealed class OpenIddictValidationOwinHandler : AuthenticationHandler<Auth
var context = transaction.GetProperty<ProcessAuthenticationContext>(typeof(ProcessAuthenticationContext).FullName!);
if (context is null)
{
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction)
{
CancellationToken = Request.CallCancelled
});
await _dispatcher.DispatchAsync(context = new ProcessAuthenticationContext(transaction));
// Store the context object in the transaction so it can be later retrieved by handlers
// that want to access the authentication result without triggering a new authentication flow.
@ -222,7 +224,6 @@ public sealed class OpenIddictValidationOwinHandler : AuthenticationHandler<Auth
var context = new ProcessChallengeContext(transaction)
{
CancellationToken = Request.CallCancelled,
Response = new OpenIddictResponse()
};
@ -237,7 +238,6 @@ public sealed class OpenIddictValidationOwinHandler : AuthenticationHandler<Auth
{
var notification = new ProcessErrorContext(transaction)
{
CancellationToken = Request.CallCancelled,
Error = context.Error ?? Errors.InvalidRequest,
ErrorDescription = context.ErrorDescription,
ErrorUri = context.ErrorUri,

8
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs

@ -334,18 +334,20 @@ public static partial class OpenIddictValidationOwinHandlers
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0120));
// If a client certificate was used during the TLS handshake, attach it to the context.
if (request.IsSecure && await GetClientCertificateAsync(request.Context) is X509Certificate2 certificate)
if (request.IsSecure && await GetClientCertificateAsync(request.Context,
context.CancellationToken) is X509Certificate2 certificate)
{
context.Transaction.RemoteCertificate = certificate;
}
static async ValueTask<X509Certificate2?> GetClientCertificateAsync(IOwinContext context)
static async ValueTask<X509Certificate2?> GetClientCertificateAsync(
IOwinContext context, CancellationToken cancellationToken)
{
// If a loading function was provided by the OWIN host, always invoke it before trying
// to resolve the certificate to ensure it is present in the environment dictionary.
if (context.Get<Func<Task>>("ssl.LoadClientCertAsync") is Func<Task> loader)
{
await loader();
await loader().WaitAsync(cancellationToken);
}
return context.Get<X509Certificate>("ssl.ClientCertificate") is X509Certificate certificate

14
src/OpenIddict.Validation.SystemNetHttp/OpenIddictValidationSystemNetHttpHandlers.cs

@ -607,7 +607,7 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
else if (string.Equals(encoding, ContentEncodings.Gzip, StringComparison.OrdinalIgnoreCase))
{
stream ??= await response.Content.ReadAsStreamAsync();
stream ??= await response.Content.ReadAsStreamAsync().WaitAsync(context.CancellationToken);
stream = new GZipStream(stream, CompressionMode.Decompress);
}
@ -621,13 +621,13 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
// For more information, read https://www.rfc-editor.org/rfc/rfc9110.html#name-deflate-coding.
else if (string.Equals(encoding, ContentEncodings.Deflate, StringComparison.OrdinalIgnoreCase))
{
stream ??= await response.Content.ReadAsStreamAsync();
stream ??= await response.Content.ReadAsStreamAsync().WaitAsync(context.CancellationToken);
stream = new ZLibStream(stream, CompressionMode.Decompress);
}
else if (string.Equals(encoding, ContentEncodings.Brotli, StringComparison.OrdinalIgnoreCase))
{
stream ??= await response.Content.ReadAsStreamAsync();
stream ??= await response.Content.ReadAsStreamAsync().WaitAsync(context.CancellationToken);
stream = new BrotliStream(stream, CompressionMode.Decompress);
}
#endif
@ -651,7 +651,7 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
// (e.g if the JSON deserialization process fails, the stream is read as a string
// during a second pass a second time for logging/debuggability purposes).
var content = new StreamContent(stream);
await content.LoadIntoBufferAsync();
await content.LoadIntoBufferAsync(context.CancellationToken);
// Copy the headers from the original content to the new instance.
foreach (var header in response.Content.Headers)
@ -724,7 +724,7 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
catch (Exception exception) when (!OpenIddictHelpers.IsFatal(exception))
{
context.Logger.LogError(6183, exception, SR.GetResourceString(SR.ID6183),
await response.Content.ReadAsStringAsync());
await response.Content.ReadAsStringAsync(context.CancellationToken));
context.Reject(
error: Errors.ServerError,
@ -902,7 +902,7 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
if (!response.IsSuccessStatusCode && string.IsNullOrEmpty(context.Transaction.Response?.Error))
{
context.Logger.LogError(6184, SR.GetResourceString(SR.ID6184), response.StatusCode,
await response.Content.ReadAsStringAsync());
await response.Content.ReadAsStringAsync(context.CancellationToken));
context.Reject(
error: (int) response.StatusCode switch
@ -926,7 +926,7 @@ public static partial class OpenIddictValidationSystemNetHttpHandlers
if (context.Transaction.Response is null)
{
context.Logger.LogError(6185, SR.GetResourceString(SR.ID6185), response.StatusCode,
response.Content.Headers.ContentType, await response.Content.ReadAsStringAsync());
response.Content.Headers.ContentType, await response.Content.ReadAsStringAsync(context.CancellationToken));
context.Reject(
error: Errors.ServerError,

6
src/OpenIddict.Validation/IOpenIddictValidationFactory.cs

@ -18,9 +18,13 @@ public interface IOpenIddictValidationFactory
/// Creates a new <see cref="OpenIddictValidationTransaction"/> that is used as a
/// way to store per-request data needed to process the requested operation.
/// </summary>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <remarks>
/// Note: the specified <see cref="CancellationToken"/> is automatically attached to the returned transaction.
/// </remarks>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous
/// operation, whose result returns the created transaction.
/// </returns>
ValueTask<OpenIddictValidationTransaction> CreateTransactionAsync();
ValueTask<OpenIddictValidationTransaction> CreateTransactionAsync(CancellationToken cancellationToken);
}

2
src/OpenIddict.Validation/OpenIddictValidationDispatcher.cs

@ -40,6 +40,8 @@ public sealed class OpenIddictValidationDispatcher : IOpenIddictValidationDispat
await foreach (var handler in GetHandlersAsync())
{
context.CancellationToken.ThrowIfCancellationRequested();
try
{
await handler.HandleAsync(context);

14
src/OpenIddict.Validation/OpenIddictValidationEvents.cs

@ -31,19 +31,9 @@ public static partial class OpenIddictValidationEvents
public OpenIddictValidationTransaction Transaction { get; }
/// <summary>
/// Gets or sets the cancellation token that will be
/// used to determine if the operation was aborted.
/// Gets the cancellation token used to determine if the operation was aborted.
/// </summary>
/// <remarks>
/// Note: for security reasons, this property shouldn't be used by event
/// handlers to abort security-sensitive operations. As such, it is
/// recommended to use this property only for user-dependent operations.
/// </remarks>
public CancellationToken CancellationToken
{
get => Transaction.CancellationToken;
set => Transaction.CancellationToken = value;
}
public CancellationToken CancellationToken => Transaction.CancellationToken;
/// <summary>
/// Gets or sets the endpoint type that handled the request, if applicable.

12
src/OpenIddict.Validation/OpenIddictValidationFactory.cs

@ -31,10 +31,18 @@ public sealed class OpenIddictValidationFactory : IOpenIddictValidationFactory
}
/// <inheritdoc/>
public ValueTask<OpenIddictValidationTransaction> CreateTransactionAsync()
=> new(new OpenIddictValidationTransaction
public ValueTask<OpenIddictValidationTransaction> CreateTransactionAsync(CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested)
{
return new(Task.FromCanceled<OpenIddictValidationTransaction>(cancellationToken));
}
return new(new OpenIddictValidationTransaction
{
CancellationToken = cancellationToken,
Logger = _logger,
Options = _options.CurrentValue
});
}
}

34
src/OpenIddict.Validation/OpenIddictValidationHandlers.Protection.cs

@ -220,7 +220,7 @@ public static partial class OpenIddictValidationHandlers
}
// If the reference token cannot be found, don't return an error to allow another handler to validate it.
var token = await _tokenManager.FindByReferenceIdAsync(context.Token);
var token = await _tokenManager.FindByReferenceIdAsync(context.Token, context.CancellationToken);
if (token is null)
{
return;
@ -230,8 +230,8 @@ public static partial class OpenIddictValidationHandlers
if (!(context.ValidTokenTypes.Count switch
{
0 => true, // If no specific token type is expected, accept all token types at this stage.
1 => await _tokenManager.HasTypeAsync(token, context.ValidTokenTypes.ElementAt(0)),
_ => await _tokenManager.HasTypeAsync(token, [.. context.ValidTokenTypes])
1 => await _tokenManager.HasTypeAsync(token, context.ValidTokenTypes.ElementAt(0), context.CancellationToken),
_ => await _tokenManager.HasTypeAsync(token, [.. context.ValidTokenTypes], context.CancellationToken)
}))
{
context.Reject(
@ -242,7 +242,7 @@ public static partial class OpenIddictValidationHandlers
return;
}
var payload = await _tokenManager.GetPayloadAsync(token);
var payload = await _tokenManager.GetPayloadAsync(token, context.CancellationToken);
if (string.IsNullOrEmpty(payload))
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0026));
@ -253,7 +253,7 @@ public static partial class OpenIddictValidationHandlers
// used to restore the properties associated with the token.
context.IsReferenceToken = true;
context.Token = payload;
context.TokenId = await _tokenManager.GetIdAsync(token);
context.TokenId = await _tokenManager.GetIdAsync(token, context.CancellationToken);
}
}
@ -562,7 +562,7 @@ public static partial class OpenIddictValidationHandlers
}
// If the token entry cannot be found, return a generic error.
var token = await _tokenManager.FindByIdAsync(identifier);
var token = await _tokenManager.FindByIdAsync(identifier, context.CancellationToken);
if (token is null)
{
context.Reject(
@ -576,9 +576,9 @@ public static partial class OpenIddictValidationHandlers
// If the token was not validated as a reference token but has a reference identifier attached, this
// may indicate that the payload stored in the database has leaked and is being used as a regular,
// non-reference token. To prevent this, reject the token if the reference identifier is not null.
if (!context.IsReferenceToken && !string.IsNullOrEmpty(await _tokenManager.GetReferenceIdAsync(token)))
if (!context.IsReferenceToken && !string.IsNullOrEmpty(await _tokenManager.GetReferenceIdAsync(token, context.CancellationToken)))
{
context.Logger.LogWarning(6292, SR.GetResourceString(SR.ID6292), await _tokenManager.GetIdAsync(token));
context.Logger.LogWarning(6292, SR.GetResourceString(SR.ID6292), await _tokenManager.GetIdAsync(token, context.CancellationToken));
context.Reject(
error: Errors.InvalidToken,
@ -590,11 +590,11 @@ public static partial class OpenIddictValidationHandlers
// Restore the creation/expiration dates/identifiers from the token entry metadata.
context.Principal
.SetCreationDate(await _tokenManager.GetCreationDateAsync(token))
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token))
.SetAuthorizationId(context.AuthorizationId = await _tokenManager.GetAuthorizationIdAsync(token))
.SetTokenId(context.TokenId = await _tokenManager.GetIdAsync(token))
.SetTokenType(await _tokenManager.GetTypeAsync(token));
.SetCreationDate(await _tokenManager.GetCreationDateAsync(token, context.CancellationToken))
.SetExpirationDate(await _tokenManager.GetExpirationDateAsync(token, context.CancellationToken))
.SetAuthorizationId(context.AuthorizationId = await _tokenManager.GetAuthorizationIdAsync(token, context.CancellationToken))
.SetTokenId(context.TokenId = await _tokenManager.GetIdAsync(token, context.CancellationToken))
.SetTokenType(await _tokenManager.GetTypeAsync(token, context.CancellationToken));
}
}
@ -922,10 +922,10 @@ public static partial class OpenIddictValidationHandlers
Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
Debug.Assert(!string.IsNullOrEmpty(context.TokenId), SR.GetResourceString(SR.ID4017));
var token = await _tokenManager.FindByIdAsync(context.TokenId)
var token = await _tokenManager.FindByIdAsync(context.TokenId, context.CancellationToken)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0021));
if (!await _tokenManager.HasStatusAsync(token, Statuses.Valid))
if (!await _tokenManager.HasStatusAsync(token, Statuses.Valid, context.CancellationToken))
{
context.Logger.LogInformation(6005, SR.GetResourceString(SR.ID6005), context.TokenId);
@ -972,8 +972,8 @@ public static partial class OpenIddictValidationHandlers
Debug.Assert(context.Principal is { Identity: ClaimsIdentity }, SR.GetResourceString(SR.ID4006));
Debug.Assert(!string.IsNullOrEmpty(context.AuthorizationId), SR.GetResourceString(SR.ID4018));
var authorization = await _authorizationManager.FindByIdAsync(context.AuthorizationId);
if (authorization is null || !await _authorizationManager.HasStatusAsync(authorization, Statuses.Valid))
var authorization = await _authorizationManager.FindByIdAsync(context.AuthorizationId, context.CancellationToken);
if (authorization is null || !await _authorizationManager.HasStatusAsync(authorization, Statuses.Valid, context.CancellationToken))
{
context.Logger.LogInformation(6006, SR.GetResourceString(SR.ID6006), context.AuthorizationId);

12
src/OpenIddict.Validation/OpenIddictValidationService.cs

@ -47,7 +47,7 @@ public class OpenIddictValidationService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictValidationDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictValidationFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
var context = new ProcessAuthenticationContext(transaction)
{
@ -92,7 +92,7 @@ public class OpenIddictValidationService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictValidationDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictValidationFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
var request = new OpenIddictRequest();
request = await PrepareConfigurationRequestAsync();
@ -214,7 +214,7 @@ public class OpenIddictValidationService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictValidationDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictValidationFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
var request = new OpenIddictRequest();
request = await PrepareJsonWebKeySetRequestAsync();
@ -344,7 +344,7 @@ public class OpenIddictValidationService
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictValidationDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictValidationFactory>();
var transaction = await factory.CreateTransactionAsync();
var transaction = await factory.CreateTransactionAsync(cancellationToken);
request = await PrepareIntrospectionRequestAsync();
request = await ApplyIntrospectionRequestAsync();
@ -357,7 +357,6 @@ public class OpenIddictValidationService
{
var context = new PrepareIntrospectionRequestContext(transaction)
{
CancellationToken = cancellationToken,
ClientAuthenticationMethod = method,
Configuration = configuration,
RemoteUri = uri,
@ -381,7 +380,6 @@ public class OpenIddictValidationService
{
var context = new ApplyIntrospectionRequestContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Configuration = configuration,
Request = request
@ -405,7 +403,6 @@ public class OpenIddictValidationService
{
var context = new ExtractIntrospectionResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Configuration = configuration,
Request = request
@ -431,7 +428,6 @@ public class OpenIddictValidationService
{
var context = new HandleIntrospectionResponseContext(transaction)
{
CancellationToken = cancellationToken,
RemoteUri = uri,
Configuration = configuration,
Request = request,

8
src/OpenIddict.Validation/OpenIddictValidationTransaction.cs

@ -17,14 +17,8 @@ namespace OpenIddict.Validation;
public sealed class OpenIddictValidationTransaction
{
/// <summary>
/// Gets or sets the cancellation token that will be
/// used to determine if the operation was aborted.
/// Gets or sets the cancellation token used to determine if the operation was aborted.
/// </summary>
/// <remarks>
/// Note: for security reasons, this property shouldn't be used by event
/// handlers to abort security-sensitive operations. As such, it is
/// recommended to use this property only for user-dependent operations.
/// </remarks>
public CancellationToken CancellationToken { get; set; }
/// <summary>

Loading…
Cancel
Save