Add policies for content template handling (#15482)

This commit is contained in:
Kenn Jacobsen
2023-12-19 14:18:48 +01:00
committed by Bjarke Berg
parent 38f7df2b0c
commit e8a81e30b1
4 changed files with 22 additions and 5 deletions

View File

@@ -826,6 +826,7 @@ public class ContentController : ContentControllerBase
/// <param name="contentId">The content id to copy</param>
/// <param name="name">The name of the blueprint</param>
/// <returns></returns>
[Authorize(Policy = AuthorizationPolicies.ContentPermissionCreateBlueprintFromId)]
[HttpPost]
public ActionResult<SimpleNotificationModel> CreateBlueprintFromContent(
[FromQuery] int contentId,
@@ -881,8 +882,9 @@ public class ContentController : ContentControllerBase
/// <summary>
/// Saves content
/// </summary>
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)]
[FileUploadCleanupFilter]
[ContentSaveValidation]
[ContentSaveValidation(skipUserAccessValidation:true)] // skip user access validation because we "only" require Settings access to create new blueprints from scratch
public async Task<ActionResult<ContentItemDisplay<ContentVariantDisplay>?>?> PostSaveBlueprint(
[ModelBinder(typeof(BlueprintItemBinder))] ContentItemSave contentItem)
{
@@ -2077,6 +2079,7 @@ public class ContentController : ContentControllerBase
return Ok();
}
[Authorize(Policy = AuthorizationPolicies.TreeAccessDocumentTypes)]
[HttpDelete]
[HttpPost]
public IActionResult DeleteBlueprint(int id)

View File

@@ -179,6 +179,13 @@ public static partial class UmbracoBuilderExtensions
policy.Requirements.Add(new ContentPermissionsQueryStringRequirement(ActionDelete.ActionLetter));
});
options.AddPolicy(AuthorizationPolicies.ContentPermissionCreateBlueprintFromId, policy =>
{
policy.AuthenticationSchemes.Add(backOfficeAuthenticationScheme);
policy.Requirements.Add(
new ContentPermissionsQueryStringRequirement(ActionCreateBlueprintFromContent.ActionLetter, "contentId"));
});
options.AddPolicy(AuthorizationPolicies.BackOfficeAccess, policy =>
{
policy.AuthenticationSchemes.Add(backOfficeAuthenticationScheme);

View File

@@ -20,9 +20,12 @@ namespace Umbraco.Cms.Web.BackOffice.Filters;
/// </summary>
internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
{
public ContentSaveValidationAttribute() : base(typeof(ContentSaveValidationFilter)) =>
public ContentSaveValidationAttribute(bool skipUserAccessValidation = false)
: base(typeof(ContentSaveValidationFilter))
{
Order = -3000; // More important than ModelStateInvalidFilter.FilterOrder
Arguments = new object[] { skipUserAccessValidation };
}
private sealed class ContentSaveValidationFilter : IAsyncActionFilter
{
@@ -32,6 +35,7 @@ internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
private readonly ILocalizationService _localizationService;
private readonly ILoggerFactory _loggerFactory;
private readonly IPropertyValidationService _propertyValidationService;
private readonly bool _skipUserAccessValidation;
public ContentSaveValidationFilter(
@@ -40,7 +44,8 @@ internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
IPropertyValidationService propertyValidationService,
IAuthorizationService authorizationService,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
ILocalizationService localizationService)
ILocalizationService localizationService,
bool skipUserAccessValidation)
{
_loggerFactory = loggerFactory ?? throw new ArgumentNullException(nameof(loggerFactory));
_contentService = contentService ?? throw new ArgumentNullException(nameof(contentService));
@@ -49,6 +54,7 @@ internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
_authorizationService = authorizationService;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_localizationService = localizationService;
_skipUserAccessValidation = skipUserAccessValidation;
}
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
@@ -88,7 +94,7 @@ internal sealed class ContentSaveValidationAttribute : TypeFilterAttribute
return;
}
if (!await ValidateUserAccessAsync(model, context))
if (_skipUserAccessValidation is false && await ValidateUserAccessAsync(model, context) is false)
{
return;
}

View File

@@ -22,6 +22,7 @@ public static class AuthorizationPolicies
public const string ContentPermissionProtectById = nameof(ContentPermissionProtectById);
public const string ContentPermissionBrowseById = nameof(ContentPermissionBrowseById);
public const string ContentPermissionDeleteById = nameof(ContentPermissionDeleteById);
public const string ContentPermissionCreateBlueprintFromId = nameof(ContentPermissionCreateBlueprintFromId);
public const string MediaPermissionByResource = nameof(MediaPermissionByResource);
public const string MediaPermissionPathById = nameof(MediaPermissionPathById);