Browse Source

Update the OpenIddict validation ASP.NET Core and OWIN hosts to allow controlling access token extraction

pull/2077/head
Kévin Chalet 2 years ago
parent
commit
d657bdf34a
  1. 24
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreBuilder.cs
  2. 3
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreExtensions.cs
  3. 70
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlerFilters.cs
  4. 3
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlers.cs
  5. 21
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreOptions.cs
  6. 24
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinBuilder.cs
  7. 3
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinExtensions.cs
  8. 70
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlerFilters.cs
  9. 4
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlers.cs
  10. 21
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinOptions.cs
  11. 2
      src/OpenIddict.Validation.ServerIntegration/OpenIddictValidationServerIntegrationConfiguration.cs

24
src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreBuilder.cs

@ -46,6 +46,30 @@ public sealed class OpenIddictValidationAspNetCoreBuilder
return this;
}
/// <summary>
/// Prevents OpenIddict from extracting access tokens from the standard "Authorization" header.
/// </summary>
/// <remarks>
/// Disabling access token extraction from the "Authorization" header is NOT recommended.
/// </remarks>
/// <returns>The <see cref="OpenIddictValidationAspNetCoreBuilder"/> instance.</returns>
public OpenIddictValidationAspNetCoreBuilder DisableAccessTokenExtractionFromAuthorizationHeader()
=> Configure(options => options.DisableAccessTokenExtractionFromAuthorizationHeader = true);
/// <summary>
/// Prevents OpenIddict from extracting access tokens from the standard "access_token" body form parameter.
/// </summary>
/// <returns>The <see cref="OpenIddictValidationAspNetCoreBuilder"/> instance.</returns>
public OpenIddictValidationAspNetCoreBuilder DisableAccessTokenExtractionFromBodyForm()
=> Configure(options => options.DisableAccessTokenExtractionFromBodyForm = true);
/// <summary>
/// Prevents OpenIddict from extracting access tokens from the standard "access_token" query string parameter.
/// </summary>
/// <returns>The <see cref="OpenIddictValidationAspNetCoreBuilder"/> instance.</returns>
public OpenIddictValidationAspNetCoreBuilder DisableAccessTokenExtractionFromQueryString()
=> Configure(options => options.DisableAccessTokenExtractionFromQueryString = true);
/// <summary>
/// Sets the realm returned to the caller as part of the WWW-Authenticate header.
/// </summary>

3
src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreExtensions.cs

@ -38,6 +38,9 @@ public static class OpenIddictValidationAspNetCoreExtensions
builder.Services.TryAdd(OpenIddictValidationAspNetCoreHandlers.DefaultHandlers.Select(descriptor => descriptor.ServiceDescriptor));
// Register the built-in filters used by the default OpenIddict ASP.NET Core validation event handlers.
builder.Services.TryAddSingleton<RequireAccessTokenExtractionFromAuthorizationHeaderEnabled>();
builder.Services.TryAddSingleton<RequireAccessTokenExtractionFromBodyFormEnabled>();
builder.Services.TryAddSingleton<RequireAccessTokenExtractionFromQueryStringEnabled>();
builder.Services.TryAddSingleton<RequireHttpRequest>();
// Register the option initializer used by the OpenIddict ASP.NET Core validation integration services.

70
src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandlerFilters.cs

@ -6,6 +6,7 @@
using System.ComponentModel;
using Microsoft.AspNetCore;
using Microsoft.Extensions.Options;
namespace OpenIddict.Validation.AspNetCore;
@ -15,6 +16,75 @@ namespace OpenIddict.Validation.AspNetCore;
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static class OpenIddictValidationAspNetCoreHandlerFilters
{
/// <summary>
/// Represents a filter that excludes the associated handlers if
/// access token extraction from the Authorization header was disabled.
/// </summary>
public sealed class RequireAccessTokenExtractionFromAuthorizationHeaderEnabled : IOpenIddictValidationHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictValidationAspNetCoreOptions> _options;
public RequireAccessTokenExtractionFromAuthorizationHeaderEnabled(IOptionsMonitor<OpenIddictValidationAspNetCoreOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(!_options.CurrentValue.DisableAccessTokenExtractionFromAuthorizationHeader);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if access token
/// extraction from the "access_token" body form parameter was disabled.
/// </summary>
public sealed class RequireAccessTokenExtractionFromBodyFormEnabled : IOpenIddictValidationHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictValidationAspNetCoreOptions> _options;
public RequireAccessTokenExtractionFromBodyFormEnabled(IOptionsMonitor<OpenIddictValidationAspNetCoreOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(!_options.CurrentValue.DisableAccessTokenExtractionFromBodyForm);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if access token
/// extraction from the "access_token" query string parameter was disabled.
/// </summary>
public sealed class RequireAccessTokenExtractionFromQueryStringEnabled : IOpenIddictValidationHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictValidationAspNetCoreOptions> _options;
public RequireAccessTokenExtractionFromQueryStringEnabled(IOptionsMonitor<OpenIddictValidationAspNetCoreOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(!_options.CurrentValue.DisableAccessTokenExtractionFromQueryString);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if no ASP.NET Core request can be found.
/// </summary>

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

@ -182,6 +182,7 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireHttpRequest>()
.AddFilter<RequireAccessTokenExtracted>()
.AddFilter<RequireAccessTokenExtractionFromAuthorizationHeaderEnabled>()
.UseSingletonHandler<ExtractAccessTokenFromAuthorizationHeader>()
.SetOrder(EvaluateValidatedTokens.Descriptor.Order + 500)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
@ -233,6 +234,7 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireHttpRequest>()
.AddFilter<RequireAccessTokenExtracted>()
.AddFilter<RequireAccessTokenExtractionFromBodyFormEnabled>()
.UseSingletonHandler<ExtractAccessTokenFromBodyForm>()
.SetOrder(ExtractAccessTokenFromAuthorizationHeader.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
@ -288,6 +290,7 @@ public static partial class OpenIddictValidationAspNetCoreHandlers
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireHttpRequest>()
.AddFilter<RequireAccessTokenExtracted>()
.AddFilter<RequireAccessTokenExtractionFromQueryStringEnabled>()
.UseSingletonHandler<ExtractAccessTokenFromQueryString>()
.SetOrder(ExtractAccessTokenFromBodyForm.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)

21
src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreOptions.cs

@ -11,6 +11,27 @@ namespace OpenIddict.Validation.AspNetCore;
/// </summary>
public sealed class OpenIddictValidationAspNetCoreOptions : AuthenticationSchemeOptions
{
/// <summary>
/// Gets or sets a boolean indicating whether the built-in logic extracting
/// access tokens from the standard "Authorization" header should be disabled.
/// </summary>
/// <remarks>
/// Disabling access token extraction from the "Authorization" header is NOT recommended.
/// </remarks>
public bool DisableAccessTokenExtractionFromAuthorizationHeader { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the built-in logic extracting access
/// tokens from the standard "access_token" body form parameter should be disabled.
/// </summary>
public bool DisableAccessTokenExtractionFromBodyForm { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the built-in logic extracting access
/// tokens from the standard "access_token" query string parameter should be disabled.
/// </summary>
public bool DisableAccessTokenExtractionFromQueryString { get; set; }
/// <summary>
/// Gets or sets the optional "realm" value returned to the caller as part of the WWW-Authenticate header.
/// </summary>

24
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinBuilder.cs

@ -46,6 +46,30 @@ public sealed class OpenIddictValidationOwinBuilder
return this;
}
/// <summary>
/// Prevents OpenIddict from extracting access tokens from the standard "Authorization" header.
/// </summary>
/// <remarks>
/// Disabling access token extraction from the "Authorization" header is NOT recommended.
/// </remarks>
/// <returns>The <see cref="OpenIddictValidationOwinBuilder"/> instance.</returns>
public OpenIddictValidationOwinBuilder DisableAccessTokenExtractionFromAuthorizationHeader()
=> Configure(options => options.DisableAccessTokenExtractionFromAuthorizationHeader = true);
/// <summary>
/// Prevents OpenIddict from extracting access tokens from the standard "access_token" body form parameter.
/// </summary>
/// <returns>The <see cref="OpenIddictValidationOwinBuilder"/> instance.</returns>
public OpenIddictValidationOwinBuilder DisableAccessTokenExtractionFromBodyForm()
=> Configure(options => options.DisableAccessTokenExtractionFromBodyForm = true);
/// <summary>
/// Prevents OpenIddict from extracting access tokens from the standard "access_token" query string parameter.
/// </summary>
/// <returns>The <see cref="OpenIddictValidationOwinBuilder"/> instance.</returns>
public OpenIddictValidationOwinBuilder DisableAccessTokenExtractionFromQueryString()
=> Configure(options => options.DisableAccessTokenExtractionFromQueryString = true);
/// <summary>
/// Configures the OpenIddict validation OWIN integration to use active authentication.
/// When using active authentication, the principal resolved from the access token is

3
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinExtensions.cs

@ -39,6 +39,9 @@ public static class OpenIddictValidationOwinExtensions
builder.Services.TryAdd(OpenIddictValidationOwinHandlers.DefaultHandlers.Select(descriptor => descriptor.ServiceDescriptor));
// Register the built-in filters used by the default OpenIddict OWIN validation event handlers.
builder.Services.TryAddSingleton<RequireAccessTokenExtractionFromAuthorizationHeaderEnabled>();
builder.Services.TryAddSingleton<RequireAccessTokenExtractionFromBodyFormEnabled>();
builder.Services.TryAddSingleton<RequireAccessTokenExtractionFromQueryStringEnabled>();
builder.Services.TryAddSingleton<RequireOwinRequest>();
// Register the option initializers used by the OpenIddict OWIN validation integration services.

70
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandlerFilters.cs

@ -4,6 +4,7 @@
* the license and the contributors participating to this project.
*/
using Microsoft.Extensions.Options;
using Owin;
namespace OpenIddict.Validation.Owin;
@ -13,6 +14,75 @@ namespace OpenIddict.Validation.Owin;
/// </summary>
public static class OpenIddictValidationOwinHandlerFilters
{
/// <summary>
/// Represents a filter that excludes the associated handlers if
/// access token extraction from the Authorization header was disabled.
/// </summary>
public sealed class RequireAccessTokenExtractionFromAuthorizationHeaderEnabled : IOpenIddictValidationHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictValidationOwinOptions> _options;
public RequireAccessTokenExtractionFromAuthorizationHeaderEnabled(IOptionsMonitor<OpenIddictValidationOwinOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(!_options.CurrentValue.DisableAccessTokenExtractionFromAuthorizationHeader);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if access token
/// extraction from the "access_token" body form parameter was disabled.
/// </summary>
public sealed class RequireAccessTokenExtractionFromBodyFormEnabled : IOpenIddictValidationHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictValidationOwinOptions> _options;
public RequireAccessTokenExtractionFromBodyFormEnabled(IOptionsMonitor<OpenIddictValidationOwinOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(!_options.CurrentValue.DisableAccessTokenExtractionFromBodyForm);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if access token
/// extraction from the "access_token" query string parameter was disabled.
/// </summary>
public sealed class RequireAccessTokenExtractionFromQueryStringEnabled : IOpenIddictValidationHandlerFilter<BaseContext>
{
private readonly IOptionsMonitor<OpenIddictValidationOwinOptions> _options;
public RequireAccessTokenExtractionFromQueryStringEnabled(IOptionsMonitor<OpenIddictValidationOwinOptions> options)
=> _options = options ?? throw new ArgumentNullException(nameof(options));
/// <inheritdoc/>
public ValueTask<bool> IsActiveAsync(BaseContext context)
{
if (context is null)
{
throw new ArgumentNullException(nameof(context));
}
return new(!_options.CurrentValue.DisableAccessTokenExtractionFromQueryString);
}
}
/// <summary>
/// Represents a filter that excludes the associated handlers if no OWIN request can be found.
/// </summary>

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

@ -31,6 +31,7 @@ public static partial class OpenIddictValidationOwinHandlers
/*
* Authentication processing:
*/
ValidateHostHeader.Descriptor,
ExtractAccessTokenFromAuthorizationHeader.Descriptor,
ExtractAccessTokenFromBodyForm.Descriptor,
ExtractAccessTokenFromQueryString.Descriptor,
@ -181,6 +182,7 @@ public static partial class OpenIddictValidationOwinHandlers
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireOwinRequest>()
.AddFilter<RequireAccessTokenExtracted>()
.AddFilter<RequireAccessTokenExtractionFromAuthorizationHeaderEnabled>()
.UseSingletonHandler<ExtractAccessTokenFromAuthorizationHeader>()
.SetOrder(EvaluateValidatedTokens.Descriptor.Order + 500)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
@ -232,6 +234,7 @@ public static partial class OpenIddictValidationOwinHandlers
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireOwinRequest>()
.AddFilter<RequireAccessTokenExtracted>()
.AddFilter<RequireAccessTokenExtractionFromBodyFormEnabled>()
.UseSingletonHandler<ExtractAccessTokenFromBodyForm>()
.SetOrder(ExtractAccessTokenFromAuthorizationHeader.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)
@ -288,6 +291,7 @@ public static partial class OpenIddictValidationOwinHandlers
= OpenIddictValidationHandlerDescriptor.CreateBuilder<ProcessAuthenticationContext>()
.AddFilter<RequireOwinRequest>()
.AddFilter<RequireAccessTokenExtracted>()
.AddFilter<RequireAccessTokenExtractionFromQueryStringEnabled>()
.UseSingletonHandler<ExtractAccessTokenFromQueryString>()
.SetOrder(ExtractAccessTokenFromBodyForm.Descriptor.Order + 1_000)
.SetType(OpenIddictValidationHandlerType.BuiltIn)

21
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinOptions.cs

@ -18,6 +18,27 @@ public sealed class OpenIddictValidationOwinOptions : AuthenticationOptions
: base(OpenIddictValidationOwinDefaults.AuthenticationType)
=> AuthenticationMode = AuthenticationMode.Passive;
/// <summary>
/// Gets or sets a boolean indicating whether the built-in logic extracting
/// access tokens from the standard "Authorization" header should be disabled.
/// </summary>
/// <remarks>
/// Disabling access token extraction from the "Authorization" header is NOT recommended.
/// </remarks>
public bool DisableAccessTokenExtractionFromAuthorizationHeader { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the built-in logic extracting access
/// tokens from the standard "access_token" body form parameter should be disabled.
/// </summary>
public bool DisableAccessTokenExtractionFromBodyForm { get; set; }
/// <summary>
/// Gets or sets a boolean indicating whether the built-in logic extracting access
/// tokens from the standard "access_token" query string parameter should be disabled.
/// </summary>
public bool DisableAccessTokenExtractionFromQueryString { get; set; }
/// <summary>
/// Gets or sets the optional "realm" value returned to the caller as part of the WWW-Authenticate header.
/// </summary>

2
src/OpenIddict.Validation.ServerIntegration/OpenIddictValidationServerIntegrationConfiguration.cs

@ -63,7 +63,7 @@ public sealed class OpenIddictValidationServerIntegrationConfiguration : IConfig
throw new ArgumentNullException(nameof(options));
}
if (options.ValidationType != OpenIddictValidationType.Direct)
if (options.ValidationType is not OpenIddictValidationType.Direct)
{
throw new InvalidOperationException(SR.GetResourceString(SR.ID0170));
}

Loading…
Cancel
Save