diff --git a/src/Orchard.Web/Core/Common/Permissions.cs b/src/Orchard.Web/Core/Common/Permissions.cs index b20fb866c..c5b62e6c1 100644 --- a/src/Orchard.Web/Core/Common/Permissions.cs +++ b/src/Orchard.Web/Core/Common/Permissions.cs @@ -20,7 +20,7 @@ namespace Orchard.Core.Common { new PermissionStereotype { Name = "Administrator", Permissions = new[] {ChangeOwner} - } + }, }; } } diff --git a/src/Orchard.Web/Core/Common/Security/AuthorizationEventHandler.cs b/src/Orchard.Web/Core/Common/Security/AuthorizationEventHandler.cs new file mode 100644 index 000000000..fa0beacfb --- /dev/null +++ b/src/Orchard.Web/Core/Common/Security/AuthorizationEventHandler.cs @@ -0,0 +1,57 @@ +using JetBrains.Annotations; +using Orchard.ContentManagement; +using Orchard.ContentManagement.Aspects; +using Orchard.Core.Common.Models; +using Orchard.Security; +using Orchard.Security.Permissions; + +namespace Orchard.Core.Common.Security +{ + [UsedImplicitly] + public class AuthorizationEventHandler : IAuthorizationServiceEventHandler + { + public void Checking(CheckAccessContext context) { } + public void Complete(CheckAccessContext context) { } + + public void Adjust(CheckAccessContext context) + { + if (!context.Granted && + context.Content.Is() && + OwnerVariationExists(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 OwnerVariationExists(Permission permission) + { + return GetOwnerVariation(permission) != null; + } + + private static Permission GetOwnerVariation(Permission permission) + { + if (permission.Name == Contents.Permissions.PublishOthersContent.Name) + return Contents.Permissions.PublishContent; + if (permission.Name == Contents.Permissions.EditOthersContent.Name) + return Contents.Permissions.EditContent; + if (permission.Name == Contents.Permissions.DeleteOthersContent.Name) + return Contents.Permissions.DeleteContent; + return null; + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs b/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs index c7aef33ee..9b6c89c97 100644 --- a/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs +++ b/src/Orchard.Web/Core/Contents/Controllers/AdminController.cs @@ -134,34 +134,38 @@ namespace Orchard.Core.Contents.Controllers { [HttpPost, ActionName("List")] [FormValueRequired("submit.BulkEdit")] public ActionResult ListPOST(ContentOptions options, IEnumerable itemIds, string returnUrl) { + var accessChecked = false; switch (options.BulkAction) { case ContentsBulkAction.None: break; case ContentsBulkAction.PublishNow: - if (!Services.Authorizer.Authorize(Permissions.PublishContent, T("Couldn't publish selected content."))) - return new HttpUnauthorizedResult(); - foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) { + if (!accessChecked && !Services.Authorizer.Authorize(Permissions.PublishContent, item, T("Couldn't publish selected content."))) + return new HttpUnauthorizedResult(); + + accessChecked = true; _contentManager.Publish(item); Services.ContentManager.Flush(); } Services.Notifier.Information(T("Content successfully published.")); break; case ContentsBulkAction.Unpublish: - if (!Services.Authorizer.Authorize(Permissions.PublishContent, T("Couldn't unpublish selected content."))) - return new HttpUnauthorizedResult(); - foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) { + if (!accessChecked && !Services.Authorizer.Authorize(Permissions.PublishContent, item, T("Couldn't unpublish selected content."))) + return new HttpUnauthorizedResult(); + + accessChecked = true; _contentManager.Unpublish(item); Services.ContentManager.Flush(); } Services.Notifier.Information(T("Content successfully unpublished.")); break; case ContentsBulkAction.Remove: - if (!Services.Authorizer.Authorize(Permissions.PublishContent, T("Couldn't delete selected content."))) - return new HttpUnauthorizedResult(); - foreach (var item in itemIds.Select(itemId => _contentManager.GetLatest(itemId))) { + if (!accessChecked && !Services.Authorizer.Authorize(Permissions.DeleteContent, item, T("Couldn't remove selected content."))) + return new HttpUnauthorizedResult(); + + accessChecked = true; _contentManager.Remove(item); Services.ContentManager.Flush(); } @@ -210,6 +214,10 @@ namespace Orchard.Core.Contents.Controllers { return CreatableTypeList(); var contentItem = _contentManager.New(id); + + if (!Services.Authorizer.Authorize(Permissions.PublishContent, contentItem, T("Cannot create content"))) + return new HttpUnauthorizedResult(); + var model = new CreateItemViewModel { Id = id, Content = _contentManager.BuildEditorModel(contentItem) @@ -221,8 +229,11 @@ namespace Orchard.Core.Contents.Controllers { [HttpPost] public ActionResult Create(CreateItemViewModel model) { - //todo: need to integrate permissions into generic content management var contentItem = _contentManager.New(model.Id); + + if (!Services.Authorizer.Authorize(Permissions.PublishContent, contentItem, T("Couldn't create content"))) + return new HttpUnauthorizedResult(); + _contentManager.Create(contentItem, VersionOptions.Draft); model.Content = _contentManager.UpdateEditorModel(contentItem, this); @@ -246,6 +257,9 @@ namespace Orchard.Core.Contents.Controllers { if (contentItem == null) return new NotFoundResult(); + if (!Services.Authorizer.Authorize(Permissions.EditOthersContent, contentItem, T("Cannot edit content"))) + return new HttpUnauthorizedResult(); + var model = new EditItemViewModel { Id = id, Content = _contentManager.BuildEditorModel(contentItem) @@ -263,6 +277,9 @@ namespace Orchard.Core.Contents.Controllers { if (contentItem == null) return new NotFoundResult(); + if (!Services.Authorizer.Authorize(Permissions.EditOthersContent, contentItem, T("Couldn't edit content"))) + return new HttpUnauthorizedResult(); + model.Content = _contentManager.UpdateEditorModel(contentItem, this); if (!ModelState.IsValid) { _transactionManager.Cancel(); @@ -280,6 +297,10 @@ namespace Orchard.Core.Contents.Controllers { [HttpPost, ActionName("Remove")] public ActionResult RemovePOST(int id, string returnUrl) { var contentItem = _contentManager.Get(id, VersionOptions.Latest); + + if (!Services.Authorizer.Authorize(Permissions.DeleteOthersContent, contentItem, T("Couldn't remove content"))) + return new HttpUnauthorizedResult(); + if (contentItem != null) _contentManager.Remove(contentItem); @@ -291,13 +312,13 @@ namespace Orchard.Core.Contents.Controllers { [HttpPost] public ActionResult Publish(int id, string returnUrl) { - if (!Services.Authorizer.Authorize(Permissions.PublishContent, T("Couldn't publish content"))) - return new HttpUnauthorizedResult(); - var contentItem = _contentManager.GetLatest(id); if (contentItem == null) return new NotFoundResult(); + if (!Services.Authorizer.Authorize(Permissions.PublishContent, contentItem, T("Couldn't publish content"))) + return new HttpUnauthorizedResult(); + _contentManager.Publish(contentItem); Services.ContentManager.Flush(); Services.Notifier.Information(T("{0} successfully published.", contentItem.TypeDefinition.DisplayName)); @@ -310,13 +331,13 @@ namespace Orchard.Core.Contents.Controllers { [HttpPost] public ActionResult Unpublish(int id, string returnUrl) { - if (!Services.Authorizer.Authorize(Permissions.PublishContent, T("Couldn't unpublish content"))) - return new HttpUnauthorizedResult(); - var contentItem = _contentManager.GetLatest(id); if (contentItem == null) return new NotFoundResult(); + if (!Services.Authorizer.Authorize(Permissions.PublishContent, contentItem, T("Couldn't unpublish content"))) + return new HttpUnauthorizedResult(); + _contentManager.Unpublish(contentItem); Services.ContentManager.Flush(); Services.Notifier.Information(T("{0} successfully unpublished.", contentItem.TypeDefinition.DisplayName)); diff --git a/src/Orchard.Web/Core/Contents/Permissions.cs b/src/Orchard.Web/Core/Contents/Permissions.cs index e9f16b824..f6e3f9773 100644 --- a/src/Orchard.Web/Core/Contents/Permissions.cs +++ b/src/Orchard.Web/Core/Contents/Permissions.cs @@ -19,7 +19,7 @@ namespace Orchard.Core.Contents { } public IEnumerable GetPermissions() { - return new Permission[] { + return new [] { EditContent, EditOthersContent, PublishContent, diff --git a/src/Orchard.Web/Core/Orchard.Core.csproj b/src/Orchard.Web/Core/Orchard.Core.csproj index e0a38c22a..2e0c936d3 100644 --- a/src/Orchard.Web/Core/Orchard.Core.csproj +++ b/src/Orchard.Web/Core/Orchard.Core.csproj @@ -67,6 +67,7 @@ +