Skip to content

Commit

Permalink
Add UsersFolder for media assets (#9357)
Browse files Browse the repository at this point in the history
  • Loading branch information
felixhoi committed Aug 10, 2021
1 parent 572077a commit 140fb02
Show file tree
Hide file tree
Showing 10 changed files with 200 additions and 105 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class AdminController : Controller
private readonly ILogger _logger;
private readonly IStringLocalizer S;
private readonly MediaOptions _mediaOptions;
private readonly IUserAssetFolderNameProvider _userAssetFolderNameProvider;

public AdminController(
IMediaFileStore mediaFileStore,
Expand All @@ -35,7 +36,8 @@ public class AdminController : Controller
IContentTypeProvider contentTypeProvider,
IOptions<MediaOptions> options,
ILogger<AdminController> logger,
IStringLocalizer<AdminController> stringLocalizer
IStringLocalizer<AdminController> stringLocalizer,
IUserAssetFolderNameProvider userAssetFolderNameProvider
)
{
_mediaFileStore = mediaFileStore;
Expand All @@ -46,6 +48,7 @@ IStringLocalizer<AdminController> stringLocalizer
_allowedFileExtensions = _mediaOptions.AllowedFileExtensions;
_logger = logger;
S = stringLocalizer;
_userAssetFolderNameProvider = userAssetFolderNameProvider;
}

public async Task<IActionResult> Index()
Expand Down Expand Up @@ -75,8 +78,15 @@ public async Task<ActionResult<IEnumerable<IFileStoreEntry>>> GetFolders(string
return NotFound();
}

// create default folders if not exist
if (await _authorizationService.AuthorizeAsync(User, Permissions.ManageOwnMedia)
&& await _mediaFileStore.GetDirectoryInfoAsync(_mediaFileStore.Combine(_mediaOptions.AssetsUsersFolder, _userAssetFolderNameProvider.GetUserAssetFolderName(User))) == null)
{
await _mediaFileStore.TryCreateDirectoryAsync(_mediaFileStore.Combine(_mediaOptions.AssetsUsersFolder, _userAssetFolderNameProvider.GetUserAssetFolderName(User)));
}

var allowed = _mediaFileStore.GetDirectoryContentAsync(path)
.WhereAwait(async e => e.IsDirectory && await _authorizationService.AuthorizeAsync(User, Permissions.ManageAttachedMediaFieldsFolder, (object)e.Path));
.WhereAwait(async e => e.IsDirectory && await _authorizationService.AuthorizeAsync(User, Permissions.ManageMediaFolder, (object)e.Path));

return Ok(await allowed.ToListAsync());
}
Expand All @@ -89,7 +99,7 @@ public async Task<ActionResult<IEnumerable<object>>> GetMediaItems(string path)
}

if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageMedia)
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageAttachedMediaFieldsFolder, (object)path))
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageMediaFolder, (object)path))
{
return Forbid();
}
Expand All @@ -100,7 +110,7 @@ public async Task<ActionResult<IEnumerable<object>>> GetMediaItems(string path)
}

var allowed = _mediaFileStore.GetDirectoryContentAsync(path)
.WhereAwait(async e => !e.IsDirectory && await _authorizationService.AuthorizeAsync(User, Permissions.ManageAttachedMediaFieldsFolder, (object)e.Path))
.WhereAwait(async e => !e.IsDirectory && await _authorizationService.AuthorizeAsync(User, Permissions.ManageMediaFolder, (object)e.Path))
.Select(e => CreateFileResult(e));

