diff --git a/src/Orchard.Tests/UI/Navigation/NavigationManagerTests.cs b/src/Orchard.Tests/UI/Navigation/NavigationManagerTests.cs index c05cf6bc5..644723ce9 100644 --- a/src/Orchard.Tests/UI/Navigation/NavigationManagerTests.cs +++ b/src/Orchard.Tests/UI/Navigation/NavigationManagerTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using NUnit.Framework; +using Orchard.ContentManagement; using Orchard.Security; using Orchard.Security.Permissions; using Orchard.UI.Navigation; @@ -19,10 +20,10 @@ namespace Orchard.Tests.UI.Navigation { } public class StubAuth : IAuthorizationService { - public void CheckAccess(IUser user, Permission permission) { + public void CheckAccess(Permission permission, IUser user, IContent content) { } - public bool TryCheckAccess(IUser user, Permission permission) { + public bool TryCheckAccess(Permission permission, IUser user, IContent content) { return true; } } diff --git a/src/Orchard.Web/Core/Common/Providers/CommonAspectHandler.cs b/src/Orchard.Web/Core/Common/Providers/CommonAspectHandler.cs index da42033a7..1f289b742 100644 --- a/src/Orchard.Web/Core/Common/Providers/CommonAspectHandler.cs +++ b/src/Orchard.Web/Core/Common/Providers/CommonAspectHandler.cs @@ -134,7 +134,7 @@ namespace Orchard.Core.Common.Providers { private void GetEditor(BuildEditorModelContext context, CommonAspect instance) { var currentUser = _authenticationService.GetAuthenticatedUser(); - if (!_authorizationService.TryCheckAccess(currentUser, Permissions.ChangeOwner)) { + if (!_authorizationService.TryCheckAccess(Permissions.ChangeOwner, currentUser, instance)) { return; } var viewModel = new OwnerEditorViewModel(); @@ -152,7 +152,7 @@ namespace Orchard.Core.Common.Providers { instance.VersionModifiedUtc = _clock.UtcNow; var currentUser = _authenticationService.GetAuthenticatedUser(); - if (!_authorizationService.TryCheckAccess(currentUser, Permissions.ChangeOwner)) { + if (!_authorizationService.TryCheckAccess(Permissions.ChangeOwner, currentUser, instance)) { return; } diff --git a/src/Orchard.Web/Packages/Orchard.Media/Services/XmlRpcHandler.cs b/src/Orchard.Web/Packages/Orchard.Media/Services/XmlRpcHandler.cs index 4885d7c85..61c5e8ed9 100644 --- a/src/Orchard.Web/Packages/Orchard.Media/Services/XmlRpcHandler.cs +++ b/src/Orchard.Web/Packages/Orchard.Media/Services/XmlRpcHandler.cs @@ -46,7 +46,7 @@ namespace Orchard.Media.Services { XRpcStruct file) { var user = _membershipService.ValidateUser(userName, password); - if (!_authorizationService.TryCheckAccess(user, Permissions.UploadMediaFiles)) { + if (!_authorizationService.TryCheckAccess(Permissions.UploadMediaFiles, user, null)) { //TEMP: return appropriate access-denied response for user throw new ApplicationException("Access denied"); } diff --git a/src/Orchard.Web/Packages/Orchard.Pages/Controllers/AdminController.cs b/src/Orchard.Web/Packages/Orchard.Pages/Controllers/AdminController.cs index cd93c7937..fcdf03dbd 100644 --- a/src/Orchard.Web/Packages/Orchard.Pages/Controllers/AdminController.cs +++ b/src/Orchard.Web/Packages/Orchard.Pages/Controllers/AdminController.cs @@ -14,15 +14,15 @@ using Orchard.UI.Notify; namespace Orchard.Pages.Controllers { [ValidateInput(false)] public class AdminController : Controller, IUpdateModel { - private readonly IOrchardServices _services; private readonly IPageService _pageService; public AdminController(IOrchardServices services, IPageService pageService) { - _services = services; + Services = services; _pageService = pageService; T = NullLocalizer.Instance; } + public IOrchardServices Services { get; private set; } private Localizer T { get; set; } public ActionResult List(PagesOptions options) { @@ -58,7 +58,7 @@ namespace Orchard.Pages.Controllers { case PagesBulkAction.None: break; case PagesBulkAction.PublishNow: - if (!_services.Authorizer.Authorize(Permissions.PublishPages, T("Couldn't publish page"))) + if (!Services.Authorizer.Authorize(Permissions.PublishPages, T("Couldn't publish page"))) return new HttpUnauthorizedResult(); foreach (PageEntry entry in checkedEntries) { @@ -67,7 +67,7 @@ namespace Orchard.Pages.Controllers { } break; case PagesBulkAction.Unpublish: - if (!_services.Authorizer.Authorize(Permissions.PublishPages, T("Couldn't unpublish page"))) + if (!Services.Authorizer.Authorize(Permissions.PublishPages, T("Couldn't unpublish page"))) return new HttpUnauthorizedResult(); foreach (PageEntry entry in checkedEntries) { var page = _pageService.GetLatest(entry.PageId); @@ -75,7 +75,7 @@ namespace Orchard.Pages.Controllers { } break; case PagesBulkAction.Delete: - if (!_services.Authorizer.Authorize(Permissions.DeletePages, T("Couldn't delete page"))) + if (!Services.Authorizer.Authorize(Permissions.DeletePages, T("Couldn't delete page"))) return new HttpUnauthorizedResult(); foreach (PageEntry entry in checkedEntries) { @@ -99,10 +99,10 @@ namespace Orchard.Pages.Controllers { } public ActionResult Create() { - if (!_services.Authorizer.Authorize(Permissions.EditPages, T("Not allowed to create a page"))) + if (!Services.Authorizer.Authorize(Permissions.EditPages, T("Not allowed to create a page"))) return new HttpUnauthorizedResult(); - var page = _services.ContentManager.BuildEditorModel(_services.ContentManager.New("page")); + var page = Services.ContentManager.BuildEditorModel(Services.ContentManager.New("page")); var model = new PageCreateViewModel { Page = page @@ -113,7 +113,7 @@ namespace Orchard.Pages.Controllers { [HttpPost, ActionName("Create")] public ActionResult CreatePOST(PageCreateViewModel model) { - if (!_services.Authorizer.Authorize(Permissions.EditPages, T("Couldn't create page"))) + if (!Services.Authorizer.Authorize(Permissions.EditPages, T("Couldn't create page"))) return new HttpUnauthorizedResult(); //TODO: (erikpo) Move this duplicate code somewhere else @@ -129,38 +129,37 @@ namespace Orchard.Pages.Controllers { } } - model.Page = _services.ContentManager.UpdateEditorModel(_services.ContentManager.New("page"), this); + model.Page = Services.ContentManager.UpdateEditorModel(Services.ContentManager.New("page"), this); if (!publishNow && publishDate != null) model.Page.Item.Published = publishDate.Value; if (!ModelState.IsValid) { - _services.TransactionManager.Cancel(); + Services.TransactionManager.Cancel(); return View(model); } - _services.ContentManager.Create(model.Page.Item.ContentItem, publishNow ? VersionOptions.Published : VersionOptions.Draft); + Services.ContentManager.Create(model.Page.Item.ContentItem, publishNow ? VersionOptions.Published : VersionOptions.Draft); if (publishNow) - _services.Notifier.Information(T("Page has been published")); + Services.Notifier.Information(T("Page has been published")); else if (publishDate != null) - _services.Notifier.Information(T("Page has been scheduled for publishing")); + Services.Notifier.Information(T("Page has been scheduled for publishing")); else - _services.Notifier.Information(T("Page draft has been saved")); + Services.Notifier.Information(T("Page draft has been saved")); return RedirectToAction("Edit", "Admin", new { id = model.Page.Item.ContentItem.Id }); } public ActionResult Edit(int id) { - if (!_services.Authorizer.Authorize(Permissions.EditPages, T("Couldn't edit page"))) - return new HttpUnauthorizedResult(); - Page page = _pageService.GetLatest(id); - if (page == null) return new NotFoundResult(); + if (!Services.Authorizer.Authorize(Permissions.EditOthersPages, page, T("Couldn't edit page"))) + return new HttpUnauthorizedResult(); + var model = new PageEditViewModel { - Page = _services.ContentManager.BuildEditorModel(page) + Page = Services.ContentManager.BuildEditorModel(page) }; return View(model); @@ -168,14 +167,14 @@ namespace Orchard.Pages.Controllers { [HttpPost, ActionName("Edit")] public ActionResult EditPOST(int id) { - if (!_services.Authorizer.Authorize(Permissions.EditPages, T("Couldn't edit page"))) - return new HttpUnauthorizedResult(); - Page page = _pageService.GetPageOrDraft(id); - if (page == null) return new NotFoundResult(); + if (!Services.Authorizer.Authorize(Permissions.EditOthersPages, page, T("Couldn't edit page"))) + return new HttpUnauthorizedResult(); + + //TODO: (erikpo) Move this duplicate code somewhere else DateTime? publishDate = null; bool publishNow = false; @@ -198,40 +197,39 @@ namespace Orchard.Pages.Controllers { _pageService.Unpublish(page); var model = new PageEditViewModel { - Page = _services.ContentManager.UpdateEditorModel(page, this) + Page = Services.ContentManager.UpdateEditorModel(page, this) }; TryUpdateModel(model); if (!ModelState.IsValid) { - _services.TransactionManager.Cancel(); + Services.TransactionManager.Cancel(); return View(model); } if (publishNow) - _services.Notifier.Information(T("Page has been published")); + Services.Notifier.Information(T("Page has been published")); else if (publishDate != null) - _services.Notifier.Information(T("Page has been scheduled for publishing")); + Services.Notifier.Information(T("Page has been scheduled for publishing")); else - _services.Notifier.Information(T("Page draft has been saved")); + Services.Notifier.Information(T("Page draft has been saved")); return RedirectToAction("Edit", "Admin", new { id = model.Page.Item.ContentItem.Id }); } [HttpPost] public ActionResult Delete(int id) { - if (!_services.Authorizer.Authorize(Permissions.DeletePages, T("Couldn't delete page"))) - return new HttpUnauthorizedResult(); - Page page = _pageService.Get(id); - if (page == null) return new NotFoundResult(); + if (!Services.Authorizer.Authorize(Permissions.DeleteOthersPages, page, T("Couldn't delete page"))) + return new HttpUnauthorizedResult(); + _pageService.Delete(page); - _services.Notifier.Information(T("Page was successfully deleted")); + Services.Notifier.Information(T("Page was successfully deleted")); return RedirectToAction("List"); } diff --git a/src/Orchard.Web/Packages/Orchard.Pages/Orchard.Pages.csproj b/src/Orchard.Web/Packages/Orchard.Pages/Orchard.Pages.csproj index aa937264f..17d448292 100644 --- a/src/Orchard.Web/Packages/Orchard.Pages/Orchard.Pages.csproj +++ b/src/Orchard.Web/Packages/Orchard.Pages/Orchard.Pages.csproj @@ -82,6 +82,7 @@ + diff --git a/src/Orchard.Web/Packages/Orchard.Pages/Security/Authorization.cs b/src/Orchard.Web/Packages/Orchard.Pages/Security/Authorization.cs new file mode 100644 index 000000000..ed7f068b6 --- /dev/null +++ b/src/Orchard.Web/Packages/Orchard.Pages/Security/Authorization.cs @@ -0,0 +1,96 @@ +using JetBrains.Annotations; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Aspects; +using Orchard.Pages.Models; +using Orchard.Security; +using Orchard.Security.Permissions; + +namespace Orchard.Pages.Security { + [UsedImplicitly] + public class Authorization : AuthorizationServiceEvents { + public override void Adjust(CheckAccessContext context) { + if (context.Granted == false && + context.Content.Is() && + HasOwnerVariation(context.Permission) && + HasOwnership(context.User, context.Content)) { + + context.Adjusted = true; + context.Permission = GetOwnerVariation(context.Permission); + } + } + + private static bool HasOwnership(IUser user, IContent content) { + if (user==null || content==null) + return false; + + var common = content.As(); + if (common==null || common.Owner==null) + return false; + + return user.Id == common.Owner.Id; + } + + private static bool HasOwnerVariation(Permission permission) { + return GetOwnerVariation(permission) != null; + } + + private static Permission GetOwnerVariation(Permission permission) { + if (permission.Name == Permissions.PublishOthersPages.Name) + return Permissions.PublishPages; + if (permission.Name == Permissions.EditOthersPages.Name) + return Permissions.EditPages; + if (permission.Name == Permissions.DeleteOthersPages.Name) + return Permissions.DeletePages; + return null; + } + + } +} +using JetBrains.Annotations; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Aspects; +using Orchard.Pages.Models; +using Orchard.Security; +using Orchard.Security.Permissions; + +namespace Orchard.Pages.Security { + [UsedImplicitly] + public class Authorization : AuthorizationServiceEvents { + public override void Adjust(CheckAccessContext context) { + if (context.Granted == false && + context.Content.Is() && + HasOwnerVariation(context.Permission) && + HasOwnership(context.User, context.Content)) { + + context.Adjusted = true; + context.Permission = GetOwnerVariation(context.Permission); + } + } + + private static bool HasOwnership(IUser user, IContent content) { + if (user==null || content==null) + return false; + + var common = content.As(); + if (common==null || common.Owner==null) + return false; + + return user.Id == common.Owner.Id; + } + + private static bool HasOwnerVariation(Permission permission) { + return GetOwnerVariation(permission) != null; + } + + private static Permission GetOwnerVariation(Permission permission) { + if (permission.Name == Permissions.PublishOthersPages.Name) + return Permissions.PublishPages; + if (permission.Name == Permissions.EditOthersPages.Name) + return Permissions.EditPages; + if (permission.Name == Permissions.DeleteOthersPages.Name) + return Permissions.DeletePages; + return null; + } + + } +} diff --git a/src/Orchard.Web/Packages/Orchard.Roles/Controllers/AdminController.cs b/src/Orchard.Web/Packages/Orchard.Roles/Controllers/AdminController.cs index 8ea9a97b1..7a5143438 100644 --- a/src/Orchard.Web/Packages/Orchard.Roles/Controllers/AdminController.cs +++ b/src/Orchard.Web/Packages/Orchard.Roles/Controllers/AdminController.cs @@ -111,7 +111,7 @@ namespace Orchard.Roles.Controllers { var simulation = UserSimulation.Create(role.Name); model.EffectivePermissions = model.PackagePermissions .SelectMany(group => group.Value) - .Where(permission => _authorizationService.TryCheckAccess(simulation, permission)) + .Where(permission => _authorizationService.TryCheckAccess(permission, simulation, null)) .Select(permission=>permission.Name) .Distinct() .ToList(); diff --git a/src/Orchard.Web/Packages/Orchard.Roles/Controllers/UserRolesDriver.cs b/src/Orchard.Web/Packages/Orchard.Roles/Controllers/UserRolesDriver.cs index 1eb3092b4..43d273f78 100644 --- a/src/Orchard.Web/Packages/Orchard.Roles/Controllers/UserRolesDriver.cs +++ b/src/Orchard.Web/Packages/Orchard.Roles/Controllers/UserRolesDriver.cs @@ -40,7 +40,7 @@ namespace Orchard.Roles.Controllers { protected override DriverResult Editor(UserRoles userRoles) { // don't show editor without apply roles permission - if (!_authorizationService.TryCheckAccess(_authenticationService.GetAuthenticatedUser(), Permissions.ApplyRoles)) + if (!_authorizationService.TryCheckAccess(Permissions.ApplyRoles, _authenticationService.GetAuthenticatedUser(), userRoles)) return null; var roles = @@ -61,7 +61,7 @@ namespace Orchard.Roles.Controllers { protected override DriverResult Editor(UserRoles userRoles, IUpdateModel updater) { // don't apply editor without apply roles permission - if (!_authorizationService.TryCheckAccess(_authenticationService.GetAuthenticatedUser(), Permissions.ApplyRoles)) + if (!_authorizationService.TryCheckAccess(Permissions.ApplyRoles, _authenticationService.GetAuthenticatedUser(), userRoles)) return null; var model = new UserRolesViewModel { diff --git a/src/Orchard.Web/Packages/Orchard.Roles/Services/RolesBasedAuthorizationService.cs b/src/Orchard.Web/Packages/Orchard.Roles/Services/RolesBasedAuthorizationService.cs index e603f420d..3f459b67f 100644 --- a/src/Orchard.Web/Packages/Orchard.Roles/Services/RolesBasedAuthorizationService.cs +++ b/src/Orchard.Web/Packages/Orchard.Roles/Services/RolesBasedAuthorizationService.cs @@ -13,9 +13,11 @@ using Orchard.Settings; namespace Orchard.Roles.Services { public class RolesBasedAuthorizationService : IAuthorizationService { private readonly IRoleService _roleService; + private readonly IEnumerable _events; - public RolesBasedAuthorizationService(IRoleService roleService) { + public RolesBasedAuthorizationService(IRoleService roleService, IEnumerable events) { _roleService = roleService; + _events = events; Logger = NullLogger.Instance; } @@ -24,37 +26,54 @@ namespace Orchard.Roles.Services { #region Implementation of IAuthorizationService - public void CheckAccess(IUser user, Permission permission) { - if (!TryCheckAccess(user, permission)) { + public void CheckAccess(Permission permission, IUser user, IContent content) { + if (!TryCheckAccess(permission, user, content)) { throw new OrchardSecurityException { PermissionName = permission.Name }; } } - public bool TryCheckAccess(IUser user, Permission permission) { - if (user == null) { - return false; - } + public bool TryCheckAccess(Permission permission, IUser user, IContent content) { + var context = new CheckAccessContext { Permission = permission, User = user, Content = content }; - if (String.Equals(user.UserName, "Administrator", StringComparison.OrdinalIgnoreCase) || - ((!String.IsNullOrEmpty(CurrentSite.SuperUser) && - String.Equals(user.UserName, CurrentSite.SuperUser, StringComparison.OrdinalIgnoreCase)))) { - return true; - } + _events.Invoke(x => x.Checking(context), Logger); - var grantingNames = PermissionNames(permission, Enumerable.Empty()).ToArray(); - - IEnumerable rolesForUser = user.As().Roles; - foreach (var role in rolesForUser) { - RoleRecord roleRecord = _roleService.GetRoleByName(role); - foreach (var permissionName in _roleService.GetPermissionsForRole(roleRecord.Id)) { - string possessedName = permissionName; - if (grantingNames.Any(grantingName => String.Equals(possessedName, grantingName, StringComparison.OrdinalIgnoreCase))) { - return true; + for (var adjustmentLimiter = 0; adjustmentLimiter != 3; ++adjustmentLimiter) { + if (!context.Granted && context.User != null) { + if (String.Equals(context.User.UserName, "Administrator", StringComparison.OrdinalIgnoreCase) || + ((!String.IsNullOrEmpty(CurrentSite.SuperUser) && + String.Equals(context.User.UserName, CurrentSite.SuperUser, StringComparison.OrdinalIgnoreCase)))) { + context.Granted = true; } } + + if (!context.Granted && context.User != null && context.User.Has()) { + var grantingNames = PermissionNames(context.Permission, Enumerable.Empty()).ToArray(); + IEnumerable rolesForUser = context.User.As().Roles; + + foreach (var role in rolesForUser) { + RoleRecord roleRecord = _roleService.GetRoleByName(role); + foreach (var permissionName in _roleService.GetPermissionsForRole(roleRecord.Id)) { + string possessedName = permissionName; + if (grantingNames.Any(grantingName => String.Equals(possessedName, grantingName, StringComparison.OrdinalIgnoreCase))) { + context.Granted = true; + } + + if (context.Granted) + break; + } + + if (context.Granted) + break; + } + } + + context.Adjusted = false; + _events.Invoke(x => x.Adjust(context), Logger); } - return false; + _events.Invoke(x => x.Complete(context), Logger); + + return context.Granted; } private static IEnumerable PermissionNames(Permission permission, IEnumerable stack) { diff --git a/src/Orchard.Web/Packages/Orchard.Tags/Controllers/HasTagsDriver.cs b/src/Orchard.Web/Packages/Orchard.Tags/Controllers/HasTagsDriver.cs index 7fb2b65eb..f37ec06e1 100644 --- a/src/Orchard.Web/Packages/Orchard.Tags/Controllers/HasTagsDriver.cs +++ b/src/Orchard.Web/Packages/Orchard.Tags/Controllers/HasTagsDriver.cs @@ -28,7 +28,7 @@ namespace Orchard.Tags.Controllers { } protected override DriverResult Editor(HasTags part) { - if (!_authorizationService.TryCheckAccess(CurrentUser, Permissions.ApplyTag)) + if (!_authorizationService.TryCheckAccess(Permissions.ApplyTag, CurrentUser, part)) return null; var model = new EditTagsViewModel { @@ -38,7 +38,7 @@ namespace Orchard.Tags.Controllers { } protected override DriverResult Editor(HasTags part, IUpdateModel updater) { - if (!_authorizationService.TryCheckAccess(CurrentUser, Permissions.ApplyTag)) + if (!_authorizationService.TryCheckAccess(Permissions.ApplyTag, CurrentUser, part)) return null; var model = new EditTagsViewModel(); diff --git a/src/Orchard.Web/Packages/Orchard.Tags/Services/TagService.cs b/src/Orchard.Web/Packages/Orchard.Tags/Services/TagService.cs index bb60c6ea5..a45e5a678 100644 --- a/src/Orchard.Web/Packages/Orchard.Tags/Services/TagService.cs +++ b/src/Orchard.Web/Packages/Orchard.Tags/Services/TagService.cs @@ -66,7 +66,7 @@ namespace Orchard.Tags.Services { public void CreateTag(string tagName) { if (_tagRepository.Get(x => x.TagName == tagName) == null) { - _authorizationService.CheckAccess(CurrentUser, Permissions.CreateTag); + _authorizationService.CheckAccess(Permissions.CreateTag, CurrentUser, null); Tag tag = new Tag { TagName = tagName }; _tagRepository.Create(tag); @@ -129,7 +129,7 @@ namespace Orchard.Tags.Services { foreach (var tagContentItem in currentTagsForContentItem) { if (!newTagsForContentItem.Contains(tagContentItem.TagId)) { - _authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag); + _authorizationService.CheckAccess(Permissions.ApplyTag, CurrentUser, null); _tagsContentItemsRepository.Delete(tagContentItem); } @@ -139,7 +139,7 @@ namespace Orchard.Tags.Services { } foreach (var newTagForContentItem in newTagsForContentItem) { - _authorizationService.CheckAccess(CurrentUser, Permissions.ApplyTag); + _authorizationService.CheckAccess(Permissions.ApplyTag, CurrentUser, null); _tagsContentItemsRepository.Create(new TagsContentItems { ContentItemId = contentItemId, TagId = newTagForContentItem }); } diff --git a/src/Orchard.Web/Packages/Orchard.Users/Controllers/AdminController.cs b/src/Orchard.Web/Packages/Orchard.Users/Controllers/AdminController.cs index af0212cd7..be54b4db4 100644 --- a/src/Orchard.Web/Packages/Orchard.Users/Controllers/AdminController.cs +++ b/src/Orchard.Web/Packages/Orchard.Users/Controllers/AdminController.cs @@ -26,7 +26,7 @@ namespace Orchard.Users.Controllers { public ActionResult Index() { - if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage settings"))) + if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to list users"))) return new HttpUnauthorizedResult(); var users = Services.ContentManager @@ -44,7 +44,7 @@ namespace Orchard.Users.Controllers { } public ActionResult Create() { - if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage settings"))) + if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage users"))) return new HttpUnauthorizedResult(); var user = Services.ContentManager.New(UserDriver.ContentType.Name); @@ -56,7 +56,7 @@ namespace Orchard.Users.Controllers { [HttpPost, ActionName("Create")] public ActionResult CreatePOST() { - if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage settings"))) + if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage users"))) return new HttpUnauthorizedResult(); var model = new UserCreateViewModel(); @@ -83,7 +83,7 @@ namespace Orchard.Users.Controllers { } public ActionResult Edit(int id) { - if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage settings"))) + if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage users"))) return new HttpUnauthorizedResult(); return View(new UserEditViewModel { @@ -93,7 +93,7 @@ namespace Orchard.Users.Controllers { [HttpPost, ActionName("Edit")] public ActionResult EditPOST(int id) { - if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage settings"))) + if (!Services.Authorizer.Authorize(Permissions.ManageUsers, T("Not authorized to manage users"))) return new HttpUnauthorizedResult(); var model = new UserEditViewModel { diff --git a/src/Orchard/Orchard.csproj b/src/Orchard/Orchard.csproj index 1827e74cf..744f97b0a 100644 --- a/src/Orchard/Orchard.csproj +++ b/src/Orchard/Orchard.csproj @@ -137,6 +137,7 @@ + diff --git a/src/Orchard/Security/Authorizer.cs b/src/Orchard/Security/Authorizer.cs index 465aa5a45..a851ed417 100644 --- a/src/Orchard/Security/Authorizer.cs +++ b/src/Orchard/Security/Authorizer.cs @@ -1,4 +1,7 @@ -using JetBrains.Annotations; +using System; +using JetBrains.Annotations; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Aspects; using Orchard.Localization; using Orchard.Security.Permissions; using Orchard.UI.Notify; @@ -6,6 +9,7 @@ using Orchard.UI.Notify; namespace Orchard.Security { public interface IAuthorizer : IDependency { bool Authorize(Permission permission, LocalizedString message); + bool Authorize(Permission permission, IContent content, LocalizedString message); } public class Authorizer : IAuthorizer { @@ -24,7 +28,11 @@ namespace Orchard.Security { public Localizer T { get; set; } public bool Authorize(Permission permission, LocalizedString message) { - if (_authorizationService.TryCheckAccess(CurrentUser, permission)) + return Authorize(permission, null, message); + } + + public bool Authorize(Permission permission, IContent content, LocalizedString message) { + if (_authorizationService.TryCheckAccess(permission, CurrentUser, content)) return true; if (CurrentUser == null) { @@ -37,5 +45,6 @@ namespace Orchard.Security { } return false; } + } } diff --git a/src/Orchard/Security/IAuthorizationService.cs b/src/Orchard/Security/IAuthorizationService.cs index fe5362929..e16c40f3e 100644 --- a/src/Orchard/Security/IAuthorizationService.cs +++ b/src/Orchard/Security/IAuthorizationService.cs @@ -1,4 +1,5 @@ -using Orchard.Security.Permissions; +using Orchard.ContentManagement; +using Orchard.Security.Permissions; namespace Orchard.Security { /// @@ -6,7 +7,9 @@ namespace Orchard.Security { /// provided by default. /// public interface IAuthorizationService : IDependency { - void CheckAccess(IUser user, Permission permission); - bool TryCheckAccess(IUser user, Permission permission); + void CheckAccess(Permission permission, IUser user, IContent content); + bool TryCheckAccess(Permission permission, IUser user, IContent content); } + + } diff --git a/src/Orchard/Security/IAuthorizationServiceEvents.cs b/src/Orchard/Security/IAuthorizationServiceEvents.cs new file mode 100644 index 000000000..5bdcde136 --- /dev/null +++ b/src/Orchard/Security/IAuthorizationServiceEvents.cs @@ -0,0 +1,50 @@ +using System; +using Orchard.ContentManagement; +using Orchard.Security.Permissions; + +namespace Orchard.Security { + public interface IAuthorizationServiceEvents : IEvents { + void Checking(CheckAccessContext context); + void Adjust(CheckAccessContext context); + void Complete(CheckAccessContext context); + } + + public class CheckAccessContext { + public Permission Permission { get; set; } + public IUser User { get; set; } + public IContent Content { get; set; } + public bool Granted { get; set; } + public bool Adjusted { get; set; } + } + + public abstract class AuthorizationServiceEvents : IAuthorizationServiceEvents { + public virtual void Checking(CheckAccessContext context) { } + public virtual void Adjust(CheckAccessContext context) { } + public virtual void Complete(CheckAccessContext context) { } + } +} +using System; +using Orchard.ContentManagement; +using Orchard.Security.Permissions; + +namespace Orchard.Security { + public interface IAuthorizationServiceEvents : IEvents { + void Checking(CheckAccessContext context); + void Adjust(CheckAccessContext context); + void Complete(CheckAccessContext context); + } + + public class CheckAccessContext { + public Permission Permission { get; set; } + public IUser User { get; set; } + public IContent Content { get; set; } + public bool Granted { get; set; } + public bool Adjusted { get; set; } + } + + public abstract class AuthorizationServiceEvents : IAuthorizationServiceEvents { + public virtual void Checking(CheckAccessContext context) { } + public virtual void Adjust(CheckAccessContext context) { } + public virtual void Complete(CheckAccessContext context) { } + } +} diff --git a/src/Orchard/Security/Permissions/Permission.cs b/src/Orchard/Security/Permissions/Permission.cs index c1e99a390..200fe8f8f 100644 --- a/src/Orchard/Security/Permissions/Permission.cs +++ b/src/Orchard/Security/Permissions/Permission.cs @@ -5,7 +5,9 @@ namespace Orchard.Security.Permissions { public class Permission { public string Name { get; set; } public string Description { get; set; } + public IEnumerable ImpliedBy { get; set; } + public bool RequiresOwnership { get; set; } public static Permission Named(string name) { return new Permission { Name = name }; diff --git a/src/Orchard/UI/Navigation/NavigationManager.cs b/src/Orchard/UI/Navigation/NavigationManager.cs index 3573c90cc..e6fa418dc 100644 --- a/src/Orchard/UI/Navigation/NavigationManager.cs +++ b/src/Orchard/UI/Navigation/NavigationManager.cs @@ -34,11 +34,11 @@ namespace Orchard.UI.Navigation { } private IEnumerable Reduce(IEnumerable items) { - var hasDebugShowAllMenuItems = _authorizationService.TryCheckAccess(CurrentUser, Permission.Named("DebugShowAllMenuItems")); + var hasDebugShowAllMenuItems = _authorizationService.TryCheckAccess(Permission.Named("DebugShowAllMenuItems"), CurrentUser, null); foreach (var item in items) { if (hasDebugShowAllMenuItems || !item.Permissions.Any() || - item.Permissions.Any(x => _authorizationService.TryCheckAccess(CurrentUser, x))) { + item.Permissions.Any(x => _authorizationService.TryCheckAccess(x, CurrentUser, null))) { yield return new MenuItem { Items = Reduce(item.Items), Permissions = item.Permissions,