Browse Source

Decouple the ASP.NET Core/OWIN integration options from the authentication scheme options

pull/2479/head
Kévin Chalet 4 months ago
parent
commit
fff7694505
  1. 6
      sandbox/OpenIddict.Sandbox.AspNet.Client/Web.config
  2. 6
      sandbox/OpenIddict.Sandbox.AspNet.Server/Web.config
  3. 20
      src/OpenIddict.Abstractions/OpenIddictResources.resx
  4. 4
      src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreHandler.cs
  5. 2
      src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreOptions.cs
  6. 5
      src/OpenIddict.Client.Owin/OpenIddictClientOwinConfiguration.cs
  7. 1
      src/OpenIddict.Client.Owin/OpenIddictClientOwinExtensions.cs
  8. 47
      src/OpenIddict.Client.Owin/OpenIddictClientOwinHandler.cs
  9. 52
      src/OpenIddict.Client.Owin/OpenIddictClientOwinMiddleware.cs
  10. 13
      src/OpenIddict.Client.Owin/OpenIddictClientOwinMiddlewareFactory.cs
  11. 9
      src/OpenIddict.Client.Owin/OpenIddictClientOwinOptions.cs
  12. 4
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreHandler.cs
  13. 2
      src/OpenIddict.Server.AspNetCore/OpenIddictServerAspNetCoreOptions.cs
  14. 18
      src/OpenIddict.Server.Owin/OpenIddictServerOwinConfiguration.cs
  15. 4
      src/OpenIddict.Server.Owin/OpenIddictServerOwinExtensions.cs
  16. 2
      src/OpenIddict.Server.Owin/OpenIddictServerOwinHandler.cs
  17. 39
      src/OpenIddict.Server.Owin/OpenIddictServerOwinMiddleware.cs
  18. 13
      src/OpenIddict.Server.Owin/OpenIddictServerOwinMiddlewareFactory.cs
  19. 9
      src/OpenIddict.Server.Owin/OpenIddictServerOwinOptions.cs
  20. 4
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreHandler.cs
  21. 2
      src/OpenIddict.Validation.AspNetCore/OpenIddictValidationAspNetCoreOptions.cs
  22. 1
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinExtensions.cs
  23. 2
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinHandler.cs
  24. 43
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinMiddleware.cs
  25. 13
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinMiddlewareFactory.cs
  26. 11
      src/OpenIddict.Validation.Owin/OpenIddictValidationOwinOptions.cs

6
sandbox/OpenIddict.Sandbox.AspNet.Client/Web.config

@ -100,12 +100,6 @@
<bindingRedirect oldVersion="0.0.0.0-4.2.4.0" newVersion="4.2.4.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />

6
sandbox/OpenIddict.Sandbox.AspNet.Server/Web.config

@ -124,12 +124,6 @@
<bindingRedirect oldVersion="0.0.0.0-4.2.4.0" newVersion="4.2.4.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
</assemblyBinding>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" />

20
src/OpenIddict.Abstractions/OpenIddictResources.resx

