v14: Merge NewBackOfficeSettings into SecuritySettings. (#15586)

* Merge NewBackOfficeSettings into SecuritySettings.

* Apply suggestions from code review

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>

* Remove hardcoded callback path

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
This commit is contained in:
Nikolaj Geisle
2024-01-17 13:26:09 +01:00
committed by GitHub
parent 547da0b191
commit 43791c2b33
9 changed files with 47 additions and 59 deletions

View File

@@ -2,8 +2,8 @@ using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.Configuration;
using Umbraco.Cms.Web.Common.ApplicationBuilder;
namespace Umbraco.Cms.Api.Management.DependencyInjection;
@@ -12,10 +12,9 @@ internal static class BackOfficeCorsPolicyBuilderExtensions
{
internal static IUmbracoBuilder AddCorsPolicy(this IUmbracoBuilder builder)
{
// FIXME: Get the correct settings once NewBackOfficeSettings is merged with relevant existing settings from Core
Uri? backOfficeHost = builder.Config
.GetSection($"{Constants.Configuration.ConfigPrefix}NewBackOffice")
.Get<NewBackOfficeSettings>()?.BackOfficeHost;
.GetSection(Constants.Configuration.ConfigSecurity)
.Get<SecuritySettings>()?.BackOfficeHost;
if (backOfficeHost is null)
{

View File

@@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Common.Configuration;
using Umbraco.Cms.Api.Common.DependencyInjection;
using Umbraco.Cms.Api.Management.Configuration;
@@ -8,7 +7,6 @@ using Umbraco.Cms.Api.Management.Serialization;
using Umbraco.Cms.Api.Management.Services;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models.Configuration;
using Umbraco.Cms.Web.Common.ApplicationBuilder;
namespace Umbraco.Extensions;
@@ -78,11 +76,6 @@ public static class UmbracoBuilderExtensions
applicationBuilder => { },
applicationBuilder => applicationBuilder.UseEndpoints()));
});
// FIXME: when this is moved to core, make the AddUmbracoOptions extension private again and remove core InternalsVisibleTo for Umbraco.Cms.Api.Management
builder.AddUmbracoOptions<NewBackOfficeSettings>();
// FIXME: remove this when NewBackOfficeSettings is moved to core
services.AddSingleton<IValidateOptions<NewBackOfficeSettings>, NewBackOfficeSettingsValidator>();
}
return builder;

View File

