Browse Source

Revamp the access token extraction logic used in the validation stack

pull/1004/head
Kévin Chalet 6 years ago
parent
commit
675037fe6d
  1. 1
      src/OpenIddict.Server/OpenIddictServerHandlers.cs
  2. 134
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
  3. 135
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
  4. 25
      src/OpenIddict.Validation/OpenIddictValidationHandlers.cs
  5. 70
      src/OpenIddict.Validation/OpenIddictValidationService.cs

1
src/OpenIddict.Server/OpenIddictServerHandlers.cs

@ -446,6 +446,7 @@ namespace OpenIddict.Server
var parameters = context.Options.TokenValidationParameters.Clone();
parameters.ValidIssuer ??= context.Issuer?.AbsoluteUri;
parameters.ValidateIssuer = !string.IsNullOrEmpty(parameters.ValidIssuer);
parameters.ValidTypes = context.TokenType switch
{
// If no specific token type is expected, accept all token types at this stage.

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

@ -9,7 +9,6 @@ using System.Collections.Generic;
using System.Collections.Immutable;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Encodings.Web;
using System.Text.Json;
@ -20,8 +19,8 @@ using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Validation.AspNetCore.OpenIddictValidationAspNetCoreHandlerFilters;
using static OpenIddict.Validation.OpenIddictValidationEvents;
@ -37,8 +36,13 @@ namespace OpenIddict.Validation.AspNetCore
* Request top-level processing:
*/
InferIssuerFromHost.Descriptor,
ExtractGetOrPostRequest.Descriptor,
ExtractAccessToken.Descriptor,
/*
* Authentication processing:
*/
ExtractAccessTokenFromAuthorizationHeader.Descriptor,
ExtractAccessTokenFromBodyForm.Descriptor,
ExtractAccessTokenFromQueryString.Descriptor,
/*
* Challenge processing:
@ -132,19 +136,19 @@ namespace OpenIddict.Validation.AspNetCore
}
/// <summary>
/// Contains the logic responsible of extracting OpenID Connect requests from GET or POST HTTP requests.
/// Contains the logic responsible of extracting the access token from the standard HTTP Authorization header.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public class ExtractGetOrPostRequest : IOpenIddictValidationHandler<ProcessRequestContext>
public class ExtractAccessTokenFromAuthorizationHeader : IOpenIddictValidationHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireHttpRequest>()
.UseSingletonHandler<ExtractGetOrPostRequest>()
.SetOrder(InferIssuerFromHost.Descriptor.Order + 1_000)
.UseSingletonHandler<ExtractAccessTokenFromAuthorizationHeader>()
.SetOrder(int.MinValue + 50_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
@ -155,13 +159,19 @@ namespace OpenIddict.Validation.AspNetCore
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async ValueTask HandleAsync([NotNull] ProcessRequestContext context)
public ValueTask HandleAsync([NotNull] ProcessAuthenticationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// If a token was already resolved, don't overwrite it.
if (!string.IsNullOrEmpty(context.Token))
{
return default;
}
// This handler only applies to ASP.NET Core requests. If the HTTP context cannot be resolved,
// this may indicate that the request was incorrectly processed by another server stack.
var request = context.Transaction.GetHttpRequest();
@ -170,38 +180,99 @@ namespace OpenIddict.Validation.AspNetCore
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved.");
}
if (HttpMethods.IsGet(request.Method))
// Resolve the access token from the standard Authorization header.
// See https://tools.ietf.org/html/rfc6750#section-2.1 for more information.
string header = request.Headers[HeaderNames.Authorization];
if (!string.IsNullOrEmpty(header) && header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
{
context.Token = header.Substring("Bearer ".Length);
context.TokenType = TokenTypeHints.AccessToken;
return default;
}
return default;
}
}
/// <summary>
/// Contains the logic responsible of extracting the access token from the standard access_token form parameter.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public class ExtractAccessTokenFromBodyForm : IOpenIddictValidationHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireHttpRequest>()
.UseSingletonHandler<ExtractAccessTokenFromBodyForm>()
.SetOrder(ExtractAccessTokenFromAuthorizationHeader.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <summary>
/// Processes the event.
/// </summary>
/// <param name="context">The context associated with the event to process.</param>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async ValueTask HandleAsync([NotNull] ProcessAuthenticationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// If a token was already resolved, don't overwrite it.
if (!string.IsNullOrEmpty(context.Token))
{
context.Request = new OpenIddictRequest(request.Query);
return;
}
else if (HttpMethods.IsPost(request.Method) && !string.IsNullOrEmpty(request.ContentType) &&
request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
// This handler only applies to ASP.NET Core requests. If the HTTP context cannot be resolved,
// this may indicate that the request was incorrectly processed by another server stack.
var request = context.Transaction.GetHttpRequest();
if (request == null)
{
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved.");
}
if (string.IsNullOrEmpty(request.ContentType) ||
!request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
{
context.Request = new OpenIddictRequest(await request.ReadFormAsync(request.HttpContext.RequestAborted));
return;
}
else
// Resolve the access token from the standard access_token form parameter.
// See https://tools.ietf.org/html/rfc6750#section-2.2 for more information.
var form = await request.ReadFormAsync(request.HttpContext.RequestAborted);
if (form.TryGetValue(Parameters.AccessToken, out StringValues token))
{
context.Request = new OpenIddictRequest();
context.Token = token;
context.TokenType = TokenTypeHints.AccessToken;
return;
}
}
}
/// <summary>
/// Contains the logic responsible of extracting an access token from the standard HTTP Authorization header.
/// Contains the logic responsible of extracting the access token from the standard access_token query parameter.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by ASP.NET Core.
/// </summary>
public class ExtractAccessToken : IOpenIddictValidationHandler<ProcessRequestContext>
public class ExtractAccessTokenFromQueryString : IOpenIddictValidationHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireHttpRequest>()
.UseSingletonHandler<ExtractAccessToken>()
.SetOrder(ExtractGetOrPostRequest.Descriptor.Order + 1_000)
.UseSingletonHandler<ExtractAccessTokenFromQueryString>()
.SetOrder(ExtractAccessTokenFromBodyForm.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
@ -212,13 +283,19 @@ namespace OpenIddict.Validation.AspNetCore
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public ValueTask HandleAsync([NotNull] ProcessRequestContext context)
public ValueTask HandleAsync([NotNull] ProcessAuthenticationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// If a token was already resolved, don't overwrite it.
if (!string.IsNullOrEmpty(context.Token))
{
return default;
}
// This handler only applies to ASP.NET Core requests. If the HTTP context cannot be resolved,
// this may indicate that the request was incorrectly processed by another server stack.
var request = context.Transaction.GetHttpRequest();
@ -227,15 +304,16 @@ namespace OpenIddict.Validation.AspNetCore
throw new InvalidOperationException("The ASP.NET Core HTTP request cannot be resolved.");
}
string header = request.Headers[HeaderNames.Authorization];
if (string.IsNullOrEmpty(header) || !header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
// Resolve the access token from the standard access_token query parameter.
// See https://tools.ietf.org/html/rfc6750#section-2.3 for more information.
if (request.Query.TryGetValue(Parameters.AccessToken, out StringValues token))
{
context.Token = token;
context.TokenType = TokenTypeHints.AccessToken;
return default;
}
// Attach the access token to the request message.
context.Request.AccessToken = header.Substring("Bearer ".Length);
return default;
}
}

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

@ -17,7 +17,6 @@ using JetBrains.Annotations;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Owin.Security;
using OpenIddict.Abstractions;
using Owin;
using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Validation.OpenIddictValidationEvents;
@ -34,8 +33,13 @@ namespace OpenIddict.Validation.Owin
* Request top-level processing:
*/
InferIssuerFromHost.Descriptor,
ExtractGetOrPostRequest.Descriptor,
ExtractAccessToken.Descriptor,
/*
* Authentication processing:
*/
ExtractAccessTokenFromAuthorizationHeader.Descriptor,
ExtractAccessTokenFromBodyForm.Descriptor,
ExtractAccessTokenFromQueryString.Descriptor,
/*
* Challenge processing:
@ -129,19 +133,19 @@ namespace OpenIddict.Validation.Owin
}
/// <summary>
/// Contains the logic responsible of extracting OpenID Connect requests from GET or POST HTTP requests.
/// Contains the logic responsible of extracting the access token from the standard HTTP Authorization header.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary>
public class ExtractGetOrPostRequest : IOpenIddictValidationHandler<ProcessRequestContext>
public class ExtractAccessTokenFromAuthorizationHeader : IOpenIddictValidationHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireOwinRequest>()
.UseSingletonHandler<ExtractGetOrPostRequest>()
.SetOrder(InferIssuerFromHost.Descriptor.Order + 1_000)
.UseSingletonHandler<ExtractAccessTokenFromAuthorizationHeader>()
.SetOrder(int.MinValue + 50_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
@ -152,13 +156,19 @@ namespace OpenIddict.Validation.Owin
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async ValueTask HandleAsync([NotNull] ProcessRequestContext context)
public ValueTask HandleAsync([NotNull] ProcessAuthenticationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// If a token was already resolved, don't overwrite it.
if (!string.IsNullOrEmpty(context.Token))
{
return default;
}
// This handler only applies to OWIN requests. If The OWIN request cannot be resolved,
// this may indicate that the request was incorrectly processed by another server stack.
var request = context.Transaction.GetOwinRequest();
@ -167,39 +177,100 @@ namespace OpenIddict.Validation.Owin
throw new InvalidOperationException("The OWIN request cannot be resolved.");
}
if (string.Equals(request.Method, "GET", StringComparison.OrdinalIgnoreCase))
// Resolve the access token from the standard Authorization header.
// See https://tools.ietf.org/html/rfc6750#section-2.1 for more information.
string header = request.Headers["Authorization"];
if (!string.IsNullOrEmpty(header) && header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
{
context.Token = header.Substring("Bearer ".Length);
context.TokenType = TokenTypeHints.AccessToken;
return default;
}
return default;
}
}
/// <summary>
/// Contains the logic responsible of extracting the access token from the standard access_token form parameter.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary>
public class ExtractAccessTokenFromBodyForm : IOpenIddictValidationHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireOwinRequest>()
.UseSingletonHandler<ExtractAccessTokenFromBodyForm>()
.SetOrder(ExtractAccessTokenFromAuthorizationHeader.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
/// <summary>
/// Processes the event.
/// </summary>
/// <param name="context">The context associated with the event to process.</param>
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public async ValueTask HandleAsync([NotNull] ProcessAuthenticationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// If a token was already resolved, don't overwrite it.
if (!string.IsNullOrEmpty(context.Token))
{
context.Request = new OpenIddictRequest(request.Query);
return;
}
else if (string.Equals(request.Method, "POST", StringComparison.OrdinalIgnoreCase) &&
!string.IsNullOrEmpty(request.ContentType) &&
request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
// This handler only applies to OWIN requests. If The OWIN request cannot be resolved,
// this may indicate that the request was incorrectly processed by another server stack.
var request = context.Transaction.GetOwinRequest();
if (request == null)
{
throw new InvalidOperationException("The OWIN request cannot be resolved.");
}
if (string.IsNullOrEmpty(request.ContentType) ||
!request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase))
{
context.Request = new OpenIddictRequest(await request.ReadFormAsync());
return;
}
else
// Resolve the access token from the standard access_token form parameter.
// See https://tools.ietf.org/html/rfc6750#section-2.2 for more information.
var form = await request.ReadFormAsync();
string token = form[Parameters.AccessToken];
if (!string.IsNullOrEmpty(token))
{
context.Request = new OpenIddictRequest();
context.Token = token;
context.TokenType = TokenTypeHints.AccessToken;
return;
}
}
}
/// <summary>
/// Contains the logic responsible of extracting an access token from the standard HTTP Authorization header.
/// Contains the logic responsible of extracting the access token from the standard access_token query parameter.
/// Note: this handler is not used when the OpenID Connect request is not initially handled by OWIN.
/// </summary>
public class ExtractAccessToken : IOpenIddictValidationHandler<ProcessRequestContext>
public class ExtractAccessTokenFromQueryString : IOpenIddictValidationHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessRequestContext>()
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireOwinRequest>()
.UseSingletonHandler<ExtractAccessToken>()
.SetOrder(ExtractGetOrPostRequest.Descriptor.Order + 1_000)
.UseSingletonHandler<ExtractAccessTokenFromQueryString>()
.SetOrder(ExtractAccessTokenFromBodyForm.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
@ -210,13 +281,19 @@ namespace OpenIddict.Validation.Owin
/// <returns>
/// A <see cref="ValueTask"/> that can be used to monitor the asynchronous operation.
/// </returns>
public ValueTask HandleAsync([NotNull] ProcessRequestContext context)
public ValueTask HandleAsync([NotNull] ProcessAuthenticationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
// If a token was already resolved, don't overwrite it.
if (!string.IsNullOrEmpty(context.Token))
{
return default;
}
// This handler only applies to OWIN requests. If The OWIN request cannot be resolved,
// this may indicate that the request was incorrectly processed by another server stack.
var request = context.Transaction.GetOwinRequest();
@ -225,15 +302,17 @@ namespace OpenIddict.Validation.Owin
throw new InvalidOperationException("The OWIN request cannot be resolved.");
}
string header = request.Headers["Authorization"];
if (string.IsNullOrEmpty(header) || !header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
// Resolve the access token from the standard access_token query parameter.
// See https://tools.ietf.org/html/rfc6750#section-2.3 for more information.
string token = request.Query[Parameters.AccessToken];
if (!string.IsNullOrEmpty(token))
{
context.Token = token;
context.TokenType = TokenTypeHints.AccessToken;
return default;
}
// Attach the access token to the request message.
context.Request.AccessToken = header.Substring("Bearer ".Length);
return default;
}
}

25
src/OpenIddict.Validation/OpenIddictValidationHandlers.cs

@ -30,7 +30,7 @@ namespace OpenIddict.Validation
/*
* Authentication processing:
*/
ValidateAccessTokenParameter.Descriptor,
ValidateToken.Descriptor,
ValidateReferenceTokenIdentifier.Descriptor,
ValidateIdentityModelToken.Descriptor,
IntrospectToken.Descriptor,
@ -52,16 +52,16 @@ namespace OpenIddict.Validation
.AddRange(Introspection.DefaultHandlers);
/// <summary>
/// Contains the logic responsible of validating the access token resolved from the current request.
/// Contains the logic responsible of ensuring a token was correctly resolved from the context.
/// </summary>
public class ValidateAccessTokenParameter : IOpenIddictValidationHandler<ProcessAuthenticationContext>
public class ValidateToken : IOpenIddictValidationHandler<ProcessAuthenticationContext>
{
/// <summary>
/// Gets the default descriptor definition assigned to this handler.
/// </summary>
public static OpenIddictValidationHandlerDescriptor Descriptor { get; }
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.UseSingletonHandler<ValidateAccessTokenParameter>()
.UseSingletonHandler<ValidateToken>()
.SetOrder(int.MinValue + 100_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
@ -80,18 +80,22 @@ namespace OpenIddict.Validation
throw new ArgumentNullException(nameof(context));
}
if (string.IsNullOrEmpty(context.Request.AccessToken))
// Note: unlike the equivalent event in the server stack, authentication can be triggered for
// arbitrary requests (typically, API endpoints that are not owned by the validation stack).
// As such, the token is not directly resolved from the request, that may be null at this stage.
// Instead, the token is expected to be populated by one or multiple handlers provided by the host.
//
// Note: this event can also be triggered by the validation service to validate an arbitrary token.
if (string.IsNullOrEmpty(context.Token))
{
context.Reject(
error: Errors.MissingToken,
description: "The access token is missing.");
description: "The security token is missing.");
return default;
}
context.Token = context.Request.AccessToken;
context.TokenType = TokenTypeHints.AccessToken;
return default;
}
}
@ -121,7 +125,7 @@ namespace OpenIddict.Validation
.AddFilter<RequireLocalValidation>()
.AddFilter<RequireTokenEntryValidationEnabled>()
.UseScopedHandler<ValidateReferenceTokenIdentifier>()
.SetOrder(ValidateAccessTokenParameter.Descriptor.Order + 1_000)
.SetOrder(ValidateToken.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
.Build();
@ -223,6 +227,7 @@ namespace OpenIddict.Validation
// OpenID Connect server configuration (that can be static or retrieved using discovery).
var parameters = context.Options.TokenValidationParameters.Clone();
parameters.ValidIssuer ??= configuration.Issuer ?? context.Issuer?.AbsoluteUri;
parameters.ValidateIssuer = !string.IsNullOrEmpty(parameters.ValidIssuer);
// Combine the signing keys registered statically in the token validation parameters
// with the signing keys resolved from the OpenID Connect server configuration.

70
src/OpenIddict.Validation/OpenIddictValidationService.cs

@ -14,6 +14,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
using OpenIddict.Abstractions;
using static OpenIddict.Abstractions.OpenIddictConstants;
using static OpenIddict.Validation.OpenIddictValidationEvents;
namespace OpenIddict.Validation
@ -568,5 +569,74 @@ namespace OpenIddict.Validation
}
}
}
/// <summary>
/// Validates the specified access token and returns the principal extracted from the token.
/// </summary>
/// <param name="token">The access token to validate.</param>
/// <param name="cancellationToken">The <see cref="CancellationToken"/> that can be used to abort the operation.</param>
/// <returns>The principal containing the claims extracted from the token.</returns>
public async ValueTask<ClaimsPrincipal> ValidateAccessTokenAsync(
[NotNull] string token, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(token))
{
throw new ArgumentException("The access token cannot be null or empty.", nameof(token));
}
cancellationToken.ThrowIfCancellationRequested();
// Note: this service is registered as a singleton service. As such, it cannot
// directly depend on scoped services like the validation provider. To work around
// this limitation, a scope is manually created for each method to this service.
var scope = _provider.CreateScope();
// Note: a try/finally block is deliberately used here to ensure the service scope
// can be disposed of asynchronously if it implements IAsyncDisposable.
try
{
var dispatcher = scope.ServiceProvider.GetRequiredService<IOpenIddictValidationDispatcher>();
var factory = scope.ServiceProvider.GetRequiredService<IOpenIddictValidationFactory>();
var transaction = await factory.CreateTransactionAsync();
var context = new ProcessAuthenticationContext(transaction)
{
Token = token,
TokenType = TokenTypeHints.AccessToken
};
await dispatcher.DispatchAsync(context);
if (context.IsRejected)
{
var message = new StringBuilder()
.AppendLine("An error occurred while validating the access token.")
.AppendFormat("Error: {0}", context.Error ?? "(not available)")
.AppendLine()
.AppendFormat("Error description: {0}", context.ErrorDescription ?? "(not available)")
.AppendLine()
.AppendFormat("Error URI: {0}", context.ErrorUri ?? "(not available)")
.ToString();
throw new OpenIddictExceptions.GenericException(message,
context.Error, context.ErrorDescription, context.ErrorUri);
}
return context.Principal;
}
finally
{
if (scope is IAsyncDisposable disposable)
{
await disposable.DisposeAsync();
}
else
{
scope.Dispose();
}
}
}
}
}

Loading…
Cancel
Save