Further work updating security model

--HG--
extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4045825
This commit is contained in:
loudej 2010-01-22 05:25:54 +00:00
parent 95d5398f50
commit 6d95217b6a
33 changed files with 290 additions and 83 deletions

View File

@ -13,7 +13,9 @@ using Orchard.Environment;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.Records;
using Orchard.Localization;
using Orchard.Security;
using Orchard.Security.Permissions;
using Orchard.UI.Notify;
using Orchard.Users.Controllers;
using Orchard.Users.Models;
@ -24,6 +26,7 @@ namespace Orchard.Tests.Packages.Users.Controllers {
[TestFixture]
public class AdminControllerTests : DatabaseEnabledTestsBase {
private AdminController _controller;
private Mock<IAuthorizer> _authorizer;
public override void Register(ContainerBuilder builder) {
builder.Register<AdminController>();
@ -34,7 +37,8 @@ namespace Orchard.Tests.Packages.Users.Controllers {
builder.Register<OrchardServices>().As<IOrchardServices>();
builder.Register<TransactionManager>().As<ITransactionManager>();
builder.Register(new Mock<INotifier>().Object);
builder.Register(new Mock<IAuthorizer>().Object);
_authorizer = new Mock<IAuthorizer>();
builder.Register(_authorizer.Object);
}
protected override IEnumerable<Type> DatabaseTypes {
@ -73,6 +77,8 @@ namespace Orchard.Tests.Packages.Users.Controllers {
[Test]
public void IndexShouldReturnRowsForUsers() {
_authorizer.Setup(x => x.Authorize(It.IsAny<Permission>(), It.IsAny<LocalizedString>())).Returns(true);
var controller = _container.Resolve<AdminController>();
var result = (ViewResult)controller.Index();
var model = (UsersIndexViewModel)result.ViewData.Model;
@ -83,13 +89,15 @@ namespace Orchard.Tests.Packages.Users.Controllers {
[Test]
public void CreateShouldAddUserAndRedirect() {
_authorizer.Setup(x => x.Authorize(It.IsAny<Permission>(), It.IsAny<LocalizedString>())).Returns(true);
var controller = _container.Resolve<AdminController>();
controller.ValueProvider = Values.From(new {
UserName = "four",
Password = "five",
ConfirmPassword = "five"
});
var result = controller._Create();
var result = controller.CreatePOST();
Assert.That(result, Is.TypeOf<RedirectToRouteResult>());
var redirect = (RedirectToRouteResult)result;
@ -101,6 +109,8 @@ namespace Orchard.Tests.Packages.Users.Controllers {
[Test]
public void EditShouldDisplayUserAndStoreChanges() {
_authorizer.Setup(x => x.Authorize(It.IsAny<Permission>(), It.IsAny<LocalizedString>())).Returns(true);
var repository = _container.Resolve<IRepository<UserRecord>>();
var id = repository.Get(x => x.UserName == "two").Id;
var result = (ViewResult)_container.Resolve<AdminController>().Edit(id);
@ -112,7 +122,7 @@ namespace Orchard.Tests.Packages.Users.Controllers {
UserName = "bubba",
Email = "hotep",
});
var result2 = controller._Edit(id);
var result2 = controller.EditPOST(id);
Assert.That(result2, Is.TypeOf<RedirectToRouteResult>());
}
}

View File

@ -7,7 +7,7 @@ namespace Orchard.Core.Settings {
public void GetNavigation(NavigationBuilder builder) {
builder.Add("Settings", "11",
menu => menu
.Add("Manage Settings", "2.0", item => item.Action("Index", "Admin", new { area = "Settings" })));
.Add("Manage Settings", "2.0", item => item.Action("Index", "Admin", new { area = "Settings" }).Permission(Permissions.ManageSettings)));
}
}
}

View File

@ -3,6 +3,8 @@ using Orchard.Core.Settings.Models;
using Orchard.Core.Settings.ViewModels;
using Orchard.Localization;
using Orchard.ContentManagement;
using Orchard.Security;
using Orchard.Security.Permissions;
using Orchard.Settings;
using Orchard.UI.Notify;
@ -10,40 +12,43 @@ namespace Orchard.Core.Settings.Controllers {
[ValidateInput(false)]
public class AdminController : Controller, IUpdateModel {
private readonly ISiteService _siteService;
private readonly IContentManager _modelManager;
private readonly INotifier _notifier;
public IOrchardServices Services { get; private set; }
public AdminController(ISiteService siteService, IContentManager modelManager, INotifier notifier) {
public AdminController(ISiteService siteService, IOrchardServices services) {
_siteService = siteService;
_modelManager = modelManager;
_notifier = notifier;
Services = services;
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public ActionResult Index(string tabName) {
if (!Services.Authorizer.Authorize(Permissions.ManageSettings, T("Not authorized to manage settings")))
return new HttpUnauthorizedResult();
var model = new SettingsIndexViewModel {
Site = _siteService.GetSiteSettings().As<SiteSettings>()
};
model.ViewModel = _modelManager.BuildEditorModel(model.Site);
model.ViewModel = Services.ContentManager.BuildEditorModel(model.Site);
return View(model);
}
[HttpPost, ActionName("Index")]
public ActionResult IndexPOST(string tabName) {
if (!Services.Authorizer.Authorize(Permissions.ManageSettings, T("Not authorized to manage settings")))
return new HttpUnauthorizedResult();
var viewModel = new SettingsIndexViewModel { Site = _siteService.GetSiteSettings().As<SiteSettings>() };
viewModel.ViewModel = _modelManager.UpdateEditorModel(viewModel.Site.ContentItem, this);
viewModel.ViewModel = Services.ContentManager.UpdateEditorModel(viewModel.Site.ContentItem, this);
if (!TryUpdateModel(viewModel)) {
return View(viewModel);
}
_notifier.Information(T("Settings updated"));
Services.Notifier.Information(T("Settings updated"));
return RedirectToAction("Index");
}
#region IUpdateModel Members
bool IUpdateModel.TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties) {
return TryUpdateModel(model, prefix, includeProperties, excludeProperties);
@ -52,7 +57,5 @@ namespace Orchard.Core.Settings.Controllers {
void IUpdateModel.AddModelError(string key, LocalizedString errorMessage) {
ModelState.AddModelError(key, errorMessage.ToString());
}
#endregion
}
}

View File

@ -7,7 +7,8 @@ namespace Orchard.Core.Themes {
public void GetNavigation(NavigationBuilder builder) {
builder.Add("Themes", "11",
menu => menu
.Add("Manage Themes", "2.0", item => item.Action("Index", "Admin", new { area = "Themes" })));
.Add("Manage Themes", "2.0", item => item.Action("Index", "Admin", new { area = "Themes" })
.Permission(Permissions.ManageThemes).Permission(Permissions.ApplyTheme)));
}
}
}

View File

@ -7,8 +7,8 @@ namespace Orchard.Blogs {
public void GetNavigation(NavigationBuilder builder) {
builder.Add("Blogs", "2",
menu => menu
.Add("Manage Blogs", "1.0", item => item.Action("List", "BlogAdmin", new { area = "Orchard.Blogs" }))
.Add("Add New Blog", "1.1", item => item.Action("Create", "BlogAdmin", new { area = "Orchard.Blogs" })));
.Add("Manage Blogs", "1.0", item => item.Action("List", "BlogAdmin", new { area = "Orchard.Blogs" }).Permission(Permissions.MetaListBlogs))
.Add("Add New Blog", "1.1", item => item.Action("Create", "BlogAdmin", new { area = "Orchard.Blogs" }).Permission(Permissions.ManageBlogs)));
}
}
}

View File

@ -4,15 +4,17 @@ using Orchard.Security.Permissions;
namespace Orchard.Blogs {
public class Permissions : IPermissionProvider {
public static readonly Permission ManageBlogs = new Permission { Description = "Edit blog properties", Name = "ManageBlogs" };//q: Should edit_blog be ManageBlogs?
public static readonly Permission ManageBlogs = new Permission { Description = "Manage blogs", Name = "ManageBlogs" };//q: Should edit_blog be ManageBlogs?
public static readonly Permission EditBlogPost = new Permission { Description = "Edit own blog posts", Name = "EditBlogPost" };
public static readonly Permission EditOthersBlogPost = new Permission { Description = "Edit any blog posts", Name = "EditOthersBlogPost" };
public static readonly Permission PublishBlogPost = new Permission { Description = "Publish or unpublish blog post", Name = "PublishBlogPost" };
public static readonly Permission PublishOthersBlogPost = new Permission { Description = "Publish or unpublish blog post for others", Name = "PublishOthersBlogPost" };
public static readonly Permission DeleteBlogPost = new Permission { Description = "Delete blog post", Name = "DeleteBlogPost" };
public static readonly Permission DeleteOthersBlogPost = new Permission { Description = "Delete blog post for others", Name = "DeleteOthersBlogPost" };
public static readonly Permission PublishOthersBlogPost = new Permission { Description = "Publish or unpublish blog post for others", Name = "PublishOthersBlogPost", ImpliedBy = new[] { ManageBlogs } };
public static readonly Permission PublishBlogPost = new Permission { Description = "Publish or unpublish blog post", Name = "PublishBlogPost", ImpliedBy = new[] { PublishOthersBlogPost } };
public static readonly Permission EditOthersBlogPost = new Permission { Description = "Edit any blog posts", Name = "EditOthersBlogPost", ImpliedBy = new[] { PublishOthersBlogPost } };
public static readonly Permission EditBlogPost = new Permission { Description = "Edit own blog posts", Name = "EditBlogPost", ImpliedBy = new[] { EditOthersBlogPost, PublishBlogPost } };
public static readonly Permission DeleteOthersBlogPost = new Permission { Description = "Delete blog post for others", Name = "DeleteOthersBlogPost", ImpliedBy = new[] { ManageBlogs } };
public static readonly Permission DeleteBlogPost = new Permission { Description = "Delete blog post", Name = "DeleteBlogPost", ImpliedBy = new[] { DeleteOthersBlogPost } };
public static readonly Permission MetaListOthersBlogs = new Permission { ImpliedBy = new[] { EditOthersBlogPost, PublishOthersBlogPost, DeleteOthersBlogPost } };
public static readonly Permission MetaListBlogs = new Permission { ImpliedBy = new[] { EditBlogPost, PublishBlogPost, DeleteBlogPost } };
public string PackageName {
get {

View File

@ -7,7 +7,7 @@ namespace Orchard.Comments {
public void GetNavigation(NavigationBuilder builder) {
builder.Add("Comments", "3",
menu => menu
.Add("Manage Comments", "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.Comments" }))
.Add("Manage Comments", "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.Comments" }).Permission(Permissions.ManageComments))
);
}
}

View File

@ -1,14 +1,11 @@
using Orchard.UI.Navigation;
namespace Orchard.Media {
namespace Orchard.DevTools {
public class AdminMenu : INavigationProvider {
public string MenuName { get { return "admin"; } }
public void GetNavigation(NavigationBuilder builder) {
builder.Add("Media", "4",
menu => menu
.Add("Manage Folders", "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.Media" }))
);
}
}
}
}

View File

@ -70,6 +70,7 @@
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Models\DebugLinkHandler.cs" />
<Compile Include="Models\ShowDebugLink.cs" />
<Compile Include="Permissions.cs" />
<Compile Include="Profiler.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewModels\ContentIndexViewModel.cs" />

View File

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Orchard.Security.Permissions;
namespace Orchard.DevTools {
public class Permissions : IPermissionProvider {
public static readonly Permission DebugShowAllMenuItems = new Permission { Description = "DevTools: Show all menu items", Name = "DebugShowAllMenuItems" };
public string PackageName {
get {
return "DevTools";
}
}
public IEnumerable<Permission> GetPermissions() {
return new Permission[] {
DebugShowAllMenuItems,
};
}
public IEnumerable<PermissionStereotype> GetDefaultStereotypes() {
return Enumerable.Empty<PermissionStereotype>();
}
}
}

View File

@ -7,7 +7,7 @@ namespace Orchard.Media {
public void GetNavigation(NavigationBuilder builder) {
builder.Add("Media", "4",
menu => menu
.Add("Manage Folders", "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.Media" }))
.Add("Manage Folders", "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.Media" }).Permission(Permissions.ManageMediaFiles))
);
}
}

