Browse Source

Use SuppressChildValidationMetadataProvider to exclude OpenIdConnectRequest/OpenIdConnectResponse from child validation

pull/711/head
Kévin Chalet 7 years ago
parent
commit
d668c82d8b
  1. 39
      src/OpenIddict.Mvc/Internal/OpenIddictMvcConfiguration.cs
  2. 19
      src/OpenIddict.Mvc/OpenIddictMvcExtensions.cs
  3. 7
      src/OpenIddict.Server/Internal/OpenIddictServerConfiguration.cs
  4. 7
      src/OpenIddict.Validation/Internal/OpenIddictValidationConfiguration.cs
  5. 71
      test/OpenIddict.Mvc.Tests/Internal/OpenIddictMvcConfigurationTests.cs
  6. 8
      test/OpenIddict.Mvc.Tests/OpenIddictMvcExtensionsTests.cs
  7. 14
      test/OpenIddict.Server.Tests/Internal/OpenIddictServerConfigurationTests.cs
  8. 2
      test/OpenIddict.Server.Tests/OpenIddictServerExtensionsTests.cs
  9. 12
      test/OpenIddict.Validation.Tests/Internal/OpenIddictValidationConfigurationTests.cs
  10. 2
      test/OpenIddict.Validation.Tests/OpenIddictValidationExtensionsTests.cs

39
src/OpenIddict.Mvc/Internal/OpenIddictMvcConfiguration.cs

@ -0,0 +1,39 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using AspNet.Security.OpenIdConnect.Primitives;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Options;
namespace OpenIddict.Mvc.Internal
{
/// <summary>
/// Contains the methods required to ensure that the OpenIddict MVC configuration is valid.
/// 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 OpenIddictMvcConfiguration : IConfigureOptions<MvcOptions>
{
/// <summary>
/// Registers the OpenIddict MVC components in the MVC options.
/// </summary>
/// <param name="options">The options instance to initialize.</param>
public void Configure([NotNull] MvcOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(options));
}
options.ModelBinderProviders.Insert(0, new OpenIddictMvcBinderProvider());
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(OpenIdConnectRequest)));
options.ModelMetadataDetailsProviders.Add(new SuppressChildValidationMetadataProvider(typeof(OpenIdConnectResponse)));
}
}
}

19
src/OpenIddict.Mvc/OpenIddictMvcExtensions.cs

@ -7,6 +7,8 @@
using System;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using OpenIddict.Mvc.Internal;
namespace Microsoft.Extensions.DependencyInjection
@ -29,20 +31,9 @@ namespace Microsoft.Extensions.DependencyInjection
throw new ArgumentNullException(nameof(builder));
}
builder.Services.Configure<MvcOptions>(options =>
{
// Skip the binder registration if it was already added to the providers collection.
for (var index = 0; index < options.ModelBinderProviders.Count; index++)
{
var provider = options.ModelBinderProviders[index];
if (provider is OpenIddictMvcBinderProvider)
{
return;
}
}
options.ModelBinderProviders.Insert(0, new OpenIddictMvcBinderProvider());
});
// Register the options initializer used by the OpenIddict MVC binding/validation components.
// Note: TryAddEnumerable() is used here to ensure the initializer is only registered once.
builder.Services.TryAddEnumerable(ServiceDescriptor.Singleton<IConfigureOptions<MvcOptions>, OpenIddictMvcConfiguration>());
return new OpenIddictMvcBuilder(builder.Services);
}

7
src/OpenIddict.Server/Internal/OpenIddictServerConfiguration.cs

@ -47,8 +47,13 @@ namespace OpenIddict.Server.Internal
/// 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)
public void Configure([NotNull] AuthenticationOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(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))

7
src/OpenIddict.Validation/Internal/OpenIddictValidationConfiguration.cs

