Netcore: Handle tree authentication (#8866)

* Added helper methods to invoke the authorization filters of the other controller action

Signed-off-by: Bjarke Berg <mail@bergmania.dk>

* Implemented Tree Auth

Signed-off-by: Bjarke Berg <mail@bergmania.dk>

* cleanup

Signed-off-by: Bjarke Berg <mail@bergmania.dk>

* Throw forbidden if user has no access instead of InternalServerError

Signed-off-by: Bjarke Berg <mail@bergmania.dk>

* EnsureBackofficeSecurity for background jobs

Signed-off-by: Bjarke Berg <mail@bergmania.dk>

Co-authored-by: Elitsa Marinovska <elm@umbraco.dk>
This commit is contained in:
Bjarke Berg
2020-09-22 13:19:54 +02:00
committed by GitHub
parent 96facc4d35
commit a80de91031
8 changed files with 170 additions and 115 deletions

View File

@@ -8,10 +8,12 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Primitives;
using Umbraco.Core;
using Umbraco.Core.Services;
using Umbraco.Extensions;
using Umbraco.Web.BackOffice.Controllers;
using Umbraco.Web.BackOffice.Trees;
using Umbraco.Web.Common.Attributes;
@@ -35,18 +37,22 @@ namespace Umbraco.Web.Trees
private readonly ISectionService _sectionService;
private readonly ILocalizedTextService _localizedTextService;
private readonly IControllerFactory _controllerFactory;
private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
public ApplicationTreeController(
ITreeService treeService,
ISectionService sectionService,
ILocalizedTextService localizedTextService,
IControllerFactory controllerFactory
IControllerFactory controllerFactory,
IActionDescriptorCollectionProvider actionDescriptorCollectionProvider
)
{
_treeService = treeService;
_sectionService = sectionService;
_localizedTextService = localizedTextService;
_controllerFactory = controllerFactory;
_actionDescriptorCollectionProvider = actionDescriptorCollectionProvider;
}
/// <summary>
@@ -251,67 +257,36 @@ namespace Umbraco.Web.Trees
private async Task<object> GetApiControllerProxy(Type controllerType, string action, FormCollection querystring)
{
// note: this is all required in order to execute the auth-filters for the sub request, we
// need to "trick" web-api into thinking that it is actually executing the proxied controller.
// need to "trick" mvc into thinking that it is actually executing the proxied controller.
var controllerName = controllerType.Name.Substring(0, controllerType.Name.Length - 10); // remove controller part of name;
// create proxy route data specifying the action & controller to execute
var routeData = new RouteData(new RouteValueDictionary()
{
["action"] = action,
["controller"] = controllerType.Name.Substring(0,controllerType.Name.Length-10) // remove controller part of name;
["controller"] = controllerName
});
if (!(querystring is null))
{
foreach (var (key,value) in querystring)
{
routeData.Values[key] = value;
}
}
var actionDescriptor = _actionDescriptorCollectionProvider.ActionDescriptors.Items
.Cast<ControllerActionDescriptor>()
.First(x =>
x.ControllerName.Equals(controllerName) &&
x.ActionName == action);
var controllerContext = new ControllerContext(
new ActionContext(
HttpContext,
routeData,
new ControllerActionDescriptor()
{
ControllerTypeInfo = controllerType.GetTypeInfo()
}
));
var actionContext = new ActionContext(HttpContext, routeData, actionDescriptor);
var proxyControllerContext = new ControllerContext(actionContext);
var controller = (TreeController) _controllerFactory.CreateController(proxyControllerContext);
var controller = (TreeController) _controllerFactory.CreateController(controllerContext);
//TODO Refactor trees or reimplement this hacks to check authentication.
//https://dev.azure.com/umbraco/D-Team%20Tracker/_workitems/edit/3694
// var context = ControllerContext;
//
// // get the controller
// var controller = (TreeController) DependencyResolver.Current.GetService(controllerType)
// ?? throw new Exception($"Failed to create controller of type {controllerType.FullName}.");
//
// // create the proxy URL for the controller action
// var proxyUrl = HttpContext.Request.RequestUri.GetLeftPart(UriPartial.Authority)
// + HttpContext.Request.GetUrlHelper().GetUmbracoApiService(action, controllerType)
// + "?" + querystring.ToQueryString();
//
//
//
// // create a proxy request
// var proxyRequest = new HttpRequestMessage(HttpMethod.Get, proxyUrl);
//
// // create a proxy controller context
// var proxyContext = new HttpControllerContext(context.Configuration, proxyRoute, proxyRequest)
// {
// ControllerDescriptor = new HttpControllerDescriptor(context.ControllerDescriptor.Configuration, ControllerExtensions.GetControllerName(controllerType), controllerType),
// RequestContext = context.RequestContext,
// Controller = controller
// };
//
// // wire everything
// controller.ControllerContext = proxyContext;
// controller.Request = proxyContext.Request;
// controller.RequestContext.RouteData = proxyRoute;
//
// // auth
// var authResult = await controller.ControllerContext.InvokeAuthorizationFiltersForRequest();
// if (authResult != null)
// throw new HttpResponseException(authResult);
var isAllowed = await controller.ControllerContext.InvokeAuthorizationFiltersForRequest(actionContext);
if (!isAllowed)
throw new HttpResponseException(HttpStatusCode.Forbidden);
return controller;
}