Browse Source

Move the handlers registration logic to OpenIddictServerConfiguration/OpenIddictValidationConfiguration

pull/670/merge
Kévin Chalet 8 years ago
parent
commit
84055f634c
  1. 30
      src/OpenIddict.Server/Internal/OpenIddictServerConfiguration.cs
  2. 30
      src/OpenIddict.Server/OpenIddictServerExtensions.cs
  3. 31
      src/OpenIddict.Validation/Internal/OpenIddictValidationConfiguration.cs
  4. 35
      src/OpenIddict.Validation/OpenIddictValidationExtensions.cs
  5. 29
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerConfigurationTests.cs
  6. 2
      test/OpenIddict.Server.Tests/OpenIddictServerExtensionsTests.cs
  7. 27
      test/OpenIddict.Validation.Tests/Internal/OpenIddictValidationConfigurationTests.cs
  8. 2
      test/OpenIddict.Validation.Tests/OpenIddictValidationExtensionsTests.cs

30
src/OpenIddict.Server/Internal/OpenIddictServerInitializer.cs → src/OpenIddict.Server/Internal/OpenIddictServerConfiguration.cs

@ -23,17 +23,18 @@ namespace OpenIddict.Server.Internal
/// Note: this API supports the OpenIddict infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future minor releases.
/// </summary>
public class OpenIddictServerInitializer : IPostConfigureOptions<OpenIddictServerOptions>
public class OpenIddictServerConfiguration : IConfigureOptions<AuthenticationOptions>,
IPostConfigureOptions<OpenIddictServerOptions>
{
private readonly IDistributedCache _cache;
private readonly IDataProtectionProvider _dataProtectionProvider;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictServerInitializer"/> class.
/// Creates a new instance of the <see cref="OpenIddictServerConfiguration"/> class.
/// Note: this API supports the OpenIddict infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future minor releases.
/// </summary>
public OpenIddictServerInitializer(
public OpenIddictServerConfiguration(
[NotNull] IDistributedCache cache,
[NotNull] IDataProtectionProvider dataProtectionProvider)
{
@ -41,6 +42,29 @@ namespace OpenIddict.Server.Internal
_dataProtectionProvider = dataProtectionProvider;
}
/// <summary>
/// Registers the OpenIddict server handler in the global authentication options.
/// </summary>
/// <param name="options">The options instance to initialize.</param>
public void Configure(AuthenticationOptions options)
{
// If a handler was already registered and the type doesn't correspond to the OpenIddict handler, throw an exception.
if (options.SchemeMap.TryGetValue(OpenIddictServerDefaults.AuthenticationScheme, out var builder) &&
builder.HandlerType != typeof(OpenIddictServerHandler))
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The OpenIddict server handler cannot be registered as an authentication scheme.")
.AppendLine("This may indicate that an instance of the OpenID Connect server was registered.")
.Append("Make sure that 'services.AddAuthentication().AddOpenIdConnectServer()' is not used.")
.ToString());
}
options.AddScheme(OpenIddictServerDefaults.AuthenticationScheme, scheme =>
{
scheme.HandlerType = typeof(OpenIddictServerHandler);
});
}
/// <summary>
/// Populates the default OpenID Connect server options and ensure
/// that the configuration is in a consistent and valid state.

30
src/OpenIddict.Server/OpenIddictServerExtensions.cs

@ -65,37 +65,11 @@ namespace Microsoft.Extensions.DependencyInjection
// Note: TryAddEnumerable() is used here to ensure the initializers are only registered once.
builder.Services.TryAddEnumerable(new[]
{
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictServerOptions>, OpenIddictServerInitializer>(),
ServiceDescriptor.Singleton<IConfigureOptions<AuthenticationOptions>, OpenIddictServerConfiguration>(),
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictServerOptions>, OpenIddictServerConfiguration>(),
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictServerOptions>, OpenIdConnectServerInitializer>()
});
// Register the OpenID Connect server handler in the authentication options,
// so it can be discovered by the default authentication handler provider.
builder.Services.Configure<AuthenticationOptions>(options =>
{
// Note: this method is guaranteed to be idempotent. To prevent multiple schemes from being
// registered (which would result in an exception being thrown), a manual check is made here.
if (options.SchemeMap.TryGetValue(OpenIddictServerDefaults.AuthenticationScheme, out var handler))
{
// If the handler type doesn't correspond to the OpenIddict handler, throw an exception.
if (handler.HandlerType != typeof(OpenIddictServerHandler))
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The OpenIddict server handler cannot be registered as an authentication scheme.")
.AppendLine("This may indicate that an instance of the OpenID Connect server was registered.")
.Append("Make sure that 'services.AddAuthentication().AddOpenIdConnectServer()' is not used.")
.ToString());
}
return;
}
options.AddScheme(OpenIddictServerDefaults.AuthenticationScheme, scheme =>
{
scheme.HandlerType = typeof(OpenIddictServerHandler);
});
});
return new OpenIddictServerBuilder(builder.Services);
}

31
src/OpenIddict.Validation/Internal/OpenIddictValidationInitializer.cs → src/OpenIddict.Validation/Internal/OpenIddictValidationConfiguration.cs

@ -18,20 +18,45 @@ namespace OpenIddict.Validation.Internal
/// Note: this API supports the OpenIddict infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future minor releases.
/// </summary>
public class OpenIddictValidationInitializer : IPostConfigureOptions<OpenIddictValidationOptions>
public class OpenIddictValidationConfiguration : IConfigureOptions<AuthenticationOptions>,
IPostConfigureOptions<OpenIddictValidationOptions>
{
private readonly IDataProtectionProvider _dataProtectionProvider;
/// <summary>
/// Creates a new instance of the <see cref="OpenIddictValidationInitializer"/> class.
/// Creates a new instance of the <see cref="OpenIddictValidationConfiguration"/> class.
/// Note: this API supports the OpenIddict infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future minor releases.
/// </summary>
public OpenIddictValidationInitializer([NotNull] IDataProtectionProvider dataProtectionProvider)
public OpenIddictValidationConfiguration([NotNull] IDataProtectionProvider dataProtectionProvider)
{
_dataProtectionProvider = dataProtectionProvider;
}
/// <summary>
/// Registers the OpenIddict server handler in the global authentication options.
/// </summary>
/// <param name="options">The options instance to initialize.</param>
public void Configure(AuthenticationOptions options)
{
// If a handler was already registered and the type doesn't correspond to the OpenIddict handler, throw an exception.
if (options.SchemeMap.TryGetValue(OpenIddictValidationDefaults.AuthenticationScheme, out var builder) &&
builder.HandlerType != typeof(OpenIddictValidationHandler))
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The OpenIddict validation handler cannot be registered as an authentication scheme.")
.AppendLine("This may indicate that an instance of the OAuth validation or JWT bearer handler was registered.")
.Append("Make sure that neither 'services.AddAuthentication().AddOAuthValidation()' nor ")
.Append("'services.AddAuthentication().AddJwtBearer()' are called from 'ConfigureServices'.")
.ToString());
}
options.AddScheme(OpenIddictValidationDefaults.AuthenticationScheme, scheme =>
{
scheme.HandlerType = typeof(OpenIddictValidationHandler);
});
}
/// <summary>
/// Populates the default OpenIddict validation options and ensure
/// that the configuration is in a consistent and valid state.

35
src/OpenIddict.Validation/OpenIddictValidationExtensions.cs

@ -5,7 +5,6 @@
*/
using System;
using System.Text;
using AspNet.Security.OAuth.Validation;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authentication;
@ -45,41 +44,15 @@ namespace Microsoft.Extensions.DependencyInjection
builder.Services.TryAddScoped<OpenIddictValidationHandler>();
builder.Services.TryAddScoped<OpenIddictValidationProvider>();
// Note: TryAddEnumerable() is used here to ensure the initializer is only registered once.
// Register the options initializers used by the OAuth validation handler and OpenIddict.
// Note: TryAddEnumerable() is used here to ensure the initializers are only registered once.
builder.Services.TryAddEnumerable(new[]
{
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictValidationOptions>, OpenIddictValidationInitializer>(),
ServiceDescriptor.Singleton<IConfigureOptions<AuthenticationOptions>, OpenIddictValidationConfiguration>(),
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictValidationOptions>, OpenIddictValidationConfiguration>(),
ServiceDescriptor.Singleton<IPostConfigureOptions<OpenIddictValidationOptions>, OAuthValidationInitializer>()
});
// Register the OpenIddict validation handler in the authentication options,
// so it can be discovered by the default authentication handler provider.
builder.Services.Configure<AuthenticationOptions>(options =>
{
// Note: this method is guaranteed to be idempotent. To prevent multiple schemes from being
// registered (which would result in an exception being thrown), a manual check is made here.
if (options.SchemeMap.TryGetValue(OpenIddictValidationDefaults.AuthenticationScheme, out var handler))
{
// If the handler type doesn't correspond to the OpenIddict handler, throw an exception.
if (handler.HandlerType != typeof(OpenIddictValidationHandler))
{
throw new InvalidOperationException(new StringBuilder()
.AppendLine("The OpenIddict validation handler cannot be registered as an authentication scheme.")
.AppendLine("This may indicate that an instance of the OAuth validation or JWT bearer handler was registered.")
.Append("Make sure that neither 'services.AddAuthentication().AddOAuthValidation()' nor ")
.Append("'services.AddAuthentication().AddJwtBearer()' are called from 'ConfigureServices'.")
.ToString());
}
return;
}
options.AddScheme(OpenIddictValidationDefaults.AuthenticationScheme, scheme =>
{
scheme.HandlerType = typeof(OpenIddictValidationHandler);
});
});
return new OpenIddictValidationBuilder(builder.Services);
}

29
test/OpenIddict.Server.Tests/Internal/OpenIddictServerInitializerTests.cs → test/OpenIddict.Server.Tests/Internal/OpenIddictServerConfigurationTests.cs

@ -11,18 +11,45 @@ using AspNet.Security.OpenIdConnect.Client;
using AspNet.Security.OpenIdConnect.Server;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using OpenIddict.Abstractions;
using Xunit;
namespace OpenIddict.Server.Internal.Tests
{
public class OpenIddictServerInitializerTests
public class OpenIddictServerConfigurationTests
{
[Fact]
public void Configure_ThrowsAnExceptionWhenSchemeIsAlreadyRegisteredWithDifferentHandlerType()
{
// Arrange
var options = new AuthenticationOptions();
options.AddScheme(OpenIddictServerDefaults.AuthenticationScheme, builder =>
{
builder.HandlerType = typeof(OpenIdConnectServerHandler);
});
var initializer = new OpenIddictServerConfiguration(
Mock.Of<IDistributedCache>(),
Mock.Of<IDataProtectionProvider>());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => initializer.Configure(options));
Assert.Equal(new StringBuilder()
.AppendLine("The OpenIddict server handler cannot be registered as an authentication scheme.")
.AppendLine("This may indicate that an instance of the OpenID Connect server was registered.")
.Append("Make sure that 'services.AddAuthentication().AddOpenIdConnectServer()' is not used.")
.ToString(), exception.Message);
}
[Fact]
public async Task PostConfigure_ThrowsAnExceptionWhenRandomNumberGeneratorIsNull()
{

2
test/OpenIddict.Server.Tests/OpenIddictServerExtensionsTests.cs

@ -173,7 +173,7 @@ namespace OpenIddict.Server.Tests
}
[Theory]
[InlineData(typeof(IPostConfigureOptions<OpenIddictServerOptions>), typeof(OpenIddictServerInitializer))]
[InlineData(typeof(IPostConfigureOptions<OpenIddictServerOptions>), typeof(OpenIddictServerConfiguration))]
[InlineData(typeof(IPostConfigureOptions<OpenIddictServerOptions>), typeof(OpenIdConnectServerInitializer))]
public void AddServer_RegistersInitializers(Type serviceType, Type implementationType)
{

27
test/OpenIddict.Validation.Tests/Internal/OpenIddictValidationInitializerTests.cs → test/OpenIddict.Validation.Tests/Internal/OpenIddictValidationConfigurationTests.cs

@ -10,16 +10,41 @@ using System.Threading.Tasks;
using AspNet.Security.OAuth.Validation;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
namespace OpenIddict.Validation.Internal.Tests
{
public class OpenIddictValidationInitializerTests
public class OpenIddictValidationConfigurationTests
{
[Fact]
public void Configure_ThrowsAnExceptionWhenSchemeIsAlreadyRegisteredWithDifferentHandlerType()
{
// Arrange
var options = new AuthenticationOptions();
options.AddScheme(OpenIddictValidationDefaults.AuthenticationScheme, builder =>
{
builder.HandlerType = typeof(OAuthValidationHandler);
});
var initializer = new OpenIddictValidationConfiguration(Mock.Of<IDataProtectionProvider>());
// Act and assert
var exception = Assert.Throws<InvalidOperationException>(() => initializer.Configure(options));
Assert.Equal(new StringBuilder()
.AppendLine("The OpenIddict validation handler cannot be registered as an authentication scheme.")
.AppendLine("This may indicate that an instance of the OAuth validation or JWT bearer handler was registered.")
.Append("Make sure that neither 'services.AddAuthentication().AddOAuthValidation()' nor ")
.Append("'services.AddAuthentication().AddJwtBearer()' are called from 'ConfigureServices'.")
.ToString(), exception.Message);
}
[Fact]
public async Task PostConfigure_ThrowsAnExceptionWhenEventsTypeIsNull()
{

2
test/OpenIddict.Validation.Tests/OpenIddictValidationExtensionsTests.cs

@ -134,7 +134,7 @@ namespace OpenIddict.Validation.Tests
}
[Theory]
[InlineData(typeof(IPostConfigureOptions<OpenIddictValidationOptions>), typeof(OpenIddictValidationInitializer))]
[InlineData(typeof(IPostConfigureOptions<OpenIddictValidationOptions>), typeof(OpenIddictValidationConfiguration))]
[InlineData(typeof(IPostConfigureOptions<OpenIddictValidationOptions>), typeof(OAuthValidationInitializer))]
public void AddValidation_RegistersInitializers(Type serviceType, Type implementationType)
{

Loading…
Cancel
Save