diff --git a/src/Umbraco.Web/Actions/ActionCreateBlueprintFromContent.cs b/src/Umbraco.Web/Actions/ActionCreateBlueprintFromContent.cs index 0a46393a8156..d0de6470ae63 100644 --- a/src/Umbraco.Web/Actions/ActionCreateBlueprintFromContent.cs +++ b/src/Umbraco.Web/Actions/ActionCreateBlueprintFromContent.cs @@ -6,7 +6,8 @@ namespace Umbraco.Web.Actions { public class ActionCreateBlueprintFromContent : IAction { - public char Letter => 'ï'; + public const char ActionLetter = 'ï'; + public char Letter => ActionLetter; public bool ShowInNotifier => false; public bool CanBePermissionAssigned => true; public string Icon => "blueprint"; diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 06aeee3a5b43..4409096fe19b 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -657,6 +657,7 @@ public PagedResult> GetChildren( /// The content id to copy /// The name of the blueprint /// + [EnsureUserPermissionForContent("contentId", ActionCreateBlueprintFromContent.ActionLetter)] [HttpPost] public SimpleNotificationModel CreateBlueprintFromContent([FromUri] int contentId, [FromUri] string name) { @@ -696,8 +697,9 @@ private void EnsureUniqueName(string name, IContent content, string modelName) /// Saves content /// /// + [UmbracoTreeAuthorize(Constants.Trees.DocumentTypes)] [FileUploadCleanupFilter] - [ContentSaveValidation] + [ContentSaveValidation(skipUserAccessValidation:true)] // skip user access validation because we "only" require Settings access to create new blueprints from scratch public ContentItemDisplay PostSaveBlueprint([ModelBinder(typeof(BlueprintItemBinder))] ContentItemSave contentItem) { var contentItemDisplay = PostSaveInternal(contentItem, @@ -1586,6 +1588,7 @@ public HttpResponseMessage PostPublishById(int id) } + [UmbracoTreeAuthorize(Constants.Trees.DocumentTypes)] [HttpDelete] [HttpPost] public HttpResponseMessage DeleteBlueprint(int id) diff --git a/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs b/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs index 82659e177e9a..ba112e176220 100644 --- a/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs +++ b/src/Umbraco.Web/Editors/Filters/ContentSaveValidationAttribute.cs @@ -32,11 +32,12 @@ internal sealed class ContentSaveValidationAttribute : ActionFilterAttribute private readonly IUserService _userService; private readonly IEntityService _entityService; private readonly AppCaches _appCaches; + private readonly bool _skipUserAccessValidation; - public ContentSaveValidationAttribute(): this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.TextService, Current.Services.ContentService, Current.Services.UserService, Current.Services.EntityService, Current.AppCaches) + public ContentSaveValidationAttribute(bool skipUserAccessValidation = false): this(Current.Logger, Current.UmbracoContextAccessor, Current.Services.TextService, Current.Services.ContentService, Current.Services.UserService, Current.Services.EntityService, Current.AppCaches, skipUserAccessValidation) { } - public ContentSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IContentService contentService, IUserService userService, IEntityService entityService, AppCaches appCaches) + public ContentSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor umbracoContextAccessor, ILocalizedTextService textService, IContentService contentService, IUserService userService, IEntityService entityService, AppCaches appCaches, bool skipUserAccessValidation) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor)); @@ -45,6 +46,7 @@ public ContentSaveValidationAttribute(ILogger logger, IUmbracoContextAccessor um _userService = userService ?? throw new ArgumentNullException(nameof(userService)); _entityService = entityService ?? throw new ArgumentNullException(nameof(entityService)); _appCaches = appCaches; + _skipUserAccessValidation = skipUserAccessValidation; } public override void OnActionExecuting(HttpActionContext actionContext) @@ -54,8 +56,8 @@ public override void OnActionExecuting(HttpActionContext actionContext) if (!ValidateAtLeastOneVariantIsBeingSaved(model, actionContext)) return; if (!contentItemValidator.ValidateExistingContent(model, actionContext)) return; - if (!ValidateUserAccess(model, actionContext, _umbracoContextAccessor.UmbracoContext.Security)) return; - + if (!_skipUserAccessValidation && !ValidateUserAccess(model, actionContext, _umbracoContextAccessor.UmbracoContext.Security)) return; + //validate for each variant that is being updated foreach (var variant in model.Variants.Where(x => x.Save)) { @@ -88,7 +90,7 @@ private bool ValidateAtLeastOneVariantIsBeingSaved(ContentItemSave contentItem, /// /// private bool ValidateUserAccess(ContentItemSave contentItem, HttpActionContext actionContext, WebSecurity webSecurity) - { + { //We now need to validate that the user is allowed to be doing what they are doing. //Based on the action we need to check different permissions. @@ -172,7 +174,7 @@ private bool ValidateUserAccess(ContentItemSave contentItem, HttpActionContext a } break; case ContentSaveAction.ScheduleNew: - + permissionToCheck.Add(ActionNew.ActionLetter); permissionToCheck.Add(ActionUpdate.ActionLetter); permissionToCheck.Add(ActionPublish.ActionLetter);