From 7e26af908ef068407961479d21539079f5ffadfb Mon Sep 17 00:00:00 2001 From: Kiran Challa Date: Thu, 7 Dec 2017 10:02:50 -0800 Subject: [PATCH] [Fixes #6514] Add default ctor overload to AuthorizeFilter --- .../Authorization/AuthorizeFilter.cs | 8 ++++ .../Authorization/AuthorizeFilterTest.cs | 20 ++++++++ .../GlobalAuthorizationFilterTest.cs | 46 +++++++++++++++++++ .../Controllers/AdministrationController.cs | 24 ++++++++++ .../StartupWithGlobalDenyAnonymousFilter.cs | 36 +++++++++++++++ 5 files changed, 134 insertions(+) create mode 100644 test/Microsoft.AspNetCore.Mvc.FunctionalTests/GlobalAuthorizationFilterTest.cs create mode 100644 test/WebSites/SecurityWebSite/Controllers/AdministrationController.cs create mode 100644 test/WebSites/SecurityWebSite/StartupWithGlobalDenyAnonymousFilter.cs diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Authorization/AuthorizeFilter.cs b/src/Microsoft.AspNetCore.Mvc.Core/Authorization/AuthorizeFilter.cs index c6ecc5c699..356276852d 100644 --- a/src/Microsoft.AspNetCore.Mvc.Core/Authorization/AuthorizeFilter.cs +++ b/src/Microsoft.AspNetCore.Mvc.Core/Authorization/AuthorizeFilter.cs @@ -22,6 +22,14 @@ namespace Microsoft.AspNetCore.Mvc.Authorization /// public class AuthorizeFilter : IAsyncAuthorizationFilter, IFilterFactory { + /// + /// Initializes a new instance. + /// + public AuthorizeFilter() + : this(authorizeData: new[] { new AuthorizeAttribute() }) + { + } + /// /// Initialize a new instance. /// diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Authorization/AuthorizeFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Authorization/AuthorizeFilterTest.cs index 3429bad91e..7222cb16ab 100644 --- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Authorization/AuthorizeFilterTest.cs +++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Authorization/AuthorizeFilterTest.cs @@ -26,6 +26,26 @@ namespace Microsoft.AspNetCore.Mvc.Authorization Assert.Contains(authorizationContext.HttpContext.User.Identities, i => i.IsAuthenticated); } + [Fact] + public async Task DefaultConstructor_DeniesAnonymousUsers() + { + // Arrange + var authorizationContext = GetAuthorizationContext(anonymous: true); + // The type 'AuthorizeFilter' is both a filter by itself and also a filter factory. + // The default filter provider first checks if a type is a filter factory and creates an instance of + // this filter. + var authorizeFilterFactory = new AuthorizeFilter(); + var filterFactory = authorizeFilterFactory as IFilterFactory; + var authorizeFilter = (AuthorizeFilter)filterFactory.CreateInstance( + authorizationContext.HttpContext.RequestServices); + + // Act + await authorizeFilter.OnAuthorizationAsync(authorizationContext); + + // Assert + Assert.IsType(authorizationContext.Result); + } + [Fact] public async Task AuthorizeFilter_CreatedWithAuthorizeData_ThrowsWhenOnAuthorizationAsyncIsCalled() { diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/GlobalAuthorizationFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/GlobalAuthorizationFilterTest.cs new file mode 100644 index 0000000000..9eecde77ed --- /dev/null +++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/GlobalAuthorizationFilterTest.cs @@ -0,0 +1,46 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Net; +using System.Net.Http; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Mvc.FunctionalTests +{ + public class GlobalAuthorizationFilterTest : IClassFixture> + { + public GlobalAuthorizationFilterTest(MvcTestFixture fixture) + { + Client = fixture.Client; + } + + public HttpClient Client { get; } + + [Fact] + public async Task DeniesAnonymousUsers_ByDefault() + { + // Arrange & Act + var response = await Client.GetAsync("http://localhost/Administration/Index"); + + // Assert + Assert.Equal(HttpStatusCode.Redirect, response.StatusCode); + Assert.NotNull(response.Headers.Location); + Assert.Equal( + "http://localhost/Home/Login?ReturnUrl=%2FAdministration%2FIndex", + response.Headers.Location.ToString()); + } + + [Fact] + public async Task AllowAnonymousUsers_ForActionsWithAllowAnonymousAttribute() + { + // Arrange & Act + var response = await Client.GetAsync("http://localhost/Administration/AllowAnonymousAction"); + + // Assert + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + var body = await response.Content.ReadAsStringAsync(); + Assert.Equal("Administration.AllowAnonymousAction", body); + } + } +} \ No newline at end of file diff --git a/test/WebSites/SecurityWebSite/Controllers/AdministrationController.cs b/test/WebSites/SecurityWebSite/Controllers/AdministrationController.cs new file mode 100644 index 0000000000..ac7be06b5e --- /dev/null +++ b/test/WebSites/SecurityWebSite/Controllers/AdministrationController.cs @@ -0,0 +1,24 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace SecurityWebSite.Controllers +{ + // This controller is secured through the globally added authorize filter which + // allows only authenticated users. + public class AdministrationController : Controller + { + public IActionResult Index() + { + return Content("Administration.Index"); + } + + [AllowAnonymous] + public IActionResult AllowAnonymousAction() + { + return Content("Administration.AllowAnonymousAction"); + } + } +} diff --git a/test/WebSites/SecurityWebSite/StartupWithGlobalDenyAnonymousFilter.cs b/test/WebSites/SecurityWebSite/StartupWithGlobalDenyAnonymousFilter.cs new file mode 100644 index 0000000000..af49233670 --- /dev/null +++ b/test/WebSites/SecurityWebSite/StartupWithGlobalDenyAnonymousFilter.cs @@ -0,0 +1,36 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Mvc.Authorization; +using Microsoft.Extensions.DependencyInjection; + +namespace SecurityWebSite +{ + public class StartupWithGlobalDenyAnonymousFilter + { + public void ConfigureServices(IServiceCollection services) + { + services + .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) + .AddCookie(options => + { + options.LoginPath = "/Home/Login"; + options.LogoutPath = "/Home/Logout"; + }); + + services.AddMvc(o => + { + o.Filters.Add(new AuthorizeFilter()); + }); + } + + public void Configure(IApplicationBuilder app) + { + app.UseAuthentication(); + + app.UseMvcWithDefaultRoute(); + } + } +}