// Copyright (c) Umbraco. // See LICENSE for more details. using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Primitives; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; namespace Umbraco.Cms.Web.BackOffice.Authorization; /// /// Used to authorize if the user has the correct permission access to the content for the content id specified in a /// query string. /// public class ContentPermissionsQueryStringHandler : PermissionsQueryStringHandler { private readonly ContentPermissions _contentPermissions; /// /// Initializes a new instance of the class. /// /// Accessor for back-office security. /// Accessor for the HTTP context of the current request. /// Service for entity operations. /// Helper for content authorization checks. public ContentPermissionsQueryStringHandler( IBackOfficeSecurityAccessor backOfficeSecurityAccessor, IHttpContextAccessor httpContextAccessor, IEntityService entityService, ContentPermissions contentPermissions) : base(backOfficeSecurityAccessor, httpContextAccessor, entityService) => _contentPermissions = contentPermissions; /// protected override Task IsAuthorized(AuthorizationHandlerContext context, ContentPermissionsQueryStringRequirement requirement) { int nodeId; if (requirement.NodeId.HasValue == false) { if (HttpContextAccessor.HttpContext is null || requirement.QueryStringName is null || !HttpContextAccessor.HttpContext.Request.Query.TryGetValue(requirement.QueryStringName, out StringValues routeVal)) { // Must succeed this requirement since we cannot process it return Task.FromResult(true); } var argument = routeVal.ToString(); if (!TryParseNodeId(argument, out nodeId)) { // Must succeed this requirement since we cannot process it. return Task.FromResult(true); } } else { nodeId = requirement.NodeId.Value; } ContentPermissions.ContentAccess permissionResult = _contentPermissions.CheckPermissions( nodeId, BackOfficeSecurityAccessor.BackOfficeSecurity?.CurrentUser, out IContent? contentItem, new[] { requirement.PermissionToCheck }); if (HttpContextAccessor.HttpContext is not null && contentItem is not null) { // Store the content item in request cache so it can be resolved in the controller without re-looking it up. HttpContextAccessor.HttpContext.Items[typeof(IContent).ToString()] = contentItem; } return permissionResult switch { ContentPermissions.ContentAccess.Denied => Task.FromResult(false), _ => Task.FromResult(true) }; } }