Removes UmbracoApplicationAuthorizeAttribute and migrates usages to authz policies
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Configuration;
|
||||
@@ -7,6 +8,7 @@ using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.ModelsBuilder.Embedded.Building;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Umbraco.Web.BackOffice.Controllers;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
|
||||
@@ -20,7 +22,7 @@ namespace Umbraco.ModelsBuilder.Embedded.BackOffice
|
||||
/// correct CSRF security is adhered to for angular and it also ensures that this controller is not subseptipal to
|
||||
/// global WebApi formatters being changed since this is always forced to only return Angular JSON Specific formats.
|
||||
/// </remarks>
|
||||
[UmbracoApplicationAuthorize(Core.Constants.Applications.Settings)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)]
|
||||
public class ModelsBuilderDashboardController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly ModelsBuilderSettings _config;
|
||||
|
||||
@@ -2,31 +2,47 @@
|
||||
{
|
||||
public static class AuthorizationPolicies
|
||||
{
|
||||
public const string TreeAccessUsers = "TreeAccessUsers";
|
||||
public const string TreeAccessPartialViews = "TreeAccessPartialViews";
|
||||
public const string TreeAccessPartialViewMacros = "TreeAccessPartialViewMacros";
|
||||
public const string TreeAccessDataTypes = "TreeAccessDataTypes";
|
||||
public const string TreeAccessPackages = "TreeAccessPackages";
|
||||
public const string TreeAccessLogs = "TreeAccessLogs";
|
||||
public const string TreeAccessTemplates = "TreeAccessTemplates";
|
||||
public const string TreeAccessDictionary = "TreeAccessDictionary";
|
||||
public const string TreeAccessRelationTypes = "TreeAccessRelationTypes";
|
||||
public const string TreeAccessMediaTypes = "TreeAccessMediaTypes";
|
||||
public const string TreeAccessMacros = "TreeAccessMacros";
|
||||
public const string TreeAccessLanguages = "TreeAccessLanguages";
|
||||
public const string TreeAccessMemberGroups = "TreeAccessMemberGroups";
|
||||
public const string TreeAccessDocumentTypes = "TreeAccessDocumentTypes";
|
||||
public const string TreeAccessMemberTypes = "TreeAccessMemberTypes";
|
||||
public const string TreeAccessDocumentsOrDocumentTypes = "TreeAccessDocumentsAndDocumentTypes";
|
||||
public const string TreeAccessMediaOrMediaTypes = "TreeAccessMediaAndMediaTypes";
|
||||
public const string TreeAccessMembersOrMemberTypes = "TreeAccessMembersAndMemberTypes";
|
||||
public const string TreeAccessAnySchemaTypes = "TreeAccessSchemaTypes";
|
||||
public const string TreeAccessDictionaryOrTemplates = "TreeAccessDictionaryOrTemplates";
|
||||
// TODO: Rethink these names! Describe what they are doing probably
|
||||
|
||||
public const string SectionAccessContentOrMedia = nameof(SectionAccessContentOrMedia);
|
||||
public const string SectionAccessContent = nameof(SectionAccessContent);
|
||||
public const string SectionAccessPackages = nameof(SectionAccessPackages);
|
||||
public const string SectionAccessUsers = nameof(SectionAccessUsers);
|
||||
public const string SectionAccessMedia = nameof(SectionAccessMedia);
|
||||
public const string SectionAccessSettings = nameof(SectionAccessSettings);
|
||||
public const string SectionAccessForTinyMce = nameof(SectionAccessForTinyMce);
|
||||
public const string SectionAccessForMemberTree = nameof(SectionAccessForMemberTree);
|
||||
public const string SectionAccessForMediaTree = nameof(SectionAccessForMediaTree);
|
||||
public const string SectionAccessForContentTree = nameof(SectionAccessForContentTree);
|
||||
public const string SectionAccessForDataTypeReading = nameof(SectionAccessForDataTypeReading);
|
||||
public const string SectionAccessMembers = nameof(SectionAccessMembers);
|
||||
|
||||
public const string TreeAccessDocuments = nameof(TreeAccessDocuments);
|
||||
public const string TreeAccessUsers = nameof(TreeAccessUsers);
|
||||
public const string TreeAccessPartialViews = nameof(TreeAccessPartialViews);
|
||||
public const string TreeAccessPartialViewMacros = nameof(TreeAccessPartialViewMacros);
|
||||
public const string TreeAccessDataTypes = nameof(TreeAccessDataTypes);
|
||||
public const string TreeAccessPackages = nameof(TreeAccessPackages);
|
||||
public const string TreeAccessLogs = nameof(TreeAccessLogs);
|
||||
public const string TreeAccessTemplates = nameof(TreeAccessTemplates);
|
||||
public const string TreeAccessDictionary = nameof(TreeAccessDictionary);
|
||||
public const string TreeAccessRelationTypes = nameof(TreeAccessRelationTypes);
|
||||
public const string TreeAccessMediaTypes = nameof(TreeAccessMediaTypes);
|
||||
public const string TreeAccessMacros = nameof(TreeAccessMacros);
|
||||
public const string TreeAccessLanguages = nameof(TreeAccessLanguages);
|
||||
public const string TreeAccessMemberGroups = nameof(TreeAccessMemberGroups);
|
||||
public const string TreeAccessDocumentTypes = nameof(TreeAccessDocumentTypes);
|
||||
public const string TreeAccessMemberTypes = nameof(TreeAccessMemberTypes);
|
||||
public const string TreeAccessDocumentsOrDocumentTypes = nameof(TreeAccessDocumentsOrDocumentTypes);
|
||||
public const string TreeAccessMediaOrMediaTypes = nameof(TreeAccessMediaOrMediaTypes);
|
||||
public const string TreeAccessMembersOrMemberTypes = nameof(TreeAccessMembersOrMemberTypes);
|
||||
public const string TreeAccessAnySchemaTypes = nameof(TreeAccessAnySchemaTypes);
|
||||
public const string TreeAccessDictionaryOrTemplates = nameof(TreeAccessDictionaryOrTemplates);
|
||||
|
||||
/// <summary>
|
||||
/// Defines access based on if the user has access to any tree's exposing any types of content (documents, media, members)
|
||||
/// or any content types (document types, media types, member types)
|
||||
/// </summary>
|
||||
public const string TreeAccessAnyContentOrTypes = "TreeAccessAnyContentOrTypes";
|
||||
public const string TreeAccessAnyContentOrTypes = nameof(TreeAccessAnyContentOrTypes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
/// <summary>
|
||||
/// Authorization requirements for <see cref="UmbracoSectionAuthorizeHandler"/>
|
||||
/// </summary>
|
||||
public class SectionAliasesRequirement : 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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the current user has access to the section
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The user only needs access to one of the sections specified, not all of the sections.
|
||||
/// </remarks>
|
||||
public class UmbracoSectionAuthorizeHandler : AuthorizationHandler<SectionAliasesRequirement>
|
||||
{
|
||||
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
|
||||
|
||||
public UmbracoSectionAuthorizeHandler(IBackOfficeSecurityAccessor backofficeSecurityAccessor)
|
||||
{
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor;
|
||||
}
|
||||
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SectionAliasesRequirement requirement)
|
||||
{
|
||||
if (IsAuthorized(requirement))
|
||||
{
|
||||
context.Succeed(requirement);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Fail();
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private bool IsAuthorized(SectionAliasesRequirement requirement)
|
||||
{
|
||||
var authorized = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null
|
||||
&& requirement.SectionAliases.Any(app => _backofficeSecurityAccessor.BackOfficeSecurity.UserHasSectionAccess(
|
||||
app, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser));
|
||||
|
||||
return authorized;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,9 @@ using Umbraco.Web.Services;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Authorization
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the current user has access to the application for which the specified tree(s) belongs
|
||||
/// Ensures that the current user has access to the section for which the specified tree(s) belongs
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This would allow a tree to be moved between sections.
|
||||
@@ -17,10 +18,6 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
/// </remarks>
|
||||
public class UmbracoTreeAuthorizeHandler : AuthorizationHandler<TreeAliasesRequirement>
|
||||
{
|
||||
/// <summary>
|
||||
/// Can be used by unit tests to enable/disable this filter
|
||||
/// </summary>
|
||||
internal static readonly bool Enable = true;
|
||||
|
||||
private readonly ITreeService _treeService;
|
||||
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
|
||||
@@ -40,25 +37,6 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor));
|
||||
}
|
||||
|
||||
private bool IsAuthorized(TreeAliasesRequirement requirement)
|
||||
{
|
||||
if (Enable == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var apps = requirement.TreeAliases.Select(x => _treeService
|
||||
.GetByAlias(x))
|
||||
.WhereNotNull()
|
||||
.Select(x => x.SectionAlias)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
return _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null
|
||||
&& apps.Any(app => _backofficeSecurityAccessor.BackOfficeSecurity.UserHasSectionAccess(
|
||||
app, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser));
|
||||
}
|
||||
|
||||
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TreeAliasesRequirement requirement)
|
||||
{
|
||||
if (IsAuthorized(requirement))
|
||||
@@ -72,5 +50,19 @@ namespace Umbraco.Web.BackOffice.Authorization
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private bool IsAuthorized(TreeAliasesRequirement requirement)
|
||||
{
|
||||
var apps = requirement.TreeAliases.Select(x => _treeService
|
||||
.GetByAlias(x))
|
||||
.WhereNotNull()
|
||||
.Select(x => x.SectionAlias)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
return _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null
|
||||
&& apps.Any(app => _backofficeSecurityAccessor.BackOfficeSecurity.UserHasSectionAccess(
|
||||
app, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core;
|
||||
@@ -14,6 +15,7 @@ using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Core.Strings.Css;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.Common.ActionsResults;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
@@ -28,7 +30,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
// ref: https://www.exceptionnotfound.net/the-asp-net-web-api-exception-handling-pipeline-a-guided-tour/
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
//[PrefixlessBodyModelValidator]
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Settings)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)]
|
||||
public class CodeFileController : BackOfficeNotificationsController
|
||||
{
|
||||
private readonly IIOHelper _ioHelper;
|
||||
|
||||
@@ -37,19 +37,16 @@ using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Common.Exceptions;
|
||||
using Umbraco.Web.Common.Filters;
|
||||
using Umbraco.Web.Models.Mapping;
|
||||
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// The API controller used for editing content
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This controller is decorated with the UmbracoApplicationAuthorizeAttribute which means that any user requesting
|
||||
/// access to ALL of the methods on this controller will need access to the content application.
|
||||
/// </remarks>
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Content)]
|
||||
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocuments)]
|
||||
public class ContentController : ContentControllerBase
|
||||
{
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
|
||||
@@ -416,8 +416,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <remarks>
|
||||
/// Permission is granted to this method if the user has access to any of these sections: Content, media, settings, developer, members
|
||||
/// </remarks>
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members,
|
||||
Constants.Applications.Settings, Constants.Applications.Packages)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessForDataTypeReading)]
|
||||
public IEnumerable<DataTypeBasic> GetAll()
|
||||
{
|
||||
return _dataTypeService
|
||||
@@ -432,8 +431,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <remarks>
|
||||
/// Permission is granted to this method if the user has access to any of these sections: Content, media, settings, developer, members
|
||||
/// </remarks>
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members,
|
||||
Constants.Applications.Settings, Constants.Applications.Packages)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessForDataTypeReading)]
|
||||
public IDictionary<string, IEnumerable<DataTypeBasic>> GetGroupedDataTypes()
|
||||
{
|
||||
var dataTypes = _dataTypeService
|
||||
@@ -464,8 +462,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <remarks>
|
||||
/// Permission is granted to this method if the user has access to any of these sections: Content, media, settings, developer, members
|
||||
/// </remarks>
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members,
|
||||
Constants.Applications.Settings, Constants.Applications.Packages)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessForDataTypeReading)]
|
||||
public IDictionary<string, IEnumerable<DataTypeBasic>> GetGroupedPropertyEditors()
|
||||
{
|
||||
var datatypes = new List<DataTypeBasic>();
|
||||
@@ -496,8 +493,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <remarks>
|
||||
/// Permission is granted to this method if the user has access to any of these sections: Content, media, settings, developer, members
|
||||
/// </remarks>
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members,
|
||||
Constants.Applications.Settings, Constants.Applications.Packages)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessForDataTypeReading)]
|
||||
public IEnumerable<PropertyEditorBasic> GetAllPropertyEditors()
|
||||
{
|
||||
return _propertyEditorCollection
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
@@ -10,6 +11,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
@@ -52,7 +54,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
_sqlContext = sqlContext ?? throw new ArgumentNullException(nameof(sqlContext));
|
||||
}
|
||||
|
||||
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Content, Constants.Applications.Media)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessContentOrMedia)]
|
||||
public PagedResult<AuditLog> GetPagedEntityLog(int id,
|
||||
int pageNumber = 1,
|
||||
int pageSize = 10,
|
||||
|
||||
@@ -40,6 +40,8 @@ using Umbraco.Web.Common.Exceptions;
|
||||
using Umbraco.Web.ContentApps;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
@@ -48,7 +50,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// access to ALL of the methods on this controller will need access to the media application.
|
||||
/// </remarks>
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Media)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessMedia)]
|
||||
public class MediaController : ContentControllerBase
|
||||
{
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Net.Http;
|
||||
using System.Net.Mime;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -24,6 +25,7 @@ using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Extensions;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.BackOffice.ModelBinders;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
@@ -41,7 +43,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// access to ALL of the methods on this controller will need access to the member application.
|
||||
/// </remarks>
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Members)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessMembers)]
|
||||
[OutgoingNoHyphenGuidFormat]
|
||||
public class MemberController : ContentControllerBase
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Semver;
|
||||
@@ -12,6 +13,7 @@ using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.Models.Packaging;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Common.Exceptions;
|
||||
@@ -23,7 +25,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// A controller used for managing packages in the back office
|
||||
/// </summary>
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Packages)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessPackages)]
|
||||
public class PackageController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
|
||||
@@ -22,6 +22,8 @@ using Umbraco.Web.Common.Exceptions;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Security;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
@@ -29,7 +31,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// A controller used for installing packages and managing all of the data in the packages section in the back office
|
||||
/// </summary>
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Packages)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessPackages)]
|
||||
public class PackageInstallController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
|
||||
|
||||
@@ -3,11 +3,13 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.Common.ActionsResults;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
@@ -18,7 +20,7 @@ using Constants = Umbraco.Core.Constants;
|
||||
namespace Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Content)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessContent)]
|
||||
public class RelationController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly UmbracoMapper _umbracoMapper;
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
@@ -14,6 +15,7 @@ using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Media;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.Common.ActionsResults;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
@@ -23,10 +25,7 @@ using Constants = Umbraco.Core.Constants;
|
||||
namespace Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorize(
|
||||
Constants.Applications.Content,
|
||||
Constants.Applications.Media,
|
||||
Constants.Applications.Members)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessForTinyMce)]
|
||||
public class TinyMceController : UmbracoAuthorizedApiController
|
||||
{
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
|
||||
@@ -16,11 +16,13 @@ using Umbraco.Web.Common.Exceptions;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Security;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Users)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessUsers)]
|
||||
[PrefixlessBodyModelValidator]
|
||||
public class UserGroupsController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
|
||||
@@ -42,11 +42,13 @@ using Task = System.Threading.Tasks.Task;
|
||||
using Umbraco.Net;
|
||||
using Umbraco.Web.Common.ActionsResults;
|
||||
using Umbraco.Web.Common.Security;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Users)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessUsers)]
|
||||
[PrefixlessBodyModelValidator]
|
||||
[IsCurrentUserModelFilter]
|
||||
public class UsersController : UmbracoAuthorizedJsonController
|
||||
|
||||
@@ -109,10 +109,66 @@ namespace Umbraco.Extensions
|
||||
return new BackOfficeIdentityBuilder(services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add authorization handlers and policies
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
private static void AddBackOfficeAuthorizationPolicies(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<IAuthorizationHandler, UmbracoTreeAuthorizeHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, UmbracoSectionAuthorizeHandler>();
|
||||
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessContent, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Content)));
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessContentOrMedia, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Content, Constants.Applications.Media)));
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessUsers, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Users)));
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessForTinyMce, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(
|
||||
Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members)));
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessMedia, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Media)));
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessMembers, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Members)));
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessPackages, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(Constants.Applications.Packages)));
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessSettings, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(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
|
||||
// this is not ideal but until we change permissions to be tree based (not section) there's not much else we can do here.
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessForContentTree, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(
|
||||
Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Users,
|
||||
Constants.Applications.Settings, Constants.Applications.Packages, Constants.Applications.Members)));
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessForMediaTree, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(
|
||||
Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Users,
|
||||
Constants.Applications.Settings, Constants.Applications.Packages, Constants.Applications.Members)));
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessForMemberTree, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(
|
||||
Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members)));
|
||||
|
||||
// Permission is granted to this policy if the user has access to any of these sections: Content, media, settings, developer, members
|
||||
options.AddPolicy(AuthorizationPolicies.SectionAccessForDataTypeReading, policy =>
|
||||
policy.Requirements.Add(new SectionAliasesRequirement(
|
||||
Constants.Applications.Content, Constants.Applications.Media, Constants.Applications.Members,
|
||||
Constants.Applications.Settings, Constants.Applications.Packages)));
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessDocuments, policy =>
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Content)));
|
||||
|
||||
options.AddPolicy(AuthorizationPolicies.TreeAccessUsers, policy =>
|
||||
policy.Requirements.Add(new TreeAliasesRequirement(Constants.Trees.Users)));
|
||||
|
||||
@@ -182,8 +238,6 @@ namespace Umbraco.Extensions
|
||||
Constants.Trees.MediaTypes, Constants.Trees.Media,
|
||||
Constants.Trees.MemberTypes, Constants.Trees.Members)));
|
||||
});
|
||||
|
||||
services.AddSingleton<IAuthorizationHandler, UmbracoTreeAuthorizeHandler>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Umbraco.Core.Security;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Filters
|
||||
{
|
||||
public class UmbracoApplicationAuthorizeAttribute : TypeFilterAttribute
|
||||
{
|
||||
public UmbracoApplicationAuthorizeAttribute(params string[] appName) : base(typeof(UmbracoApplicationAuthorizeFilter))
|
||||
{
|
||||
base.Arguments = new object[]
|
||||
{
|
||||
appName
|
||||
};
|
||||
}
|
||||
|
||||
private class UmbracoApplicationAuthorizeFilter : IAuthorizationFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Can be used by unit tests to enable/disable this filter
|
||||
/// </summary>
|
||||
internal static bool Enable = true;
|
||||
|
||||
private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor;
|
||||
private readonly string[] _appNames;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to set any number of applications that the user needs access to be authorized
|
||||
/// </summary>
|
||||
/// <param name="backofficeSecurityAccessor"></param>
|
||||
/// <param name="appName">
|
||||
/// If the user has access to any of the specified apps, they will be authorized.
|
||||
/// </param>
|
||||
public UmbracoApplicationAuthorizeFilter(IBackOfficeSecurityAccessor backofficeSecurityAccessor, params string[] appName)
|
||||
{
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor;
|
||||
_appNames = appName;
|
||||
}
|
||||
|
||||
|
||||
public void OnAuthorization(AuthorizationFilterContext context)
|
||||
{
|
||||
if (!IsAuthorized())
|
||||
{
|
||||
context.Result = new ForbidResult();
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsAuthorized()
|
||||
{
|
||||
if (Enable == false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var authorized = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser != null
|
||||
&& _appNames.Any(app => _backofficeSecurityAccessor.BackOfficeSecurity.UserHasSectionAccess(
|
||||
app, _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser));
|
||||
|
||||
return authorized;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,8 @@ using Umbraco.Web.BackOffice.Controllers;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.HealthCheck
|
||||
{
|
||||
@@ -17,7 +19,7 @@ namespace Umbraco.Web.BackOffice.HealthCheck
|
||||
/// The API controller used to display the health check info and execute any actions
|
||||
/// </summary>
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Settings)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)]
|
||||
public class HealthCheckController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly HealthCheckCollection _checks;
|
||||
|
||||
@@ -4,6 +4,8 @@ using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.BackOffice.Controllers;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Common.Controllers;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Profiling
|
||||
{
|
||||
@@ -11,7 +13,7 @@ namespace Umbraco.Web.BackOffice.Profiling
|
||||
/// The API controller used to display the state of the web profiler
|
||||
/// </summary>
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeApiArea)]
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Settings)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessSettings)]
|
||||
public class WebProfilingController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
private readonly IHostingEnvironment _hosting;
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Actions;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
@@ -21,7 +23,7 @@ namespace Umbraco.Web.BackOffice.Trees
|
||||
/// <remarks>
|
||||
/// This authorizes based on access to the content section even though it exists in the settings
|
||||
/// </remarks>
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Content)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessContent)]
|
||||
[Tree(Constants.Applications.Settings, Constants.Trees.ContentBlueprints, SortOrder = 12, TreeGroup = Constants.Trees.Groups.Settings)]
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeTreeArea)]
|
||||
[CoreTree]
|
||||
|
||||
@@ -12,29 +12,20 @@ using Umbraco.Web.Actions;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Search;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Security;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Umbraco.Web.BackOffice.Filters;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Common.Exceptions;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Web.Trees;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Trees
|
||||
{
|
||||
//We will not allow the tree to render unless the user has access to any of the sections that the tree gets rendered
|
||||
// this is not ideal but until we change permissions to be tree based (not section) there's not much else we can do here.
|
||||
[UmbracoApplicationAuthorize(
|
||||
Constants.Applications.Content,
|
||||
Constants.Applications.Media,
|
||||
Constants.Applications.Users,
|
||||
Constants.Applications.Settings,
|
||||
Constants.Applications.Packages,
|
||||
Constants.Applications.Members)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessForContentTree)]
|
||||
[Tree(Constants.Applications.Content, Constants.Trees.Content)]
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeTreeArea)]
|
||||
[CoreTree]
|
||||
|
||||
@@ -20,17 +20,12 @@ using Umbraco.Web.Common.Exceptions;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Trees
|
||||
{
|
||||
//We will not allow the tree to render unless the user has access to any of the sections that the tree gets rendered
|
||||
// this is not ideal but until we change permissions to be tree based (not section) there's not much else we can do here.
|
||||
[UmbracoApplicationAuthorize(
|
||||
Constants.Applications.Content,
|
||||
Constants.Applications.Media,
|
||||
Constants.Applications.Settings,
|
||||
Constants.Applications.Packages,
|
||||
Constants.Applications.Members)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessForMediaTree)]
|
||||
[Tree(Constants.Applications.Media, Constants.Trees.Media)]
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeTreeArea)]
|
||||
[CoreTree]
|
||||
|
||||
@@ -20,15 +20,12 @@ using Constants = Umbraco.Core.Constants;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Web.BackOffice.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Trees
|
||||
{
|
||||
//We will not allow the tree to render unless the user has access to any of the sections that the tree gets rendered
|
||||
// this is not ideal but until we change permissions to be tree based (not section) there's not much else we can do here.
|
||||
[UmbracoApplicationAuthorize(
|
||||
Constants.Applications.Content,
|
||||
Constants.Applications.Media,
|
||||
Constants.Applications.Members)]
|
||||
[Authorize(Policy = AuthorizationPolicies.SectionAccessForMemberTree)]
|
||||
[Tree(Constants.Applications.Members, Constants.Trees.Members, SortOrder = 0)]
|
||||
[PluginController(Constants.Web.Mvc.BackOfficeTreeArea)]
|
||||
[CoreTree]
|
||||
|
||||
Reference in New Issue
Block a user