From a3ede677773d7a06625886c3b816f53d47d4a9fc Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Fri, 16 Aug 2024 09:29:03 +0200 Subject: [PATCH 1/7] bump version --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index f912de9385..e6cb0690c0 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", - "version": "14.1.1", + "version": "14.1.2", "assemblyVersion": { "precision": "build" }, From d0c76171dddd44d1373b3a7a782e7edd7e506a76 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 19 Aug 2024 15:05:02 +0200 Subject: [PATCH 2/7] Merge commit from fork * Use Debug Mode to determine content of the ProblemDetails * Cache the debug value --- .../ApplicationBuilderExtensions.cs | 7 ++++--- .../AspNetCore/AspNetCoreHostingEnvironment.cs | 16 ++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs index 9018b97bee..870c4d3e1e 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs @@ -33,6 +33,7 @@ internal static class ApplicationBuilderExtensions { innerBuilder.UseExceptionHandler(exceptionBuilder => exceptionBuilder.Run(async context => { + var isDebug = context.RequestServices.GetRequiredService().IsDebugMode; Exception? exception = context.Features.Get()?.Error; if (exception is null) { @@ -42,16 +43,16 @@ internal static class ApplicationBuilderExtensions var response = new ProblemDetails { Title = exception.Message, - Detail = exception.StackTrace, + Detail = isDebug ? exception.StackTrace : null, Status = StatusCodes.Status500InternalServerError, - Instance = exception.GetType().Name, + Instance = isDebug ? exception.GetType().Name : null, Type = "Error" }; await context.Response.WriteAsJsonAsync(response); })); }); - internal static IApplicationBuilder UseEndpoints(this IApplicationBuilder applicationBuilder) +internal static IApplicationBuilder UseEndpoints(this IApplicationBuilder applicationBuilder) { IServiceProvider provider = applicationBuilder.ApplicationServices; diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs index 8d471428de..324781b5a3 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs @@ -43,14 +43,14 @@ public class AspNetCoreHostingEnvironment : IHostingEnvironment _webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment)); _urlProviderMode = _webRoutingSettings.CurrentValue.UrlProviderMode; - SetSiteName(hostingSettings.CurrentValue.SiteName); + SetSiteNameAndDebugMode(hostingSettings.CurrentValue); // We have to ensure that the OptionsMonitor is an actual options monitor since we have a hack // where we initially use an OptionsMonitorAdapter, which doesn't implement OnChange. // See summery of OptionsMonitorAdapter for more information. if (hostingSettings is OptionsMonitor) { - hostingSettings.OnChange(settings => SetSiteName(settings.SiteName)); + hostingSettings.OnChange(settings => SetSiteNameAndDebugMode(settings)); } ApplicationPhysicalPath = webHostEnvironment.ContentRootPath; @@ -95,7 +95,7 @@ public class AspNetCoreHostingEnvironment : IHostingEnvironment _hostingSettings.CurrentValue.ApplicationVirtualPath?.EnsureStartsWith('/') ?? "/"; /// - public bool IsDebugMode => _hostingSettings.CurrentValue.Debug; + public bool IsDebugMode { get; private set; } public string LocalTempPath { @@ -188,8 +188,12 @@ public class AspNetCoreHostingEnvironment : IHostingEnvironment } } - private void SetSiteName(string? siteName) => - SiteName = string.IsNullOrWhiteSpace(siteName) + private void SetSiteNameAndDebugMode(HostingSettings hostingSettings) + { + SiteName = string.IsNullOrWhiteSpace(hostingSettings.SiteName) ? _webHostEnvironment.ApplicationName - : siteName; + : hostingSettings.SiteName; + + IsDebugMode = hostingSettings.Debug; + } } From 72bef8861d94a39d5cc9530a04c4797b91fcbecf Mon Sep 17 00:00:00 2001 From: Sven Geusens Date: Mon, 19 Aug 2024 15:04:08 +0200 Subject: [PATCH 3/7] 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; } +} From b76070c794925932cb159ef50b851db6e966a004 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 19 Aug 2024 15:05:02 +0200 Subject: [PATCH 4/7] Merge commit from fork * Use Debug Mode to determine content of the ProblemDetails * Cache the debug value --- .../ApplicationBuilderExtensions.cs | 7 ++++--- .../AspNetCore/AspNetCoreHostingEnvironment.cs | 16 ++++++++++------ 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs index 9018b97bee..870c4d3e1e 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/ApplicationBuilderExtensions.cs @@ -33,6 +33,7 @@ internal static class ApplicationBuilderExtensions { innerBuilder.UseExceptionHandler(exceptionBuilder => exceptionBuilder.Run(async context => { + var isDebug = context.RequestServices.GetRequiredService().IsDebugMode; Exception? exception = context.Features.Get()?.Error; if (exception is null) { @@ -42,16 +43,16 @@ internal static class ApplicationBuilderExtensions var response = new ProblemDetails { Title = exception.Message, - Detail = exception.StackTrace, + Detail = isDebug ? exception.StackTrace : null, Status = StatusCodes.Status500InternalServerError, - Instance = exception.GetType().Name, + Instance = isDebug ? exception.GetType().Name : null, Type = "Error" }; await context.Response.WriteAsJsonAsync(response); })); }); - internal static IApplicationBuilder UseEndpoints(this IApplicationBuilder applicationBuilder) +internal static IApplicationBuilder UseEndpoints(this IApplicationBuilder applicationBuilder) { IServiceProvider provider = applicationBuilder.ApplicationServices; diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs index 8d471428de..324781b5a3 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreHostingEnvironment.cs @@ -43,14 +43,14 @@ public class AspNetCoreHostingEnvironment : IHostingEnvironment _webHostEnvironment = webHostEnvironment ?? throw new ArgumentNullException(nameof(webHostEnvironment)); _urlProviderMode = _webRoutingSettings.CurrentValue.UrlProviderMode; - SetSiteName(hostingSettings.CurrentValue.SiteName); + SetSiteNameAndDebugMode(hostingSettings.CurrentValue); // We have to ensure that the OptionsMonitor is an actual options monitor since we have a hack // where we initially use an OptionsMonitorAdapter, which doesn't implement OnChange. // See summery of OptionsMonitorAdapter for more information. if (hostingSettings is OptionsMonitor) { - hostingSettings.OnChange(settings => SetSiteName(settings.SiteName)); + hostingSettings.OnChange(settings => SetSiteNameAndDebugMode(settings)); } ApplicationPhysicalPath = webHostEnvironment.ContentRootPath; @@ -95,7 +95,7 @@ public class AspNetCoreHostingEnvironment : IHostingEnvironment _hostingSettings.CurrentValue.ApplicationVirtualPath?.EnsureStartsWith('/') ?? "/"; /// - public bool IsDebugMode => _hostingSettings.CurrentValue.Debug; + public bool IsDebugMode { get; private set; } public string LocalTempPath { @@ -188,8 +188,12 @@ public class AspNetCoreHostingEnvironment : IHostingEnvironment } } - private void SetSiteName(string? siteName) => - SiteName = string.IsNullOrWhiteSpace(siteName) + private void SetSiteNameAndDebugMode(HostingSettings hostingSettings) + { + SiteName = string.IsNullOrWhiteSpace(hostingSettings.SiteName) ? _webHostEnvironment.ApplicationName - : siteName; + : hostingSettings.SiteName; + + IsDebugMode = hostingSettings.Debug; + } } From 1ff3858a9efcd847631df3380584f19d13a89582 Mon Sep 17 00:00:00 2001 From: leekelleher Date: Tue, 20 Aug 2024 09:56:00 +0100 Subject: [PATCH 5/7] update backoffice submodule --- src/Umbraco.Web.UI.Client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client b/src/Umbraco.Web.UI.Client index bb6abdc884..d52d9c70bf 160000 --- a/src/Umbraco.Web.UI.Client +++ b/src/Umbraco.Web.UI.Client @@ -1 +1 @@ -Subproject commit bb6abdc88452bbd3a47bf867dcb1332f536ad264 +Subproject commit d52d9c70bff68fab77412c539b99a0e91a9dbe7c From bf805a181ae27574c668d53683d48d0f3d8af0ea Mon Sep 17 00:00:00 2001 From: Nikolaj Geisle <70372949+Zeegaan@users.noreply.github.com> Date: Tue, 20 Aug 2024 12:54:19 +0200 Subject: [PATCH 6/7] Bump version --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 2d3aca5f9d..1cec93bcea 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", - "version": "14.2.0-rc3", + "version": "14.2.0", "assemblyVersion": { "precision": "build" }, From 1b21caa20ac98c6e7f54d7f325a64858646313f7 Mon Sep 17 00:00:00 2001 From: Sven Geusens Date: Thu, 22 Aug 2024 12:14:43 +0200 Subject: [PATCH 7/7] Update backoffice submodule with hotfix for breaking change that broke forms. --- src/Umbraco.Web.UI.Client | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client b/src/Umbraco.Web.UI.Client index d52d9c70bf..a9d3a43969 160000 --- a/src/Umbraco.Web.UI.Client +++ b/src/Umbraco.Web.UI.Client @@ -1 +1 @@ -Subproject commit d52d9c70bff68fab77412c539b99a0e91a9dbe7c +Subproject commit a9d3a4396968e4cc47c1d1cd290ca8b1cf764e12