Merge commit from fork

This commit is contained in:
Sven Geusens
2024-08-19 15:04:08 +02:00
committed by Nikolaj Geisle
parent a3ede67777
commit 72bef8861d
4 changed files with 62 additions and 5 deletions

View File

@@ -29,6 +29,7 @@ internal static class BackOfficeAuthPolicyBuilderExtensions
builder.Services.AddSingleton<IAuthorizationHandler, UserGroupPermissionHandler>();
builder.Services.AddSingleton<IAuthorizationHandler, UserPermissionHandler>();
builder.Services.AddSingleton<IAuthorizationHandler, AllowedApplicationHandler>();
builder.Services.AddSingleton<IAuthorizationHandler, BackOfficeHandler>();
builder.Services.AddAuthorization(CreatePolicies);
return builder;
@@ -46,7 +47,7 @@ internal static class BackOfficeAuthPolicyBuilderExtensions
options.AddPolicy(AuthorizationPolicies.BackOfficeAccess, policy =>
{
policy.AuthenticationSchemes.Add(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme);
policy.RequireAuthenticatedUser();
policy.Requirements.Add(new BackOfficeRequirement());
});
options.AddPolicy(AuthorizationPolicies.RequireAdminAccess, policy =>

View File

@@ -1,5 +1,6 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Infrastructure;
using Umbraco.Cms.Api.Management.Security.Authorization.User;
namespace Umbraco.Cms.Api.Management.Security.Authorization.DenyLocalLogin;
@@ -24,12 +25,12 @@ public class DenyLocalLoginHandler : MustSatisfyRequirementAuthorizationHandler<
if (isDenied is false)
{
// AuthorizationPolicies.BackOfficeAccess policy adds this requirement by policy.RequireAuthenticatedUser()
// AuthorizationPolicies.BackOfficeAccess policy adds this requirement by policy.Requirements.Add(new BackOfficeRequirement());
// Since we want to "allow anonymous" for some endpoints (i.e. BackOfficeController.Login()), it is necessary to succeed this requirement
IEnumerable<DenyAnonymousAuthorizationRequirement> denyAnonymousUserRequirements = context.PendingRequirements.OfType<DenyAnonymousAuthorizationRequirement>();
foreach (DenyAnonymousAuthorizationRequirement denyAnonymousUserRequirement in denyAnonymousUserRequirements)
IEnumerable<BackOfficeRequirement> backOfficeRequirements = context.PendingRequirements.OfType<BackOfficeRequirement>();
foreach (BackOfficeRequirement backOfficeRequirement in backOfficeRequirements)
{
context.Succeed(denyAnonymousUserRequirement);
context.Succeed(backOfficeRequirement);
}
}

View File

@@ -0,0 +1,35 @@
using Microsoft.AspNetCore.Authorization;
using Umbraco.Cms.Core.Security;
namespace Umbraco.Cms.Api.Management.Security.Authorization.User;
/// <summary>
/// Ensures authorization is successful for a back office user.
/// </summary>
public class BackOfficeHandler : MustSatisfyRequirementAuthorizationHandler<BackOfficeRequirement>
{
private readonly IBackOfficeSecurityAccessor _backOfficeSecurity;
public BackOfficeHandler(IBackOfficeSecurityAccessor backOfficeSecurity)
{
_backOfficeSecurity = backOfficeSecurity;
}
protected override Task<bool> IsAuthorized(AuthorizationHandlerContext context, BackOfficeRequirement requirement)
{
if (context.HasFailed is false && context.HasSucceeded is true)
{
return Task.FromResult(true);
}
if (!_backOfficeSecurity.BackOfficeSecurity?.IsAuthenticated() ?? false)
{
return Task.FromResult(false);
}
var userApprovalSucceeded = !requirement.RequireApproval ||
(_backOfficeSecurity.BackOfficeSecurity?.CurrentUser?.IsApproved ?? false);
return Task.FromResult(userApprovalSucceeded);
}
}

View File

@@ -0,0 +1,20 @@
using Microsoft.AspNetCore.Authorization;
namespace Umbraco.Cms.Api.Management.Security.Authorization.User;
/// <summary>
/// Authorization requirement for the <see cref="BackOfficeHandler" />.
/// </summary>
public class BackOfficeRequirement : IAuthorizationRequirement
{
/// <summary>
/// Initializes a new instance of the <see cref="BackOfficeRequirement" /> class.
/// </summary>
/// <param name="requireApproval">Flag for whether back-office user approval is required.</param>
public BackOfficeRequirement(bool requireApproval = true) => RequireApproval = requireApproval;
/// <summary>
/// Gets a value indicating whether back-office user approval is required.
/// </summary>
public bool RequireApproval { get; }
}