From 72bef8861d94a39d5cc9530a04c4797b91fcbecf Mon Sep 17 00:00:00 2001 From: Sven Geusens Date: Mon, 19 Aug 2024 15:04:08 +0200 Subject: [PATCH] Merge commit from fork --- .../BackOfficeAuthPolicyBuilderExtensions.cs | 3 +- .../DenyLocalLogin/DenyLocalLoginHandler.cs | 9 ++--- .../Authorization/User/BackOfficeHandler.cs | 35 +++++++++++++++++++ .../User/BackOfficeRequirement.cs | 20 +++++++++++ 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 src/Umbraco.Cms.Api.Management/Security/Authorization/User/BackOfficeHandler.cs create mode 100644 src/Umbraco.Cms.Api.Management/Security/Authorization/User/BackOfficeRequirement.cs diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthPolicyBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthPolicyBuilderExtensions.cs index 45eccad5ec..11940d243f 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthPolicyBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthPolicyBuilderExtensions.cs @@ -29,6 +29,7 @@ internal static class BackOfficeAuthPolicyBuilderExtensions builder.Services.AddSingleton(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); + builder.Services.AddSingleton(); 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 => diff --git a/src/Umbraco.Cms.Api.Management/Security/Authorization/DenyLocalLogin/DenyLocalLoginHandler.cs b/src/Umbraco.Cms.Api.Management/Security/Authorization/DenyLocalLogin/DenyLocalLoginHandler.cs index e57eb6c742..cd9a675bfc 100644 --- a/src/Umbraco.Cms.Api.Management/Security/Authorization/DenyLocalLogin/DenyLocalLoginHandler.cs +++ b/src/Umbraco.Cms.Api.Management/Security/Authorization/DenyLocalLogin/DenyLocalLoginHandler.cs @@ -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 denyAnonymousUserRequirements = context.PendingRequirements.OfType(); - foreach (DenyAnonymousAuthorizationRequirement denyAnonymousUserRequirement in denyAnonymousUserRequirements) + IEnumerable backOfficeRequirements = context.PendingRequirements.OfType(); + foreach (BackOfficeRequirement backOfficeRequirement in backOfficeRequirements) { - context.Succeed(denyAnonymousUserRequirement); + context.Succeed(backOfficeRequirement); } } diff --git a/src/Umbraco.Cms.Api.Management/Security/Authorization/User/BackOfficeHandler.cs b/src/Umbraco.Cms.Api.Management/Security/Authorization/User/BackOfficeHandler.cs new file mode 100644 index 0000000000..ff79e344ae --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Security/Authorization/User/BackOfficeHandler.cs @@ -0,0 +1,35 @@ +using Microsoft.AspNetCore.Authorization; +using Umbraco.Cms.Core.Security; + +namespace Umbraco.Cms.Api.Management.Security.Authorization.User; + +/// +/// Ensures authorization is successful for a back office user. +/// +public class BackOfficeHandler : MustSatisfyRequirementAuthorizationHandler +{ + private readonly IBackOfficeSecurityAccessor _backOfficeSecurity; + + public BackOfficeHandler(IBackOfficeSecurityAccessor backOfficeSecurity) + { + _backOfficeSecurity = backOfficeSecurity; + } + + protected override Task 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); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Security/Authorization/User/BackOfficeRequirement.cs b/src/Umbraco.Cms.Api.Management/Security/Authorization/User/BackOfficeRequirement.cs new file mode 100644 index 0000000000..8c6f97b24f --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Security/Authorization/User/BackOfficeRequirement.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Authorization; + +namespace Umbraco.Cms.Api.Management.Security.Authorization.User; + +/// +/// Authorization requirement for the . +/// +public class BackOfficeRequirement : IAuthorizationRequirement +{ + /// + /// Initializes a new instance of the class. + /// + /// Flag for whether back-office user approval is required. + public BackOfficeRequirement(bool requireApproval = true) => RequireApproval = requireApproval; + + /// + /// Gets a value indicating whether back-office user approval is required. + /// + public bool RequireApproval { get; } +}