@ -497,10 +497,6 @@ This may indicate that the event handler responsible for processing OpenID Conne
<data name="ID0115" xml:space="preserve">
<value>Only strings, booleans, integers, arrays of strings and instances of type 'OpenIddictParameter', 'JsonElement' or derived from 'JsonNode' can be returned as custom parameters.</value>
</data>
<data name="ID0119" xml:space="preserve">
<value>The OpenIddict OWIN server handler cannot be used as an active authentication handler.
Make sure that 'OpenIddictServerOwinOptions.AuthenticationMode' is not set to 'Active'.</value>
</data>
<data name="ID0120" xml:space="preserve">
<value>The OWIN request cannot be resolved.</value>
</data>
@ -510,8 +506,8 @@ For the OpenIddict server services to work correctly, a per-request 'IServicePro
Note: when using a dependency injection container supporting middleware resolution (like Autofac), the 'app.UseOpenIddictServer()' extension MUST NOT be called.</value>
</data>
<data name="ID0122" xml:space="preserve">
<value>The OpenIddict server services cannot be resolved from the DI container.
To register the server services, use 'services.AddOpenIddict().AddServer()'.</value>
<value>The authentication handler used by the OpenIddict server components cannot be resolved from the DI container.
To register the OWIN integration, use 'services.AddOpenIddict().AddServer().UseOwin()'.</value>
</data>
<data name="ID0123" xml:space="preserve">
<value>Audiences cannot be null or empty.</value>
@ -702,8 +698,8 @@ For the OpenIddict validation services to work correctly, a per-request 'IServic
Note: when using a dependency injection container supporting middleware resolution (like Autofac), the 'app.UseOpenIddictValidation()' extension MUST NOT be called.</value>
</data>
<data name="ID0169" xml:space="preserve">
<value>The OpenIddict validation services cannot be resolved from the DI container.
To register the validation services, use 'services.AddOpenIddict().AddValidation()'.</value>
<value>The authentication handler used by the OpenIddict validation components cannot be resolved from the DI container.
To register the OWIN integration, use 'services.AddOpenIddict().AddValidation().UseOwin()'.</value>
</data>
<data name="ID0170" xml:space="preserve">
<value>The local server integration can only be used with direct validation.</value>
@ -1097,10 +1093,6 @@ This may indicate that it was not properly registered in the dependency injectio
<data name="ID0313" xml:space="preserve">
<value>A discovery client must be registered when using server discovery.
Reference the 'OpenIddict.Client.SystemNetHttp' package and call 'services.AddOpenIddict().AddClient().UseSystemNetHttp()' to register the default System.Net.Http-based integration.</value>
</data>
<data name="ID0314" xml:space="preserve">
<value>The OpenIddict OWIN client handler cannot be used as an active authentication handler.
Make sure that 'OpenIddictClientOwinOptions.AuthenticationMode' is not set to 'Active'.</value>
</data>
<data name="ID0315" xml:space="preserve">
<value>An error occurred while retrieving the OpenIddict client context. On ASP.NET Core, this may indicate that the authentication middleware was not registered early enough in the request pipeline. Make sure that 'app.UseAuthentication()' is registered before 'app.UseAuthorization()' and 'app.UseEndpoints()' (or 'app.UseMvc()') and try again.</value>
@ -1111,8 +1103,8 @@ For the OpenIddict client services to work correctly, a per-request 'IServicePro
Note: when using a dependency injection container supporting middleware resolution (like Autofac), the 'app.UseOpenIddictClient()' extension MUST NOT be called.</value>
</data>
<data name="ID0317" xml:space="preserve">
<value>The OpenIddict client services cannot be resolved from the DI container.
To register the client services, use 'services.AddOpenIddict().AddClient()'.</value>
<value>The authentication handler used by the OpenIddict client components cannot be resolved from the DI container.
To register the OWIN integration, use 'services.AddOpenIddict().AddClient().UseOwin()'.</value>
</data>
<data name="ID0318" xml:space="preserve">
<value>The core services must be registered when enabling the OpenIddict client feature.

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

@ -19,7 +19,7 @@ namespace OpenIddict.Client.AspNetCore;
/// Provides the logic necessary to extract, validate and handle OpenID Connect requests.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<OpenIddictClientAspNetCoreOptions>,
public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<AuthenticationSchemeOptions>,
IAuthenticationRequestHandler,
IAuthenticationSignOutHandler
{
@ -32,7 +32,7 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Op
public OpenIddictClientAspNetCoreHandler(
IOpenIddictClientDispatcher dispatcher,
IOpenIddictClientFactory factory,
IOptionsMonitor<OpenIddictClientAspNetCoreOptions> options,
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder)
: base(options, logger, encoder)

2
src/OpenIddict.Client.AspNetCore/OpenIddictClientAspNetCoreOptions.cs

@ -11,7 +11,7 @@ namespace OpenIddict.Client.AspNetCore;
/// <summary>
/// Provides various settings needed to configure the OpenIddict ASP.NET Core client integration.
/// </summary>
public sealed class OpenIddictClientAspNetCoreOptions : AuthenticationSchemeOptions
public sealed class OpenIddictClientAspNetCoreOptions
{
/// <summary>
/// Gets or sets a boolean indicating whether the static client registrations with a non-null

5
src/OpenIddict.Client.Owin/OpenIddictClientOwinConfiguration.cs

@ -100,11 +100,6 @@ public sealed class OpenIddictClientOwinConfiguration : IConfigureOptions<OpenId
var builder = new ValidateOptionsResultBuilder();
if (options.AuthenticationMode is AuthenticationMode.Active)
{
builder.AddError(SR.GetResourceString(SR.ID0314));
}
// Ensure multiple client registrations don't share the same provider
// name when automatic authentication type forwarding is enabled.
if (!options.DisableAutomaticAuthenticationTypeForwarding)

1
src/OpenIddict.Client.Owin/OpenIddictClientOwinExtensions.cs

@ -31,6 +31,7 @@ public static class OpenIddictClientOwinExtensions
// Note: unlike regular OWIN middleware, the OpenIddict client middleware is registered
// as a scoped service in the DI container. This allows containers that support middleware
// resolution (like Autofac) to use it without requiring additional configuration.
builder.Services.TryAddScoped<OpenIddictClientOwinHandler>();
builder.Services.TryAddScoped<OpenIddictClientOwinMiddleware>();
// Register the built-in event handlers used by the OpenIddict OWIN client components.

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

@ -10,6 +10,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using Microsoft.Extensions.Options;
using Microsoft.Owin.Security.Infrastructure;
using static OpenIddict.Client.Owin.OpenIddictClientOwinConstants;
using Properties = OpenIddict.Client.Owin.OpenIddictClientOwinConstants.Properties;
@ -20,22 +21,26 @@ namespace OpenIddict.Client.Owin;
/// Provides the entry point necessary to register the OpenIddict client in an OWIN pipeline.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddictClientOwinOptions>
public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<AuthenticationOptions>
{
private readonly IOpenIddictClientDispatcher _dispatcher;
private readonly IOpenIddictClientFactory _factory;
private readonly IOptionsMonitor<OpenIddictClientOwinOptions> _options;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictClientOwinHandler"/> class.
/// </summary>
/// <param name="dispatcher">The OpenIddict client dispatcher used by this instance.</param>
/// <param name="factory">The OpenIddict client factory used by this instance.</param>
/// <param name="options">The OpenIddict client OWIN options.</param>
public OpenIddictClientOwinHandler(
IOpenIddictClientDispatcher dispatcher,
IOpenIddictClientFactory factory)
IOpenIddictClientFactory factory,
IOptionsMonitor<OpenIddictClientOwinOptions> options)
{
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
_options = options ?? throw new ArgumentNullException(nameof(options));
}
/// <inheritdoc/>
@ -280,10 +285,14 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
// OpenIddictClientOwinMiddleware is assumed to be the only middleware allowed to write
// to the response stream when a response grant (sign-in/out or challenge) was applied.
var descriptions = _options.CurrentValue.ForwardedAuthenticationTypes;
// Note: unlike the ASP.NET Core host, the OWIN host MUST check whether the status code
// corresponds to a challenge response, as LookupChallenge() will always return a non-null
// value when active authentication is used, even if no challenge was actually triggered.
var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode) ?? LookupForwardedChallenge();
var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode)
?? LookupForwardedChallenge(Context.Authentication, descriptions);
if (challenge is not null && Response.StatusCode is 401 or 403)
{
var transaction = Context.Get<OpenIddictClientTransaction>(typeof(OpenIddictClientTransaction).FullName) ??
@ -327,7 +336,9 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
}
}
var signout = Helper.LookupSignOut(Options.AuthenticationType, Options.AuthenticationMode) ?? LookupForwardedSignOut();
var signout = Helper.LookupSignOut(Options.AuthenticationType, Options.AuthenticationMode)
?? LookupForwardedSignOut(Context.Authentication, descriptions);
if (signout is not null)
{
var transaction = Context.Get<OpenIddictClientTransaction>(typeof(OpenIddictClientTransaction).FullName) ??
@ -371,7 +382,8 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
}
}
AuthenticationResponseChallenge? LookupForwardedChallenge()
static AuthenticationResponseChallenge? LookupForwardedChallenge(
IAuthenticationManager manager, IReadOnlyList<AuthenticationDescription> descriptions)
{
// Note: unlike its server counterpart, the OpenIddict OWIN client authentication handler allows
// associating additional authentication types to trigger a provider-specific challenge. For that,
@ -379,14 +391,14 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
// managed by OpenIddict, a challenge pointing to the OpenIddict OWIN client authentication handler
// is dynamically forwarded with the appropriate provider name authentication property attached.
if (Context.Authentication.AuthenticationResponseChallenge?.AuthenticationTypes is { Length: > 0 } types)
if (manager.AuthenticationResponseChallenge?.AuthenticationTypes is { Length: > 0 } types)
{
foreach (var type in types)
{
if (TryGetForwardedAuthenticationType(type, out _))
if (TryGetForwardedAuthenticationType(descriptions, type, out _))
{
// Ensure no client registration information was attached to the authentication properties.
if (Context.Authentication.AuthenticationResponseChallenge.Properties is AuthenticationProperties properties &&
if (manager.AuthenticationResponseChallenge.Properties is AuthenticationProperties properties &&
(properties.Dictionary.ContainsKey(Properties.Issuer) ||
properties.Dictionary.ContainsKey(Properties.ProviderName) ||
properties.Dictionary.ContainsKey(Properties.RegistrationId)))
@ -397,7 +409,7 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
return new AuthenticationResponseChallenge(
authenticationTypes: [OpenIddictClientOwinDefaults.AuthenticationType],
properties : new AuthenticationProperties(dictionary: new Dictionary<string, string>(
Context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary ??
manager.AuthenticationResponseChallenge.Properties.Dictionary ??
ImmutableDictionary.Create<string, string>())
{
[Properties.ProviderName] = type
@ -409,7 +421,8 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
return null;
}
AuthenticationResponseRevoke? LookupForwardedSignOut()
static AuthenticationResponseRevoke? LookupForwardedSignOut(
IAuthenticationManager manager, IReadOnlyList<AuthenticationDescription> descriptions)
{
// Note: unlike its server counterpart, the OpenIddict OWIN client authentication handler allows
// associating additional authentication types to trigger a provider-specific sign-out. For that,
@ -417,14 +430,14 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
// managed by OpenIddict, a sign-out pointing to the OpenIddict OWIN client authentication handler
// is dynamically forwarded with the appropriate provider name authentication property attached.
if (Context.Authentication.AuthenticationResponseRevoke?.AuthenticationTypes is { Length: > 0 } types)
if (manager.AuthenticationResponseRevoke?.AuthenticationTypes is { Length: > 0 } types)
{
foreach (var type in types)
{
if (TryGetForwardedAuthenticationType(type, out _))
if (TryGetForwardedAuthenticationType(descriptions, type, out _))
{
// Ensure no client registration information was attached to the authentication properties.
if (Context.Authentication.AuthenticationResponseRevoke.Properties is AuthenticationProperties properties &&
if (manager.AuthenticationResponseRevoke.Properties is AuthenticationProperties properties &&
(properties.Dictionary.ContainsKey(Properties.Issuer) ||
properties.Dictionary.ContainsKey(Properties.ProviderName) ||
properties.Dictionary.ContainsKey(Properties.RegistrationId)))
@ -435,7 +448,7 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
return new AuthenticationResponseRevoke(
authenticationTypes: [OpenIddictClientOwinDefaults.AuthenticationType],
properties : new AuthenticationProperties(dictionary: new Dictionary<string, string>(
Context.Authentication.AuthenticationResponseRevoke.Properties.Dictionary ??
manager.AuthenticationResponseRevoke.Properties.Dictionary ??
ImmutableDictionary.Create<string, string>())
{
[Properties.ProviderName] = type
@ -448,10 +461,12 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
bool TryGetForwardedAuthenticationType(string type, [NotNullWhen(true)] out AuthenticationDescription? result)
static bool TryGetForwardedAuthenticationType(IReadOnlyList<AuthenticationDescription> descriptions,
string type, [NotNullWhen(true)] out AuthenticationDescription? result)
{
foreach (var description in Options.ForwardedAuthenticationTypes)
for (var index = 0; index < descriptions.Count; index++)
{
var description = descriptions[index];
if (string.Equals(description.AuthenticationType, type, StringComparison.Ordinal))
{
result = description;

52
src/OpenIddict.Client.Owin/OpenIddictClientOwinMiddleware.cs

@ -9,6 +9,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Security.Principal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Owin.Security.Infrastructure;
@ -32,34 +33,30 @@ using AuthenticateDelegate = Func<
/// it is NOT recommended to instantiate it as a singleton like a regular OWIN middleware.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictClientOwinMiddleware : AuthenticationMiddleware<OpenIddictClientOwinOptions>
public sealed class OpenIddictClientOwinMiddleware : AuthenticationMiddleware<AuthenticationOptions>
{
private readonly IOpenIddictClientDispatcher _dispatcher;
private readonly IOpenIddictClientFactory _factory;
private readonly IServiceProvider _provider;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictClientOwinMiddleware"/> class.
/// </summary>
/// <param name="next">The next middleware in the pipeline, if applicable.</param>
/// <param name="options">The OpenIddict client OWIN options.</param>
/// <param name="dispatcher">The OpenIddict client dispatcher.</param>
/// <param name="factory">The OpenIddict client factory.</param>
/// <param name="provider">The service provider.</param>
public OpenIddictClientOwinMiddleware(
OwinMiddleware? next,
IOptionsMonitor<OpenIddictClientOwinOptions> options,
IOpenIddictClientDispatcher dispatcher,
IOpenIddictClientFactory factory)
: base(next, options.CurrentValue)
{
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}
IServiceProvider provider)
: base(next, new InternalOptions())
=> _provider = provider ?? throw new ArgumentNullException(nameof(provider));
/// <inheritdoc/>
public override async Task Invoke(IOwinContext context)
{
ArgumentNullException.ThrowIfNull(context);
// Resolve the list of forwarded authentication types from the options.
var options = _provider.GetService<IOptionsMonitor<OpenIddictClientOwinOptions>>()
?.CurrentValue ?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0316));
// Retrieve the existing authentication delegate.
var function = context.Get<AuthenticateDelegate?>("security.Authenticate");
@ -73,7 +70,7 @@ public sealed class OpenIddictClientOwinMiddleware : AuthenticationMiddleware<Op
// In this case, iterate all the forwarded authentication types and call the callback action for each type.
if (types is null)
{
foreach (var description in Options.ForwardedAuthenticationTypes)
foreach (var description in options.ForwardedAuthenticationTypes)
{
callback(null, null, description.Properties, state);
}
@ -88,7 +85,7 @@ public sealed class OpenIddictClientOwinMiddleware : AuthenticationMiddleware<Op
// corresponding authentication middleware handle it if it matches a registered type.
if (string.IsNullOrEmpty(type) ||
string.Equals(type, OpenIddictClientOwinDefaults.AuthenticationType, StringComparison.Ordinal) ||
!TryGetForwardedAuthenticationType(type, out AuthenticationDescription? description))
!TryGetForwardedAuthenticationType(options.ForwardedAuthenticationTypes, type, out AuthenticationDescription? description))
{
continue;
}
@ -134,10 +131,12 @@ public sealed class OpenIddictClientOwinMiddleware : AuthenticationMiddleware<Op
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
bool TryGetForwardedAuthenticationType(string type, [NotNullWhen(true)] out AuthenticationDescription? result)
static bool TryGetForwardedAuthenticationType(IReadOnlyList<AuthenticationDescription> descriptions,
string type, [NotNullWhen(true)] out AuthenticationDescription? result)
{
foreach (var description in Options.ForwardedAuthenticationTypes)
for (var index = 0; index < descriptions.Count; index++)
{
var description = descriptions[index];
if (string.Equals(description.AuthenticationType, type, StringComparison.Ordinal))
{
result = description;
@ -154,6 +153,19 @@ public sealed class OpenIddictClientOwinMiddleware : AuthenticationMiddleware<Op
/// Creates and returns a new <see cref="OpenIddictClientOwinHandler"/> instance.
/// </summary>
/// <returns>A new instance of the <see cref="OpenIddictClientOwinHandler"/> class.</returns>
protected override AuthenticationHandler<OpenIddictClientOwinOptions> CreateHandler()
=> new OpenIddictClientOwinHandler(_dispatcher, _factory);
protected override AuthenticationHandler<AuthenticationOptions> CreateHandler()
=> _provider.GetService<OpenIddictClientOwinHandler>()
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0317));
/// <summary>
/// Provides the options used by the <see cref="OpenIddictClientOwinMiddleware"/> class.
/// </summary>
private sealed class InternalOptions : AuthenticationOptions
{
/// <summary>
/// Creates a new instance of the <see cref="InternalOptions"/> class.
/// </summary>
public InternalOptions() : base(OpenIddictClientOwinDefaults.AuthenticationType)
=> AuthenticationMode = AuthenticationMode.Passive;
}
}

13
src/OpenIddict.Client.Owin/OpenIddictClientOwinMiddlewareFactory.cs

@ -5,8 +5,6 @@
*/
using System.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace OpenIddict.Client.Owin;
@ -39,22 +37,15 @@ public sealed class OpenIddictClientOwinMiddlewareFactory : OwinMiddleware
{
ArgumentNullException.ThrowIfNull(context);
var provider = context.Get<IServiceProvider>(typeof(IServiceProvider).FullName) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0316));
// Note: the Microsoft.Extensions.DependencyInjection container doesn't support resolving services
// with arbitrary parameters, which prevents the client OWIN middleware from being resolved directly
// from the DI container, as the next middleware in the pipeline cannot be specified as a parameter.
// To work around this limitation, the client OWIN middleware is manually instantiated and invoked.
var middleware = new OpenIddictClientOwinMiddleware(
next: Next,
options: GetRequiredService<IOptionsMonitor<OpenIddictClientOwinOptions>>(provider),
dispatcher: GetRequiredService<IOpenIddictClientDispatcher>(provider),
factory: GetRequiredService<IOpenIddictClientFactory>(provider));
provider: context.Get<IServiceProvider>(typeof(IServiceProvider).FullName)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0316)));
return middleware.Invoke(context);
static T GetRequiredService<T>(IServiceProvider provider) => provider.GetService<T>() ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0317));
}
}

9
src/OpenIddict.Client.Owin/OpenIddictClientOwinOptions.cs

@ -11,15 +11,8 @@ namespace OpenIddict.Client.Owin;
/// <summary>
/// Provides various settings needed to configure the OpenIddict OWIN client integration.
/// </summary>
public sealed class OpenIddictClientOwinOptions : AuthenticationOptions
public sealed class OpenIddictClientOwinOptions
{
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictClientOwinOptions"/> class.
/// </summary>
public OpenIddictClientOwinOptions()
: base(OpenIddictClientOwinDefaults.AuthenticationType)
=> AuthenticationMode = AuthenticationMode.Passive;
/// <summary>
/// Gets or sets a boolean indicating whether the static client registrations with a non-null
/// provider name attached are automatically added to <see cref="ForwardedAuthenticationTypes"/>.

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

@ -18,7 +18,7 @@ namespace OpenIddict.Server.AspNetCore;
/// Provides the logic necessary to extract, validate and handle OpenID Connect requests.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<OpenIddictServerAspNetCoreOptions>,
public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<AuthenticationSchemeOptions>,
IAuthenticationRequestHandler,
IAuthenticationSignInHandler,
IAuthenticationSignOutHandler
@ -32,7 +32,7 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Op
public OpenIddictServerAspNetCoreHandler(
IOpenIddictServerDispatcher dispatcher,
IOpenIddictServerFactory factory,
IOptionsMonitor<OpenIddictServerAspNetCoreOptions> options,
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder)
: base(options, logger, encoder)

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

@ -11,7 +11,7 @@ namespace OpenIddict.Server.AspNetCore;
/// <summary>
/// Provides various settings needed to configure the OpenIddict ASP.NET Core server integration.
/// </summary>
public sealed class OpenIddictServerAspNetCoreOptions : AuthenticationSchemeOptions
public sealed class OpenIddictServerAspNetCoreOptions
{
/// <summary>
/// Gets or sets a boolean indicating whether incoming requests arriving on insecure endpoints should be rejected.

18
src/OpenIddict.Server.Owin/OpenIddictServerOwinConfiguration.cs

@ -14,8 +14,7 @@ namespace OpenIddict.Server.Owin;
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictServerOwinConfiguration : IConfigureOptions<OpenIddictServerOptions>,
IPostConfigureOptions<OpenIddictServerOptions>,
IValidateOptions<OpenIddictServerOwinOptions>
IPostConfigureOptions<OpenIddictServerOptions>
{
/// <inheritdoc/>
public void Configure(OpenIddictServerOptions options)
@ -46,19 +45,4 @@ public sealed class OpenIddictServerOwinConfiguration : IConfigureOptions<OpenId
options.ClientAuthenticationMethods.Add(ClientAuthenticationMethods.SelfSignedTlsClientAuth);
}
}
/// <inheritdoc/>
public ValidateOptionsResult Validate(string? name, OpenIddictServerOwinOptions options)
{
ArgumentNullException.ThrowIfNull(options);
var builder = new ValidateOptionsResultBuilder();
if (options.AuthenticationMode is AuthenticationMode.Active)
{
builder.AddError(SR.GetResourceString(SR.ID0119));
}
return builder.Build();
}
}

4
src/OpenIddict.Server.Owin/OpenIddictServerOwinExtensions.cs

@ -31,6 +31,7 @@ public static class OpenIddictServerOwinExtensions
// Note: unlike regular OWIN middleware, the OpenIddict server middleware is registered
// as a scoped service in the DI container. This allows containers that support middleware
// resolution (like Autofac) to use it without requiring additional configuration.
builder.Services.TryAddScoped<OpenIddictServerOwinHandler>();
builder.Services.TryAddScoped<OpenIddictServerOwinMiddleware>();
// Register the built-in event handlers used by the OpenIddict OWIN server components.
@ -55,9 +56,6 @@ public static class OpenIddictServerOwinExtensions
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
IPostConfigureOptions<OpenIddictServerOptions>, OpenIddictServerOwinConfiguration>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
IValidateOptions<OpenIddictServerOwinOptions>, OpenIddictServerOwinConfiguration>());
return new OpenIddictServerOwinBuilder(builder.Services);
}

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

@ -16,7 +16,7 @@ namespace OpenIddict.Server.Owin;
/// Provides the entry point necessary to register the OpenIddict server in an OWIN pipeline.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<OpenIddictServerOwinOptions>
public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<AuthenticationOptions>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
private readonly IOpenIddictServerFactory _factory;

39
src/OpenIddict.Server.Owin/OpenIddictServerOwinMiddleware.cs

@ -5,7 +5,7 @@
*/
using System.ComponentModel;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Owin.Security.Infrastructure;
namespace OpenIddict.Server.Owin;
@ -17,33 +17,38 @@ namespace OpenIddict.Server.Owin;
/// it is NOT recommended to instantiate it as a singleton like a regular OWIN middleware.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictServerOwinMiddleware : AuthenticationMiddleware<OpenIddictServerOwinOptions>
public sealed class OpenIddictServerOwinMiddleware : AuthenticationMiddleware<AuthenticationOptions>
{
private readonly IOpenIddictServerDispatcher _dispatcher;
private readonly IOpenIddictServerFactory _factory;
private readonly IServiceProvider _provider;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictServerOwinMiddleware"/> class.
/// </summary>
/// <param name="next">The next middleware in the pipeline, if applicable.</param>
/// <param name="options">The OpenIddict server OWIN options.</param>
/// <param name="dispatcher">The OpenIddict server dispatcher.</param>
/// <param name="factory">The OpenIddict server factory.</param>
/// <param name="provider">The service provider.</param>
public OpenIddictServerOwinMiddleware(
OwinMiddleware? next,
IOptionsMonitor<OpenIddictServerOwinOptions> options,
IOpenIddictServerDispatcher dispatcher,
IOpenIddictServerFactory factory)
: base(next, options.CurrentValue)
{
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}
IServiceProvider provider)
: base(next, new InternalOptions())
=> _provider = provider ?? throw new ArgumentNullException(nameof(provider));
/// <summary>
/// Creates and returns a new <see cref="OpenIddictServerOwinHandler"/> instance.
/// </summary>
/// <returns>A new instance of the <see cref="OpenIddictServerOwinHandler"/> class.</returns>
protected override AuthenticationHandler<OpenIddictServerOwinOptions> CreateHandler()
=> new OpenIddictServerOwinHandler(_dispatcher, _factory);
protected override AuthenticationHandler<AuthenticationOptions> CreateHandler()
=> _provider.GetService<OpenIddictServerOwinHandler>()
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0122));
/// <summary>
/// Provides the options used by the <see cref="OpenIddictServerOwinMiddleware"/> class.
/// </summary>
private sealed class InternalOptions : AuthenticationOptions
{
/// <summary>
/// Creates a new instance of the <see cref="InternalOptions"/> class.
/// </summary>
public InternalOptions() : base(OpenIddictServerOwinDefaults.AuthenticationType)
=> AuthenticationMode = AuthenticationMode.Passive;
}
}

13
src/OpenIddict.Server.Owin/OpenIddictServerOwinMiddlewareFactory.cs

@ -5,8 +5,6 @@
*/
using System.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace OpenIddict.Server.Owin;
@ -39,22 +37,15 @@ public sealed class OpenIddictServerOwinMiddlewareFactory : OwinMiddleware
{
ArgumentNullException.ThrowIfNull(context);
var provider = context.Get<IServiceProvider>(typeof(IServiceProvider).FullName) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0121));
// Note: the Microsoft.Extensions.DependencyInjection container doesn't support resolving services
// with arbitrary parameters, which prevents the server OWIN middleware from being resolved directly
// from the DI container, as the next middleware in the pipeline cannot be specified as a parameter.
// To work around this limitation, the server OWIN middleware is manually instantiated and invoked.
var middleware = new OpenIddictServerOwinMiddleware(
next: Next,
options: GetRequiredService<IOptionsMonitor<OpenIddictServerOwinOptions>>(provider),
dispatcher: GetRequiredService<IOpenIddictServerDispatcher>(provider),
factory: GetRequiredService<IOpenIddictServerFactory>(provider));
provider: context.Get<IServiceProvider>(typeof(IServiceProvider).FullName)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0121)));
return middleware.Invoke(context);
static T GetRequiredService<T>(IServiceProvider provider) => provider.GetService<T>() ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0122));
}
}

