Skip to content

Commit b0f3009

Browse files
authored
Authorize copy and move destination for the create granular permission (#19303)
1 parent 23df7f1 commit b0f3009

File tree

5 files changed

+44
-5
lines changed

5 files changed

+44
-5
lines changed

src/Umbraco.Cms.Api.Management/Controllers/Document/CopyDocumentController.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Asp.Versioning;
1+
using Asp.Versioning;
22
using Microsoft.AspNetCore.Authorization;
33
using Microsoft.AspNetCore.Http;
44
using Microsoft.AspNetCore.Mvc;
@@ -42,12 +42,16 @@ public async Task<IActionResult> Copy(
4242
Guid id,
4343
CopyDocumentRequestModel copyDocumentRequestModel)
4444
{
45-
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
45+
AuthorizationResult sourceAuthorizationResult = await _authorizationService.AuthorizeResourceAsync(
4646
User,
47-
ContentPermissionResource.WithKeys(ActionCopy.ActionLetter, new[] { copyDocumentRequestModel.Target?.Id, id }),
47+
ContentPermissionResource.WithKeys(ActionCopy.ActionLetter, [id]),
48+
AuthorizationPolicies.ContentPermissionByResource);
49+
AuthorizationResult destinationAuthorizationResult = await _authorizationService.AuthorizeResourceAsync(
50+
User,
51+
ContentPermissionResource.WithKeys(ActionNew.ActionLetter, [copyDocumentRequestModel.Target?.Id]),
4852
AuthorizationPolicies.ContentPermissionByResource);
4953

50-
if (!authorizationResult.Succeeded)
54+
if (sourceAuthorizationResult.Succeeded is false || destinationAuthorizationResult.Succeeded is false)
5155
{
5256
return Forbidden();
5357
}

src/Umbraco.Cms.Api.Management/Controllers/Document/MoveDocumentController.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
using Asp.Versioning;
1+
using Asp.Versioning;
22
using Microsoft.AspNetCore.Authorization;
33
using Microsoft.AspNetCore.Http;
44
using Microsoft.AspNetCore.Mvc;
@@ -39,6 +39,20 @@ public MoveDocumentController(
3939
[ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
4040
public async Task<IActionResult> Move(CancellationToken cancellationToken, Guid id, MoveDocumentRequestModel moveDocumentRequestModel)
4141
{
42+
AuthorizationResult sourceAuthorizationResult = await _authorizationService.AuthorizeResourceAsync(
43+
User,
44+
ContentPermissionResource.WithKeys(ActionMove.ActionLetter, [id]),
45+
AuthorizationPolicies.ContentPermissionByResource);
46+
AuthorizationResult destinationAuthorizationResult = await _authorizationService.AuthorizeResourceAsync(
47+
User,
48+
ContentPermissionResource.WithKeys(ActionNew.ActionLetter, [moveDocumentRequestModel.Target?.Id]),
49+
AuthorizationPolicies.ContentPermissionByResource);
50+
51+
if (sourceAuthorizationResult.Succeeded is false || destinationAuthorizationResult.Succeeded is false)
52+
{
53+
return Forbidden();
54+
}
55+
4256
AuthorizationResult authorizationResult = await _authorizationService.AuthorizeResourceAsync(
4357
User,
4458
ContentPermissionResource.WithKeys(ActionMove.ActionLetter, new[] { moveDocumentRequestModel.Target?.Id, id }),

src/Umbraco.Web.UI.Client/src/packages/core/resources/api-interceptor.controller.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export class UmbApiInterceptorController extends UmbControllerBase {
1616
this.addAuthResponseInterceptor(client);
1717
this.addUmbGeneratedResourceInterceptor(client);
1818
this.addUmbNotificationsInterceptor(client);
19+
this.addForbiddenResponseInterceptor(client);
1920
this.addErrorInterceptor(client);
2021
}
2122

@@ -38,6 +39,24 @@ export class UmbApiInterceptorController extends UmbControllerBase {
3839
});
3940
}
4041

42+
/**
43+
* Interceptor which checks responses for 403 errors and displays them as a notification.
44+
* @param {umbHttpClient} client The OpenAPI client to add the interceptor to. It can be any client supporting Response and Request interceptors.
45+
* @internal
46+
*/
47+
addForbiddenResponseInterceptor(client: typeof umbHttpClient) {
48+
client.interceptors.response.use(async (response: Response) => {
49+
if (response.status === 403) {
50+
const headline = 'Permission Denied';
51+
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.';
52+
53+
this.#peekError(headline, message, null);
54+
}
55+
56+
return response;
57+
});
58+
}
59+
4160
/**
4261
* Interceptor which checks responses for the Umb-Generated-Resource header and replaces the value into the response body.
4362
* @param {umbHttpClient} client The OpenAPI client to add the interceptor to. It can be any client supporting Response and Request interceptors.

src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/duplicate/repository/document-duplicate.server.data-source.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export class UmbDuplicateDocumentServerDataSource {
3939
includeDescendants: args.includeDescendants,
4040
},
4141
}),
42+
{ disableNotifications: true },
4243
);
4344
}
4445
}

src/Umbraco.Web.UI.Client/src/packages/documents/documents/entity-actions/move-to/repository/document-move.server.data-source.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ export class UmbMoveDocumentServerDataSource implements UmbMoveDataSource {
3939
target: args.destination.unique ? { id: args.destination.unique } : null,
4040
},
4141
}),
42+
{ disableNotifications: true },
4243
);
4344
}
4445
}

0 commit comments

Comments
 (0)