@@ -3,7 +3,7 @@ using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using OpenIddict.Abstractions;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models.Configuration;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Infrastructure.Security;
@@ -14,12 +14,12 @@ public class BackOfficeApplicationManager : OpenIdDictApplicationManagerBase, IB
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly IRuntimeState _runtimeState;
private readonly Uri? _backOfficeHost;
private readonly string? _authorizeCallbackPathName;
private readonly string _authorizeCallbackPathName;
public BackOfficeApplicationManager(
IOpenIddictApplicationManager applicationManager,
IWebHostEnvironment webHostEnvironment,
IOptions<NewBackOfficeSettings> securitySettings,
IOptions<SecuritySettings> securitySettings,
IRuntimeState runtimeState)
: base(applicationManager)
{
@@ -101,14 +101,14 @@ public class BackOfficeApplicationManager : OpenIdDictApplicationManagerBase, IB
ClientId = Constants.OAuthClientIds.BackOffice,
RedirectUris =
{
CallbackUrlFor(_backOfficeHost ?? backOfficeUrl, _authorizeCallbackPathName ?? "/umbraco")
CallbackUrlFor(_backOfficeHost ?? backOfficeUrl, _authorizeCallbackPathName)
},
Type = OpenIddictConstants.ClientTypes.Public,
PostLogoutRedirectUris =
{
CallbackUrlFor(_backOfficeHost ?? backOfficeUrl, _authorizeCallbackPathName ?? "/umbraco/login"),
CallbackUrlFor(_backOfficeHost ?? backOfficeUrl, _authorizeCallbackPathName + "/login"),
// FIXME: remove when we no longer use Umbraco.Web.UI project
CallbackUrlFor(_backOfficeHost ?? backOfficeUrl, _authorizeCallbackPathName ?? "/umbraco")
CallbackUrlFor(_backOfficeHost ?? backOfficeUrl, _authorizeCallbackPathName)
},
Permissions =
{

View File

@@ -25,6 +25,7 @@ public class SecuritySettings
internal const int StaticMemberDefaultLockoutTimeInMinutes = 30 * 24 * 60;
internal const int StaticUserDefaultLockoutTimeInMinutes = 30 * 24 * 60;
internal const string StaticAuthorizeCallbackPathName = "/umbraco";
/// <summary>
/// Gets or sets a value indicating whether to keep the user logged in.
@@ -116,4 +117,15 @@ public class SecuritySettings
/// </summary>
[DefaultValue(StaticAllowConcurrentLogins)]
public bool AllowConcurrentLogins { get; set; } = StaticAllowConcurrentLogins;
/// <summary>
/// Gets or sets a value of the back-office host URI. Use this when running the back-office client and the Management API on different hosts. Leave empty when running both on the same host.
/// </summary>
public Uri? BackOfficeHost { get; set; }
/// <summary>
/// The path to use for authorization callback. Will be appended to the BackOfficeHost.
/// </summary>
[DefaultValue(StaticAuthorizeCallbackPathName)]
public string AuthorizeCallbackPathName { get; set; } = StaticAuthorizeCallbackPathName;
}

View File

@@ -0,0 +1,24 @@
using Microsoft.Extensions.Options;
namespace Umbraco.Cms.Core.Configuration.Models.Validation;
public class SecuritySettingsValidator : ConfigurationValidatorBase, IValidateOptions<SecuritySettings>
{
public ValidateOptionsResult Validate(string? name, SecuritySettings options)
{
if (options.BackOfficeHost != null)
{
if (options.BackOfficeHost.IsAbsoluteUri == false)
{
return ValidateOptionsResult.Fail($"{nameof(SecuritySettings.BackOfficeHost)} must be an absolute URL");
}
if (options.BackOfficeHost.PathAndQuery != "/")
{
return ValidateOptionsResult.Fail($"{nameof(SecuritySettings.BackOfficeHost)} must not have any path or query");
}
}
return ValidateOptionsResult.Success;
}
}

View File

@@ -14,7 +14,7 @@ namespace Umbraco.Cms.Core.DependencyInjection;
/// </summary>
public static partial class UmbracoBuilderExtensions
{
internal static IUmbracoBuilder AddUmbracoOptions<TOptions>(this IUmbracoBuilder builder, Action<OptionsBuilder<TOptions>>? configure = null)
private static IUmbracoBuilder AddUmbracoOptions<TOptions>(this IUmbracoBuilder builder, Action<OptionsBuilder<TOptions>>? configure = null)
where TOptions : class
{
UmbracoOptionsAttribute? umbracoOptionsAttribute = typeof(TOptions).GetCustomAttribute<UmbracoOptionsAttribute>();
@@ -45,6 +45,7 @@ public static partial class UmbracoBuilderExtensions
builder.Services.AddSingleton<IValidateOptions<HealthChecksSettings>, HealthChecksSettingsValidator>();
builder.Services.AddSingleton<IValidateOptions<RequestHandlerSettings>, RequestHandlerSettingsValidator>();
builder.Services.AddSingleton<IValidateOptions<UnattendedSettings>, UnattendedSettingsValidator>();
builder.Services.AddSingleton<IValidateOptions<SecuritySettings>, SecuritySettingsValidator>();
// Register configuration sections.
builder

View File

@@ -1,12 +0,0 @@
using Umbraco.Cms.Core.Configuration.Models;
namespace Umbraco.Cms.Core.Models.Configuration;
// FIXME: merge this class with relevant existing settings from Core and clean up
[UmbracoOptions($"{Umbraco.Cms.Core.Constants.Configuration.ConfigPrefix}NewBackOffice")]
public class NewBackOfficeSettings
{
public Uri? BackOfficeHost { get; set; } = null;
public string? AuthorizeCallbackPathName { get; set; } = null;
}

View File

@@ -1,25 +0,0 @@
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Configuration.Models.Validation;
namespace Umbraco.Cms.Core.Models.Configuration;
// TODO: merge this class with relevant existing settings validators from Core and clean up
public class NewBackOfficeSettingsValidator : ConfigurationValidatorBase, IValidateOptions<NewBackOfficeSettings>
{
public ValidateOptionsResult Validate(string? name, NewBackOfficeSettings options)
{
if (options.BackOfficeHost != null)
{
if (options.BackOfficeHost.IsAbsoluteUri == false)
{
return ValidateOptionsResult.Fail($"{nameof(NewBackOfficeSettings.BackOfficeHost)} must be an absolute URL");
}
if (options.BackOfficeHost.PathAndQuery != "/")
{
return ValidateOptionsResult.Fail($"{nameof(NewBackOfficeSettings.BackOfficeHost)} must not have any path or query");
}
}
return ValidateOptionsResult.Success;
}
}

View File

@@ -38,10 +38,6 @@
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>DynamicProxyGenAssembly2</_Parameter1>
</AssemblyAttribute>
<!-- TODO: remove this when new backoffice config etc. can be moved to core -->
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Umbraco.Cms.Api.Management</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
<ItemGroup>