diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/CopyDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/CopyDocumentController.cs index 7300e6f88a..8d8c6fd57d 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/CopyDocumentController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/CopyDocumentController.cs @@ -1,4 +1,4 @@ -using Asp.Versioning; +using Asp.Versioning; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -42,12 +42,16 @@ public class CopyDocumentController : DocumentControllerBase Guid id, CopyDocumentRequestModel copyDocumentRequestModel) { - AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync( + AuthorizationResult sourceAuthorizationResult = await _authorizationService.AuthorizeResourceAsync( User, - ContentPermissionResource.WithKeys(ActionCopy.ActionLetter, new[] { copyDocumentRequestModel.Target?.Id, id }), + ContentPermissionResource.WithKeys(ActionCopy.ActionLetter, [id]), + AuthorizationPolicies.ContentPermissionByResource); + AuthorizationResult destinationAuthorizationResult = await _authorizationService.AuthorizeResourceAsync( + User, + ContentPermissionResource.WithKeys(ActionNew.ActionLetter, [copyDocumentRequestModel.Target?.Id]), AuthorizationPolicies.ContentPermissionByResource); - if (!authorizationResult.Succeeded) + if (sourceAuthorizationResult.Succeeded is false || destinationAuthorizationResult.Succeeded is false) { return Forbidden(); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/MoveDocumentController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/MoveDocumentController.cs index aa777a57f0..1141b34b5c 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/MoveDocumentController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/MoveDocumentController.cs @@ -1,4 +1,4 @@ -using Asp.Versioning; +using Asp.Versioning; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -39,6 +39,20 @@ public class MoveDocumentController : DocumentControllerBase [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)] public async Task Move(CancellationToken cancellationToken, Guid id, MoveDocumentRequestModel moveDocumentRequestModel) { + AuthorizationResult sourceAuthorizationResult = await _authorizationService.AuthorizeResourceAsync( + User, + ContentPermissionResource.WithKeys(ActionMove.ActionLetter, [id]), + AuthorizationPolicies.ContentPermissionByResource); + AuthorizationResult destinationAuthorizationResult = await _authorizationService.AuthorizeResourceAsync( + User, + ContentPermissionResource.WithKeys(ActionNew.ActionLetter, [moveDocumentRequestModel.Target?.Id]), + AuthorizationPolicies.ContentPermissionByResource); + + if (sourceAuthorizationResult.Succeeded is false || destinationAuthorizationResult.Succeeded is false) + { + return Forbidden(); + } + AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync( User, ContentPermissionResource.WithKeys(ActionMove.ActionLetter, new[] { moveDocumentRequestModel.Target?.Id, id }), diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/resources/api-interceptor.controller.ts b/src/Umbraco.Web.UI.Client/src/packages/core/resources/api-interceptor.controller.ts index 7e84e24d0c..00c5a524c4 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/resources/api-interceptor.controller.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/resources/api-interceptor.controller.ts @@ -16,6 +16,7 @@ export class UmbApiInterceptorController extends UmbControllerBase { this.addAuthResponseInterceptor(client); this.addUmbGeneratedResourceInterceptor(client); this.addUmbNotificationsInterceptor(client); + this.addForbiddenResponseInterceptor(client); this.addErrorInterceptor(client); } @@ -38,6 +39,24 @@ export class UmbApiInterceptorController extends UmbControllerBase { }); } + /** + * Interceptor which checks responses for 403 errors and displays them as a notification. + * @param {umbHttpClient} client The OpenAPI client to add the interceptor to. It can be any client supporting Response and Request interceptors. + * @internal + */ + addForbiddenResponseInterceptor(client: typeof umbHttpClient) { + client.interceptors.response.use(async (response: Response) => { + if (response.status === 403) { + const headline = 'Permission Denied'; + const message = 'You do not have the necessary permissions to complete the requested action. If you believe this is in error, please reach out to your administrator.'; + + this.#peekError(headline, message, null); + } + + return response; + }); + } + /** * Interceptor which checks responses for the Umb-Generated-Resource header and replaces the value into the response body. * @param {umbHttpClient} client The OpenAPI client to add the interceptor to. It can be any client supporting Response and Request interceptors. diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/repository/document-duplicate.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/repository/document-duplicate.server.data-source.ts index 3bf2bee93c..f2ce6d2621 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/repository/document-duplicate.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/repository/document-duplicate.server.data-source.ts @@ -39,6 +39,7 @@ export class UmbDuplicateDocumentServerDataSource { includeDescendants: args.includeDescendants, }, }), + { disableNotifications: true }, ); } } diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/move-to/repository/document-move.server.data-source.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/move-to/repository/document-move.server.data-source.ts index 854e245ec7..ce765d743d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/move-to/repository/document-move.server.data-source.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/move-to/repository/document-move.server.data-source.ts @@ -39,6 +39,7 @@ export class UmbMoveDocumentServerDataSource implements UmbMoveDataSource { target: args.destination.unique ? { id: args.destination.unique } : null, }, }), + { disableNotifications: true }, ); } }