Migrates EnsureUserPermissionForContentAttribute to authz policies
This commit is contained in:
@@ -7,7 +7,9 @@ namespace Umbraco.Web.Actions
|
||||
/// </summary>
|
||||
public class ActionCopy : IAction
|
||||
{
|
||||
public char Letter => 'O';
|
||||
public const char ActionLetter = 'O';
|
||||
|
||||
public char Letter => ActionLetter;
|
||||
public string Alias => "copy";
|
||||
public string Category => Constants.Conventions.PermissionCategories.StructureCategory;
|
||||
public string Icon => "documents";
|
||||
|
||||
@@ -7,7 +7,9 @@ namespace Umbraco.Web.Actions
|
||||
/// </summary>
|
||||
public class ActionRights : IAction
|
||||
{
|
||||
public char Letter => 'R';
|
||||
public const char ActionLetter = 'R';
|
||||
|
||||
public char Letter => ActionLetter;
|
||||
public string Alias => "rights";
|
||||
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
|
||||
public string Icon => "vcard";
|
||||
|
||||
@@ -9,7 +9,9 @@ namespace Umbraco.Web.Actions
|
||||
/// </summary>
|
||||
public class ActionSort : IAction
|
||||
{
|
||||
public char Letter => 'S';
|
||||
public const char ActionLetter = 'S';
|
||||
|
||||
public char Letter => ActionLetter;
|
||||
public string Alias => "sort";
|
||||
public string Category => Constants.Conventions.PermissionCategories.StructureCategory;
|
||||
public string Icon => "navigation-vertical";
|
||||
|
||||
@@ -10,7 +10,9 @@ namespace Umbraco.Web.Actions
|
||||
/// </summary>
|
||||
public class ActionUnpublish : IAction
|
||||
{
|
||||
public char Letter => 'Z';
|
||||
public const char ActionLetter = 'Z';
|
||||
|
||||
public char Letter => ActionLetter;
|
||||
public string Alias => "unpublish";
|
||||
public string Category => Constants.Conventions.PermissionCategories.ContentCategory;
|
||||
public string Icon => "circle-dotted";
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Editors;
|
||||
@@ -15,14 +13,14 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
/// <summary>
|
||||
/// if the users being edited is an admin then we must ensure that the current user is also an admin
|
||||
/// </summary>
|
||||
public class AdminUsersAuthorizeHandler : AuthorizationHandler<AdminUsersAuthorizeRequirement>
|
||||
public class AdminUsersHandler : AuthorizationHandler<AdminUsersRequirement>
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAcessor;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
|
||||
private readonly UserEditorAuthorizationHelper _userEditorAuthorizationHelper;
|
||||
|
||||
public AdminUsersAuthorizeHandler(IHttpContextAccessor httpContextAcessor,
|
||||
public AdminUsersHandler(IHttpContextAccessor httpContextAcessor,
|
||||
IUserService userService,
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
UserEditorAuthorizationHelper userEditorAuthorizationHelper)
|
||||
@@ -33,7 +31,7 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
_userEditorAuthorizationHelper = userEditorAuthorizationHelper;
|
||||
}
|
||||
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdminUsersAuthorizeRequirement requirement)
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AdminUsersRequirement requirement)
|
||||
{
|
||||
var isAuth = IsAuthorized(requirement);
|
||||
if (!isAuth.HasValue || isAuth.Value)
|
||||
@@ -48,7 +46,7 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private bool? IsAuthorized(AdminUsersAuthorizeRequirement requirement)
|
||||
private bool? IsAuthorized(AdminUsersRequirement requirement)
|
||||
{
|
||||
int[] userIds;
|
||||
|
||||
@@ -4,11 +4,11 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Authorization requirement for the <see cref="AdminUsersAuthorizeHandler"/>
|
||||
/// Authorization requirement for the <see cref="AdminUsersHandler"/>
|
||||
/// </summary>
|
||||
public class AdminUsersAuthorizeRequirement : IAuthorizationRequirement
|
||||
public class AdminUsersRequirement : IAuthorizationRequirement
|
||||
{
|
||||
public AdminUsersAuthorizeRequirement(string queryStringName = "id")
|
||||
public AdminUsersRequirement(string queryStringName = "id")
|
||||
{
|
||||
QueryStringName = queryStringName;
|
||||
}
|
||||
@@ -9,18 +9,18 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
/// <summary>
|
||||
/// Ensures authorization is successful for a back office user.
|
||||
/// </summary>
|
||||
public class BackOfficeAuthorizationHandler : AuthorizationHandler<BackOfficeAuthorizeRequirement>
|
||||
public class BackOfficeHandler : AuthorizationHandler<BackOfficeRequirement>
|
||||
{
|
||||
private readonly IBackOfficeSecurityAccessor _backOfficeSecurity;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
|
||||
public BackOfficeAuthorizationHandler(IBackOfficeSecurityAccessor backOfficeSecurity, IRuntimeState runtimeState)
|
||||
public BackOfficeHandler(IBackOfficeSecurityAccessor backOfficeSecurity, IRuntimeState runtimeState)
|
||||
{
|
||||
_backOfficeSecurity = backOfficeSecurity;
|
||||
_runtimeState = runtimeState;
|
||||
}
|
||||
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BackOfficeAuthorizeRequirement requirement)
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BackOfficeRequirement requirement)
|
||||
{
|
||||
if (!IsAuthorized(requirement))
|
||||
{
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private bool IsAuthorized(BackOfficeAuthorizeRequirement requirement)
|
||||
private bool IsAuthorized(BackOfficeRequirement requirement)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -3,11 +3,11 @@
|
||||
namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
/// <summary>
|
||||
/// Authorization requirement for the <see cref="BackOfficeAuthorizeRequirement"/>
|
||||
/// Authorization requirement for the <see cref="BackOfficeRequirement"/>
|
||||
/// </summary>
|
||||
public class BackOfficeAuthorizeRequirement : IAuthorizationRequirement
|
||||
public class BackOfficeRequirement : IAuthorizationRequirement
|
||||
{
|
||||
public BackOfficeAuthorizeRequirement(bool requireApproval = true)
|
||||
public BackOfficeRequirement(bool requireApproval = true)
|
||||
{
|
||||
RequireApproval = requireApproval;
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to authorize if the user has the correct permission access to the content for the <see cref="IContent"/> specified
|
||||
/// </summary>
|
||||
public class ContentPermissionResourceHandler : AuthorizationHandler<ContentPermissionResourceRequirement, IContent>
|
||||
{
|
||||
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IUserService _userService;
|
||||
|
||||
public ContentPermissionResourceHandler(
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
IEntityService entityService,
|
||||
IUserService userService)
|
||||
{
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor;
|
||||
_entityService = entityService;
|
||||
_userService = userService;
|
||||
}
|
||||
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ContentPermissionResourceRequirement requirement, IContent resource)
|
||||
{
|
||||
var permissionResult = ContentPermissionsHelper.CheckPermissions(resource,
|
||||
_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
|
||||
_userService,
|
||||
_entityService,
|
||||
new[] { requirement.PermissionToCheck });
|
||||
|
||||
if (permissionResult == ContentPermissionsHelper.ContentAccess.Denied)
|
||||
{
|
||||
context.Fail();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to authorize if the user has the correct permission access to the content for the content id specified in a query string
|
||||
/// </summary>
|
||||
public class ContentPermissionQueryStringHandler : AuthorizationHandler<ContentPermissionsQueryStringRequirement>
|
||||
{
|
||||
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IContentService _contentService;
|
||||
|
||||
public ContentPermissionQueryStringHandler(
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IEntityService entityService,
|
||||
IUserService userService,
|
||||
IContentService contentService)
|
||||
{
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor;
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
_entityService = entityService;
|
||||
_userService = userService;
|
||||
_contentService = contentService;
|
||||
}
|
||||
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ContentPermissionsQueryStringRequirement requirement)
|
||||
{
|
||||
int nodeId;
|
||||
if (requirement.NodeId.HasValue == false)
|
||||
{
|
||||
StringValues routeVal;
|
||||
foreach(var qs in requirement.QueryStringNames)
|
||||
{
|
||||
if (_httpContextAccessor.HttpContext.Request.Query.TryGetValue(qs, out routeVal))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (routeVal.Count == 0)
|
||||
{
|
||||
throw new InvalidOperationException("No argument found for the current action with by names " + string.Join(", ", requirement.QueryStringNames));
|
||||
}
|
||||
|
||||
var argument = routeVal.ToString();
|
||||
// if the argument is an int, it will parse and can be assigned to nodeId
|
||||
// if might be a udi, so check that next
|
||||
// otherwise treat it as a guid - unlikely we ever get here
|
||||
if (int.TryParse(argument, out int parsedId))
|
||||
{
|
||||
nodeId = parsedId;
|
||||
}
|
||||
else if (UdiParser.TryParse(argument, true, out var udi))
|
||||
{
|
||||
nodeId = _entityService.GetId(udi).Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
Guid.TryParse(argument, out Guid key);
|
||||
nodeId = _entityService.GetId(key, UmbracoObjectTypes.Document).Result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeId = requirement.NodeId.Value;
|
||||
}
|
||||
|
||||
var permissionResult = ContentPermissionsHelper.CheckPermissions(nodeId,
|
||||
_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
|
||||
_userService,
|
||||
_contentService,
|
||||
_entityService,
|
||||
out var contentItem,
|
||||
new[] { requirement.PermissionToCheck });
|
||||
|
||||
if (permissionResult == ContentPermissionsHelper.ContentAccess.NotFound)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (permissionResult == ContentPermissionsHelper.ContentAccess.Denied)
|
||||
{
|
||||
context.Fail();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
|
||||
|
||||
if (contentItem != null)
|
||||
{
|
||||
//store the content item in request cache so it can be resolved in the controller without re-looking it up
|
||||
_httpContextAccessor.HttpContext.Items[typeof(IContent).ToString()] = contentItem;
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
/// <summary>
|
||||
/// An authorization requirement for <see cref="ContentPermissionResourceHandler"/>
|
||||
/// </summary>
|
||||
public class ContentPermissionResourceRequirement : IAuthorizationRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an authorization requirement for a resource
|
||||
/// </summary>
|
||||
/// <param name="permissionToCheck"></param>
|
||||
public ContentPermissionResourceRequirement(char permissionToCheck)
|
||||
{
|
||||
PermissionToCheck = permissionToCheck;
|
||||
}
|
||||
|
||||
public char PermissionToCheck { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// An authorization requirement for <see cref="ContentPermissionQueryStringHandler"/>
|
||||
/// </summary>
|
||||
public class ContentPermissionsQueryStringRequirement : IAuthorizationRequirement
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Create an authorization requirement for a specific node id
|
||||
/// </summary>
|
||||
/// <param name="nodeId"></param>
|
||||
/// <param name="permissionToCheck"></param>
|
||||
public ContentPermissionsQueryStringRequirement(int nodeId, char permissionToCheck)
|
||||
{
|
||||
NodeId = nodeId;
|
||||
PermissionToCheck = permissionToCheck;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create an authorization requirement for a node id based on a query string parameter
|
||||
/// </summary>
|
||||
/// <param name="paramName"></param>
|
||||
/// <param name="permissionToCheck"></param>
|
||||
public ContentPermissionsQueryStringRequirement(char permissionToCheck, string[] paramNames)
|
||||
{
|
||||
QueryStringNames = paramNames;
|
||||
PermissionToCheck = permissionToCheck;
|
||||
}
|
||||
|
||||
public int? NodeId { get; }
|
||||
public string[] QueryStringNames { get; }
|
||||
public char PermissionToCheck { get; }
|
||||
}
|
||||
}
|
||||
@@ -8,11 +8,11 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
/// <summary>
|
||||
/// Ensures the resource cannot be accessed if <see cref="IBackOfficeExternalLoginProviders.HasDenyLocalLogin"/> returns true
|
||||
/// </summary>
|
||||
public class DenyLocalLoginAuthorizeHandler : AuthorizationHandler<DenyLocalLoginRequirement>
|
||||
public class DenyLocalLoginHandler : AuthorizationHandler<DenyLocalLoginRequirement>
|
||||
{
|
||||
private readonly IBackOfficeExternalLoginProviders _externalLogins;
|
||||
|
||||
public DenyLocalLoginAuthorizeHandler(IBackOfficeExternalLoginProviders externalLogins)
|
||||
public DenyLocalLoginHandler(IBackOfficeExternalLoginProviders externalLogins)
|
||||
{
|
||||
_externalLogins = externalLogins;
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
/// <summary>
|
||||
/// Marker requirement for the <see cref="DenyLocalLoginAuthorizeHandler"/>
|
||||
/// Marker requirement for the <see cref="DenyLocalLoginHandler"/>
|
||||
/// </summary>
|
||||
public class DenyLocalLoginRequirement : IAuthorizationRequirement
|
||||
{
|
||||
|
||||
@@ -12,16 +12,16 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
/// <remarks>
|
||||
/// The user only needs access to one of the sections specified, not all of the sections.
|
||||
/// </remarks>
|
||||
public class UmbracoSectionAuthorizeHandler : AuthorizationHandler<SectionAliasesRequirement>
|
||||
public class SectionHandler : AuthorizationHandler<SectionRequirement>
|
||||
{
|
||||
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
|
||||
|
||||
public UmbracoSectionAuthorizeHandler(IBackOfficeSecurityAccessor backofficeSecurityAccessor)
|
||||
public SectionHandler(IBackOfficeSecurityAccessor backofficeSecurityAccessor)
|
||||
{
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor;
|
||||
}
|
||||
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SectionAliasesRequirement requirement)
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SectionRequirement requirement)
|
||||
{
|
||||
if (IsAuthorized(requirement))
|
||||
{
|
||||
@@ -35,7 +35,7 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private bool IsAuthorized(SectionAliasesRequirement requirement)
|
||||
private bool IsAuthorized(SectionRequirement requirement)
|
||||
{
|
||||
var authorized = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null
|
||||
&& requirement.SectionAliases.Any(app => _backofficeSecurityAccessor.BackOfficeSecurity.UserHasSectionAccess(
|
||||
@@ -4,15 +4,15 @@ using System.Collections.Generic;
|
||||
namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
/// <summary>
|
||||
/// Authorization requirements for <see cref="UmbracoSectionAuthorizeHandler"/>
|
||||
/// Authorization requirements for <see cref="SectionHandler"/>
|
||||
/// </summary>
|
||||
public class SectionAliasesRequirement : IAuthorizationRequirement
|
||||
public class SectionRequirement : IAuthorizationRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// The aliases for sections that the user will need access to
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<string> SectionAliases { get; }
|
||||
|
||||
public SectionAliasesRequirement(params string[] aliases) => SectionAliases = aliases;
|
||||
public SectionRequirement(params string[] aliases) => SectionAliases = aliases;
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
/// This would allow a tree to be moved between sections.
|
||||
/// The user only needs access to one of the trees specified, not all of the trees.
|
||||
/// </remarks>
|
||||
public class UmbracoTreeAuthorizeHandler : AuthorizationHandler<TreeAliasesRequirement>
|
||||
public class TreeHandler : AuthorizationHandler<TreeRequirement>
|
||||
{
|
||||
|
||||
private readonly ITreeService _treeService;
|
||||
@@ -31,13 +31,13 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
/// If the user has access to the application that the treeAlias is specified in, they will be authorized.
|
||||
/// Multiple trees may be specified.
|
||||
/// </param>
|
||||
public UmbracoTreeAuthorizeHandler(ITreeService treeService, IBackOfficeSecurityAccessor backofficeSecurityAccessor)
|
||||
public TreeHandler(ITreeService treeService, IBackOfficeSecurityAccessor backofficeSecurityAccessor)
|
||||
{
|
||||
_treeService = treeService ?? throw new ArgumentNullException(nameof(treeService));
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor));
|
||||
}
|
||||
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TreeAliasesRequirement requirement)
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TreeRequirement requirement)
|
||||
{
|
||||
if (IsAuthorized(requirement))
|
||||
{
|
||||
@@ -51,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private bool IsAuthorized(TreeAliasesRequirement requirement)
|
||||
private bool IsAuthorized(TreeRequirement requirement)
|
||||
{
|
||||
var apps = requirement.TreeAliases.Select(x => _treeService
|
||||
.GetByAlias(x))
|
||||
@@ -5,15 +5,15 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Authorization requirements for <see cref="UmbracoTreeAuthorizeHandler"/>
|
||||
/// Authorization requirements for <see cref="TreeHandler"/>
|
||||
/// </summary>
|
||||
public class TreeAliasesRequirement : IAuthorizationRequirement
|
||||
public class TreeRequirement : IAuthorizationRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// The aliases for trees that the user will need access to
|
||||
/// </summary>
|
||||
public IReadOnlyCollection<string> TreeAliases { get; }
|
||||
|
||||
public TreeAliasesRequirement(params string[] aliases) => TreeAliases = aliases;
|
||||
public TreeRequirement(params string[] aliases) => TreeAliases = aliases;
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
/// <summary>
|
||||
/// Authorizes that the current user has access to the user group Id in the request
|
||||
/// </summary>
|
||||
public class UserGroupAuthorizationHandler : AuthorizationHandler<UserGroupAuthorizeRequirement>
|
||||
public class UserGroupHandler : AuthorizationHandler<UserGroupRequirement>
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAcessor;
|
||||
private readonly IUserService _userService;
|
||||
@@ -21,7 +21,7 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
|
||||
|
||||
public UserGroupAuthorizationHandler(IHttpContextAccessor httpContextAcessor,
|
||||
public UserGroupHandler(IHttpContextAccessor httpContextAcessor,
|
||||
IUserService userService,
|
||||
IContentService contentService,
|
||||
IMediaService mediaService,
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor;
|
||||
}
|
||||
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserGroupAuthorizeRequirement requirement)
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserGroupRequirement requirement)
|
||||
{
|
||||
var isAuth = IsAuthorized(requirement);
|
||||
if (!isAuth.HasValue || isAuth.Value)
|
||||
@@ -51,7 +51,7 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private bool? IsAuthorized(UserGroupAuthorizeRequirement requirement)
|
||||
private bool? IsAuthorized(UserGroupRequirement requirement)
|
||||
{
|
||||
var currentUser = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser;
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
/// <summary>
|
||||
/// Authorization requirement for the <see cref="UserGroupAuthorizationHandler"/>
|
||||
/// Authorization requirement for the <see cref="UserGroupHandler"/>
|
||||
/// </summary>
|
||||
public class UserGroupAuthorizeRequirement : IAuthorizationRequirement
|
||||
public class UserGroupRequirement : IAuthorizationRequirement
|
||||
{
|
||||
public UserGroupAuthorizeRequirement(string queryStringName = "id")
|
||||
public UserGroupRequirement(string queryStringName = "id")
|
||||
{
|
||||
QueryStringName = queryStringName;
|
||||
}
|
||||
@@ -39,6 +39,8 @@ using Umbraco.Web.Common.Filters;
|
||||
using Umbraco.Web.Models.Mapping;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Umbraco.Web.Common.Authorization;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
@@ -68,6 +70,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
private readonly ActionCollection _actionCollection;
|
||||
private readonly IMemberGroupService _memberGroupService;
|
||||
private readonly ISqlContext _sqlContext;
|
||||
private readonly IAuthorizationService _authorizationService;
|
||||
private readonly Lazy<IDictionary<string, ILanguage>> _allLangs;
|
||||
private readonly ILogger<ContentController> _logger;
|
||||
|
||||
@@ -97,7 +100,8 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
ActionCollection actionCollection,
|
||||
IMemberGroupService memberGroupService,
|
||||
ISqlContext sqlContext,
|
||||
IJsonSerializer serializer)
|
||||
IJsonSerializer serializer,
|
||||
IAuthorizationService authorizationService)
|
||||
: base(cultureDictionary, loggerFactory, shortStringHelper, eventMessages, localizedTextService, serializer)
|
||||
{
|
||||
_propertyEditors = propertyEditors;
|
||||
@@ -119,6 +123,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
_actionCollection = actionCollection;
|
||||
_memberGroupService = memberGroupService;
|
||||
_sqlContext = sqlContext;
|
||||
_authorizationService = authorizationService;
|
||||
_logger = loggerFactory.CreateLogger<ContentController>();
|
||||
|
||||
_allLangs = new Lazy<IDictionary<string, ILanguage>>(() => _localizationService.GetAllLanguages().ToDictionary(x => x.IsoCode, x => x, StringComparer.InvariantCultureIgnoreCase));
|
||||
@@ -158,16 +163,22 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <remarks>
|
||||
/// Permission check is done for letter 'R' which is for <see cref="ActionRights"/> which the user must have access to update
|
||||
/// </remarks>
|
||||
[EnsureUserPermissionForContent("saveModel.ContentId", 'R')]
|
||||
public ActionResult<IEnumerable<AssignedUserGroupPermissions>> PostSaveUserGroupPermissions(UserGroupPermissionsSave saveModel)
|
||||
{
|
||||
if (saveModel.ContentId <= 0) return NotFound();
|
||||
public async Task<ActionResult<IEnumerable<AssignedUserGroupPermissions>>> PostSaveUserGroupPermissions(UserGroupPermissionsSave saveModel)
|
||||
{ if (saveModel.ContentId <= 0) return NotFound();
|
||||
|
||||
// TODO: Should non-admins be allowed to set granular permissions?
|
||||
|
||||
var content = _contentService.GetById(saveModel.ContentId);
|
||||
if (content == null) return NotFound();
|
||||
|
||||
// Authorize...
|
||||
var requirement = new ContentPermissionResourceRequirement(ActionRights.ActionLetter);
|
||||
var authorizationResult = await _authorizationService.AuthorizeAsync(User, content, requirement);
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
//current permissions explicitly assigned to this content item
|
||||
var contentPermissions = _contentService.GetPermissions(content)
|
||||
.ToDictionary(x => x.UserGroupId, x => x);
|
||||
@@ -220,7 +231,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <remarks>
|
||||
/// Permission check is done for letter 'R' which is for <see cref="ActionRights"/> which the user must have access to view
|
||||
/// </remarks>
|
||||
[EnsureUserPermissionForContent("contentId", 'R')]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionAdministrationById)]
|
||||
public ActionResult<IEnumerable<AssignedUserGroupPermissions>> GetDetailedPermissions(int contentId)
|
||||
{
|
||||
if (contentId <= 0) return NotFound();
|
||||
@@ -336,8 +347,8 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <param name="id"></param>
|
||||
/// <param name="culture"></param>
|
||||
/// <returns></returns>
|
||||
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
|
||||
[EnsureUserPermissionForContent("id")]
|
||||
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionBrowseById)]
|
||||
[DetermineAmbiguousActionByPassingParameters]
|
||||
public ContentItemDisplay GetById(int id)
|
||||
{
|
||||
@@ -357,7 +368,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
|
||||
[EnsureUserPermissionForContent("id")]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionBrowseById)]
|
||||
[DetermineAmbiguousActionByPassingParameters]
|
||||
public ContentItemDisplay GetById(Guid id)
|
||||
{
|
||||
@@ -378,7 +389,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
|
||||
[EnsureUserPermissionForContent("id")]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionBrowseById)]
|
||||
[DetermineAmbiguousActionByPassingParameters]
|
||||
public ContentItemDisplay GetById(Udi id)
|
||||
{
|
||||
@@ -1491,8 +1502,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// The EnsureUserPermissionForContent attribute will deny access to this method if the current user
|
||||
/// does not have Publish access to this node.
|
||||
/// </remarks>
|
||||
///
|
||||
[EnsureUserPermissionForContent("id", 'U')]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionPublishById)]
|
||||
public IActionResult PostPublishById(int id)
|
||||
{
|
||||
var foundContent = GetObjectFromRequest(() => _contentService.GetById(id));
|
||||
@@ -1539,7 +1549,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// The CanAccessContentAuthorize attribute will deny access to this method if the current user
|
||||
/// does not have Delete access to this node.
|
||||
/// </remarks>
|
||||
[EnsureUserPermissionForContent("id", ActionDelete.ActionLetter)]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionDeleteById)]
|
||||
[HttpDelete]
|
||||
[HttpPost]
|
||||
public IActionResult DeleteById(int id)
|
||||
@@ -1585,7 +1595,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// </remarks>
|
||||
[HttpDelete]
|
||||
[HttpPost]
|
||||
[EnsureUserPermissionForContent(Constants.System.RecycleBinContent, ActionDelete.ActionLetter)]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionEmptyRecycleBin)]
|
||||
public IActionResult EmptyRecycleBin()
|
||||
{
|
||||
_contentService.EmptyRecycleBin(_backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(Constants.Security.SuperUserId));
|
||||
@@ -1598,8 +1608,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// </summary>
|
||||
/// <param name="sorted"></param>
|
||||
/// <returns></returns>
|
||||
[EnsureUserPermissionForContent("sorted.ParentId", 'S')]
|
||||
public IActionResult PostSort(ContentSortOrder sorted)
|
||||
public async Task<IActionResult> PostSort(ContentSortOrder sorted)
|
||||
{
|
||||
if (sorted == null)
|
||||
{
|
||||
@@ -1612,12 +1621,18 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
return Ok();
|
||||
}
|
||||
|
||||
// Authorize...
|
||||
var requirement = new ContentPermissionResourceRequirement(ActionSort.ActionLetter);
|
||||
var authorizationResult = await _authorizationService.AuthorizeAsync(User, _contentService.GetById(sorted.ParentId), requirement);
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var contentService = _contentService;
|
||||
|
||||
// Save content with new sort order and update content xml in db accordingly
|
||||
var sortResult = contentService.Sort(sorted.IdSortOrder, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Id);
|
||||
var sortResult = _contentService.Sort(sorted.IdSortOrder, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.Id);
|
||||
if (!sortResult.Success)
|
||||
{
|
||||
_logger.LogWarning("Content sorting failed, this was probably caused by an event being cancelled");
|
||||
@@ -1639,9 +1654,16 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// </summary>
|
||||
/// <param name="move"></param>
|
||||
/// <returns></returns>
|
||||
[EnsureUserPermissionForContent("move.ParentId", 'M')]
|
||||
public IActionResult PostMove(MoveOrCopy move)
|
||||
public async Task<IActionResult> PostMove(MoveOrCopy move)
|
||||
{
|
||||
// Authorize...
|
||||
var requirement = new ContentPermissionResourceRequirement(ActionMove.ActionLetter);
|
||||
var authorizationResult = await _authorizationService.AuthorizeAsync(User, _contentService.GetById(move.ParentId), requirement);
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
var toMove = ValidateMoveOrCopy(move);
|
||||
|
||||
_contentService.Move(toMove, move.ParentId, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0));
|
||||
@@ -1654,9 +1676,16 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// </summary>
|
||||
/// <param name="copy"></param>
|
||||
/// <returns></returns>
|
||||
[EnsureUserPermissionForContent("copy.ParentId", 'C')]
|
||||
public IActionResult PostCopy(MoveOrCopy copy)
|
||||
public async Task<IActionResult> PostCopy(MoveOrCopy copy)
|
||||
{
|
||||
// Authorize...
|
||||
var requirement = new ContentPermissionResourceRequirement(ActionCopy.ActionLetter);
|
||||
var authorizationResult = await _authorizationService.AuthorizeAsync(User, _contentService.GetById(copy.ParentId), requirement);
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
var toCopy = ValidateMoveOrCopy(copy);
|
||||
|
||||
var c = _contentService.Copy(toCopy, copy.ParentId, copy.RelateToOriginal, copy.Recursive, _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId().ResultOr(0));
|
||||
@@ -1669,14 +1698,23 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// </summary>
|
||||
/// <param name="model">The content and variants to unpublish</param>
|
||||
/// <returns></returns>
|
||||
[EnsureUserPermissionForContent("model.Id", 'Z')]
|
||||
[TypeFilter(typeof(OutgoingEditorModelEventAttribute))]
|
||||
public ContentItemDisplay PostUnpublish(UnpublishContent model)
|
||||
public async Task<ActionResult<ContentItemDisplay>> PostUnpublish(UnpublishContent model)
|
||||
{
|
||||
var foundContent = GetObjectFromRequest(() => _contentService.GetById(model.Id));
|
||||
var foundContent = _contentService.GetById(model.Id);
|
||||
|
||||
if (foundContent == null)
|
||||
{
|
||||
HandleContentNotFound(model.Id);
|
||||
}
|
||||
|
||||
// Authorize...
|
||||
var requirement = new ContentPermissionResourceRequirement(ActionUnpublish.ActionLetter);
|
||||
var authorizationResult = await _authorizationService.AuthorizeAsync(User, foundContent, requirement);
|
||||
if (!authorizationResult.Succeeded)
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
|
||||
var languageCount = _allLangs.Value.Count();
|
||||
if (model.Cultures.Length == 0 || model.Cultures.Length == languageCount)
|
||||
@@ -2267,7 +2305,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
return display;
|
||||
}
|
||||
|
||||
[EnsureUserPermissionForContent("contentId", ActionBrowse.ActionLetter)]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionBrowseById)]
|
||||
public ActionResult<IEnumerable<NotifySetting>> GetNotificationOptions(int contentId)
|
||||
{
|
||||
var notifications = new List<NotifySetting>();
|
||||
@@ -2359,7 +2397,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
: content.Variants.FirstOrDefault(x => x.Language.IsoCode == culture);
|
||||
}
|
||||
|
||||
[EnsureUserPermissionForContent("contentId", ActionRollback.ActionLetter)]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionRollbackById)]
|
||||
[HttpPost]
|
||||
public IActionResult PostRollbackContent(int contentId, int versionId, string culture = "*")
|
||||
{
|
||||
@@ -2391,7 +2429,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
throw HttpResponseException.CreateValidationErrorResponse(notificationModel);
|
||||
}
|
||||
|
||||
[EnsureUserPermissionForContent("contentId", ActionProtect.ActionLetter)]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionProtectById)]
|
||||
[HttpGet]
|
||||
public IActionResult GetPublicAccess(int contentId)
|
||||
{
|
||||
@@ -2440,7 +2478,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
}
|
||||
|
||||
// set up public access using role based access
|
||||
[EnsureUserPermissionForContent("contentId", ActionProtect.ActionLetter)]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionProtectById)]
|
||||
[HttpPost]
|
||||
public IActionResult PostPublicAccess(int contentId, [FromQuery(Name = "groups[]")]string[] groups, [FromQuery(Name = "usernames[]")]string[] usernames, int loginPageId, int errorPageId)
|
||||
{
|
||||
@@ -2507,7 +2545,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
: Problem();
|
||||
}
|
||||
|
||||
[EnsureUserPermissionForContent("contentId", ActionProtect.ActionLetter)]
|
||||
[Authorize(Policy = AuthorizationPolicies.ContentPermissionProtectById)]
|
||||
[HttpPost]
|
||||
public IActionResult RemovePublicAccess(int contentId)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Serialization;
|
||||
using Umbraco.Infrastructure.BackOffice;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Web.Actions;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.BackOffice.Security;
|
||||
@@ -120,39 +121,86 @@ namespace Umbraco.Extensions
|
||||
// NOTE: Even though we are registering these handlers globally they will only actually execute their logic for
|
||||
// any auth defining a matching requirement and scheme.
|
||||
|
||||
services.AddSingleton<IAuthorizationHandler, BackOfficeAuthorizationHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, UmbracoTreeAuthorizeHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, UmbracoSectionAuthorizeHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, AdminUsersAuthorizeHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, UserGroupAuthorizationHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, DenyLocalLoginAuthorizeHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, BackOfficeHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, TreeHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, SectionHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, AdminUsersHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, UserGroupHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, ContentPermissionQueryStringHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, ContentPermissionResourceHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, DenyLocalLoginHandler>();
|
||||
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
// these are the query strings we will check for content ids when permission checking
|
||||
var contentPermissionQueryStrings = new[] { "id", "contentId" };
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.ContentPermissionEmptyRecycleBin, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new ContentPermissionsQueryStringRequirement(Constants.System.RecycleBinContent, ActionDelete.ActionLetter));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.ContentPermissionAdministrationById, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new ContentPermissionsQueryStringRequirement(ActionRights.ActionLetter, contentPermissionQueryStrings));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.ContentPermissionProtectById, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new ContentPermissionsQueryStringRequirement(ActionProtect.ActionLetter, contentPermissionQueryStrings));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.ContentPermissionRollbackById, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new ContentPermissionsQueryStringRequirement(ActionRollback.ActionLetter, contentPermissionQueryStrings));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.ContentPermissionBrowseById, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new ContentPermissionsQueryStringRequirement(ActionPublish.ActionLetter, contentPermissionQueryStrings));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.ContentPermissionBrowseById, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new ContentPermissionsQueryStringRequirement(ActionBrowse.ActionLetter, contentPermissionQueryStrings));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.ContentPermissionDeleteById, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new ContentPermissionsQueryStringRequirement(ActionDelete.ActionLetter, contentPermissionQueryStrings));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.BackOfficeAccess, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new BackOfficeAuthorizeRequirement());
|
||||
policy.Requirements.Add(new BackOfficeRequirement());
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.BackOfficeAccessWithoutApproval, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new BackOfficeAuthorizeRequirement(false));
|
||||
policy.Requirements.Add(new BackOfficeRequirement(false));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.AdminUserEditsRequireAdmin, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new AdminUsersAuthorizeRequirement());
|
||||
policy.Requirements.Add(new AdminUsersAuthorizeRequirement("userIds"));
|
||||
policy.Requirements.Add(new AdminUsersRequirement());
|
||||
policy.Requirements.Add(new AdminUsersRequirement("userIds"));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.UserBelongsToUserGroupInRequest, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new UserGroupAuthorizeRequirement());
|
||||
policy.Requirements.Add(new UserGroupAuthorizeRequirement("userGroupIds"));
|
||||
policy.Requirements.Add(new UserGroupRequirement());
|
||||
policy.Requirements.Add(new UserGroupRequirement("userGroupIds"));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.DenyLocalLoginIfConfigured, policy =>
|
||||
@@ -164,50 +212,50 @@ namespace Umbraco.Extensions
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessContent, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Content));
|
||||
policy.Requirements.Add(new SectionRequirement(Constants.Applications.Content));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessContentOrMedia, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Content, Constants.Applications.Media));
|
||||
policy.Requirements.Add(new SectionRequirement(Constants.Applications.Content, Constants.Applications.Media));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessUsers, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Users));
|
||||
policy.Requirements.Add(new SectionRequirement(Constants.Applications.Users));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessForTinyMce, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(
|
||||
policy.Requirements.Add(new SectionRequirement(
|
||||
Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessMedia, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Media));
|
||||
policy.Requirements.Add(new SectionRequirement(Constants.Applications.Media));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessMembers, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Members));
|
||||
policy.Requirements.Add(new SectionRequirement(Constants.Applications.Members));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessPackages, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Packages));
|
||||
policy.Requirements.Add(new SectionRequirement(Constants.Applications.Packages));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessSettings, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Settings));
|
||||
policy.Requirements.Add(new SectionRequirement(Constants.Applications.Settings));
|
||||
});
|
||||
|
||||
//We will not allow the tree to render unless the user has access to any of the sections that the tree gets rendered
|
||||
@@ -215,21 +263,21 @@ namespace Umbraco.Extensions
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessForContentTree, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(
|
||||
policy.Requirements.Add(new SectionRequirement(
|
||||
Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Users,
|
||||
Constants.Applications.Settings, Constants.Applications.Packages, Constants.Applications.Members));
|
||||
});
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessForMediaTree, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(
|
||||
policy.Requirements.Add(new SectionRequirement(
|
||||
Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Users,
|
||||
Constants.Applications.Settings, Constants.Applications.Packages, Constants.Applications.Members));
|
||||
});
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessForMemberTree, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(
|
||||
policy.Requirements.Add(new SectionRequirement(
|
||||
Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members));
|
||||
});
|
||||
|
||||
@@ -237,7 +285,7 @@ namespace Umbraco.Extensions
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessForDataTypeReading, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(
|
||||
policy.Requirements.Add(new SectionRequirement(
|
||||
Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members,
|
||||
Constants.Applications.Settings, Constants.Applications.Packages));
|
||||
});
|
||||
@@ -245,139 +293,139 @@ namespace Umbraco.Extensions
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessDocuments, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Content));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.Content));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessUsers, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Users));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.Users));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessPartialViews, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.PartialViews));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.PartialViews));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessPartialViewMacros, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.PartialViewMacros));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.PartialViewMacros));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessPackages, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Packages));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.Packages));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessLogs, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.LogViewer));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.LogViewer));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessDataTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.DataTypes));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.DataTypes));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessTemplates, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Templates));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.Templates));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessMemberTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.MemberTypes));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.MemberTypes));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessRelationTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.RelationTypes));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.RelationTypes));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessDocumentTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.DocumentTypes));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.DocumentTypes));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessMemberGroups, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.MemberGroups));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.MemberGroups));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessMediaTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.MediaTypes));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.MediaTypes));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessMacros, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Macros));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.Macros));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessLanguages, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Languages));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.Languages));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessDocumentTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Dictionary));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.Dictionary));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessDictionary, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Dictionary, Constants.Trees.Dictionary));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.Dictionary, Constants.Trees.Dictionary));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessDictionaryOrTemplates, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Dictionary, Constants.Trees.Templates));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.Dictionary, Constants.Trees.Templates));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessDocumentsOrDocumentTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.DocumentTypes, Constants.Trees.Content));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.DocumentTypes, Constants.Trees.Content));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessMediaOrMediaTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.MediaTypes, Constants.Trees.Media));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.MediaTypes, Constants.Trees.Media));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessMembersOrMemberTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.MemberTypes, Constants.Trees.Members));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.MemberTypes, Constants.Trees.Members));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessAnySchemaTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.DataTypes, Constants.Trees.DocumentTypes, Constants.Trees.MediaTypes, Constants.Trees.MemberTypes));
|
||||
policy.Requirements.Add(new TreeRequirement(Constants.Trees.DataTypes, Constants.Trees.DocumentTypes, Constants.Trees.MediaTypes, Constants.Trees.MemberTypes));
|
||||
});
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessAnyContentOrTypes, policy =>
|
||||
{
|
||||
policy.AuthenticationSchemes.Add(Constants.Security.BackOfficeAuthenticationType);
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(
|
||||
policy.Requirements.Add(new TreeRequirement(
|
||||
Constants.Trees.DocumentTypes, Constants.Trees.Content,
|
||||
Constants.Trees.MediaTypes, Constants.Trees.Media,
|
||||
Constants.Trees.MemberTypes, Constants.Trees.Members));
|
||||
|
||||
@@ -1,252 +0,0 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Actions;
|
||||
using Umbraco.Web.Common.Exceptions;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Filters
|
||||
{
|
||||
/// <summary>
|
||||
/// Auth filter to check if the current user has access to the content item (by id).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This first checks if the user can access this based on their start node, and then checks node permissions
|
||||
/// By default the permission that is checked is browse but this can be specified in the ctor.
|
||||
/// NOTE: This cannot be an auth filter because that happens too soon and we don't have access to the action params.
|
||||
/// </remarks>
|
||||
public sealed class EnsureUserPermissionForContentAttribute : TypeFilterAttribute
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This constructor will only be able to test the start node access
|
||||
/// </summary>
|
||||
public EnsureUserPermissionForContentAttribute(int nodeId)
|
||||
: base(typeof(EnsureUserPermissionForContentFilter))
|
||||
{
|
||||
Arguments = new object[]
|
||||
{
|
||||
nodeId
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public EnsureUserPermissionForContentAttribute(int nodeId, char permissionToCheck)
|
||||
: base(typeof(EnsureUserPermissionForContentFilter))
|
||||
{
|
||||
Arguments = new object[]
|
||||
{
|
||||
nodeId, permissionToCheck
|
||||
};
|
||||
}
|
||||
|
||||
public EnsureUserPermissionForContentAttribute(string paramName)
|
||||
: base(typeof(EnsureUserPermissionForContentFilter))
|
||||
{
|
||||
if (paramName == null) throw new ArgumentNullException(nameof(paramName));
|
||||
if (string.IsNullOrEmpty(paramName))
|
||||
throw new ArgumentException("Value can't be empty.", nameof(paramName));
|
||||
|
||||
Arguments = new object[]
|
||||
{
|
||||
paramName, ActionBrowse.ActionLetter
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public EnsureUserPermissionForContentAttribute(string paramName, char permissionToCheck)
|
||||
: base(typeof(EnsureUserPermissionForContentFilter))
|
||||
{
|
||||
if (paramName == null) throw new ArgumentNullException(nameof(paramName));
|
||||
if (string.IsNullOrEmpty(paramName))
|
||||
throw new ArgumentException("Value can't be empty.", nameof(paramName));
|
||||
|
||||
Arguments = new object[]
|
||||
{
|
||||
paramName, permissionToCheck
|
||||
};
|
||||
}
|
||||
|
||||
private sealed class EnsureUserPermissionForContentFilter : IActionFilter
|
||||
{
|
||||
private readonly int? _nodeId;
|
||||
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
|
||||
private readonly IEntityService _entityService;
|
||||
private readonly IUserService _userService;
|
||||
private readonly IContentService _contentService;
|
||||
private readonly string _paramName;
|
||||
private readonly char? _permissionToCheck;
|
||||
|
||||
public EnsureUserPermissionForContentFilter(
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
IEntityService entityService,
|
||||
IUserService userService,
|
||||
IContentService contentService,
|
||||
string paramName)
|
||||
:this(backofficeSecurityAccessor, entityService, userService, contentService, null, paramName, ActionBrowse.ActionLetter)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EnsureUserPermissionForContentFilter(
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
IEntityService entityService,
|
||||
IUserService userService,
|
||||
IContentService contentService,
|
||||
int nodeId,
|
||||
char permissionToCheck)
|
||||
:this(backofficeSecurityAccessor, entityService, userService, contentService, nodeId, null, permissionToCheck)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public EnsureUserPermissionForContentFilter(
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
IEntityService entityService,
|
||||
IUserService userService,
|
||||
IContentService contentService,
|
||||
int nodeId)
|
||||
:this(backofficeSecurityAccessor, entityService, userService, contentService, nodeId, null, null)
|
||||
{
|
||||
|
||||
}
|
||||
public EnsureUserPermissionForContentFilter(
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
IEntityService entityService,
|
||||
IUserService userService,
|
||||
IContentService contentService,
|
||||
string paramName, char permissionToCheck)
|
||||
:this(backofficeSecurityAccessor, entityService, userService, contentService, null, paramName, permissionToCheck)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
private EnsureUserPermissionForContentFilter(
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
IEntityService entityService,
|
||||
IUserService userService,
|
||||
IContentService contentService,
|
||||
int? nodeId, string paramName, char? permissionToCheck)
|
||||
{
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor));
|
||||
_entityService = entityService ?? throw new ArgumentNullException(nameof(entityService));
|
||||
_userService = userService ?? throw new ArgumentNullException(nameof(userService));
|
||||
_contentService = contentService ?? throw new ArgumentNullException(nameof(contentService));
|
||||
|
||||
_paramName = paramName;
|
||||
if (permissionToCheck.HasValue)
|
||||
{
|
||||
_permissionToCheck = permissionToCheck.Value;
|
||||
}
|
||||
|
||||
|
||||
if (nodeId.HasValue)
|
||||
{
|
||||
_nodeId = nodeId.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void OnActionExecuting(ActionExecutingContext context)
|
||||
{
|
||||
if (_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser == null)
|
||||
{
|
||||
//not logged in
|
||||
throw new HttpResponseException(HttpStatusCode.Unauthorized);
|
||||
}
|
||||
|
||||
int nodeId;
|
||||
if (_nodeId.HasValue == false)
|
||||
{
|
||||
var parts = _paramName.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
if (context.ActionArguments[parts[0]] == null)
|
||||
{
|
||||
throw new InvalidOperationException("No argument found for the current action with the name: " +
|
||||
_paramName);
|
||||
}
|
||||
|
||||
if (parts.Length == 1)
|
||||
{
|
||||
var argument = context.ActionArguments[parts[0]].ToString();
|
||||
// if the argument is an int, it will parse and can be assigned to nodeId
|
||||
// if might be a udi, so check that next
|
||||
// otherwise treat it as a guid - unlikely we ever get here
|
||||
if (int.TryParse(argument, out int parsedId))
|
||||
{
|
||||
nodeId = parsedId;
|
||||
}
|
||||
else if (UdiParser.TryParse(argument, true, out var udi))
|
||||
{
|
||||
nodeId = _entityService.GetId(udi).Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
Guid.TryParse(argument, out Guid key);
|
||||
nodeId = _entityService.GetId(key, UmbracoObjectTypes.Document).Result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//now we need to see if we can get the property of whatever object it is
|
||||
var pType = context.ActionArguments[parts[0]].GetType();
|
||||
var prop = pType.GetProperty(parts[1]);
|
||||
if (prop == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"No argument found for the current action with the name: " + _paramName);
|
||||
}
|
||||
|
||||
nodeId = (int) prop.GetValue(context.ActionArguments[parts[0]]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nodeId = _nodeId.Value;
|
||||
}
|
||||
|
||||
var permissionResult = ContentPermissionsHelper.CheckPermissions(nodeId,
|
||||
_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser,
|
||||
_userService,
|
||||
_contentService,
|
||||
_entityService,
|
||||
out var contentItem,
|
||||
_permissionToCheck.HasValue ? new[] { _permissionToCheck.Value } : null);
|
||||
|
||||
if (permissionResult == ContentPermissionsHelper.ContentAccess.NotFound)
|
||||
{
|
||||
context.Result = new NotFoundResult();
|
||||
return;
|
||||
}
|
||||
|
||||
if (permissionResult == ContentPermissionsHelper.ContentAccess.Denied)
|
||||
{
|
||||
context.Result = new ForbidResult();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (contentItem != null)
|
||||
{
|
||||
//store the content item in request cache so it can be resolved in the controller without re-looking it up
|
||||
context.HttpContext.Items[typeof(IContent).ToString()] = contentItem;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,16 @@
|
||||
public const string AdminUserEditsRequireAdmin = nameof(AdminUserEditsRequireAdmin);
|
||||
public const string DenyLocalLoginIfConfigured = nameof(DenyLocalLoginIfConfigured);
|
||||
|
||||
// Content permission access
|
||||
|
||||
public const string ContentPermissionEmptyRecycleBin = nameof(ContentPermissionEmptyRecycleBin);
|
||||
public const string ContentPermissionAdministrationById = nameof(ContentPermissionAdministrationById);
|
||||
public const string ContentPermissionPublishById = nameof(ContentPermissionPublishById);
|
||||
public const string ContentPermissionRollbackById = nameof(ContentPermissionRollbackById);
|
||||
public const string ContentPermissionProtectById = nameof(ContentPermissionProtectById);
|
||||
public const string ContentPermissionBrowseById = nameof(ContentPermissionBrowseById);
|
||||
public const string ContentPermissionDeleteById = nameof(ContentPermissionDeleteById);
|
||||
|
||||
// Single section access
|
||||
|
||||
public const string SectionAccessContent = nameof(SectionAccessContent);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Web.Features;
|
||||
|
||||
@@ -34,14 +35,14 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
|
||||
private bool? IsAllowed(AuthorizationHandlerContext context)
|
||||
{
|
||||
if (context.Resource is Endpoint endpoint)
|
||||
if (!(context.Resource is Endpoint endpoint))
|
||||
{
|
||||
var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
|
||||
var controllerType = actionDescriptor.ControllerTypeInfo.AsType();
|
||||
return _umbracoFeatures.IsControllerEnabled(controllerType);
|
||||
throw new InvalidOperationException("This authorization handler can only be applied to controllers routed with endpoint routing");
|
||||
}
|
||||
|
||||
return null;
|
||||
var actionDescriptor = endpoint.Metadata.GetMetadata<ControllerActionDescriptor>();
|
||||
var controllerType = actionDescriptor.ControllerTypeInfo.AsType();
|
||||
return _umbracoFeatures.IsControllerEnabled(controllerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user