From accd4196dc8bcd76d5a5fbafcb6df146ab97e290 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 18 Sep 2015 17:03:29 -0700 Subject: [PATCH] Implementing own media management --- .../Controllers/AdminController.cs | 20 +++++- .../Modules/Orchard.MediaLibrary/AdminMenu.cs | 2 +- .../Controllers/AdminController.cs | 72 ++++++++++++++----- .../Controllers/ClientStorageController.cs | 17 ++++- .../Controllers/FolderController.cs | 40 +++++++++-- .../Controllers/OEmbedController.cs | 17 ++++- .../Controllers/WebSearchController.cs | 21 +++++- .../Orchard.MediaLibrary.csproj | 1 + .../Orchard.MediaLibrary/Permissions.cs | 5 +- .../Providers/ClientStorageMenu.cs | 2 +- .../Providers/OEmbedMenu.cs | 2 +- .../Providers/WebSearchMenu.cs | 2 +- .../MediaAuthorizationEventHandler.cs | 35 +++++++++ .../Services/IMediaLibraryService.cs | 31 +++++++- .../Services/MediaLibraryService.cs | 16 ++++- .../Services/XmlRpcHandler.cs | 7 +- .../Views/Admin/Index.cshtml | 2 +- .../Views/Folder/Create.cshtml | 10 +-- 18 files changed, 259 insertions(+), 43 deletions(-) create mode 100644 src/Orchard.Web/Modules/Orchard.MediaLibrary/Security/MediaAuthorizationEventHandler.cs diff --git a/src/Orchard.Web/Modules/Orchard.ImageEditor/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.ImageEditor/Controllers/AdminController.cs index 595db7cf3..ffe66206d 100644 --- a/src/Orchard.Web/Modules/Orchard.ImageEditor/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.ImageEditor/Controllers/AdminController.cs @@ -45,6 +45,15 @@ namespace Orchard.ImageEditor.Controllers { [Themed(false)] public ActionResult Edit(string folderPath, string filename) { + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) + return new HttpUnauthorizedResult(); + + // Check permission. + var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); + if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + return new HttpUnauthorizedResult(); + } + var media = Services.ContentManager.Query().Where(x => x.FolderPath == folderPath && x.FileName == filename).Slice(0, 1).FirstOrDefault(); if (media == null) { @@ -64,12 +73,21 @@ namespace Orchard.ImageEditor.Controllers { [HttpPost] public ActionResult Upload(int id, string content, int width, int height) { + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) + return new HttpUnauthorizedResult(); + var media = Services.ContentManager.Get(id).As(); if (media == null) { return HttpNotFound(); } + // Check permission. + var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); + if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(media.FolderPath)) { + return new HttpUnauthorizedResult(); + } + const string signature = "data:image/jpeg;base64,"; if (!content.StartsWith(signature, StringComparison.OrdinalIgnoreCase)) { @@ -96,7 +114,7 @@ namespace Orchard.ImageEditor.Controllers { } public ActionResult Proxy(string url) { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent)) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) return HttpNotFound(); var sslFailureCallback = new RemoteCertificateValidationCallback((o, cert, chain, errors) => true); diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/AdminMenu.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/AdminMenu.cs index d83aff5e5..82c32328b 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/AdminMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/AdminMenu.cs @@ -15,7 +15,7 @@ namespace Orchard.MediaLibrary { builder.AddImageSet("media-library") .Add(T("Media"), "6", menu => menu.Add(T("Media"), "0", item => item.Action("Index", "Admin", new { area = "Orchard.MediaLibrary" }) - .Permission(Permissions.ManageMediaContent))); + .Permission(Permissions.ManageOwnMedia))); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs index bd9ab44fa..c9158d4f7 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/AdminController.cs @@ -14,6 +14,7 @@ using Orchard.Themes; using Orchard.UI.Navigation; using Orchard.ContentManagement.MetaData; using Orchard.Validation; +using System.Collections.Generic; namespace Orchard.MediaLibrary.Controllers { [ValidateInput(false)] @@ -41,17 +42,21 @@ namespace Orchard.MediaLibrary.Controllers { public ILogger Logger { get; set; } public ActionResult Index(string folderPath = "", bool dialog = false) { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media"))) return new HttpUnauthorizedResult(); + // If the user is trying to access a folder above his boundaries, redirect him to his home folder + var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); + if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + return RedirectToAction("Index", new { folderPath = rootMediaFolder.MediaPath, dialog }); + } + // let other modules enhance the ui by providing custom navigation and actions var explorer = Services.ContentManager.New("MediaLibraryExplorer"); explorer.Weld(new MediaLibraryExplorerPart()); var explorerShape = Services.ContentManager.BuildDisplay(explorer); - var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); - var viewModel = new MediaManagerIndexViewModel { DialogMode = dialog, FolderPath = folderPath, @@ -73,7 +78,7 @@ namespace Orchard.MediaLibrary.Controllers { } public ActionResult Import(string folderPath) { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot import media"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot import media"))) return new HttpUnauthorizedResult(); var mediaProviderMenu = _navigationManager.BuildMenu("mediaproviders"); @@ -91,9 +96,20 @@ namespace Orchard.MediaLibrary.Controllers { [Themed(false)] public ActionResult MediaItems(string folderPath, int skip = 0, int count = 0, string order = "created", string mediaType = "") { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media"))) return new HttpUnauthorizedResult(); + // Check permission.var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); + if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + var model = new MediaManagerMediaItemsViewModel { + MediaItems = new List(), + MediaItemsCount = 0, + FolderPath = folderPath + }; + + return View(model); + } + var mediaParts = _mediaLibraryService.GetMediaContentItems(folderPath, skip, count, order, mediaType, VersionOptions.Latest); var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(folderPath, mediaType, VersionOptions.Latest); @@ -113,9 +129,19 @@ namespace Orchard.MediaLibrary.Controllers { [Themed(false)] public ActionResult ChildFolders(string folderPath = null) { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot get child folder listing"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot get child folder listing"))) return new HttpUnauthorizedResult(); + // Check permission. + var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); + if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + var model = new MediaManagerChildFoldersViewModel { + Children = new IMediaFolder[0] + }; + + return View(model); + } + var viewModel = new MediaManagerChildFoldersViewModel { Children = _mediaLibraryService.GetMediaFolders(folderPath) }; @@ -127,11 +153,13 @@ namespace Orchard.MediaLibrary.Controllers { [Themed(false)] public ActionResult RecentMediaItems(int skip = 0, int count = 0, string order = "created", string mediaType = "") { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Cannot view media"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Cannot view media"))) return new HttpUnauthorizedResult(); - var mediaParts = _mediaLibraryService.GetMediaContentItems(skip, count, order, mediaType); - var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(mediaType); + var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder().MediaPath; + + var mediaParts = _mediaLibraryService.GetMediaContentItems(rootMediaFolder, skip, count, order, mediaType); + var mediaPartsCount = _mediaLibraryService.GetMediaContentItemsCount(rootMediaFolder, mediaType); var mediaItems = mediaParts.Select(x => new MediaManagerMediaItemViewModel { @@ -149,12 +177,13 @@ namespace Orchard.MediaLibrary.Controllers { [Themed(false)] public ActionResult MediaItem(int id, string displayType = "SummaryAdmin") { - var contentItem = Services.ContentManager.Get(id, VersionOptions.Latest); + var contentItem = Services.ContentManager.Get(id, VersionOptions.Latest); if (contentItem == null) return HttpNotFound(); - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, contentItem, T("Cannot view media"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, contentItem, T("Cannot view media")) + || !_mediaLibraryService.CanManageMediaFolder(contentItem.FolderPath)) return new HttpUnauthorizedResult(); dynamic model = Services.ContentManager.BuildDisplay(contentItem, displayType); @@ -164,13 +193,20 @@ namespace Orchard.MediaLibrary.Controllers { [HttpPost] public ActionResult Delete(int[] mediaItemIds) { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't delete media items"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't delete media items"))) return new HttpUnauthorizedResult(); + var mediaItems = Services.ContentManager + .Query(VersionOptions.Latest) + .ForContentItems(mediaItemIds) + .List() + .Select(x => x.As()) + .Where(x => x != null); + try { - foreach (var media in Services.ContentManager.Query(VersionOptions.Latest).ForContentItems(mediaItemIds).List()) { - if (media != null) { - Services.ContentManager.Remove(media); + foreach (var media in mediaItems) { + if (_mediaLibraryService.CanManageMediaFolder(media.FolderPath)) { + Services.ContentManager.Remove(media.ContentItem); } } @@ -184,12 +220,16 @@ namespace Orchard.MediaLibrary.Controllers { [HttpPost] public ActionResult Clone(int mediaItemId) { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't clone media items"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't clone media items"))) return new HttpUnauthorizedResult(); try { var media = Services.ContentManager.Get(mediaItemId).As(); + if(!_mediaLibraryService.CanManageMediaFolder(media.FolderPath)) { + return new HttpUnauthorizedResult(); + } + var newFileName = Path.GetFileNameWithoutExtension(media.FileName) + " Copy" + Path.GetExtension(media.FileName); _mediaLibraryService.CopyFile(media.FolderPath, media.FileName, media.FolderPath, newFileName); diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/ClientStorageController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/ClientStorageController.cs index 4649d9873..a755bdca1 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/ClientStorageController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/ClientStorageController.cs @@ -15,11 +15,17 @@ namespace Orchard.MediaLibrary.Controllers { private readonly IMediaLibraryService _mediaLibraryService; private readonly IContentManager _contentManager; - public ClientStorageController(IMediaLibraryService mediaManagerService, IContentManager contentManager) { + public ClientStorageController( + IMediaLibraryService mediaManagerService, + IContentManager contentManager, + IOrchardServices orchardServices) { _mediaLibraryService = mediaManagerService; _contentManager = contentManager; + Services = orchardServices; } + public IOrchardServices Services { get; set; } + public ActionResult Index(string folderPath, string type) { var viewModel = new ImportMediaViewModel { @@ -32,6 +38,15 @@ namespace Orchard.MediaLibrary.Controllers { [HttpPost] public ActionResult Upload(string folderPath, string type) { + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) + return new HttpUnauthorizedResult(); + + // Check permission. + var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); + if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + return new HttpUnauthorizedResult(); + } + var statuses = new List(); // Loop through each file in the request diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/FolderController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/FolderController.cs index b08662cf8..aae4fc56f 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/FolderController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/FolderController.cs @@ -32,9 +32,15 @@ namespace Orchard.MediaLibrary.Controllers { public Localizer T { get; set; } public ActionResult Create(string folderPath) { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't create media folder"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't create media folder"))) return new HttpUnauthorizedResult(); + // If the user is trying to access a folder above his boundaries, redirect him to his home folder + var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); + if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + return RedirectToAction("Create", new { folderPath = rootMediaFolder.MediaPath }); + } + var viewModel = new MediaManagerFolderCreateViewModel { Hierarchy = _mediaLibraryService.GetMediaFolders(folderPath), FolderPath = folderPath @@ -45,12 +51,16 @@ namespace Orchard.MediaLibrary.Controllers { [HttpPost, ActionName("Create")] public ActionResult Create() { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't create media folder"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't create media folder"))) return new HttpUnauthorizedResult(); var viewModel = new MediaManagerFolderCreateViewModel(); UpdateModel(viewModel); + if (!_mediaLibraryService.CanManageMediaFolder(viewModel.FolderPath)) { + return new HttpUnauthorizedResult(); + } + try { _mediaLibraryService.CreateFolder(viewModel.FolderPath, viewModel.Name); Services.Notifier.Information(T("Media folder created")); @@ -66,9 +76,13 @@ namespace Orchard.MediaLibrary.Controllers { } public ActionResult Edit(string folderPath) { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't edit media folder"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't edit media folder"))) return new HttpUnauthorizedResult(); - + + if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { + return new HttpUnauthorizedResult(); + } + var viewModel = new MediaManagerFolderEditViewModel { FolderPath = folderPath, Name = folderPath.Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar).Last() @@ -80,12 +94,16 @@ namespace Orchard.MediaLibrary.Controllers { [HttpPost, ActionName("Edit")] [FormValueRequired("submit.Save")] public ActionResult Edit() { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't edit media folder"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't edit media folder"))) return new HttpUnauthorizedResult(); var viewModel = new MediaManagerFolderEditViewModel(); UpdateModel(viewModel); + if (!_mediaLibraryService.CanManageMediaFolder(viewModel.FolderPath)) { + return new HttpUnauthorizedResult(); + } + try { _mediaLibraryService.RenameFolder(viewModel.FolderPath, viewModel.Name); Services.Notifier.Information(T("Media folder renamed")); @@ -101,12 +119,16 @@ namespace Orchard.MediaLibrary.Controllers { [HttpPost, ActionName("Edit")] [FormValueRequired("submit.Delete")] public ActionResult Delete() { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't delete media folder"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't delete media folder"))) return new HttpUnauthorizedResult(); var viewModel = new MediaManagerFolderEditViewModel(); UpdateModel(viewModel); + if (!_mediaLibraryService.CanManageMediaFolder(viewModel.FolderPath)) { + return new HttpUnauthorizedResult(); + + } try { _mediaLibraryService.DeleteFolder(viewModel.FolderPath); Services.Notifier.Information(T("Media folder deleted")); @@ -122,9 +144,13 @@ namespace Orchard.MediaLibrary.Controllers { [HttpPost] public ActionResult Move(string folderPath, int[] mediaItemIds) { - if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent, T("Couldn't move media items"))) + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia, T("Couldn't move media items"))) return new HttpUnauthorizedResult(); + if (!_mediaLibraryService.CanManageMediaFolder(folderPath)) { + return new HttpUnauthorizedResult(); + } + foreach (var media in Services.ContentManager.Query().ForPart().ForContentItems(mediaItemIds).List()) { // don't try to rename the file if there is no associated media file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/OEmbedController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/OEmbedController.cs index 0ed803cbe..e5368bd0a 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/OEmbedController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/OEmbedController.cs @@ -9,12 +9,18 @@ using Orchard.MediaLibrary.ViewModels; using Orchard.Themes; using Orchard.UI.Admin; using Orchard.ContentManagement; +using Orchard.MediaLibrary.Services; namespace Orchard.MediaLibrary.Controllers { [Admin, Themed(false)] public class OEmbedController : Controller { - public OEmbedController(IOrchardServices services) { + private readonly IMediaLibraryService _mediaLibraryService; + + public OEmbedController( + IOrchardServices services, + IMediaLibraryService mediaManagerService) { Services = services; + _mediaLibraryService = mediaManagerService; } public IOrchardServices Services { get; set; } @@ -32,6 +38,15 @@ namespace Orchard.MediaLibrary.Controllers { [ActionName("Index")] [ValidateInput(false)] public ActionResult IndexPOST(string folderPath, string url, string type, string title, string html, string thumbnail, string width, string height, string description) { + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) + return new HttpUnauthorizedResult(); + + // Check permission. + var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); + if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + return new HttpUnauthorizedResult(); + } + var viewModel = new OEmbedViewModel { Url = url, FolderPath = folderPath diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/WebSearchController.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/WebSearchController.cs index 83154cf9c..23f7b576d 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/WebSearchController.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Controllers/WebSearchController.cs @@ -13,12 +13,19 @@ namespace Orchard.MediaLibrary.Controllers { public class WebSearchController : Controller { private readonly IMediaLibraryService _mediaLibraryService; private readonly IContentManager _contentManager; - - public WebSearchController(IMediaLibraryService mediaManagerService, IContentManager contentManager) { + + public WebSearchController( + IMediaLibraryService mediaManagerService, + IContentManager contentManager, + IOrchardServices orchardServices) { _mediaLibraryService = mediaManagerService; _contentManager = contentManager; + + Services = orchardServices; } + public IOrchardServices Services { get; set; } + public ActionResult Index(string folderPath, string type) { var viewModel = new ImportMediaViewModel { FolderPath = folderPath, @@ -30,7 +37,15 @@ namespace Orchard.MediaLibrary.Controllers { [HttpPost] - public JsonResult ImagePost(string folderPath, string type, string url) { + public ActionResult ImagePost(string folderPath, string type, string url) { + if (!Services.Authorizer.Authorize(Permissions.ManageOwnMedia)) + return new HttpUnauthorizedResult(); + + // Check permission. + var rootMediaFolder = _mediaLibraryService.GetRootMediaFolder(); + if (!Services.Authorizer.Authorize(Permissions.ManageMediaContent) && !_mediaLibraryService.CanManageMediaFolder(folderPath)) { + return new HttpUnauthorizedResult(); + } try { var buffer = new WebClient().DownloadData(url); diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj index e29e5de5f..f23562840 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Orchard.MediaLibrary.csproj @@ -174,6 +174,7 @@ + diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Permissions.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Permissions.cs index 3efd53f8e..8e9497683 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Permissions.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Permissions.cs @@ -4,13 +4,15 @@ using Orchard.Security.Permissions; namespace Orchard.MediaLibrary { public class Permissions : IPermissionProvider { - public static readonly Permission ManageMediaContent = new Permission { Description = "Managing Media", Name = "ManageMediaContent" }; + public static readonly Permission ManageMediaContent = new Permission { Description = "Manage Media", Name = "ManageMediaContent" }; + public static readonly Permission ManageOwnMedia = new Permission { Description = "Manage Own Media", Name = "ManageOwnMedia", ImpliedBy = new[] { ManageMediaContent } }; public virtual Feature Feature { get; set; } public IEnumerable GetPermissions() { return new[] { ManageMediaContent, + ManageOwnMedia, }; } @@ -33,6 +35,7 @@ namespace Orchard.MediaLibrary { }, new PermissionStereotype { Name = "Contributor", + Permissions = new[] {ManageOwnMedia} }, }; } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/ClientStorageMenu.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/ClientStorageMenu.cs index 7f8b8a973..005764bab 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/ClientStorageMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/ClientStorageMenu.cs @@ -15,7 +15,7 @@ namespace Orchard.MediaLibrary.Providers { builder.AddImageSet("clientstorage") .Add(T("My Computer"), "5", menu => menu.Action("Index", "ClientStorage", new { area = "Orchard.MediaLibrary" }) - .Permission(Permissions.ManageMediaContent)); + .Permission(Permissions.ManageOwnMedia)); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/OEmbedMenu.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/OEmbedMenu.cs index 82875e1fb..71aff8019 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/OEmbedMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/OEmbedMenu.cs @@ -15,7 +15,7 @@ namespace Orchard.MediaLibrary.Providers { builder.AddImageSet("oembed") .Add(T("Media Url"), "10", menu => menu.Action("Index", "OEmbed", new { area = "Orchard.MediaLibrary" }) - .Permission(Permissions.ManageMediaContent)); + .Permission(Permissions.ManageOwnMedia)); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/WebSearchMenu.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/WebSearchMenu.cs index 896205d0f..39fb04322 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/WebSearchMenu.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Providers/WebSearchMenu.cs @@ -15,7 +15,7 @@ namespace Orchard.MediaLibrary.Providers { builder.AddImageSet("websearch") .Add(T("Web Search"), "7", menu => menu.Action("Index", "WebSearch", new { area = "Orchard.MediaLibrary" }) - .Permission(Permissions.ManageMediaContent)); + .Permission(Permissions.ManageOwnMedia)); } } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Security/MediaAuthorizationEventHandler.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Security/MediaAuthorizationEventHandler.cs new file mode 100644 index 000000000..14bb48916 --- /dev/null +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Security/MediaAuthorizationEventHandler.cs @@ -0,0 +1,35 @@ +using Orchard.ContentManagement; +using Orchard.MediaLibrary.Models; +using Orchard.MediaLibrary.Services; +using Orchard.Security; + +namespace Orchard.MediaLibrary.Security { + public class MediaAuthorizationEventHandler : IAuthorizationServiceEventHandler { + private readonly IAuthorizer _authorizer; + private readonly IMediaLibraryService _mediaLibraryService; + + public MediaAuthorizationEventHandler( + IAuthorizer authorizer, + IMediaLibraryService mediaLibraryService) { + _authorizer = authorizer; + _mediaLibraryService = mediaLibraryService; + } + + public void Checking(CheckAccessContext context) { } + public void Complete(CheckAccessContext context) { } + + public void Adjust(CheckAccessContext context) { + var mediaPart = context.Content.As(); + if (mediaPart != null) { + if(_authorizer.Authorize(Permissions.ManageMediaContent)) { + context.Granted = true; + return; + } + + if(_authorizer.Authorize(Permissions.ManageOwnMedia)) { + context.Granted = _mediaLibraryService.CanManageMediaFolder(mediaPart.FolderPath); + } + } + } + } +} \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs index 7424c9fa5..2291f4c6f 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/IMediaLibraryService.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO; using System.Web; using Orchard.ContentManagement; @@ -36,7 +37,7 @@ namespace Orchard.MediaLibrary.Services { /// The public URL for the media. string GetMediaPublicUrl(string mediaPath, string fileName); - MediaFolder GetRootMediaFolder(); + IMediaFolder GetRootMediaFolder(); /// /// Retrieves the media folders within a given relative path. @@ -131,4 +132,30 @@ namespace Orchard.MediaLibrary.Services { /// The path to the uploaded file. string UploadMediaFile(string folderPath, string fileName, Stream inputStream); } + + public static class MediaLibrayServiceExtensions { + public static bool CanManageMediaFolder(this IMediaLibraryService service, string folderPath) { + // The current user can manage a media if he has access to the whole hierarchy + // or the media is under his personal storage folder. + + var rootMediaFolder = service.GetRootMediaFolder(); + if (rootMediaFolder == null) { + return true; + } + + var mediaPath = folderPath + "\\"; + var rootPath = rootMediaFolder.MediaPath + "\\"; + + return mediaPath.StartsWith(rootPath, StringComparison.OrdinalIgnoreCase); + } + + public static string GetRootedFolderPath(this IMediaLibraryService service, string folderPath) { + var rootMediaFolder = service.GetRootMediaFolder(); + if (rootMediaFolder != null) { + return Path.Combine(rootMediaFolder.MediaPath, folderPath ?? ""); + } + + return folderPath; + } + } } \ No newline at end of file diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs index f90c975c5..c4ae060f3 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/MediaLibraryService.cs @@ -210,7 +210,21 @@ namespace Orchard.MediaLibrary.Services { return GetPublicUrl(Path.Combine(mediaPath, fileName)); } - public MediaFolder GetRootMediaFolder() { + public IMediaFolder GetRootMediaFolder() { + if (_orchardServices.Authorizer.Authorize(Permissions.ManageMediaContent)) { + return null; + } + + if (_orchardServices.Authorizer.Authorize(Permissions.ManageOwnMedia)) { + var currentUser = _orchardServices.WorkContext.CurrentUser; + var userPath = _storageProvider.Combine("Users", currentUser.UserName); + + return new MediaFolder() { + Name = currentUser.UserName, + MediaPath = userPath + }; + } + return null; } diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/XmlRpcHandler.cs b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/XmlRpcHandler.cs index 88eb0be87..14a35ab00 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/XmlRpcHandler.cs +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Services/XmlRpcHandler.cs @@ -60,7 +60,7 @@ namespace Orchard.MediaLibrary.Services { UrlHelper url) { var user = _membershipService.ValidateUser(userName, password); - if (!_authorizationService.TryCheckAccess(Permissions.ManageMediaContent, user, null)) { + if (!_authorizationService.TryCheckAccess(Permissions.ManageOwnMedia, user, null)) { throw new OrchardCoreException(T("Access denied")); } @@ -72,6 +72,11 @@ namespace Orchard.MediaLibrary.Services { directoryName = "media"; } + // If the user only has access to his own folder, rewrite the folder name + if (!_authorizationService.TryCheckAccess(Permissions.ManageMediaContent, user, null)) { + directoryName = Path.Combine(_mediaLibraryService.GetRootedFolderPath(directoryName)); + } + try { // delete the file if it already exists, e.g. an updated image in a blog post // it's safe to delete the file as each content item gets a specific folder diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml index 5a9dce068..57eaa43e4 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Admin/Index.cshtml @@ -112,7 +112,7 @@ var mediaLibrarySettings = {
-
    +
    diff --git a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Folder/Create.cshtml b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Folder/Create.cshtml index 3ed81ac0f..c817607d0 100644 --- a/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Folder/Create.cshtml +++ b/src/Orchard.Web/Modules/Orchard.MediaLibrary/Views/Folder/Create.cshtml @@ -6,10 +6,12 @@