diff --git a/Lombiq.Hosting.Tenants.Admin.Login/Controllers/TenantLoginController.cs b/Lombiq.Hosting.Tenants.Admin.Login/Controllers/TenantLoginController.cs index d7a7afc3..6f870e9a 100644 --- a/Lombiq.Hosting.Tenants.Admin.Login/Controllers/TenantLoginController.cs +++ b/Lombiq.Hosting.Tenants.Admin.Login/Controllers/TenantLoginController.cs @@ -67,8 +67,8 @@ public async Task Index(string password) return NotFound(); } - var sitesettings = await _siteService.LoadSiteSettingsAsync(); - var adminUser = await _userSignInManager.UserManager.FindByIdAsync(sitesettings.SuperUser); + var siteSettings = await _siteService.LoadSiteSettingsAsync(); + var adminUser = await _userSignInManager.UserManager.FindByIdAsync(siteSettings.SuperUser); adminUser ??= (await _userSignInManager.UserManager.GetUsersInRoleAsync(Administrator)).FirstOrDefault(); if (adminUser == null) diff --git a/Lombiq.Hosting.Tenants.Admin.Login/Filters/TenantsIndexFilter.cs b/Lombiq.Hosting.Tenants.Admin.Login/Filters/TenantsIndexFilter.cs index 99302312..b0066196 100644 --- a/Lombiq.Hosting.Tenants.Admin.Login/Filters/TenantsIndexFilter.cs +++ b/Lombiq.Hosting.Tenants.Admin.Login/Filters/TenantsIndexFilter.cs @@ -38,18 +38,11 @@ public TenantsIndexFilter( public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) { - var actionRouteController = context.ActionDescriptor.RouteValues["Controller"]; - var actionRouteArea = context.ActionDescriptor.RouteValues["Area"]; - var actionRouteValue = context.ActionDescriptor.RouteValues["Action"]; - - if (actionRouteController == typeof(AdminController).ControllerName() && - actionRouteArea == $"{nameof(OrchardCore)}.{nameof(OrchardCore.Tenants)}" && - actionRouteValue is nameof(AdminController.Edit) && + if (IsTenantsEditAction(context) && context.Result is ViewResult && await _authorizationService.AuthorizeAsync( _hca.HttpContext.User, - TenantAdminPermissions.LoginAsAdmin) - ) + TenantAdminPermissions.LoginAsAdmin)) { var shellSettings = _shellHost.GetSettings(context.RouteData.Values["Id"].ToString()); if (shellSettings != null && @@ -70,4 +63,9 @@ await contentZone.AddAsync( await next(); } + + public static bool IsTenantsEditAction(ActionContext context) => + context.ActionDescriptor.RouteValues["Controller"] == typeof(AdminController).ControllerName() && + context.ActionDescriptor.RouteValues["Area"] == $"{nameof(OrchardCore)}.{nameof(OrchardCore.Tenants)}" && + context.ActionDescriptor.RouteValues["Action"] is nameof(AdminController.Edit); } diff --git a/Lombiq.Hosting.Tenants.Admin.Login/Services/TenantLoginSecurityPolicyProvider.cs b/Lombiq.Hosting.Tenants.Admin.Login/Services/TenantLoginSecurityPolicyProvider.cs new file mode 100644 index 00000000..e7434add --- /dev/null +++ b/Lombiq.Hosting.Tenants.Admin.Login/Services/TenantLoginSecurityPolicyProvider.cs @@ -0,0 +1,40 @@ +using Lombiq.HelpfulLibraries.AspNetCore.Security; +using Lombiq.Hosting.Tenants.Admin.Login.Filters; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using OrchardCore.Environment.Shell; +using System.Collections.Generic; +using System.Threading.Tasks; + +namespace Lombiq.Hosting.Tenants.Admin.Login.Services; + +internal sealed class TenantLoginSecurityPolicyProvider : IContentSecurityPolicyProvider +{ + private readonly IActionContextAccessor _actionContextAccessor; + private readonly IShellHost _shellHost; + + public TenantLoginSecurityPolicyProvider(IActionContextAccessor actionContextAccessor, IShellHost shellHost) + { + _actionContextAccessor = actionContextAccessor; + _shellHost = shellHost; + } + + public ValueTask UpdateAsync(IDictionary securityPolicies, HttpContext context) + { + var actionContext = _actionContextAccessor.ActionContext; + + if (!TenantsIndexFilter.IsTenantsEditAction(actionContext)) + { + return ValueTask.CompletedTask; + } + + var shellName = actionContext.RouteData.Values["Id"].ToString(); + + if (_shellHost.TryGetSettings(shellName, out var shellSettings)) + { + CspHelper.MergeValues(securityPolicies, ContentSecurityPolicyDirectives.FormAction, shellSettings.RequestUrlHosts); + } + + return ValueTask.CompletedTask; + } +} diff --git a/Lombiq.Hosting.Tenants.Admin.Login/Startup.cs b/Lombiq.Hosting.Tenants.Admin.Login/Startup.cs index 37d28b21..bc7a4b6f 100644 --- a/Lombiq.Hosting.Tenants.Admin.Login/Startup.cs +++ b/Lombiq.Hosting.Tenants.Admin.Login/Startup.cs @@ -17,5 +17,6 @@ public override void ConfigureServices(IServiceCollection services) services.Configure(options => options.Filters.Add(typeof(TenantsIndexFilter))); services.AddScoped(); services.AddSingleton(); + services.AddContentSecurityPolicyProvider(); } } diff --git a/Lombiq.Hosting.Tenants.Management/Controllers/ShellSettingsEditorController.cs b/Lombiq.Hosting.Tenants.Management/Controllers/ShellSettingsEditorController.cs index b765382b..025d34ef 100644 --- a/Lombiq.Hosting.Tenants.Management/Controllers/ShellSettingsEditorController.cs +++ b/Lombiq.Hosting.Tenants.Management/Controllers/ShellSettingsEditorController.cs @@ -1,6 +1,6 @@ using Lombiq.Hosting.Tenants.Management.Constants; using Lombiq.Hosting.Tenants.Management.Models; -using Lombiq.Hosting.Tenants.Management.Service; +using Lombiq.Hosting.Tenants.Management.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Localization; diff --git a/Lombiq.Hosting.Tenants.Management/Service/JsonConfigurationParser.cs b/Lombiq.Hosting.Tenants.Management/Services/JsonConfigurationParser.cs similarity index 95% rename from Lombiq.Hosting.Tenants.Management/Service/JsonConfigurationParser.cs rename to Lombiq.Hosting.Tenants.Management/Services/JsonConfigurationParser.cs index 4acae3a0..293d72f3 100644 --- a/Lombiq.Hosting.Tenants.Management/Service/JsonConfigurationParser.cs +++ b/Lombiq.Hosting.Tenants.Management/Services/JsonConfigurationParser.cs @@ -1,4 +1,4 @@ -// This file is a copy and slight modification of Microsoft.Extensions.Configuration.Json.JsonConfigurationFileParser +// This file is a copy and slight modification of Microsoft.Extensions.Configuration.Json.JsonConfigurationFileParser // https://github.com/dotnet/runtime/blob/main/src/libraries/Microsoft.Extensions.Configuration.Json/src/JsonConfigurationFileParser.cs. // Their recommended way of using this class is to copy it: https://github.com/dotnet/runtime/issues/73946. using Microsoft.Extensions.Configuration; @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Text.Json; -namespace Lombiq.Hosting.Tenants.Management.Service; +namespace Lombiq.Hosting.Tenants.Management.Services; public class JsonConfigurationParser { diff --git a/Lombiq.Hosting.Tenants.Management/Service/SetupWithRecipesFilterService.cs b/Lombiq.Hosting.Tenants.Management/Services/SetupWithRecipesFilterService.cs similarity index 97% rename from Lombiq.Hosting.Tenants.Management/Service/SetupWithRecipesFilterService.cs rename to Lombiq.Hosting.Tenants.Management/Services/SetupWithRecipesFilterService.cs index 5e41a207..1abe8563 100644 --- a/Lombiq.Hosting.Tenants.Management/Service/SetupWithRecipesFilterService.cs +++ b/Lombiq.Hosting.Tenants.Management/Services/SetupWithRecipesFilterService.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Threading.Tasks; -namespace Lombiq.Hosting.Tenants.Management.Service; +namespace Lombiq.Hosting.Tenants.Management.Services; public class SetupWithRecipesFilterService : ISetupService { diff --git a/Lombiq.Hosting.Tenants.Management/Startup.cs b/Lombiq.Hosting.Tenants.Management/Startup.cs index 4547afbe..37009913 100644 --- a/Lombiq.Hosting.Tenants.Management/Startup.cs +++ b/Lombiq.Hosting.Tenants.Management/Startup.cs @@ -1,6 +1,6 @@ using Lombiq.Hosting.Tenants.Management.Constants; using Lombiq.Hosting.Tenants.Management.Filters; -using Lombiq.Hosting.Tenants.Management.Service; +using Lombiq.Hosting.Tenants.Management.Services; using Lombiq.Hosting.Tenants.Management.Settings; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration;