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" /> <bindingRedirect oldVersion="0.0.0.0-4.2.4.0" newVersion="4.2.4.0" />
</dependentAssembly> </dependentAssembly>
</assemblyBinding> </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"> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" /> <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" /> <bindingRedirect oldVersion="0.0.0.0-4.2.4.0" newVersion="4.2.4.0" />
</dependentAssembly> </dependentAssembly>
</assemblyBinding> </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"> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly> <dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" culture="neutral" /> <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"> <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> <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>
<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"> <data name="ID0120" xml:space="preserve">
<value>The OWIN request cannot be resolved.</value> <value>The OWIN request cannot be resolved.</value>
</data> </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> Note: when using a dependency injection container supporting middleware resolution (like Autofac), the 'app.UseOpenIddictServer()' extension MUST NOT be called.</value>
</data> </data>
<data name="ID0122" xml:space="preserve"> <data name="ID0122" xml:space="preserve">
<value>The OpenIddict server services cannot be resolved from the DI container. <value>The authentication handler used by the OpenIddict server components cannot be resolved from the DI container.
To register the server services, use 'services.AddOpenIddict().AddServer()'.</value> To register the OWIN integration, use 'services.AddOpenIddict().AddServer().UseOwin()'.</value>
</data> </data>
<data name="ID0123" xml:space="preserve"> <data name="ID0123" xml:space="preserve">
<value>Audiences cannot be null or empty.</value> <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> Note: when using a dependency injection container supporting middleware resolution (like Autofac), the 'app.UseOpenIddictValidation()' extension MUST NOT be called.</value>
</data> </data>
<data name="ID0169" xml:space="preserve"> <data name="ID0169" xml:space="preserve">
<value>The OpenIddict validation services cannot be resolved from the DI container. <value>The authentication handler used by the OpenIddict validation components cannot be resolved from the DI container.
To register the validation services, use 'services.AddOpenIddict().AddValidation()'.</value> To register the OWIN integration, use 'services.AddOpenIddict().AddValidation().UseOwin()'.</value>
</data> </data>
<data name="ID0170" xml:space="preserve"> <data name="ID0170" xml:space="preserve">
<value>The local server integration can only be used with direct validation.</value> <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"> <data name="ID0313" xml:space="preserve">
<value>A discovery client must be registered when using server discovery. <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> 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>
<data name="ID0315" xml:space="preserve"> <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> <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> Note: when using a dependency injection container supporting middleware resolution (like Autofac), the 'app.UseOpenIddictClient()' extension MUST NOT be called.</value>
</data> </data>
<data name="ID0317" xml:space="preserve"> <data name="ID0317" xml:space="preserve">
<value>The OpenIddict client services cannot be resolved from the DI container. <value>The authentication handler used by the OpenIddict client components cannot be resolved from the DI container.
To register the client services, use 'services.AddOpenIddict().AddClient()'.</value> To register the OWIN integration, use 'services.AddOpenIddict().AddClient().UseOwin()'.</value>
</data> </data>
<data name="ID0318" xml:space="preserve"> <data name="ID0318" xml:space="preserve">
<value>The core services must be registered when enabling the OpenIddict client feature. <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. /// Provides the logic necessary to extract, validate and handle OpenID Connect requests.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<OpenIddictClientAspNetCoreOptions>, public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<AuthenticationSchemeOptions>,
IAuthenticationRequestHandler, IAuthenticationRequestHandler,
IAuthenticationSignOutHandler IAuthenticationSignOutHandler
{ {
@ -32,7 +32,7 @@ public sealed class OpenIddictClientAspNetCoreHandler : AuthenticationHandler<Op
public OpenIddictClientAspNetCoreHandler( public OpenIddictClientAspNetCoreHandler(
IOpenIddictClientDispatcher dispatcher, IOpenIddictClientDispatcher dispatcher,
IOpenIddictClientFactory factory, IOpenIddictClientFactory factory,
IOptionsMonitor<OpenIddictClientAspNetCoreOptions> options, IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, ILoggerFactory logger,
UrlEncoder encoder) UrlEncoder encoder)
: base(options, logger, encoder) : base(options, logger, encoder)

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

@ -11,7 +11,7 @@ namespace OpenIddict.Client.AspNetCore;
/// <summary> /// <summary>
/// Provides various settings needed to configure the OpenIddict ASP.NET Core client integration. /// Provides various settings needed to configure the OpenIddict ASP.NET Core client integration.
/// </summary> /// </summary>
public sealed class OpenIddictClientAspNetCoreOptions : AuthenticationSchemeOptions public sealed class OpenIddictClientAspNetCoreOptions
{ {
/// <summary> /// <summary>
/// Gets or sets a boolean indicating whether the static client registrations with a non-null /// 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(); 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 // Ensure multiple client registrations don't share the same provider
// name when automatic authentication type forwarding is enabled. // name when automatic authentication type forwarding is enabled.
if (!options.DisableAutomaticAuthenticationTypeForwarding) 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 // 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 // as a scoped service in the DI container. This allows containers that support middleware
// resolution (like Autofac) to use it without requiring additional configuration. // resolution (like Autofac) to use it without requiring additional configuration.
builder.Services.TryAddScoped<OpenIddictClientOwinHandler>();
builder.Services.TryAddScoped<OpenIddictClientOwinMiddleware>(); builder.Services.TryAddScoped<OpenIddictClientOwinMiddleware>();
// Register the built-in event handlers used by the OpenIddict OWIN client components. // 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.Globalization;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Security.Claims; using System.Security.Claims;
using Microsoft.Extensions.Options;
using Microsoft.Owin.Security.Infrastructure; using Microsoft.Owin.Security.Infrastructure;
using static OpenIddict.Client.Owin.OpenIddictClientOwinConstants; using static OpenIddict.Client.Owin.OpenIddictClientOwinConstants;
using Properties = OpenIddict.Client.Owin.OpenIddictClientOwinConstants.Properties; 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. /// Provides the entry point necessary to register the OpenIddict client in an OWIN pipeline.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddictClientOwinOptions> public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<AuthenticationOptions>
{ {
private readonly IOpenIddictClientDispatcher _dispatcher; private readonly IOpenIddictClientDispatcher _dispatcher;
private readonly IOpenIddictClientFactory _factory; private readonly IOpenIddictClientFactory _factory;
private readonly IOptionsMonitor<OpenIddictClientOwinOptions> _options;
/// <summary> /// <summary>
/// Creates a new instance of the <see cref="OpenIddictClientOwinHandler"/> class. /// Creates a new instance of the <see cref="OpenIddictClientOwinHandler"/> class.
/// </summary> /// </summary>
/// <param name="dispatcher">The OpenIddict client dispatcher used by this instance.</param> /// <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="factory">The OpenIddict client factory used by this instance.</param>
/// <param name="options">The OpenIddict client OWIN options.</param>
public OpenIddictClientOwinHandler( public OpenIddictClientOwinHandler(
IOpenIddictClientDispatcher dispatcher, IOpenIddictClientDispatcher dispatcher,
IOpenIddictClientFactory factory) IOpenIddictClientFactory factory,
IOptionsMonitor<OpenIddictClientOwinOptions> options)
{ {
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher)); _dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_factory = factory ?? throw new ArgumentNullException(nameof(factory)); _factory = factory ?? throw new ArgumentNullException(nameof(factory));
_options = options ?? throw new ArgumentNullException(nameof(options));
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -280,10 +285,14 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
// OpenIddictClientOwinMiddleware is assumed to be the only middleware allowed to write // 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. // 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 // 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 // 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. // 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) if (challenge is not null && Response.StatusCode is 401 or 403)
{ {
var transaction = Context.Get<OpenIddictClientTransaction>(typeof(OpenIddictClientTransaction).FullName) ?? 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) if (signout is not null)
{ {
var transaction = Context.Get<OpenIddictClientTransaction>(typeof(OpenIddictClientTransaction).FullName) ?? 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 // Note: unlike its server counterpart, the OpenIddict OWIN client authentication handler allows
// associating additional authentication types to trigger a provider-specific challenge. For that, // 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 // managed by OpenIddict, a challenge pointing to the OpenIddict OWIN client authentication handler
// is dynamically forwarded with the appropriate provider name authentication property attached. // 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) 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. // 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.Issuer) ||
properties.Dictionary.ContainsKey(Properties.ProviderName) || properties.Dictionary.ContainsKey(Properties.ProviderName) ||
properties.Dictionary.ContainsKey(Properties.RegistrationId))) properties.Dictionary.ContainsKey(Properties.RegistrationId)))
@ -397,7 +409,7 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
return new AuthenticationResponseChallenge( return new AuthenticationResponseChallenge(
authenticationTypes: [OpenIddictClientOwinDefaults.AuthenticationType], authenticationTypes: [OpenIddictClientOwinDefaults.AuthenticationType],
properties : new AuthenticationProperties(dictionary: new Dictionary<string, string>( properties : new AuthenticationProperties(dictionary: new Dictionary<string, string>(
Context.Authentication.AuthenticationResponseChallenge.Properties.Dictionary ?? manager.AuthenticationResponseChallenge.Properties.Dictionary ??
ImmutableDictionary.Create<string, string>()) ImmutableDictionary.Create<string, string>())
{ {
[Properties.ProviderName] = type [Properties.ProviderName] = type
@ -409,7 +421,8 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
return null; return null;
} }
AuthenticationResponseRevoke? LookupForwardedSignOut() static AuthenticationResponseRevoke? LookupForwardedSignOut(
IAuthenticationManager manager, IReadOnlyList<AuthenticationDescription> descriptions)
{ {
// Note: unlike its server counterpart, the OpenIddict OWIN client authentication handler allows // 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, // 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 // 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. // 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) 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. // 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.Issuer) ||
properties.Dictionary.ContainsKey(Properties.ProviderName) || properties.Dictionary.ContainsKey(Properties.ProviderName) ||
properties.Dictionary.ContainsKey(Properties.RegistrationId))) properties.Dictionary.ContainsKey(Properties.RegistrationId)))
@ -435,7 +448,7 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
return new AuthenticationResponseRevoke( return new AuthenticationResponseRevoke(
authenticationTypes: [OpenIddictClientOwinDefaults.AuthenticationType], authenticationTypes: [OpenIddictClientOwinDefaults.AuthenticationType],
properties : new AuthenticationProperties(dictionary: new Dictionary<string, string>( properties : new AuthenticationProperties(dictionary: new Dictionary<string, string>(
Context.Authentication.AuthenticationResponseRevoke.Properties.Dictionary ?? manager.AuthenticationResponseRevoke.Properties.Dictionary ??
ImmutableDictionary.Create<string, string>()) ImmutableDictionary.Create<string, string>())
{ {
[Properties.ProviderName] = type [Properties.ProviderName] = type
@ -448,10 +461,12 @@ public sealed class OpenIddictClientOwinHandler : AuthenticationHandler<OpenIddi
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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)) if (string.Equals(description.AuthenticationType, type, StringComparison.Ordinal))
{ {
result = description; result = description;

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

@ -9,6 +9,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Security.Claims; using System.Security.Claims;
using System.Security.Principal; using System.Security.Principal;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Owin.Security.Infrastructure; 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. /// it is NOT recommended to instantiate it as a singleton like a regular OWIN middleware.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictClientOwinMiddleware : AuthenticationMiddleware<OpenIddictClientOwinOptions> public sealed class OpenIddictClientOwinMiddleware : AuthenticationMiddleware<AuthenticationOptions>
{ {
private readonly IOpenIddictClientDispatcher _dispatcher; private readonly IServiceProvider _provider;
private readonly IOpenIddictClientFactory _factory;
/// <summary> /// <summary>
/// Creates a new instance of the <see cref="OpenIddictClientOwinMiddleware"/> class. /// Creates a new instance of the <see cref="OpenIddictClientOwinMiddleware"/> class.
/// </summary> /// </summary>
/// <param name="next">The next middleware in the pipeline, if applicable.</param> /// <param name="next">The next middleware in the pipeline, if applicable.</param>
/// <param name="options">The OpenIddict client OWIN options.</param> /// <param name="provider">The service provider.</param>
/// <param name="dispatcher">The OpenIddict client dispatcher.</param>
/// <param name="factory">The OpenIddict client factory.</param>
public OpenIddictClientOwinMiddleware( public OpenIddictClientOwinMiddleware(
OwinMiddleware? next, OwinMiddleware? next,
IOptionsMonitor<OpenIddictClientOwinOptions> options, IServiceProvider provider)
IOpenIddictClientDispatcher dispatcher, : base(next, new InternalOptions())
IOpenIddictClientFactory factory) => _provider = provider ?? throw new ArgumentNullException(nameof(provider));
: base(next, options.CurrentValue)
{
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}
/// <inheritdoc/> /// <inheritdoc/>
public override async Task Invoke(IOwinContext context) public override async Task Invoke(IOwinContext context)
{ {
ArgumentNullException.ThrowIfNull(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. // Retrieve the existing authentication delegate.
var function = context.Get<AuthenticateDelegate?>("security.Authenticate"); 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. // In this case, iterate all the forwarded authentication types and call the callback action for each type.
if (types is null) if (types is null)
{ {
foreach (var description in Options.ForwardedAuthenticationTypes) foreach (var description in options.ForwardedAuthenticationTypes)
{ {
callback(null, null, description.Properties, state); 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. // corresponding authentication middleware handle it if it matches a registered type.
if (string.IsNullOrEmpty(type) || if (string.IsNullOrEmpty(type) ||
string.Equals(type, OpenIddictClientOwinDefaults.AuthenticationType, StringComparison.Ordinal) || string.Equals(type, OpenIddictClientOwinDefaults.AuthenticationType, StringComparison.Ordinal) ||
!TryGetForwardedAuthenticationType(type, out AuthenticationDescription? description)) !TryGetForwardedAuthenticationType(options.ForwardedAuthenticationTypes, type, out AuthenticationDescription? description))
{ {
continue; continue;
} }
@ -134,10 +131,12 @@ public sealed class OpenIddictClientOwinMiddleware : AuthenticationMiddleware<Op
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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)) if (string.Equals(description.AuthenticationType, type, StringComparison.Ordinal))
{ {
result = description; result = description;
@ -154,6 +153,19 @@ public sealed class OpenIddictClientOwinMiddleware : AuthenticationMiddleware<Op
/// Creates and returns a new <see cref="OpenIddictClientOwinHandler"/> instance. /// Creates and returns a new <see cref="OpenIddictClientOwinHandler"/> instance.
/// </summary> /// </summary>
/// <returns>A new instance of the <see cref="OpenIddictClientOwinHandler"/> class.</returns> /// <returns>A new instance of the <see cref="OpenIddictClientOwinHandler"/> class.</returns>
protected override AuthenticationHandler<OpenIddictClientOwinOptions> CreateHandler() protected override AuthenticationHandler<AuthenticationOptions> CreateHandler()
=> new OpenIddictClientOwinHandler(_dispatcher, _factory); => _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 System.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace OpenIddict.Client.Owin; namespace OpenIddict.Client.Owin;
@ -39,22 +37,15 @@ public sealed class OpenIddictClientOwinMiddlewareFactory : OwinMiddleware
{ {
ArgumentNullException.ThrowIfNull(context); 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 // Note: the Microsoft.Extensions.DependencyInjection container doesn't support resolving services
// with arbitrary parameters, which prevents the client OWIN middleware from being resolved directly // 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. // 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. // To work around this limitation, the client OWIN middleware is manually instantiated and invoked.
var middleware = new OpenIddictClientOwinMiddleware( var middleware = new OpenIddictClientOwinMiddleware(
next: Next, next: Next,
options: GetRequiredService<IOptionsMonitor<OpenIddictClientOwinOptions>>(provider), provider: context.Get<IServiceProvider>(typeof(IServiceProvider).FullName)
dispatcher: GetRequiredService<IOpenIddictClientDispatcher>(provider), ?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0316)));
factory: GetRequiredService<IOpenIddictClientFactory>(provider));
return middleware.Invoke(context); 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> /// <summary>
/// Provides various settings needed to configure the OpenIddict OWIN client integration. /// Provides various settings needed to configure the OpenIddict OWIN client integration.
/// </summary> /// </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> /// <summary>
/// Gets or sets a boolean indicating whether the static client registrations with a non-null /// 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"/>. /// 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. /// Provides the logic necessary to extract, validate and handle OpenID Connect requests.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<OpenIddictServerAspNetCoreOptions>, public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<AuthenticationSchemeOptions>,
IAuthenticationRequestHandler, IAuthenticationRequestHandler,
IAuthenticationSignInHandler, IAuthenticationSignInHandler,
IAuthenticationSignOutHandler IAuthenticationSignOutHandler
@ -32,7 +32,7 @@ public sealed class OpenIddictServerAspNetCoreHandler : AuthenticationHandler<Op
public OpenIddictServerAspNetCoreHandler( public OpenIddictServerAspNetCoreHandler(
IOpenIddictServerDispatcher dispatcher, IOpenIddictServerDispatcher dispatcher,
IOpenIddictServerFactory factory, IOpenIddictServerFactory factory,
IOptionsMonitor<OpenIddictServerAspNetCoreOptions> options, IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, ILoggerFactory logger,
UrlEncoder encoder) UrlEncoder encoder)
: base(options, logger, encoder) : base(options, logger, encoder)

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

@ -11,7 +11,7 @@ namespace OpenIddict.Server.AspNetCore;
/// <summary> /// <summary>
/// Provides various settings needed to configure the OpenIddict ASP.NET Core server integration. /// Provides various settings needed to configure the OpenIddict ASP.NET Core server integration.
/// </summary> /// </summary>
public sealed class OpenIddictServerAspNetCoreOptions : AuthenticationSchemeOptions public sealed class OpenIddictServerAspNetCoreOptions
{ {
/// <summary> /// <summary>
/// Gets or sets a boolean indicating whether incoming requests arriving on insecure endpoints should be rejected. /// 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> /// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictServerOwinConfiguration : IConfigureOptions<OpenIddictServerOptions>, public sealed class OpenIddictServerOwinConfiguration : IConfigureOptions<OpenIddictServerOptions>,
IPostConfigureOptions<OpenIddictServerOptions>, IPostConfigureOptions<OpenIddictServerOptions>
IValidateOptions<OpenIddictServerOwinOptions>
{ {
/// <inheritdoc/> /// <inheritdoc/>
public void Configure(OpenIddictServerOptions options) public void Configure(OpenIddictServerOptions options)
@ -46,19 +45,4 @@ public sealed class OpenIddictServerOwinConfiguration : IConfigureOptions<OpenId
options.ClientAuthenticationMethods.Add(ClientAuthenticationMethods.SelfSignedTlsClientAuth); 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 // 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 // as a scoped service in the DI container. This allows containers that support middleware
// resolution (like Autofac) to use it without requiring additional configuration. // resolution (like Autofac) to use it without requiring additional configuration.
builder.Services.TryAddScoped<OpenIddictServerOwinHandler>();
builder.Services.TryAddScoped<OpenIddictServerOwinMiddleware>(); builder.Services.TryAddScoped<OpenIddictServerOwinMiddleware>();
// Register the built-in event handlers used by the OpenIddict OWIN server components. // 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< builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
IPostConfigureOptions<OpenIddictServerOptions>, OpenIddictServerOwinConfiguration>()); IPostConfigureOptions<OpenIddictServerOptions>, OpenIddictServerOwinConfiguration>());
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<
IValidateOptions<OpenIddictServerOwinOptions>, OpenIddictServerOwinConfiguration>());
return new OpenIddictServerOwinBuilder(builder.Services); 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. /// Provides the entry point necessary to register the OpenIddict server in an OWIN pipeline.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<OpenIddictServerOwinOptions> public sealed class OpenIddictServerOwinHandler : AuthenticationHandler<AuthenticationOptions>
{ {
private readonly IOpenIddictServerDispatcher _dispatcher; private readonly IOpenIddictServerDispatcher _dispatcher;
private readonly IOpenIddictServerFactory _factory; private readonly IOpenIddictServerFactory _factory;

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

@ -5,7 +5,7 @@
*/ */
using System.ComponentModel; using System.ComponentModel;
using Microsoft.Extensions.Options; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Owin.Security.Infrastructure; using Microsoft.Owin.Security.Infrastructure;
namespace OpenIddict.Server.Owin; 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. /// it is NOT recommended to instantiate it as a singleton like a regular OWIN middleware.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictServerOwinMiddleware : AuthenticationMiddleware<OpenIddictServerOwinOptions> public sealed class OpenIddictServerOwinMiddleware : AuthenticationMiddleware<AuthenticationOptions>
{ {
private readonly IOpenIddictServerDispatcher _dispatcher; private readonly IServiceProvider _provider;
private readonly IOpenIddictServerFactory _factory;
/// <summary> /// <summary>
/// Creates a new instance of the <see cref="OpenIddictServerOwinMiddleware"/> class. /// Creates a new instance of the <see cref="OpenIddictServerOwinMiddleware"/> class.
/// </summary> /// </summary>
/// <param name="next">The next middleware in the pipeline, if applicable.</param> /// <param name="next">The next middleware in the pipeline, if applicable.</param>
/// <param name="options">The OpenIddict server OWIN options.</param> /// <param name="provider">The service provider.</param>
/// <param name="dispatcher">The OpenIddict server dispatcher.</param>
/// <param name="factory">The OpenIddict server factory.</param>
public OpenIddictServerOwinMiddleware( public OpenIddictServerOwinMiddleware(
OwinMiddleware? next, OwinMiddleware? next,
IOptionsMonitor<OpenIddictServerOwinOptions> options, IServiceProvider provider)
IOpenIddictServerDispatcher dispatcher, : base(next, new InternalOptions())
IOpenIddictServerFactory factory) => _provider = provider ?? throw new ArgumentNullException(nameof(provider));
: base(next, options.CurrentValue)
{
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher));
_factory = factory ?? throw new ArgumentNullException(nameof(factory));
}
/// <summary> /// <summary>
/// Creates and returns a new <see cref="OpenIddictServerOwinHandler"/> instance. /// Creates and returns a new <see cref="OpenIddictServerOwinHandler"/> instance.
/// </summary> /// </summary>
/// <returns>A new instance of the <see cref="OpenIddictServerOwinHandler"/> class.</returns> /// <returns>A new instance of the <see cref="OpenIddictServerOwinHandler"/> class.</returns>
protected override AuthenticationHandler<OpenIddictServerOwinOptions> CreateHandler() protected override AuthenticationHandler<AuthenticationOptions> CreateHandler()
=> new OpenIddictServerOwinHandler(_dispatcher, _factory); => _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 System.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace OpenIddict.Server.Owin; namespace OpenIddict.Server.Owin;
@ -39,22 +37,15 @@ public sealed class OpenIddictServerOwinMiddlewareFactory : OwinMiddleware
{ {
ArgumentNullException.ThrowIfNull(context); 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 // Note: the Microsoft.Extensions.DependencyInjection container doesn't support resolving services
// with arbitrary parameters, which prevents the server OWIN middleware from being resolved directly // 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. // 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. // To work around this limitation, the server OWIN middleware is manually instantiated and invoked.
var middleware = new OpenIddictServerOwinMiddleware( var middleware = new OpenIddictServerOwinMiddleware(
next: Next, next: Next,
options: GetRequiredService<IOptionsMonitor<OpenIddictServerOwinOptions>>(provider), provider: context.Get<IServiceProvider>(typeof(IServiceProvider).FullName)
dispatcher: GetRequiredService<IOpenIddictServerDispatcher>(provider), ?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0121)));
factory: GetRequiredService<IOpenIddictServerFactory>(provider));
return middleware.Invoke(context); 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> /// <summary>
/// Provides various settings needed to configure the OpenIddict OWIN server integration. /// Provides various settings needed to configure the OpenIddict OWIN server integration.
/// </summary> /// </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> /// <summary>
/// Gets or sets a boolean indicating whether incoming requests arriving on insecure endpoints should be rejected. /// 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. /// 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. /// Provides the logic necessary to extract, validate and handle OpenID Connect requests.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandler<OpenIddictValidationAspNetCoreOptions>, public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandler<AuthenticationSchemeOptions>,
IAuthenticationRequestHandler IAuthenticationRequestHandler
{ {
private readonly IOpenIddictValidationDispatcher _dispatcher; private readonly IOpenIddictValidationDispatcher _dispatcher;
@ -30,7 +30,7 @@ public sealed class OpenIddictValidationAspNetCoreHandler : AuthenticationHandle
public OpenIddictValidationAspNetCoreHandler( public OpenIddictValidationAspNetCoreHandler(
IOpenIddictValidationDispatcher dispatcher, IOpenIddictValidationDispatcher dispatcher,
IOpenIddictValidationFactory factory, IOpenIddictValidationFactory factory,
IOptionsMonitor<OpenIddictValidationAspNetCoreOptions> options, IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, ILoggerFactory logger,
UrlEncoder encoder) UrlEncoder encoder)
: base(options, logger, encoder) : base(options, logger, encoder)

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

@ -9,7 +9,7 @@ namespace OpenIddict.Validation.AspNetCore;
/// <summary> /// <summary>
/// Provides various settings needed to configure the OpenIddict ASP.NET Core validation integration. /// Provides various settings needed to configure the OpenIddict ASP.NET Core validation integration.
/// </summary> /// </summary>
public sealed class OpenIddictValidationAspNetCoreOptions : AuthenticationSchemeOptions public sealed class OpenIddictValidationAspNetCoreOptions
{ {
/// <summary> /// <summary>
/// Gets or sets a boolean indicating whether the built-in logic extracting /// 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 // 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 // as a scoped service in the DI container. This allows containers that support middleware
// resolution (like Autofac) to use it without requiring additional configuration. // resolution (like Autofac) to use it without requiring additional configuration.
builder.Services.TryAddScoped<OpenIddictValidationOwinHandler>();
builder.Services.TryAddScoped<OpenIddictValidationOwinMiddleware>(); builder.Services.TryAddScoped<OpenIddictValidationOwinMiddleware>();
// Register the built-in event handlers used by the OpenIddict OWIN validation components. // 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. /// Provides the entry point necessary to register the OpenIddict validation in an OWIN pipeline.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictValidationOwinHandler : AuthenticationHandler<OpenIddictValidationOwinOptions> public sealed class OpenIddictValidationOwinHandler : AuthenticationHandler<AuthenticationOptions>
{ {
private readonly IOpenIddictValidationDispatcher _dispatcher; private readonly IOpenIddictValidationDispatcher _dispatcher;
private readonly IOpenIddictValidationFactory _factory; private readonly IOpenIddictValidationFactory _factory;

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

@ -5,6 +5,7 @@
*/ */
using System.ComponentModel; using System.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Microsoft.Owin.Security.Infrastructure; 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. /// it is NOT recommended to instantiate it as a singleton like a regular OWIN middleware.
/// </summary> /// </summary>
[EditorBrowsable(EditorBrowsableState.Advanced)] [EditorBrowsable(EditorBrowsableState.Advanced)]
public sealed class OpenIddictValidationOwinMiddleware : AuthenticationMiddleware<OpenIddictValidationOwinOptions> public sealed class OpenIddictValidationOwinMiddleware : AuthenticationMiddleware<AuthenticationOptions>
{ {
private readonly IOpenIddictValidationDispatcher _dispatcher; private readonly IServiceProvider _provider;
private readonly IOpenIddictValidationFactory _factory;
/// <summary> /// <summary>
/// Creates a new instance of the <see cref="OpenIddictValidationOwinMiddleware"/> class. /// Creates a new instance of the <see cref="OpenIddictValidationOwinMiddleware"/> class.
/// </summary> /// </summary>
/// <param name="next">The next middleware in the pipeline, if applicable.</param> /// <param name="next">The next middleware in the pipeline, if applicable.</param>
/// <param name="options">The OpenIddict validation OWIN options.</param> /// <param name="provider">The service provider.</param>
/// <param name="dispatcher">The OpenIddict validation dispatcher.</param>
/// <param name="factory">The OpenIddict validation factory.</param>
public OpenIddictValidationOwinMiddleware( public OpenIddictValidationOwinMiddleware(
OwinMiddleware? next, OwinMiddleware? next,
IOptionsMonitor<OpenIddictValidationOwinOptions> options, IServiceProvider provider)
IOpenIddictValidationDispatcher dispatcher, : base(next, new InternalOptions()
IOpenIddictValidationFactory factory) {
: base(next, options.CurrentValue) AuthenticationMode = provider.GetService<IOptionsMonitor<OpenIddictValidationOwinOptions>>()
{ ?.CurrentValue.AuthenticationMode
_dispatcher = dispatcher ?? throw new ArgumentNullException(nameof(dispatcher)); ?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0169))
_factory = factory ?? throw new ArgumentNullException(nameof(factory)); })
} => _provider = provider ?? throw new ArgumentNullException(nameof(provider));
/// <summary> /// <summary>
/// Creates and returns a new <see cref="OpenIddictValidationOwinHandler"/> instance. /// Creates and returns a new <see cref="OpenIddictValidationOwinHandler"/> instance.
/// </summary> /// </summary>
/// <returns>A new instance of the <see cref="OpenIddictValidationOwinHandler"/> class.</returns> /// <returns>A new instance of the <see cref="OpenIddictValidationOwinHandler"/> class.</returns>
protected override AuthenticationHandler<OpenIddictValidationOwinOptions> CreateHandler() protected override AuthenticationHandler<AuthenticationOptions> CreateHandler()
=> new OpenIddictValidationOwinHandler(_dispatcher, _factory); => _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 System.ComponentModel;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
namespace OpenIddict.Validation.Owin; namespace OpenIddict.Validation.Owin;
@ -39,22 +37,15 @@ public sealed class OpenIddictValidationOwinMiddlewareFactory : OwinMiddleware
{ {
ArgumentNullException.ThrowIfNull(context); 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 // Note: the Microsoft.Extensions.DependencyInjection container doesn't support resolving services
// with arbitrary parameters, which prevents the validation OWIN middleware from being resolved directly // 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. // 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. // To work around this limitation, the validation OWIN middleware is manually instantiated and invoked.
var middleware = new OpenIddictValidationOwinMiddleware( var middleware = new OpenIddictValidationOwinMiddleware(
next: Next, next: Next,
options: GetRequiredService<IOptionsMonitor<OpenIddictValidationOwinOptions>>(provider), provider: context.Get<IServiceProvider>(typeof(IServiceProvider).FullName)
dispatcher: GetRequiredService<IOpenIddictValidationDispatcher>(provider), ?? throw new InvalidOperationException(SR.GetResourceString(SR.ID0168)));
factory: GetRequiredService<IOpenIddictValidationFactory>(provider));
return middleware.Invoke(context); 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> /// <summary>
/// Provides various settings needed to configure the OpenIddict OWIN validation integration. /// Provides various settings needed to configure the OpenIddict OWIN validation integration.
/// </summary> /// </summary>
public sealed class OpenIddictValidationOwinOptions : AuthenticationOptions public sealed class OpenIddictValidationOwinOptions
{ {
/// <summary> /// <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> /// </summary>
public OpenIddictValidationOwinOptions() public AuthenticationMode AuthenticationMode { get; set; } = AuthenticationMode.Passive;
: base(OpenIddictValidationOwinDefaults.AuthenticationType)
=> AuthenticationMode = AuthenticationMode.Passive;
/// <summary> /// <summary>
/// Gets or sets a boolean indicating whether the built-in logic extracting /// Gets or sets a boolean indicating whether the built-in logic extracting

Loading…
Cancel
Save