V14: Add authorization policies to Management API controllers - p2 (#15211)
* Making ProblemDetails details more generic * Adding authorizer that can be replaces for external authz in handlers. Adding handler and requirement for UserBelongsToUserGroupInRequest policy * Adding method to get the GUID from claims * Adding service methods to check user group authz * Porting MustSatisfyRequirementAuthorizationHandler * Adding controllers authz * Fix return status code + produced response type * Moving to folder * Adding DenyLocalLogin policy scaffold * Implement a temp DenyLocalLoginHandler * Introducing a new Fobidden result * Fix comment * Introducing a helper class for authorizers * Changed nullability for GetCurrentUser * Changes from Attempt to Status + FIXME comments * Create a UserGroupAuthorizationStatus to be used in the future * Introduces a new authz status for checking media acess * Introducing a new permission service for media * Adding fixme * Adding more policy configurations * Adding Media policy requirement and handler * Adding media authorizer * Fix order of params * Adding duplicate code comment * Adding authz to media controllers * Migrating more logic from MediaPermissions.cs * Adding more MediaAuthorizationStatus-es * Handling of new authorization status * Fix comment * Adding NotFound case * Adding NewDenyLocalLoginIfConfigured policy && commenting [AllowAnonymous] where the policy is applied since it is already handled * Changed Forbid() to Forbidden() to get the correct status code * Remove policy that is applied on the base controller already * Implement and apply NewUmbracoFeatureEnabled policy * Renaming classes to add Permission in the name * Register permission services * Add FIXME * Introduce new IUserGroupPermissionService and refactor accordingly * Add single overload with default implementation * Adding user permission policy and related * Applying admin policy * Register all new policies * Better wording * Add default implementation for a single overload * Adding remarks to IContentPermissionService.cs * Supporting null as key in ContentPermissionService * Fix namespace * Reverting back to not supporting null as content key, but having dedicated implementation * Adding content authorizer with null values to represent root item * Removing null key support and adding dedicated implementation * Removing remarks * Adding content resource with null support * Removing null support * Adding requirement and status * Adding content authorizer + handlers * Applying policies to content controllers * Update comment * Handling of Authorization Statuses * More authz in controllers * Fix comments * New branch handler * Obsolete old implementation * Adding dedicated policies to root and bin * Adding a branch specific namespace * Bin specific requirement and namespace * Root specific requirement and namespace * Changing to new root policy * Refactoring * Save policies * Fix null check/reference * Add TODO comment * Create media root- and bin-specific policies, handlers, etc. * Apply correct policy in create and update media controllers * Apply root policy to move and sort controllers * Fix wording * Adding UserGroupAuthorizationStatusResult * Remove all AuthorizationStatusResult as we cannot get the specific AuthorizationStatus * Fixing Umbraco feature policy * Fix allow anonymous endpoints - the value returned from DenyLocalLoginHandler wasn't enough, we need to succeed DenyAnonymousAuthorizationRequirement as it is required for some of the endpoints that had the attribute * Apply DenyLocalLoginIfConfigured policy to corresponding re-implementation of PostSetInvitedUserPassword * Fix comment * Renaming performingUser to user and fixing comments * Rename helper method * Fix references * Re-add merge conflict deletion * Adding Backoffice requirement and relevant * Registering * Added a simple policy test * Fixed small test things and clean up * Temp solution * Added one more test and fix another static issue * Fix another merge conflict * Remove BackOfficePermissionRequirement and handler as they might not be necessary * Comment out again [AllowAnonymous] * Remove AuthorizationPolicies.BackOfficeAccessWithoutApproval policy as it might not be necessary * Fix temp implementation * Fix reference to correct handler * Apply authz policy to new publish/unpublish controllers * Fix comments * Removing duplicate ProducesResponseTypes * Added swagger documentation about the 401 and 403 * Added Resources to Media, User and UserGroup * Handle root, recycle bin and branch in the same handler * Handle both parent and target when moving * Check Ids for all sort requests * Xml docs * Clean up * Clean up * Fix build * Cleanup * Remove TODO * Added missing overload * Use yield * Adding some keys to check --------- Co-authored-by: Bjarke Berg <mail@bergmania.dk> Co-authored-by: Andreas Zerbst <andr317c@live.dk>
This commit is contained in:
committed by
GitHub
parent
f8b95e5c69
commit
fda866fc9e
@@ -1,5 +1,6 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
@@ -12,6 +13,11 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Common.Attributes;
|
||||
using Umbraco.Cms.Api.Delivery.Controllers.Content;
|
||||
using Umbraco.Cms.Api.Management.Controllers;
|
||||
using Umbraco.Cms.Api.Management.Controllers.ModelsBuilder;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
@@ -34,7 +40,7 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
{
|
||||
protected HttpClient Client { get; private set; }
|
||||
|
||||
protected LinkGenerator LinkGenerator { get; private set; }
|
||||
protected LinkGenerator LinkGenerator => Factory.Services.GetRequiredService<LinkGenerator>();
|
||||
|
||||
protected WebApplicationFactory<UmbracoTestServerTestBase> Factory { get; private set; }
|
||||
|
||||
@@ -48,6 +54,14 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual void CustomTestAuthSetup(IServiceCollection services)
|
||||
{
|
||||
// Add a test auth scheme with a test auth handler to authn and assign the user
|
||||
services.AddAuthentication(TestAuthHandler.TestAuthenticationScheme)
|
||||
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
|
||||
TestAuthHandler.TestAuthenticationScheme, options => { });
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
@@ -68,6 +82,7 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
*/
|
||||
var factory = new UmbracoWebApplicationFactory<UmbracoTestServerTestBase>(CreateHostBuilder);
|
||||
|
||||
|
||||
// additional host configuration for web server integration tests
|
||||
Factory = factory.WithWebHostBuilder(builder =>
|
||||
{
|
||||
@@ -79,19 +94,15 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
{
|
||||
services.AddSingleton<IWebProfilerRepository, TestWebProfilerRepository>();
|
||||
|
||||
// Add a test auth scheme with a test auth handler to authn and assign the user
|
||||
services.AddAuthentication(TestAuthHandler.TestAuthenticationScheme)
|
||||
.AddScheme<AuthenticationSchemeOptions, TestAuthHandler>(
|
||||
TestAuthHandler.TestAuthenticationScheme, options => { });
|
||||
CustomTestAuthSetup(services);
|
||||
});
|
||||
});
|
||||
|
||||
Client = Factory.CreateClient(new WebApplicationFactoryClientOptions
|
||||
{
|
||||
AllowAutoRedirect = false
|
||||
AllowAutoRedirect = false,
|
||||
BaseAddress = new Uri("https://localhost/", UriKind.Absolute)
|
||||
});
|
||||
|
||||
LinkGenerator = Factory.Services.GetRequiredService<LinkGenerator>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -106,6 +117,25 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
return PrepareUrl(url);
|
||||
}
|
||||
|
||||
protected string GetManagementApiUrl<T>(Expression<Func<T, object>> methodSelector)
|
||||
where T : ManagementApiControllerBase
|
||||
{
|
||||
MethodInfo? method = ExpressionHelper.GetMethodInfo(methodSelector);
|
||||
IDictionary<string, object?> methodParams = ExpressionHelper.GetMethodParams(methodSelector) ?? new Dictionary<string, object?>();
|
||||
|
||||
|
||||
methodParams["version"] = method?.GetCustomAttribute<MapToApiVersionAttribute>()?.Versions?.First().MajorVersion.ToString();
|
||||
if (method == null)
|
||||
{
|
||||
throw new MissingMethodException(
|
||||
$"Could not find the method {methodSelector} on type {typeof(T)} or the result ");
|
||||
}
|
||||
|
||||
var controllerName = ControllerExtensions.GetControllerName(typeof(T));
|
||||
|
||||
return LinkGenerator.GetUmbracoControllerUrl(method.Name, controllerName, null, methodParams);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepare a url before using <see cref="Client"/>.
|
||||
/// This returns the url but also sets the HttpContext.request into to use this url.
|
||||
@@ -212,6 +242,7 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
services.AddLogger(TestHelper.GetWebHostEnvironment(), Configuration);
|
||||
|
||||
var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory, TestHelper.Profiler, AppCaches.NoCache, hostingEnvironment);
|
||||
builder.Services.AddTransient<IHostedService>(sp => new TestDatabaseHostedLifecycleService(() => UseTestDatabase(sp)));
|
||||
|
||||
builder
|
||||
.AddConfiguration()
|
||||
@@ -236,6 +267,12 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
// Adds Umbraco.Web.Website
|
||||
mvcBuilder.AddApplicationPart(typeof(SurfaceController).Assembly);
|
||||
|
||||
// Adds Umbraco.Cms.Api.ManagementApi
|
||||
mvcBuilder.AddApplicationPart(typeof(ModelsBuilderControllerBase).Assembly);
|
||||
|
||||
// Adds Umbraco.Cms.Api.DeliveryApi
|
||||
mvcBuilder.AddApplicationPart(typeof(ContentApiItemControllerBase).Assembly);
|
||||
|
||||
// Adds Umbraco.Tests.Integration
|
||||
mvcBuilder.AddApplicationPart(typeof(UmbracoTestServerTestBase).Assembly);
|
||||
})
|
||||
@@ -244,11 +281,13 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
.AddUmbracoSqlServerSupport()
|
||||
.AddUmbracoSqliteSupport()
|
||||
.AddDeliveryApi()
|
||||
.AddUmbracoManagementApi()
|
||||
.AddComposers()
|
||||
.AddTestServices(TestHelper); // This is the important one!
|
||||
|
||||
CustomTestSetup(builder);
|
||||
|
||||
|
||||
builder.Build();
|
||||
}
|
||||
|
||||
@@ -262,8 +301,6 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
|
||||
protected void Configure(IApplicationBuilder app)
|
||||
{
|
||||
UseTestDatabase(app);
|
||||
|
||||
app.UseUmbraco()
|
||||
.WithMiddleware(u =>
|
||||
{
|
||||
@@ -272,9 +309,36 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
})
|
||||
.WithEndpoints(u =>
|
||||
{
|
||||
u.UseInstallerEndpoints();
|
||||
u.UseBackOfficeEndpoints();
|
||||
u.UseWebsiteEndpoints();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TestDatabaseHostedLifecycleService : IHostedLifecycleService
|
||||
{
|
||||
private readonly Action _action;
|
||||
|
||||
public TestDatabaseHostedLifecycleService(Action action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)=> Task.CompletedTask;
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
public Task StartedAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
public Task StartingAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_action();
|
||||
return Task.CompletedTask;
|
||||
|
||||
}
|
||||
public Task StoppedAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
public Task StoppingAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user