Updated Admin filter and access control

AdminController convention or [Admin] attribute activates both the security
check and "TheAdmin" theme

--HG--
branch : dev
This commit is contained in:
Louis DeJardin
2010-02-26 03:09:52 -08:00
parent fe29853912
commit a25f68ae90
8 changed files with 123 additions and 65 deletions

View File

@@ -156,7 +156,8 @@
<Compile Include="Mvc\RouteCollectionPublisherTests.cs" />
<Compile Include="Mvc\Routes\StandardExtensionRouteProviderTests.cs" />
<Compile Include="Tasks\SweepGeneratorTests.cs" />
<Compile Include="UI\Admin\AdminAttributeTests.cs" />
<Compile Include="UI\Admin\AdminAuthorizationFilterTests.cs" />
<Compile Include="UI\Admin\AdminThemeSelectorTests.cs" />
<Compile Include="UI\Notify\NotifierTests.cs" />
<Compile Include="UI\Notify\NotifyFilterTests.cs" />
<Compile Include="Services\ClockTests.cs" />

View File

@@ -1,8 +1,11 @@
using System.Collections;
using System.Collections.Generic;
using System.Web;
namespace Orchard.Tests.Stubs {
public class StubHttpContext : HttpContextBase {
private readonly string _appRelativeCurrentExecutionFilePath;
private readonly IDictionary _items = new Dictionary<object, object>();
public StubHttpContext() {
_appRelativeCurrentExecutionFilePath = "~/yadda";
@@ -16,6 +19,10 @@ namespace Orchard.Tests.Stubs {
get { return new StupHttpRequest(_appRelativeCurrentExecutionFilePath); }
}
public override IDictionary Items {
get { return _items; }
}
public class StupHttpRequest : HttpRequestBase {
private readonly string _appRelativeCurrentExecutionFilePath;

View File

@@ -1,22 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;
using NUnit.Framework;
using Orchard.Localization;
using Orchard.Security;
using Orchard.Security.Permissions;
using Orchard.Tests.Stubs;
using Orchard.UI.Admin;
namespace Orchard.Tests.UI.Admin {
[TestFixture]
public class AdminAttributeTests {
public class AdminAuthorizationFilterTests {
private static AuthorizationContext GetAuthorizationContext<TController>() {
private static AuthorizationContext GetAuthorizationContext<TController>() where TController : ControllerBase, new() {
var controllerDescriptor = new ReflectedControllerDescriptor(typeof(TController));
var controllerContext = new ControllerContext();
var controllerContext = new ControllerContext(new StubHttpContext(), new RouteData(), new TController());
return new AuthorizationContext(
controllerContext,
controllerDescriptor.FindAction(controllerContext, "Index"));
@@ -40,56 +37,39 @@ namespace Orchard.Tests.UI.Admin {
Assert.That(authorizationContext.Result, Is.Null);
}
[Test]
public void AdminRequestShouldRequirePermission() {
var authorizationContext = GetAuthorizationContext<AdminController>();
private static void TestActionThatShouldRequirePermission<TController>() where TController : ControllerBase, new() {
var authorizationContext = GetAuthorizationContext<TController>();
var filter = new AdminAuthorizationFilter(GetAuthorizer(false));
filter.OnAuthorization(authorizationContext);
Assert.That(authorizationContext.Result, Is.InstanceOf<HttpUnauthorizedResult>());
Assert.That(AdminThemeSelector.IsApplied(authorizationContext.RequestContext), Is.True);
var authorizationContext2 = GetAuthorizationContext<AdminController>();
var authorizationContext2 = GetAuthorizationContext<TController>();
var filter2 = new AdminAuthorizationFilter(GetAuthorizer(true));
filter2.OnAuthorization(authorizationContext2);
Assert.That(authorizationContext2.Result, Is.Null);
Assert.That(AdminThemeSelector.IsApplied(authorizationContext2.RequestContext), Is.True);
}
[Test]
public void AdminRequestShouldRequirePermission() {
TestActionThatShouldRequirePermission<AdminController>();
}
[Test]
public void NormalWithAttribRequestShouldRequirePermission() {
var authorizationContext = GetAuthorizationContext<NormalWithAttribController>();
var filter = new AdminAuthorizationFilter(GetAuthorizer(false));
filter.OnAuthorization(authorizationContext);
Assert.That(authorizationContext.Result, Is.InstanceOf<HttpUnauthorizedResult>());
var authorizationContext2 = GetAuthorizationContext<NormalWithAttribController>();
var filter2 = new AdminAuthorizationFilter(GetAuthorizer(true));
filter2.OnAuthorization(authorizationContext2);
Assert.That(authorizationContext2.Result, Is.Null);
TestActionThatShouldRequirePermission<NormalWithAttribController>();
}
[Test]
public void NormalWithActionAttribRequestShouldRequirePermission() {
var authorizationContext = GetAuthorizationContext<NormalWithActionAttribController>();
var filter = new AdminAuthorizationFilter(GetAuthorizer(false));
filter.OnAuthorization(authorizationContext);
Assert.That(authorizationContext.Result, Is.InstanceOf<HttpUnauthorizedResult>());
var authorizationContext2 = GetAuthorizationContext<NormalWithActionAttribController>();
var filter2 = new AdminAuthorizationFilter(GetAuthorizer(true));
filter2.OnAuthorization(authorizationContext2);
Assert.That(authorizationContext2.Result, Is.Null);
TestActionThatShouldRequirePermission<NormalWithActionAttribController>();
}
[Test]
public void InheritedAttribRequestShouldRequirePermission() {
var authorizationContext = GetAuthorizationContext<InheritedAttribController>();
var filter = new AdminAuthorizationFilter(GetAuthorizer(false));
filter.OnAuthorization(authorizationContext);
Assert.That(authorizationContext.Result, Is.InstanceOf<HttpUnauthorizedResult>());
var authorizationContext2 = GetAuthorizationContext<InheritedAttribController>();
var filter2 = new AdminAuthorizationFilter(GetAuthorizer(true));
filter2.OnAuthorization(authorizationContext2);
Assert.That(authorizationContext2.Result, Is.Null);
TestActionThatShouldRequirePermission<InheritedAttribController>();
}
}
@@ -118,7 +98,7 @@ namespace Orchard.Tests.UI.Admin {
return View();
}
}
[Admin]
public class BaseWithAttribController : Controller {
public ActionResult Something() {

View File

@@ -0,0 +1,58 @@
using System.Web.Routing;
using NUnit.Framework;
using Orchard.Tests.Stubs;
using Orchard.UI.Admin;
namespace Orchard.Tests.UI.Admin {
[TestFixture]
public class AdminThemeSelectorTests {
[Test]
public void IsAppliedShouldBeFalseByDefault() {
var context = new RequestContext(new StubHttpContext(), new RouteData());
var isApplied = AdminThemeSelector.IsApplied(context);
Assert.That(isApplied, Is.False);
}
[Test]
public void IsAppliedShouldBeTrueAfterBeingApplied() {
var context = new RequestContext(new StubHttpContext(), new RouteData());
Assert.That(AdminThemeSelector.IsApplied(context), Is.False);
AdminThemeSelector.Apply(context);
Assert.That(AdminThemeSelector.IsApplied(context), Is.True);
}
[Test]
public void IsAppliedIsFalseOnNewContext() {
var context = new RequestContext(new StubHttpContext(), new RouteData());
Assert.That(AdminThemeSelector.IsApplied(context), Is.False);
AdminThemeSelector.Apply(context);
Assert.That(AdminThemeSelector.IsApplied(context), Is.True);
context = new RequestContext(new StubHttpContext(), new RouteData());
Assert.That(AdminThemeSelector.IsApplied(context), Is.False);
}
[Test]
public void ThemeResultShouldBeNullNormally() {
var context = new RequestContext(new StubHttpContext(), new RouteData());
var selector = new AdminThemeSelector();
var result = selector.GetTheme(context);
Assert.That(result, Is.Null);
}
[Test]
public void ThemeResultShouldBeTheAdminAt100AfterBeingSet() {
var context = new RequestContext(new StubHttpContext(), new RouteData());
AdminThemeSelector.Apply(context);
var selector = new AdminThemeSelector();
var result = selector.GetTheme(context);
Assert.That(result, Is.Not.Null);
Assert.That(result.ThemeName, Is.EqualTo("TheAdmin"));
Assert.That(result.Priority, Is.EqualTo(100));
}
}
}

View File

@@ -11,10 +11,11 @@ using Orchard.Core.Common.Models;
using Orchard.Localization;
using Orchard.Mvc.Results;
using Orchard.Settings;
using Orchard.UI.Admin;
using Orchard.UI.Notify;
namespace Orchard.Blogs.Controllers {
[ValidateInput(false)]
[ValidateInput(false), Admin]
public class BlogAdminController : Controller, IUpdateModel {
private readonly IBlogService _blogService;
private readonly IBlogPostService _blogPostService;

View File

@@ -6,10 +6,11 @@ using Orchard.Blogs.ViewModels;
using Orchard.ContentManagement;
using Orchard.Localization;
using Orchard.Mvc.Results;
using Orchard.UI.Admin;
using Orchard.UI.Notify;
namespace Orchard.Blogs.Controllers {
[ValidateInput(false)]
[ValidateInput(false), Admin]
public class BlogPostAdminController : Controller, IUpdateModel {
private readonly IBlogService _blogService;
private readonly IBlogPostService _blogPostService;

View File

@@ -18,17 +18,17 @@ namespace Orchard.UI.Admin {
public Localizer T { get; set; }
public void OnAuthorization(AuthorizationContext filterContext) {
if (!IsAdmin(filterContext))
return;
if (IsAdmin(filterContext)) {
if (!_authorizer.Authorize(StandardPermissions.AccessAdminPanel, T("Can't access the admin"))) {
filterContext.Result = new HttpUnauthorizedResult();
}
if (!_authorizer.Authorize(StandardPermissions.AccessAdminPanel, T("Can't access the admin"))) {
filterContext.Result = new HttpUnauthorizedResult();
AdminThemeSelector.Apply(filterContext.RequestContext);
}
}
private static bool IsAdmin(AuthorizationContext filterContext) {
if (string.Equals(filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, "Admin",
StringComparison.InvariantCultureIgnoreCase)) {
if (IsNameAdmin(filterContext) || IsNameAdminProxy(filterContext)) {
return true;
}
@@ -39,6 +39,17 @@ namespace Orchard.UI.Admin {
return false;
}
private static bool IsNameAdmin(AuthorizationContext filterContext) {
return string.Equals(filterContext.ActionDescriptor.ControllerDescriptor.ControllerName, "Admin",
StringComparison.InvariantCultureIgnoreCase);
}
private static bool IsNameAdminProxy(AuthorizationContext filterContext) {
return filterContext.ActionDescriptor.ControllerDescriptor.ControllerName.StartsWith(
"AdminControllerProxy", StringComparison.InvariantCultureIgnoreCase) &&
filterContext.ActionDescriptor.ControllerDescriptor.ControllerName.Length == "AdminControllerProxy".Length + 32;
}
private static IEnumerable<AdminAttribute> GetAdminAttributes(ActionDescriptor descriptor) {
return descriptor.GetCustomAttributes(typeof(AdminAttribute), true)
.Concat(descriptor.ControllerDescriptor.GetCustomAttributes(typeof(AdminAttribute), true))

View File

@@ -1,24 +1,23 @@
using System.Globalization;
using System.IO;
using System.Web.Routing;
using Orchard.Settings;
using System.Web.Routing;
using Orchard.Themes;
namespace Orchard.UI.Admin {
public class AdminThemeSelector : IThemeSelector {
private readonly ISiteService _siteService;
public ThemeSelectorResult GetTheme(RequestContext context) {
if (IsApplied(context)) {
return new ThemeSelectorResult { Priority = 100, ThemeName = "TheAdmin" };
}
public AdminThemeSelector(ISiteService siteService) {
_siteService = siteService;
return null;
}
public ThemeSelectorResult GetTheme(RequestContext context) {
var siteUrl = _siteService.GetSiteSettings().SiteUrl;
//todo: (heskew) get at the admin path in a less hacky way
if (!context.HttpContext.Request.Path.StartsWith(Path.Combine(siteUrl, "admin").Replace("\\", "/"), true, CultureInfo.InvariantCulture))
return null;
public static void Apply(RequestContext context) {
// the value isn't important
context.HttpContext.Items[typeof(AdminThemeSelector)] = null;
}
return new ThemeSelectorResult { Priority = 100, ThemeName = "TheAdmin" };
public static bool IsApplied(RequestContext context) {
return context.HttpContext.Items.Contains(typeof(AdminThemeSelector));
}
}
}
}