return Ok(await allowed.ToListAsync());
Expand Down Expand Up @@ -205,7 +215,7 @@ public async Task<ActionResult<object>> GetMediaItem(string path)
public async Task<IActionResult> DeleteFolder(string path)
{
if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageMedia)
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageAttachedMediaFieldsFolder, (object)path))
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageMediaFolder, (object)path))
{
return Forbid();
}
Expand Down Expand Up @@ -233,7 +243,7 @@ public async Task<IActionResult> DeleteFolder(string path)
public async Task<IActionResult> DeleteMedia(string path)
{
if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageMedia)
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageAttachedMediaFieldsFolder, (object)path))
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageMediaFolder, (object)path))
{
return Forbid();
}
Expand All @@ -253,7 +263,7 @@ public async Task<IActionResult> DeleteMedia(string path)
public async Task<IActionResult> MoveMedia(string oldPath, string newPath)
{
if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageMedia)
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageAttachedMediaFieldsFolder, (object)oldPath))
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageMediaFolder, (object)oldPath))
{
return Forbid();
}
Expand Down Expand Up @@ -317,8 +327,8 @@ public async Task<IActionResult> DeleteMediaList(string[] paths)
public async Task<IActionResult> MoveMediaList(string[] mediaNames, string sourceFolder, string targetFolder)
{
if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManageMedia)
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageAttachedMediaFieldsFolder, (object)sourceFolder)
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageAttachedMediaFieldsFolder, (object)targetFolder))
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageMediaFolder, (object)sourceFolder)
|| !await _authorizationService.AuthorizeAsync(User, Permissions.ManageMediaFolder, (object)targetFolder))
{
return Forbid();
}
Expand Down Expand Up @@ -379,7 +389,7 @@ public async Task<IActionResult> MoveMediaList(string[] mediaNames, string sourc
var newPath = _mediaFileStore.Combine(path, name);

if (!await authorizationService.AuthorizeAsync(User, Permissions.ManageMedia)
|| !await authorizationService.AuthorizeAsync(User, Permissions.ManageAttachedMediaFieldsFolder, (object)newPath))
|| !await authorizationService.AuthorizeAsync(User, Permissions.ManageMediaFolder, (object)newPath))
{
return Forbid();
}
Expand Down
26 changes: 17 additions & 9 deletions src/OrchardCore.Modules/OrchardCore.Media/Permissions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@
namespace OrchardCore.Media
{
public class Permissions : IPermissionProvider
{
public static readonly Permission ManageMedia = new Permission("ManageMediaContent", "Manage Media");
public static readonly Permission ManageAttachedMediaFieldsFolder = new Permission("ManageAttachedMediaFieldsFolder", "Manage Attached Media Fields Folder");
{
public static readonly Permission ManageMediaFolder = new Permission("ManageMediaFolder", "Manage All Media Folders");
public static readonly Permission ManageOthersMedia = new Permission("ManageOthersMediaContent", "Manage Media For Others", new[] { ManageMediaFolder });
public static readonly Permission ManageOwnMedia = new Permission("ManageOwnMediaContent", "Manage Own Media" , new[] { ManageOthersMedia });
public static readonly Permission ManageMedia = new Permission("ManageMediaContent", "Manage Media", new[] { ManageOwnMedia });
public static readonly Permission ManageAttachedMediaFieldsFolder = new Permission("ManageAttachedMediaFieldsFolder", "Manage Attached Media Fields Folder", new[] { ManageMediaFolder});
public static readonly Permission ManageMediaProfiles = new Permission("ManageMediaProfiles", "Manage Media Profiles");
public static readonly Permission ViewMediaOptions = new Permission("ViewMediaOptions", "View Media Options");

public static readonly Permission ViewMediaOptions = new Permission("ViewMediaOptions", "View Media Options");
public Task<IEnumerable<Permission>> GetPermissionsAsync()
{
return Task.FromResult(new[]
{
ManageMedia,
ManageMediaFolder,
ManageOthersMedia,
ManageOwnMedia,
ManageAttachedMediaFieldsFolder,
ManageMediaProfiles,
ViewMediaOptions
Expand All @@ -31,12 +36,15 @@ public IEnumerable<PermissionStereotype> GetDefaultStereotypes()
new PermissionStereotype
{
Name = "Administrator",
Permissions = new[] { ManageMedia, ManageAttachedMediaFieldsFolder, ManageMediaProfiles, ViewMediaOptions }
Permissions = new[] {
ManageMediaFolder,
ManageMediaProfiles,
ViewMediaOptions }
},
new PermissionStereotype
{
Name = "Editor",
Permissions = new[] { ManageMedia }
Permissions = new[] { ManageMedia, ManageOwnMedia }
},
new PermissionStereotype
{
Expand All @@ -45,12 +53,12 @@ public IEnumerable<PermissionStereotype> GetDefaultStereotypes()
new PermissionStereotype
{
Name = "Author",
Permissions = new[] { ManageMedia } // Replace this by ManageOwnMedia when it's implemented
Permissions = new[] { ManageOwnMedia }
},
new PermissionStereotype
{
Name = "Contributor",
Permissions = new[] { ManageMedia } // Replace this by ManageOwnMedia when it's implemented
Permissions = new[] { ManageOwnMedia }
},
};
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace OrchardCore.Media.Services
{
public class DefaultUserAssetFolderNameProvider: IUserAssetFolderNameProvider
{
public string GetUserAssetFolderName(ClaimsPrincipal claimsPrincipal)
{
return claimsPrincipal.FindFirstValue(ClaimTypes.NameIdentifier);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OrchardCore.FileStorage;
using OrchardCore.Security;
using OrchardCore.Security.Permissions;

namespace OrchardCore.Media.Services
{
/// <summary>
/// Checks if the user has related permission to manage the path resource which is passed from AuthorizationHandler
/// </summary>
public class ManageMediaFolderAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
{
private readonly IServiceProvider _serviceProvider;
private readonly AttachedMediaFieldFileService _attachedMediaFieldFileService;
private readonly IMediaFileStore _fileStore;
private char _pathSeparator;
private string _mediaFieldsFolder;
private string _usersFolder;
private readonly MediaOptions _mediaOptions;
private Dictionary<string, Permission> folderPermissios = new Dictionary<string, Permission>();
private readonly IUserAssetFolderNameProvider _userAssetFolderNameProvider;

public ManageMediaFolderAuthorizationHandler(IServiceProvider serviceProvider,
AttachedMediaFieldFileService attachedMediaFieldFileService,
IMediaFileStore fileStore,
IOptions<MediaOptions> options,
IUserAssetFolderNameProvider userAssetFolderNameProvider)
{
_serviceProvider = serviceProvider;
_attachedMediaFieldFileService = attachedMediaFieldFileService;
_fileStore = fileStore;
_mediaOptions = options.Value;
_userAssetFolderNameProvider = userAssetFolderNameProvider;
}

protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
if (context.HasSucceeded)
{
// This handler is not revoking any pre-existing grants.
return;
}

if (requirement.Permission.Name != Permissions.ManageMediaFolder.Name)
{
return;
}

if (context.Resource == null)
{
return;
}

_pathSeparator = _fileStore.Combine("a", "b").Contains('/') ? '/' : '\\';

// ensure end trailing slash
_mediaFieldsFolder = _fileStore.NormalizePath(_attachedMediaFieldFileService.MediaFieldsFolder)
.TrimEnd(_pathSeparator) + _pathSeparator;

_usersFolder = _fileStore.NormalizePath(_mediaOptions.AssetsUsersFolder)
.TrimEnd(_pathSeparator) + _pathSeparator;

var path = context.Resource as string;

string userOwnFolder = _fileStore.NormalizePath(
_fileStore.Combine(_usersFolder, _userAssetFolderNameProvider.GetUserAssetFolderName(context.User)))
.TrimEnd(_pathSeparator) + _pathSeparator;

Permission permission = Permissions.ManageMedia;

// handle attached media field folder
if (IsAuthorizedFolder(_mediaFieldsFolder, path) || IsDescendantOfauthorizedFolder(_mediaFieldsFolder, path))
{
permission = Permissions.ManageAttachedMediaFieldsFolder;
}

if (IsAuthorizedFolder(_usersFolder, path) || IsAuthorizedFolder(userOwnFolder, path) || IsDescendantOfauthorizedFolder(userOwnFolder, path))
{
permission = Permissions.ManageOwnMedia;
}

if (IsDescendantOfauthorizedFolder(_usersFolder, path) && !IsAuthorizedFolder(userOwnFolder, path) && !IsDescendantOfauthorizedFolder(userOwnFolder, path))
{
permission = Permissions.ManageOthersMedia;
}

// Lazy load to prevent circular dependencies
var authorizationService = _serviceProvider.GetService<IAuthorizationService>();

if (await authorizationService.AuthorizeAsync(context.User, permission))
{
context.Succeed(requirement);
}
}

private bool IsAuthorizedFolder(string authorizedFolder, string childPath)
{
// ensure end trailing slash
childPath = _fileStore.NormalizePath(childPath)
.TrimEnd(_pathSeparator) + _pathSeparator;

return childPath.Equals(authorizedFolder);
}

private bool IsDescendantOfauthorizedFolder(string authorizedFolder, string childPath)
{
childPath = _fileStore.NormalizePath(childPath);
return childPath.StartsWith(authorizedFolder, StringComparison.Ordinal);
}
}
}

0 comments on commit 140fb02

Please sign in to comment.