@ -36,8 +36,13 @@ namespace OpenIddict.Validation.Internal
/// Registers the OpenIddict validation handler in the global authentication options.
/// </summary>
/// <param name="options">The options instance to initialize.</param>
public void Configure(AuthenticationOptions options)
public void Configure([NotNull] AuthenticationOptions options)
{
if (options == null)
{
throw new ArgumentNullException(nameof(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))

71
test/OpenIddict.Mvc.Tests/Internal/OpenIddictMvcConfigurationTests.cs

@ -0,0 +1,71 @@
/*
* Licensed under the Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0)
* See https://github.com/openiddict/openiddict-core for more information concerning
* the license and the contributors participating to this project.
*/
using System;
using System.Linq;
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OpenIddict.Mvc.Internal;
using Xunit;
namespace OpenIddict.Mvc.Tests
{
public class OpenIddictConfigurationExtensionsTests
{
[Fact]
public void Configure_ThrowsAnExceptionForNullOptions()
{
// Arrange
var configuration = new OpenIddictMvcConfiguration();
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => configuration.Configure(null));
Assert.Equal("options", exception.ParamName);
}
[Fact]
public void Configure_RegistersModelBinderProvider()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictServerBuilder(services);
// Act
builder.UseMvc();
var options = services.BuildServiceProvider().GetRequiredService<IOptions<MvcOptions>>();
// Assert
Assert.Contains(options.Value.ModelBinderProviders, binder => binder is OpenIddictMvcBinderProvider);
}
[Fact]
public void Configure_RegistersModelMetadataDetailsProviders()
{
// Arrange
var services = new ServiceCollection();
services.AddOptions();
var builder = new OpenIddictServerBuilder(services);
// Act
builder.UseMvc();
var options = services.BuildServiceProvider().GetRequiredService<IOptions<MvcOptions>>();
// Assert
var providers = options.Value.ModelMetadataDetailsProviders.OfType<SuppressChildValidationMetadataProvider>();
Assert.Contains(providers, provider => provider.Type == typeof(OpenIdConnectRequest));
Assert.Contains(providers, provider => provider.Type == typeof(OpenIdConnectResponse));
}
}
}

8
test/OpenIddict.Mvc.Tests/OpenIddictMvcExtensionsTests.cs

@ -41,7 +41,7 @@ namespace OpenIddict.Mvc.Tests
}
[Fact]
public void UseMvc_RegistersModelBinderProvider()
public void UseMvc_RegistersConfiguration()
{
// Arrange
var services = new ServiceCollection();
@ -52,11 +52,9 @@ namespace OpenIddict.Mvc.Tests
// Act
builder.UseMvc();
var provider = services.BuildServiceProvider();
var options = provider.GetRequiredService<IOptions<MvcOptions>>();
// Assert
Assert.Contains(options.Value.ModelBinderProviders, binder => binder is OpenIddictMvcBinderProvider);
Assert.Contains(services, service => service.ServiceType == typeof(IConfigureOptions<MvcOptions>) &&
service.ImplementationType == typeof(OpenIddictMvcConfiguration));
}
}
}

14
test/OpenIddict.Server.Tests/Internal/OpenIddictServerConfigurationTests.cs

@ -27,6 +27,20 @@ namespace OpenIddict.Server.Internal.Tests
{
public class OpenIddictServerConfigurationTests
{
[Fact]
public void Configure_ThrowsAnExceptionForNullOptions()
{
// Arrange
var configuration = new OpenIddictServerConfiguration(
Mock.Of<IDistributedCache>(),
Mock.Of<IDataProtectionProvider>());
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => configuration.Configure(null));
Assert.Equal("options", exception.ParamName);
}
[Fact]
public void Configure_ThrowsAnExceptionWhenSchemeIsAlreadyRegisteredWithDifferentHandlerType()
{

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

@ -175,7 +175,7 @@ namespace OpenIddict.Server.Tests
[Theory]
[InlineData(typeof(IPostConfigureOptions<OpenIddictServerOptions>), typeof(OpenIddictServerConfiguration))]
[InlineData(typeof(IPostConfigureOptions<OpenIddictServerOptions>), typeof(OpenIdConnectServerInitializer))]
public void AddServer_RegistersInitializers(Type serviceType, Type implementationType)
public void AddServer_RegistersConfiguration(Type serviceType, Type implementationType)
{
// Arrange
var services = new ServiceCollection();

12
test/OpenIddict.Validation.Tests/Internal/OpenIddictValidationConfigurationTests.cs

@ -23,6 +23,18 @@ namespace OpenIddict.Validation.Internal.Tests
{
public class OpenIddictValidationConfigurationTests
{
[Fact]
public void Configure_ThrowsAnExceptionForNullOptions()
{
// Arrange
var configuration = new OpenIddictValidationConfiguration(Mock.Of<IDataProtectionProvider>());
// Act and assert
var exception = Assert.Throws<ArgumentNullException>(() => configuration.Configure(null));
Assert.Equal("options", exception.ParamName);
}
[Theory]
[InlineData(new object[] { new string[] { OpenIddictValidationDefaults.AuthenticationScheme, null } })]
[InlineData(new object[] { new string[] { null, OpenIddictValidationDefaults.AuthenticationScheme } })]

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

@ -136,7 +136,7 @@ namespace OpenIddict.Validation.Tests
[Theory]
[InlineData(typeof(IPostConfigureOptions<OpenIddictValidationOptions>), typeof(OpenIddictValidationConfiguration))]
[InlineData(typeof(IPostConfigureOptions<OpenIddictValidationOptions>), typeof(OAuthValidationInitializer))]
public void AddValidation_RegistersInitializers(Type serviceType, Type implementationType)
public void AddValidation_RegistersConfiguration(Type serviceType, Type implementationType)
{
// Arrange
var services = new ServiceCollection();

Loading…
Cancel
Save