From fe29853912f0a1f2ea35bfbdbea6294acbcc15ae Mon Sep 17 00:00:00 2001 From: Louis DeJardin Date: Fri, 26 Feb 2010 00:50:19 -0800 Subject: [PATCH] Implementing AdminAuthorizationFilter to test for AccessAdminPanel Authorization will be required for a controller named "Admin" or when an [Admin] attribute is on controller, base controllers, or action Result will be HttpUnauthorizedResult if current user does not have StandardPermissions.AccessAdminPanel --HG-- branch : dev --- src/Orchard.Tests/Orchard.Tests.csproj | 1 + .../UI/Admin/AdminAttributeTests.cs | 134 ++++++++++++++++++ src/Orchard/Orchard.csproj | 3 +- src/Orchard/UI/Admin/AdminAttribute.cs | 6 + .../UI/Admin/AdminAuthorizationFilter.cs | 48 +++++++ src/Orchard/UI/Admin/AdminFilter.cs | 34 ----- 6 files changed, 191 insertions(+), 35 deletions(-) create mode 100644 src/Orchard.Tests/UI/Admin/AdminAttributeTests.cs create mode 100644 src/Orchard/UI/Admin/AdminAttribute.cs create mode 100644 src/Orchard/UI/Admin/AdminAuthorizationFilter.cs delete mode 100644 src/Orchard/UI/Admin/AdminFilter.cs diff --git a/src/Orchard.Tests/Orchard.Tests.csproj b/src/Orchard.Tests/Orchard.Tests.csproj index 61c86e9a8..fc3a13ca9 100644 --- a/src/Orchard.Tests/Orchard.Tests.csproj +++ b/src/Orchard.Tests/Orchard.Tests.csproj @@ -156,6 +156,7 @@ + diff --git a/src/Orchard.Tests/UI/Admin/AdminAttributeTests.cs b/src/Orchard.Tests/UI/Admin/AdminAttributeTests.cs new file mode 100644 index 000000000..18c33325d --- /dev/null +++ b/src/Orchard.Tests/UI/Admin/AdminAttributeTests.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web.Mvc; +using Moq; +using NUnit.Framework; +using Orchard.Localization; +using Orchard.Security; +using Orchard.Security.Permissions; +using Orchard.UI.Admin; + +namespace Orchard.Tests.UI.Admin { + [TestFixture] + public class AdminAttributeTests { + + private static AuthorizationContext GetAuthorizationContext() { + var controllerDescriptor = new ReflectedControllerDescriptor(typeof(TController)); + var controllerContext = new ControllerContext(); + return new AuthorizationContext( + controllerContext, + controllerDescriptor.FindAction(controllerContext, "Index")); + } + + private static IAuthorizer GetAuthorizer(bool result) { + var authorizer = new Mock(); + authorizer + .Setup(x => x.Authorize(StandardPermissions.AccessAdminPanel, It.IsAny())). + Returns(result); + return authorizer.Object; + } + + [Test] + public void NormalRequestShouldNotBeAffected() { + var authorizationContext = GetAuthorizationContext(); + + var filter = new AdminAuthorizationFilter(GetAuthorizer(false)); + filter.OnAuthorization(authorizationContext); + + Assert.That(authorizationContext.Result, Is.Null); + } + + [Test] + public void AdminRequestShouldRequirePermission() { + var authorizationContext = GetAuthorizationContext(); + var filter = new AdminAuthorizationFilter(GetAuthorizer(false)); + filter.OnAuthorization(authorizationContext); + Assert.That(authorizationContext.Result, Is.InstanceOf()); + + var authorizationContext2 = GetAuthorizationContext(); + var filter2 = new AdminAuthorizationFilter(GetAuthorizer(true)); + filter2.OnAuthorization(authorizationContext2); + Assert.That(authorizationContext2.Result, Is.Null); + } + + [Test] + public void NormalWithAttribRequestShouldRequirePermission() { + var authorizationContext = GetAuthorizationContext(); + var filter = new AdminAuthorizationFilter(GetAuthorizer(false)); + filter.OnAuthorization(authorizationContext); + Assert.That(authorizationContext.Result, Is.InstanceOf()); + + var authorizationContext2 = GetAuthorizationContext(); + var filter2 = new AdminAuthorizationFilter(GetAuthorizer(true)); + filter2.OnAuthorization(authorizationContext2); + Assert.That(authorizationContext2.Result, Is.Null); + } + + [Test] + public void NormalWithActionAttribRequestShouldRequirePermission() { + var authorizationContext = GetAuthorizationContext(); + var filter = new AdminAuthorizationFilter(GetAuthorizer(false)); + filter.OnAuthorization(authorizationContext); + Assert.That(authorizationContext.Result, Is.InstanceOf()); + + var authorizationContext2 = GetAuthorizationContext(); + var filter2 = new AdminAuthorizationFilter(GetAuthorizer(true)); + filter2.OnAuthorization(authorizationContext2); + Assert.That(authorizationContext2.Result, Is.Null); + } + + [Test] + public void InheritedAttribRequestShouldRequirePermission() { + var authorizationContext = GetAuthorizationContext(); + var filter = new AdminAuthorizationFilter(GetAuthorizer(false)); + filter.OnAuthorization(authorizationContext); + Assert.That(authorizationContext.Result, Is.InstanceOf()); + + var authorizationContext2 = GetAuthorizationContext(); + var filter2 = new AdminAuthorizationFilter(GetAuthorizer(true)); + filter2.OnAuthorization(authorizationContext2); + Assert.That(authorizationContext2.Result, Is.Null); + } + } + + public class NormalController : Controller { + public ActionResult Index() { + return View(); + } + } + + public class AdminController : Controller { + public ActionResult Index() { + return View(); + } + } + + [Admin] + public class NormalWithAttribController : Controller { + public ActionResult Index() { + return View(); + } + } + + public class NormalWithActionAttribController : Controller { + [Admin] + public ActionResult Index() { + return View(); + } + } + + [Admin] + public class BaseWithAttribController : Controller { + public ActionResult Something() { + return View(); + } + } + + public class InheritedAttribController : BaseWithAttribController { + public ActionResult Index() { + return View(); + } + } +} diff --git a/src/Orchard/Orchard.csproj b/src/Orchard/Orchard.csproj index f1a9b3760..735eb6a3a 100644 --- a/src/Orchard/Orchard.csproj +++ b/src/Orchard/Orchard.csproj @@ -225,7 +225,8 @@ - + + diff --git a/src/Orchard/UI/Admin/AdminAttribute.cs b/src/Orchard/UI/Admin/AdminAttribute.cs new file mode 100644 index 000000000..e6053299e --- /dev/null +++ b/src/Orchard/UI/Admin/AdminAttribute.cs @@ -0,0 +1,6 @@ +using System; + +namespace Orchard.UI.Admin { + public class AdminAttribute : Attribute { + } +} diff --git a/src/Orchard/UI/Admin/AdminAuthorizationFilter.cs b/src/Orchard/UI/Admin/AdminAuthorizationFilter.cs new file mode 100644 index 000000000..7399e723e --- /dev/null +++ b/src/Orchard/UI/Admin/AdminAuthorizationFilter.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web.Mvc; +using Orchard.Localization; +using Orchard.Mvc.Filters; +using Orchard.Security; + +namespace Orchard.UI.Admin { + public class AdminAuthorizationFilter : FilterProvider, IAuthorizationFilter { + private readonly IAuthorizer _authorizer; + + public AdminAuthorizationFilter(IAuthorizer authorizer) { + _authorizer = authorizer; + T = NullLocalizer.Instance; + } + + public Localizer T { get; set; } + + public void OnAuthorization(AuthorizationContext filterContext) { + if (!IsAdmin(filterContext)) + return; + + if (!_authorizer.Authorize(StandardPermissions.AccessAdminPanel, T("Can't access the admin"))) { + filterContext.Result = new HttpUnauthorizedResult(); + } + } + + private static bool IsAdmin(AuthorizationContext filterContext) { + if (string.Equals(filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, "Admin", + StringComparison.InvariantCultureIgnoreCase)) { + return true; + } + + var adminAttributes = GetAdminAttributes(filterContext.ActionDescriptor); + if (adminAttributes != null && adminAttributes.Any()) { + return true; + } + return false; + } + + private static IEnumerable GetAdminAttributes(ActionDescriptor descriptor) { + return descriptor.GetCustomAttributes(typeof(AdminAttribute), true) + .Concat(descriptor.ControllerDescriptor.GetCustomAttributes(typeof(AdminAttribute), true)) + .OfType(); + } + } +} \ No newline at end of file diff --git a/src/Orchard/UI/Admin/AdminFilter.cs b/src/Orchard/UI/Admin/AdminFilter.cs deleted file mode 100644 index 99ffaf347..000000000 --- a/src/Orchard/UI/Admin/AdminFilter.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Globalization; -using System.IO; -using System.Web.Mvc; -using Orchard.Mvc.Filters; -using Orchard.Security; -using Orchard.Settings; - -namespace Orchard.UI.Admin { - public class AdminFilter : FilterProvider, IActionFilter - { - private readonly IAuthorizer _authorizer; - private readonly ISiteService _siteService; - - public AdminFilter(IAuthorizer authorizer, ISiteService siteService) - { - _authorizer = authorizer; - _siteService = siteService; - } - - public void OnActionExecuting(ActionExecutingContext filterContext) - { - var siteUrl = _siteService.GetSiteSettings().SiteUrl; - //todo: (heskew) get at the admin path in a less hacky way - if (filterContext.HttpContext.Request.RawUrl.StartsWith(Path.Combine(siteUrl, "admin").Replace("\\", "/"), true, CultureInfo.InvariantCulture) - && !_authorizer.Authorize(StandardPermissions.AccessAdminPanel, "Can't access the admin")) { - filterContext.Result = new HttpUnauthorizedResult(); - } - } - - public void OnActionExecuted(ActionExecutedContext filterContext) - { - } - } -} \ No newline at end of file