9
src/OpenIddict.Server.Owin/OpenIddictServerOwinOptions.cs

@ -11,15 +11,8 @@ namespace OpenIddict.Server.Owin;
/// <summary>
/// Provides various settings needed to configure the OpenIddict OWIN server integration.
/// </summary>
public sealed class OpenIddictServerOwinOptions : AuthenticationOptions
public sealed class OpenIddictServerOwinOptions
{
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictServerOwinOptions"/> class.
/// </summary>
public OpenIddictServerOwinOptions()
: base(OpenIddictServerOwinDefaults.AuthenticationType)
=> AuthenticationMode = AuthenticationMode.Passive;
/// <summary>
/// Gets or sets a boolean indicating whether incoming requests arriving on insecure endpoints should be rejected.
/// By default, this property is set to <see langword="false"/> to help mitigate man-in-the-middle attacks.

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

@ -18,7 +18,7 @@ namespace OpenIddict.Validation.AspNetCore;
/// Provides the logic necessary to extract, validate and handle OpenID Connect requests.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandler<OpenIddictValidationAspNetCoreOptions>,
public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandler<AuthenticationSchemeOptions>,
IAuthenticationRequestHandler
{
private readonly IOpenIddictValidationDispatcher _dispatcher;
@ -30,7 +30,7 @@ public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandle
public OpenIddictValidationAspNetCoreHandler(
IOpenIddictValidationDispatcher dispatcher,
IOpenIddictValidationFactory factory,
IOptionsMonitor<OpenIddictValidationAspNetCoreOptions> options,
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder)
: base(options, logger, encoder)

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

@ -9,7 +9,7 @@ namespace OpenIddict.Validation.AspNetCore;
/// <summary>
/// Provides various settings needed to configure the OpenIddict ASP.NET Core validation integration.
/// </summary>
public sealed class OpenIddictValidationAspNetCoreOptions : AuthenticationSchemeOptions
public sealed class OpenIddictValidationAspNetCoreOptions
{
/// <summary>
/// Gets or sets a boolean indicating whether the built-in logic extracting

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

@ -29,6 +29,7 @@ public static class OpenIddictValidationOwinExtensions
// Note: unlike regular OWIN middleware, the OpenIddict validation middleware is registered
// as a scoped service in the DI container. This allows containers that support middleware
// resolution (like Autofac) to use it without requiring additional configuration.
builder.Services.TryAddScoped<OpenIddictValidationOwinHandler>();
builder.Services.TryAddScoped<OpenIddictValidationOwinMiddleware>();
// Register the built-in event handlers used by the OpenIddict OWIN validation components.

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

@ -16,7 +16,7 @@ namespace OpenIddict.Validation.Owin;
/// Provides the entry point necessary to register the OpenIddict validation in an OWIN pipeline.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictValidationOwinHandler : AuthenticationHandler<OpenIddictValidationOwinOptions>
public sealed class OpenIddictValidationOwinHandler : AuthenticationHandler<AuthenticationOptions>
{
private readonly IOpenIddictValidationDispatcher _dispatcher;
private readonly IOpenIddictValidationFactory _factory;

43
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinMiddleware.cs

@ -5,6 +5,7 @@
*/
using System.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Owin.Security.Infrastructure;
@ -17,33 +18,43 @@ namespace OpenIddict.Validation.Owin;
/// it is NOT recommended to instantiate it as a singleton like a regular OWIN middleware.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictValidationOwinMiddleware : AuthenticationMiddleware<OpenIddictValidationOwinOptions>
public sealed class OpenIddictValidationOwinMiddleware : AuthenticationMiddleware<AuthenticationOptions>
{
private readonly IOpenIddictValidationDispatcher _dispatcher;
private readonly IOpenIddictValidationFactory _factory;
private readonly IServiceProvider _provider;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictValidationOwinMiddleware"/> class.
/// </summary>
/// <param name="next">The next middleware in the pipeline, if applicable.</param>
/// <param name="options">The OpenIddict validation OWIN options.</param>
/// <param name="dispatcher">The OpenIddict validation dispatcher.</param>
/// <param name="factory">The OpenIddict validation factory.</param>
/// <param name="provider">The service provider.</param>
public OpenIddictValidationOwinMiddleware(
OwinMiddleware? next,
IOptionsMonitor<OpenIddictValidationOwinOptions> options,
IOpenIddictValidationDispatcher dispatcher,
IOpenIddictValidationFactory factory)
: base(next, options.CurrentValue)
{
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}
IServiceProvider provider)
: base(next, new InternalOptions()
{
AuthenticationMode = provider.GetService<IOptionsMonitor<OpenIddictValidationOwinOptions>>()
?.CurrentValue.AuthenticationMode
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0169))
})
=> _provider = provider ?? throw new ArgumentNullException(nameof(provider));
/// <summary>
/// Creates and returns a new <see cref="OpenIddictValidationOwinHandler"/> instance.
/// </summary>
/// <returns>A new instance of the <see cref="OpenIddictValidationOwinHandler"/> class.</returns>
protected override AuthenticationHandler<OpenIddictValidationOwinOptions> CreateHandler()
=> new OpenIddictValidationOwinHandler(_dispatcher, _factory);
protected override AuthenticationHandler<AuthenticationOptions> CreateHandler()
=> _provider.GetService<OpenIddictValidationOwinHandler>()
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0169));
/// <summary>
/// Provides the options used by the <see cref="OpenIddictValidationOwinMiddleware"/> class.
/// </summary>
private sealed class InternalOptions : AuthenticationOptions
{
/// <summary>
/// Creates a new instance of the <see cref="InternalOptions"/> class.
/// </summary>
public InternalOptions() : base(OpenIddictValidationOwinDefaults.AuthenticationType)
=> AuthenticationMode = AuthenticationMode.Passive;
}
}

