using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Filters; using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.WebApi { internal static class HttpControllerContextExtensions { /// /// Invokes the authorization filters for the controller action. /// /// The response of the first filter returning a result, if any, otherwise null (authorized). internal static async Task InvokeAuthorizationFiltersForRequest(this HttpControllerContext controllerContext) { var controllerDescriptor = controllerContext.ControllerDescriptor; var controllerServices = controllerDescriptor.Configuration.Services; var actionDescriptor = controllerServices.GetActionSelector().SelectAction(controllerContext); var filters = actionDescriptor.GetFilterPipeline(); var filterGrouping = new FilterGrouping(filters); // because the continuation gets built from the inside out we need to reverse the filter list // so that least specific filters (Global) get run first and the most specific filters (Action) get run last. var authorizationFilters = filterGrouping.AuthorizationFilters.Reverse().ToList(); if (authorizationFilters.Count == 0) return null; // if the authorization filter returns a result, it means it failed to authorize var actionContext = new HttpActionContext(controllerContext, actionDescriptor); return await ExecuteAuthorizationFiltersAsync(actionContext, CancellationToken.None, authorizationFilters); } /// /// Executes a chain of filters. /// /// /// Recursively calls in to itself as its continuation for the next filter in the chain. /// private static async Task ExecuteAuthorizationFiltersAsync(HttpActionContext actionContext, CancellationToken token, IList filters, int index = 0) { return await filters[index].ExecuteAuthorizationFilterAsync(actionContext, token, () => ++index == filters.Count ? Task.FromResult(null) : ExecuteAuthorizationFiltersAsync(actionContext, token, filters, index)); } } }