View File

@ -7,8 +7,8 @@ namespace Orchard.Pages {
public void GetNavigation(NavigationBuilder builder) {
builder.Add("Pages", "1",
menu => menu
.Add("Manage Pages", "1.0", item => item.Action("List", "Admin", new { area = "Orchard.Pages" }))
.Add("Add New Page", "1.1", item => item.Action("Create", "Admin", new { area = "Orchard.Pages" })));
.Add("Manage Pages", "1.0", item => item.Action("List", "Admin", new { area = "Orchard.Pages" }).Permission(Permissions.MetaListPages))
.Add("Add New Page", "1.1", item => item.Action("Create", "Admin", new { area = "Orchard.Pages" }).Permission(Permissions.EditPages)));
}
}
}

View File

@ -4,12 +4,14 @@ using Orchard.Security.Permissions;
namespace Orchard.Pages {
public class Permissions : IPermissionProvider {
public static readonly Permission EditPages = new Permission { Description = "Edit page", Name = "EditPages" };
public static readonly Permission EditOthersPages = new Permission { Description = "Edit page for others", Name = "EditOthersPages" };
public static readonly Permission PublishPages = new Permission { Description = "Publish or unpublish page", Name = "PublishPages" };
public static readonly Permission PublishOthersPages = new Permission { Description = "Publish or unpublish page for others", Name = "PublishOthersPages" };
public static readonly Permission DeletePages = new Permission { Description = "Delete page", Name = "DeletePages" };
public static readonly Permission PublishPages = new Permission { Description = "Publish or unpublish page", Name = "PublishPages", ImpliedBy = new[] { PublishOthersPages } };
public static readonly Permission EditOthersPages = new Permission { Description = "Edit page for others", Name = "EditOthersPages", ImpliedBy = new[] { PublishOthersPages } };
public static readonly Permission EditPages = new Permission { Description = "Edit page", Name = "EditPages", ImpliedBy = new[] { EditOthersPages, PublishPages } };
public static readonly Permission DeleteOthersPages = new Permission { Description = "Delete page for others", Name = "DeleteOthersPages" };
public static readonly Permission DeletePages = new Permission { Description = "Delete page", Name = "DeletePages", ImpliedBy = new[] { DeleteOthersPages } };
public static readonly Permission MetaListPages = new Permission { ImpliedBy = new[] { EditPages, PublishPages, DeletePages } };
public string PackageName {
get {

View File

@ -7,8 +7,8 @@ namespace Orchard.Roles {
public void GetNavigation(NavigationBuilder builder) {
builder.Add("Users", "5",
menu => menu
.Add("Manage Roles", "2.0", item => item.Action("Index", "Admin", new { area = "Orchard.Roles" }))
.Add("Add New Role", "2.1", item => item.Action("Create", "Admin", new { area = "Orchard.Roles" })));
.Add("Manage Roles", "2.0", item => item.Action("Index", "Admin", new { area = "Orchard.Roles" }).Permission(Permissions.ManageRoles))
.Add("Add New Role", "2.1", item => item.Action("Create", "Admin", new { area = "Orchard.Roles" }).Permission(Permissions.ManageRoles)));
}
}
}

View File

@ -1,10 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Orchard.Localization;
using Orchard.Roles.Models;
using Orchard.Roles.Records;
using Orchard.Roles.Services;
using Orchard.Roles.ViewModels;
using Orchard.Security;
using Orchard.Security.Permissions;
using Orchard.UI.Notify;
namespace Orchard.Roles.Controllers {
@ -12,13 +17,27 @@ namespace Orchard.Roles.Controllers {
public class AdminController : Controller {
private readonly IRoleService _roleService;
private readonly INotifier _notifier;
private readonly IAuthorizationService _authorizationService;
public AdminController(IRoleService roleService, INotifier notifier) {
public AdminController(
IOrchardServices services,
IRoleService roleService,
INotifier notifier,
IAuthorizationService authorizationService) {
Services = services;
_roleService = roleService;
_notifier = notifier;
_authorizationService = authorizationService;
}
public IOrchardServices Services { get; set; }
public Localizer T { get; set; }
public ActionResult Index() {
if (!Services.Authorizer.Authorize(Permissions.ManageRoles, T("Not authorized to manage roles")))
return new HttpUnauthorizedResult();
var model = new RolesIndexViewModel { Rows = _roleService.GetRoles() as IList<RoleRecord> };
return View(model);
@ -26,6 +45,9 @@ namespace Orchard.Roles.Controllers {
[HttpPost, ActionName("Index")]
public ActionResult IndexPOST() {
if (!Services.Authorizer.Authorize(Permissions.ManageRoles, T("Not authorized to manage roles")))
return new HttpUnauthorizedResult();
try {
foreach (string key in Request.Form.Keys) {
if (key.StartsWith("Checkbox.") && Request.Form[key] == "true") {
@ -42,12 +64,18 @@ namespace Orchard.Roles.Controllers {
}
public ActionResult Create() {
if (!Services.Authorizer.Authorize(Permissions.ManageRoles, T("Not authorized to manage roles")))
return new HttpUnauthorizedResult();
var model = new RoleCreateViewModel { PackagePermissions = _roleService.GetInstalledPermissions() };
return View(model);
}
[HttpPost, ActionName("Create")]
public ActionResult CreatePOST() {
if (!Services.Authorizer.Authorize(Permissions.ManageRoles, T("Not authorized to manage roles")))
return new HttpUnauthorizedResult();
var viewModel = new RoleCreateViewModel();
try {
UpdateModel(viewModel);
@ -55,7 +83,7 @@ namespace Orchard.Roles.Controllers {
foreach (string key in Request.Form.Keys) {
if (key.StartsWith("Checkbox.") && Request.Form[key] == "true") {
string permissionName = key.Substring("Checkbox.".Length);
_roleService.CreatePermissionForRole(viewModel.Name,
_roleService.CreatePermissionForRole(viewModel.Name,
permissionName);
}
}
@ -68,6 +96,9 @@ namespace Orchard.Roles.Controllers {
}
public ActionResult Edit(int id) {
if (!Services.Authorizer.Authorize(Permissions.ManageRoles, T("Not authorized to manage roles")))
return new HttpUnauthorizedResult();
var role = _roleService.GetRole(id);
if (role == null) {
//TODO: Error message
@ -77,11 +108,22 @@ namespace Orchard.Roles.Controllers {
PackagePermissions = _roleService.GetInstalledPermissions(),
CurrentPermissions = _roleService.GetPermissionsForRole(id)};
var simulation = UserSimulation.Create(role.Name);
model.EffectivePermissions = model.PackagePermissions
.SelectMany(group => group.Value)
.Where(permission => _authorizationService.CheckAccess(simulation, permission))
.Select(permission=>permission.Name)
.Distinct()
.ToList();
return View(model);
}
[HttpPost, ActionName("Edit")]
public ActionResult EditPOST() {
if (!Services.Authorizer.Authorize(Permissions.ManageRoles, T("Not authorized to manage roles")))
return new HttpUnauthorizedResult();
var viewModel = new RoleEditViewModel();
try {
UpdateModel(viewModel);
@ -99,7 +141,7 @@ namespace Orchard.Roles.Controllers {
else if (!String.IsNullOrEmpty(HttpContext.Request.Form["submit.Delete"])) {
_roleService.DeleteRole(viewModel.Id);
}
return RedirectToAction("Index");
return RedirectToAction("Edit", new { viewModel.Id });
}
catch (Exception exception) {
_notifier.Error("Editing Role failed: " + exception.Message);

View File

@ -1,12 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Linq;
using JetBrains.Annotations;
using Orchard.ContentManagement.Drivers;
using Orchard.Data;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.ViewModels;
using Orchard.Roles.Models.NoRecord;
using Orchard.Roles.Records;
using Orchard.Roles.Services;
@ -15,18 +11,25 @@ using Orchard.Security;
using Orchard.UI.Notify;
namespace Orchard.Roles.Controllers {
[UsedImplicitly]
public class UserRolesDriver : ContentPartDriver<UserRoles> {
private readonly IRepository<UserRolesRecord> _userRolesRepository;
private readonly IRoleService _roleService;
private readonly INotifier _notifier;
private readonly IAuthenticationService _authenticationService;
private readonly IAuthorizationService _authorizationService;
public UserRolesDriver(
IRepository<UserRolesRecord> userRolesRepository,
IRoleService roleService,
INotifier notifier) {
INotifier notifier,
IAuthenticationService authenticationService,
IAuthorizationService authorizationService) {
_userRolesRepository = userRolesRepository;
_roleService = roleService;
_notifier = notifier;
_authenticationService = authenticationService;
_authorizationService = authorizationService;
}
protected override string Prefix {
@ -36,6 +39,10 @@ namespace Orchard.Roles.Controllers {
}
protected override DriverResult Editor(UserRoles userRoles) {
// don't show editor without apply roles permission
if (!_authorizationService.CheckAccess(_authenticationService.GetAuthenticatedUser(), Permissions.ApplyRoles))
return null;
var roles =
_roleService.GetRoles().Select(
x => new UserRoleEntry {
@ -53,6 +60,10 @@ namespace Orchard.Roles.Controllers {
}
protected override DriverResult Editor(UserRoles userRoles, IUpdateModel updater) {
// don't apply editor without apply roles permission
if (!_authorizationService.CheckAccess(_authenticationService.GetAuthenticatedUser(), Permissions.ApplyRoles))
return null;
var model = new UserRolesViewModel {
User = userRoles.As<IUser>(),
UserRoles = userRoles,

View File

@ -65,6 +65,7 @@
<Compile Include="Controllers\AdminController.cs" />
<Compile Include="Controllers\UserRolesDriver.cs" />
<Compile Include="Extension.cs" />
<Compile Include="Models\UserSimulation.cs" />
<Compile Include="Permissions.cs" />
<Compile Include="Records\PermissionRecord.cs" />
<Compile Include="Records\RoleRecord.cs" />

View File

@ -7,7 +7,7 @@ namespace Orchard.Roles {
[UsedImplicitly]
public class Permissions : IPermissionProvider {
public static readonly Permission ManageRoles = new Permission { Description = "Create and manage roles", Name = "ManageRoles" };
public static readonly Permission AssignUsersToRoles = new Permission { Description = "Assign users to roles", Name = "AssignUsersToRoles" };
public static readonly Permission ApplyRoles = new Permission { Description = "Assign users to roles", Name = "AssignUsersToRoles", ImpliedBy = new[] { ManageRoles } };
public string PackageName {
get {
@ -18,7 +18,7 @@ namespace Orchard.Roles {
public IEnumerable<Permission> GetPermissions() {
return new Permission[] {
ManageRoles,
AssignUsersToRoles,
ApplyRoles,
};
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Orchard.Logging;
using Orchard.ContentManagement;
@ -28,17 +29,20 @@ namespace Orchard.Roles.Services {
return false;
}
if (String.Equals(user.UserName, "Administrator", StringComparison.OrdinalIgnoreCase) ||
if (String.Equals(user.UserName, "Administrator", StringComparison.OrdinalIgnoreCase) ||
((!String.IsNullOrEmpty(CurrentSite.SuperUser) &&
String.Equals(user.UserName, CurrentSite.SuperUser, StringComparison.OrdinalIgnoreCase)))) {
return true;
}
var grantingNames = PermissionNames(permission, Enumerable.Empty<string>()).ToArray();
IEnumerable<string> rolesForUser = user.As<IUserRoles>().Roles;
foreach (var role in rolesForUser) {
RoleRecord roleRecord = _roleService.GetRoleByName(role);
foreach (var permissionName in _roleService.GetPermissionsForRole(roleRecord.Id)) {
if (String.Equals(permissionName, permission.Name, StringComparison.OrdinalIgnoreCase)) {
string possessedName = permissionName;
if (grantingNames.Any(grantingName => String.Equals(possessedName, grantingName, StringComparison.OrdinalIgnoreCase))) {
return true;
}
}
@ -47,6 +51,25 @@ namespace Orchard.Roles.Services {
return false;
}
private static IEnumerable<string> PermissionNames(Permission permission, IEnumerable<string> stack) {
// the given name is tested
yield return permission.Name;
// iterate implied permissions to grant, it present
if (permission.ImpliedBy != null && permission.ImpliedBy.Any()) {
foreach (var impliedBy in permission.ImpliedBy) {
// avoid potential recursion
if (stack.Contains(impliedBy.Name))
continue;
// otherwise accumulate the implied permission names recursively
foreach (var impliedName in PermissionNames(impliedBy, stack.Concat(new[] { permission.Name }))) {
yield return impliedName;
}
}
}
}
#endregion
}
}

View File

@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Orchard.Mvc.ViewModels;
using Orchard.Security.Permissions;
@ -10,5 +11,6 @@ namespace Orchard.Roles.ViewModels {
public string Name { get; set; }
public IDictionary<string, IEnumerable<Permission>> PackagePermissions { get; set; }
public IEnumerable<string> CurrentPermissions { get; set; }
public IEnumerable<string> EffectivePermissions { get; set; }
}
}

View File

@ -23,6 +23,7 @@
<tr>
<th scope="col"><%=_Encoded("Permission") %></th>
<th scope="col"><%=_Encoded("Allow") %></th>
<th scope="col"><%=_Encoded("Effective") %></th>
</tr>
</thead>
<% foreach (var permission in Model.PackagePermissions[packageName]) { %>
@ -34,7 +35,14 @@
<% } else {%>
<input type="checkbox" value="true" name="<%=_Encoded("Checkbox.{0}", permission.Name) %>"/>
<% }%>
</td>
</td>
<td style="width:60px;/* todo: (heskew) make not inline :(">
<% if (Model.EffectivePermissions.Contains(permission.Name)) { %>
<input type="checkbox" disabled="disabled" name="<%=_Encoded("Effective.{0}", permission.Name) %>" checked="checked"/>
<% } else {%>
<input type="checkbox" disabled="disabled" name="<%=_Encoded("Effective.{0}", permission.Name) %>"/>
<% }%>
</td>
</tr>
<% } %>
</table>

View File

@ -7,7 +7,7 @@ namespace Orchard.Tags {
public void GetNavigation(NavigationBuilder builder) {
builder.Add("Tags", "3",
menu => menu
.Add("Manage Tags", "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.Tags" }))
.Add("Manage Tags", "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.Tags" }).Permission(Permissions.ManageTags))
);
}
}

View File

@ -2,6 +2,7 @@
using JetBrains.Annotations;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.Security;
using Orchard.Tags.Helpers;
using Orchard.Tags.Models;
using Orchard.Tags.Services;
@ -12,16 +13,24 @@ namespace Orchard.Tags.Controllers {
[UsedImplicitly]
public class HasTagsDriver : ContentPartDriver<HasTags> {
private readonly ITagService _tagService;
private readonly IAuthorizationService _authorizationService;
public HasTagsDriver(ITagService tagService) {
public HasTagsDriver(ITagService tagService,
IAuthorizationService authorizationService) {
_tagService = tagService;
_authorizationService = authorizationService;
}
public virtual IUser CurrentUser { get; set; }
protected override DriverResult Display(HasTags part, string displayType) {
return ContentPartTemplate(part, "Parts/Tags.ShowTags").Location("primary", "49");
}
protected override DriverResult Editor(HasTags part) {
if (!_authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag))
return null;
var model = new EditTagsViewModel {
Tags = string.Join(", ", part.CurrentTags.Select((t, i) => t.TagName).ToArray())
};
@ -29,6 +38,8 @@ namespace Orchard.Tags.Controllers {
}
protected override DriverResult Editor(HasTags part, IUpdateModel updater) {
if (!_authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag))
return null;
var model = new EditTagsViewModel();
updater.TryUpdateModel(model, Prefix, null, null);

View File

@ -5,8 +5,8 @@ using Orchard.Security.Permissions;
namespace Orchard.Tags {
public class Permissions : IPermissionProvider {
public static readonly Permission ManageTags = new Permission { Description = "Manage tags", Name = "ManageTags" };
public static readonly Permission CreateTag = new Permission { Description = "Create tag", Name = "CreateTag" };
public static readonly Permission ApplyTag = new Permission { Description = "Applying a Tag", Name = "ApplyTag" };
public static readonly Permission CreateTag = new Permission { Description = "Create tag", Name = "CreateTag", ImpliedBy = new[] { ManageTags } };
public static readonly Permission ApplyTag = new Permission { Description = "Applying a Tag", Name = "ApplyTag", ImpliedBy = new[] { ManageTags, CreateTag } };
public string PackageName {
get {

View File

@ -6,6 +6,7 @@ using Orchard.Data;
using Orchard.Localization;
using Orchard.Logging;
using Orchard.ContentManagement;
using Orchard.Security;
using Orchard.Settings;
using Orchard.Tags.Models;
using Orchard.UI.Notify;
@ -28,21 +29,25 @@ namespace Orchard.Tags.Services {
private readonly IRepository<TagsContentItems> _tagsContentItemsRepository;
private readonly IContentManager _contentManager;
private readonly INotifier _notifier;
private readonly IAuthorizationService _authorizationService;
public TagService(IRepository<Tag> tagRepository,
public TagService(IRepository<Tag> tagRepository,
IRepository<TagsContentItems> tagsContentItemsRepository,
IContentManager contentManager,
INotifier notifier) {
INotifier notifier,
IAuthorizationService authorizationService) {
_tagRepository = tagRepository;
_tagsContentItemsRepository = tagsContentItemsRepository;
_contentManager = contentManager;
_notifier = notifier;
_authorizationService = authorizationService;
Logger = NullLogger.Instance;
T = NullLocalizer.Instance;
}
public ILogger Logger { get; set; }
protected virtual ISite CurrentSite { get; [UsedImplicitly] private set; }
public virtual ISite CurrentSite { get; set; }
public virtual IUser CurrentUser { get; set; }
public Localizer T { get; set; }
#region ITagService Members
@ -61,6 +66,9 @@ namespace Orchard.Tags.Services {
public void CreateTag(string tagName) {
if (_tagRepository.Get(x => x.TagName == tagName) == null) {
if (!_authorizationService.CheckAccess(CurrentUser, Permissions.CreateTag))
throw new UnauthorizedException();
Tag tag = new Tag { TagName = tagName };
_tagRepository.Create(tag);
}
@ -119,15 +127,23 @@ namespace Orchard.Tags.Services {
private void ModifyTagsForContentItem(int contentItemId, IEnumerable<int> tagsForContentItem) {
List<int> newTagsForContentItem = new List<int>(tagsForContentItem);
IEnumerable<TagsContentItems> currentTagsForContentItem = _tagsContentItemsRepository.Fetch(x => x.ContentItemId == contentItemId);
foreach (var tagContentItem in currentTagsForContentItem) {
if (!newTagsForContentItem.Contains(tagContentItem.TagId)) {
if (!_authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag))
throw new UnauthorizedException();
_tagsContentItemsRepository.Delete(tagContentItem);
}
else {
newTagsForContentItem.Remove(tagContentItem.TagId);
}
}
foreach (var newTagForContentItem in newTagsForContentItem) {
if (!_authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag))
throw new UnauthorizedException();
_tagsContentItemsRepository.Create(new TagsContentItems { ContentItemId = contentItemId, TagId = newTagForContentItem });
}
}

View File

@ -7,8 +7,8 @@ namespace Orchard.Users {
public void GetNavigation(NavigationBuilder builder) {
builder.Add("Users", "5",
menu => menu
.Add("Manage Users", "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.Users" }))
.Add("Add New User", "1.1", item => item.Action("Create", "Admin", new { area = "Orchard.Users" })));
.Add("Manage Users", "1.0", item => item.Action("Index", "Admin", new { area = "Orchard.Users" }).Permission(Permissions.ManageUsers))
.Add("Add New User", "1.1", item => item.Action("Create", "Admin", new { area = "Orchard.Users" }).Permission(Permissions.ManageUsers)));
}
}
}

View File

@ -26,6 +26,9 @@ namespace Orchard.Users.Controllers {
public ActionResult Index() {
if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage settings")))
return new HttpUnauthorizedResult();
var users = Services.ContentManager
.Query<User, UserRecord>()
.Where(x => x.UserName != null)
@ -41,6 +44,9 @@ namespace Orchard.Users.Controllers {
}
public ActionResult Create() {
if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage settings")))
return new HttpUnauthorizedResult();
var user = Services.ContentManager.New<IUser>(UserDriver.ContentType.Name);
var model = new UserCreateViewModel {
User = Services.ContentManager.BuildEditorModel(user)
@ -49,7 +55,9 @@ namespace Orchard.Users.Controllers {
}
[HttpPost, ActionName("Create")]
public ActionResult _Create() {
public ActionResult CreatePOST() {
if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage settings")))
return new HttpUnauthorizedResult();
var model = new UserCreateViewModel();
UpdateModel(model);
@ -75,13 +83,19 @@ namespace Orchard.Users.Controllers {
}
public ActionResult Edit(int id) {
if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage settings")))
return new HttpUnauthorizedResult();
return View(new UserEditViewModel {
User = Services.ContentManager.BuildEditorModel<User>(id)
});
}
[HttpPost, ActionName("Edit")]
public ActionResult _Edit(int id) {
public ActionResult EditPOST(int id) {
if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage settings")))
return new HttpUnauthorizedResult();
var model = new UserEditViewModel {
User = Services.ContentManager.UpdateEditorModel<User>(id, this)
};

View File

@ -7,7 +7,6 @@ namespace Orchard.Users {
[UsedImplicitly]
public class Permissions : IPermissionProvider {
public static readonly Permission ManageUsers = new Permission { Description = "Manage users", Name = "ManageUsers" };
public static readonly Permission AddUsers = new Permission { Description = "Add users", Name = "AddUsers" };
public string PackageName {
get {
@ -18,7 +17,6 @@ namespace Orchard.Users {
public IEnumerable<Permission> GetPermissions() {
return new Permission[] {
ManageUsers,
AddUsers,
};
}

View File

@ -13,12 +13,26 @@ namespace Orchard {
dispatch(sink);
}
catch (Exception ex) {
logger.Error(ex, "{2} thrown from {0} by {1}",
typeof(TEvents).Name,
sink.GetType().FullName,
ex.GetType().Name);
if (IsLogged(ex)) {
logger.Error(ex, "{2} thrown from {0} by {1}",
typeof(TEvents).Name,
sink.GetType().FullName,
ex.GetType().Name);
}
if (IsFatal(ex)) {
throw;
}
}
}
}
private static bool IsLogged(Exception exception) {
return true;
}
private static bool IsFatal(Exception exception) {
return false;
}
}
}

View File

@ -137,6 +137,7 @@
<Compile Include="Extensions\Loaders\AreaExtensionLoader.cs" />
<Compile Include="Extensions\UriExtensions.cs" />
<Compile Include="Security\StandardPermissions.cs" />
<Compile Include="Security\UnauthorizedException.cs" />
<Compile Include="Tasks\Scheduling\IScheduledTask.cs" />
<Compile Include="ContentManagement\ContentExtensions.cs" />
<Compile Include="ContentManagement\ContentItem.cs" />

View File

@ -1,6 +1,14 @@
namespace Orchard.Security.Permissions {
using System;
using System.Collections.Generic;
namespace Orchard.Security.Permissions {
public class Permission {
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<Permission> ImpliedBy { get; set; }
public static Permission Named(string name) {
return new Permission { Name = name };
}
}
}

View File

@ -1,15 +1,19 @@
using System.Web.Mvc;
using System;
using System.Linq;
using System.Web.Mvc;
using JetBrains.Annotations;
using Orchard.Mvc.Filters;
using Orchard.Mvc.ViewModels;
namespace Orchard.Security {
public class SecurityFilter : FilterProvider, IResultFilter {
[UsedImplicitly]
public class SecurityFilter : FilterProvider, IResultFilter, IExceptionFilter {
private readonly IAuthenticationService _authenticationService;
public SecurityFilter(IAuthenticationService authenticationService) {
_authenticationService = authenticationService;
}
public void OnResultExecuting(ResultExecutingContext filterContext) {
var viewResult = filterContext.Result as ViewResultBase;
if (viewResult == null)
@ -26,5 +30,12 @@ namespace Orchard.Security {
public void OnResultExecuted(ResultExecutedContext filterContext) {
}
public void OnException(ExceptionContext filterContext) {
if (filterContext.Exception is UnauthorizedException) {
filterContext.Result = new HttpUnauthorizedResult();
filterContext.ExceptionHandled = true;
}
}
}
}

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Orchard.Security;
using Orchard.Security.Permissions;
namespace Orchard.UI.Navigation {
public interface INavigationManager : IDependency {
@ -26,9 +27,11 @@ namespace Orchard.UI.Navigation {
}
private IEnumerable<MenuItem> Reduce(IEnumerable<MenuItem> items) {
foreach(var item in items) {
if (!item.Permissions.Any() ||
item.Permissions.Any(x=>_authorizationService.CheckAccess(CurrentUser, x))) {
var hasDebugShowAllMenuItems = _authorizationService.CheckAccess(CurrentUser, Permission.Named("DebugShowAllMenuItems"));
foreach (var item in items) {
if (hasDebugShowAllMenuItems ||
!item.Permissions.Any() ||
item.Permissions.Any(x => _authorizationService.CheckAccess(CurrentUser, x))) {
yield return new MenuItem {
Items = Reduce(item.Items),
Permissions = item.Permissions,
@ -68,7 +71,7 @@ namespace Orchard.UI.Navigation {
RouteValues = items.First().RouteValues,
Items = Merge(items.Select(x => x.Items)).ToArray(),
Position = SelectBestPositionValue(items.Select(x => x.Position)),
Permissions = items.SelectMany(x=>x.Permissions),
Permissions = items.SelectMany(x => x.Permissions),
};
return joined;
}