13
src/OpenIddict.Validation.Owin/OpenIddictValidationOwinMiddlewareFactory.cs

@ -5,8 +5,6 @@
*/
using System.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace OpenIddict.Validation.Owin;
@ -39,22 +37,15 @@ public sealed class OpenIddictValidationOwinMiddlewareFactory : OwinMiddleware
{
ArgumentNullException.ThrowIfNull(context);
var provider = context.Get<IServiceProvider>(typeof(IServiceProvider).FullName) ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0168));
// Note: the Microsoft.Extensions.DependencyInjection container doesn't support resolving services
// with arbitrary parameters, which prevents the validation OWIN middleware from being resolved directly
// from the DI container, as the next middleware in the pipeline cannot be specified as a parameter.
// To work around this limitation, the validation OWIN middleware is manually instantiated and invoked.
var middleware = new OpenIddictValidationOwinMiddleware(
next: Next,
options: GetRequiredService<IOptionsMonitor<OpenIddictValidationOwinOptions>>(provider),
dispatcher: GetRequiredService<IOpenIddictValidationDispatcher>(provider),
factory: GetRequiredService<IOpenIddictValidationFactory>(provider));
provider: context.Get<IServiceProvider>(typeof(IServiceProvider).FullName)
?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0168)));
return middleware.Invoke(context);
static T GetRequiredService<T>(IServiceProvider provider) => provider.GetService<T>() ??
throw new InvalidOperationException(SR.GetResourceString(SR.ID0169));
}
}

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

@ -9,14 +9,15 @@ namespace OpenIddict.Validation.Owin;
/// <summary>
/// Provides various settings needed to configure the OpenIddict OWIN validation integration.
/// </summary>
public sealed class OpenIddictValidationOwinOptions : AuthenticationOptions
public sealed class OpenIddictValidationOwinOptions
{
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictValidationOwinOptions"/> class.
/// Gets or sets the authentication mode that will be assigned to the OpenIddict
/// OWIN validation middleware: when using the active mode, the authentication
/// middleware will automatically populate the user identity when the request
/// is processed and will infer a challenge response from HTTP 401 responses.
/// </summary>
public OpenIddictValidationOwinOptions()
: base(OpenIddictValidationOwinDefaults.AuthenticationType)
=> AuthenticationMode = AuthenticationMode.Passive;
public AuthenticationMode AuthenticationMode { get; set; } = AuthenticationMode.Passive;
/// <summary>
/// Gets or sets a boolean indicating whether the built-in logic extracting

Loading…
Cancel
Save