Use compatibility switch for auth filters
This commit is contained in:
parent
c922b0b90d
commit
d342ebf8c8
|
|
@ -122,7 +122,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
_mvcOptions = context.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>().Value;
|
||||
}
|
||||
|
||||
if (_mvcOptions.CombineAuthorizeFilters)
|
||||
if (_mvcOptions.AllowCombiningAuthorizeFilters)
|
||||
{
|
||||
if (!context.IsEffectivePolicy<AuthorizeFilter>(this))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
|
||||
if (Version >= CompatibilityVersion.Version_2_1)
|
||||
{
|
||||
values[nameof(MvcOptions.SuppressBindingUndefinedValueToEnumType)] = true;
|
||||
values[nameof(MvcOptions.AllowCombiningAuthorizeFilters)] = true;
|
||||
values[nameof(MvcOptions.InputFormatterExceptionPolicy)] = InputFormatterExceptionPolicy.MalformedInputExceptions;
|
||||
values[nameof(MvcOptions.SuppressBindingUndefinedValueToEnumType)] = true;
|
||||
}
|
||||
|
||||
return values;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
using Microsoft.AspNetCore.Mvc.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
|
@ -23,6 +24,7 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;
|
||||
|
||||
// See CompatibilitySwitch.cs for guide on how to implement these.
|
||||
private readonly CompatibilitySwitch<bool> _allowCombiningAuthorizeFilters;
|
||||
private readonly CompatibilitySwitch<InputFormatterExceptionPolicy> _inputFormatterExceptionPolicy;
|
||||
private readonly CompatibilitySwitch<bool> _suppressBindingUndefinedValueToEnumType;
|
||||
private readonly ICompatibilitySwitch[] _switches;
|
||||
|
|
@ -44,11 +46,13 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
ModelValidatorProviders = new List<IModelValidatorProvider>();
|
||||
ValueProviderFactories = new List<IValueProviderFactory>();
|
||||
|
||||
_allowCombiningAuthorizeFilters = new CompatibilitySwitch<bool>(nameof(AllowCombiningAuthorizeFilters));
|
||||
_inputFormatterExceptionPolicy = new CompatibilitySwitch<InputFormatterExceptionPolicy>(nameof(InputFormatterExceptionPolicy), InputFormatterExceptionPolicy.AllExceptions);
|
||||
_suppressBindingUndefinedValueToEnumType = new CompatibilitySwitch<bool>(nameof(SuppressBindingUndefinedValueToEnumType));
|
||||
|
||||
_switches = new ICompatibilitySwitch[]
|
||||
{
|
||||
_allowCombiningAuthorizeFilters,
|
||||
_inputFormatterExceptionPolicy,
|
||||
_suppressBindingUndefinedValueToEnumType,
|
||||
};
|
||||
|
|
@ -66,6 +70,44 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </example>
|
||||
public bool AllowEmptyInputInBodyModelBinding { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that determines if policies on instances of <see cref="AuthorizeFilter" />
|
||||
/// will be combined into a single effective policy. The default value of the property is <c>false</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Authorization policies are designed such that multiple authorization policies applied to an endpoint
|
||||
/// should be combined and executed a single policy. The <see cref="AuthorizeFilter"/> (commonly applied
|
||||
/// by <see cref="AuthorizeAttribute"/>) can be applied globally, to controllers, and to actions - which
|
||||
/// specifies multiple authorization policies for an action. In all ASP.NET Core releases prior to 2.1
|
||||
/// these multiple policies would not combine as intended. This compatibility switch configures whether the
|
||||
/// old (unintended) behavior or the new combining behavior will be used when multiple authorization policies
|
||||
/// are applied.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// This property is associated with a compatibility switch and can provide a different behavior depending on
|
||||
/// the configured compatibility version for the application. See <see cref="CompatibilityVersion"/> for
|
||||
/// guidance and examples of setting the application's compatibility version.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Configuring the desired value of the compatibility switch by calling this property's setter will take precedence
|
||||
/// over the value implied by the application's <see cref="CompatibilityVersion"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_0"/> then
|
||||
/// this setting will have the value <c>false</c> unless explicitly configured.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
|
||||
/// higher then this setting will have the value <c>true</c> unless explicitly configured.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool AllowCombiningAuthorizeFilters
|
||||
{
|
||||
get => _allowCombiningAuthorizeFilters.Value;
|
||||
set => _allowCombiningAuthorizeFilters.Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Dictionary of CacheProfile Names, <see cref="CacheProfile"/> which are pre-defined settings for
|
||||
/// response caching.
|
||||
|
|
@ -105,13 +147,13 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_0"/> then
|
||||
/// this setting will have the value <see cref="InputFormatterExceptionPolicy.AllExceptions"/> if
|
||||
/// not explicitly configured.
|
||||
/// this setting will have the value <see cref="InputFormatterExceptionPolicy.AllExceptions"/> unless
|
||||
/// explicitly configured.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
|
||||
/// higher then this setting will have the value
|
||||
/// <see cref="InputFormatterExceptionPolicy.MalformedInputExceptions"/> if not explicitly configured.
|
||||
/// <see cref="InputFormatterExceptionPolicy.MalformedInputExceptions"/> unless explicitly configured.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public InputFormatterExceptionPolicy InputFormatterExceptionPolicy
|
||||
|
|
@ -141,11 +183,11 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_0"/> then
|
||||
/// this setting will have the value <c>false</c> if not explicitly configured.
|
||||
/// this setting will have the value <c>false</c> unless explicitly configured.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
|
||||
/// higher then this setting will have the value <c>true</c> if not explicitly configured.
|
||||
/// higher then this setting will have the value <c>true</c> unless explicitly configured.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool SuppressBindingUndefinedValueToEnumType
|
||||
|
|
@ -243,13 +285,6 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </summary>
|
||||
public bool RequireHttpsPermanent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value that determines if policies on instances of <see cref="AuthorizeFilter" />
|
||||
/// will be combined into a single effective policy. This was always to be the intended behavior,
|
||||
/// but was not the case.
|
||||
/// </summary>
|
||||
public bool CombineAuthorizeFilters { get; set;}
|
||||
|
||||
IEnumerator<ICompatibilitySwitch> IEnumerable<ICompatibilitySwitch>.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<ICompatibilitySwitch>)_switches).GetEnumerator();
|
||||
|
|
|
|||
|
|
@ -53,11 +53,11 @@ namespace Microsoft.AspNetCore.Mvc
|
|||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_0"/> then
|
||||
/// this setting will have value <c>false</c> if not explicitly configured.
|
||||
/// this setting will have value <c>false</c> unless explicitly configured.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
|
||||
/// higher then this setting will have value <c>true</c> if not explicitly configured.
|
||||
/// higher then this setting will have value <c>true</c> unless explicitly configured.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool AllowInputFormatterExceptionMessages
|
||||
|
|
|
|||
|
|
@ -81,11 +81,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
|
|||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_0"/> then
|
||||
/// this setting will have value <c>false</c> if not explicitly configured.
|
||||
/// this setting will have value <c>false</c> unless explicitly configured.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If the application's compatibility version is set to <see cref="CompatibilityVersion.Version_2_1"/> or
|
||||
/// higher then this setting will have value <c>true</c> if not explicitly configured.
|
||||
/// higher then this setting will have value <c>true</c> unless explicitly configured.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public bool AllowAreas
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
{
|
||||
// Arrange
|
||||
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.CombineAuthorizeFilters = true));
|
||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.AllowCombiningAuthorizeFilters = true));
|
||||
// Effective policy should fail, if both are combined
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
||||
|
|
@ -244,7 +244,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
{
|
||||
// Arrange
|
||||
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.CombineAuthorizeFilters = true));
|
||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.AllowCombiningAuthorizeFilters = true));
|
||||
// Effective policy should fail, if both are combined
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
var secondFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => false).Build());
|
||||
|
|
@ -262,7 +262,7 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
|
|||
{
|
||||
// Arrange
|
||||
var authorizeFilter = new AuthorizeFilter(new AuthorizationPolicyBuilder().RequireAssertion(a => true).Build());
|
||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.CombineAuthorizeFilters = true));
|
||||
var authorizationContext = GetAuthorizationContext(anonymous: false, registerServices: s => s.Configure<MvcOptions>(o => o.AllowCombiningAuthorizeFilters = true));
|
||||
// Effective policy should fail, if both are combined
|
||||
authorizationContext.Filters.Add(authorizeFilter);
|
||||
authorizationContext.Filters.Add(new DerivedAuthorizeFilter());
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@ using Xunit;
|
|||
|
||||
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||
{
|
||||
public class CombineAuthorizeTests : IClassFixture<MvcTestFixture<StartupWithGlobalAuthorizeAndCombineAuthorizeFilters>>
|
||||
public class CombineAuthorizeTests : IClassFixture<MvcTestFixture<StartupWithGlobalAuthorizeAndAllowCombiningAuthorizeFilters>>
|
||||
{
|
||||
public CombineAuthorizeTests(MvcTestFixture<StartupWithGlobalAuthorizeAndCombineAuthorizeFilters> fixture)
|
||||
public CombineAuthorizeTests(MvcTestFixture<StartupWithGlobalAuthorizeAndAllowCombiningAuthorizeFilters> fixture)
|
||||
{
|
||||
Client = fixture.Client;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var razorPagesOptions = services.GetRequiredService<IOptions<RazorPagesOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.False(mvcOptions.AllowCombiningAuthorizeFilters);
|
||||
Assert.False(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||
Assert.Equal(InputFormatterExceptionPolicy.AllExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||
Assert.False(jsonOptions.AllowInputFormatterExceptionMessages);
|
||||
|
|
@ -55,6 +56,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var razorPagesOptions = services.GetRequiredService<IOptions<RazorPagesOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.True(mvcOptions.AllowCombiningAuthorizeFilters);
|
||||
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||
Assert.True(jsonOptions.AllowInputFormatterExceptionMessages);
|
||||
|
|
@ -77,6 +79,7 @@ namespace Microsoft.AspNetCore.Mvc.IntegrationTest
|
|||
var razorPagesOptions = services.GetRequiredService<IOptions<RazorPagesOptions>>().Value;
|
||||
|
||||
// Assert
|
||||
Assert.True(mvcOptions.AllowCombiningAuthorizeFilters);
|
||||
Assert.True(mvcOptions.SuppressBindingUndefinedValueToEnumType);
|
||||
Assert.Equal(InputFormatterExceptionPolicy.MalformedInputExceptions, mvcOptions.InputFormatterExceptionPolicy);
|
||||
Assert.True(jsonOptions.AllowInputFormatterExceptionMessages);
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ namespace SecurityWebSite.Controllers
|
|||
return Content("Administration.Index");
|
||||
}
|
||||
|
||||
// Either cookie should allow access to this action (if CombineAuthorizeFilters is true)
|
||||
// If CombineAuthorizeFilters is false, the main cookie is required.
|
||||
// Either cookie should allow access to this action (if AllowCombiningAuthorizeFilters is true)
|
||||
// If AllowCombiningAuthorizeFilters is false, the main cookie is required.
|
||||
[Authorize(AuthenticationSchemes = "Cookie2")]
|
||||
public IActionResult EitherCookie()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||
|
||||
namespace SecurityWebSite
|
||||
{
|
||||
public class StartupWithGlobalAuthorizeAndCombineAuthorizeFilters
|
||||
public class StartupWithGlobalAuthorizeAndAllowCombiningAuthorizeFilters
|
||||
{
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
|
|
@ -17,7 +17,7 @@ namespace SecurityWebSite
|
|||
// Add framework services.
|
||||
services.AddMvc(o =>
|
||||
{
|
||||
o.CombineAuthorizeFilters = true;
|
||||
o.AllowCombiningAuthorizeFilters = true;
|
||||
o.Filters.Add(new AuthorizeFilter());
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue