Introduced IBasicAuthService
This commit is contained in:
@@ -46,6 +46,7 @@ namespace JsonSchema
|
||||
public UnattendedSettings Unattended { get; set; }
|
||||
public RichTextEditorSettings RichTextEditor { get; set; }
|
||||
public RuntimeMinificationSettings RuntimeMinification { get; set; }
|
||||
public BasicAuthSettings BasicAuth { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
33
src/Umbraco.Core/Services/BasicAuthService.cs
Normal file
33
src/Umbraco.Core/Services/BasicAuthService.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Net;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
public class BasicAuthService : IBasicAuthService
|
||||
{
|
||||
private BasicAuthSettings _basicAuthSettings;
|
||||
|
||||
public BasicAuthService(IOptionsMonitor<BasicAuthSettings> optionsMonitor)
|
||||
{
|
||||
_basicAuthSettings = optionsMonitor.CurrentValue;
|
||||
|
||||
optionsMonitor.OnChange(basicAuthSettings => _basicAuthSettings = basicAuthSettings);
|
||||
}
|
||||
|
||||
public bool IsBasicAuthEnabled() => _basicAuthSettings.Enabled;
|
||||
|
||||
public bool IsIpAllowListed(IPAddress clientIpAddress)
|
||||
{
|
||||
foreach (var allowedIpString in _basicAuthSettings.AllowedIPs)
|
||||
{
|
||||
if(IPAddress.TryParse(allowedIpString, out var allowedIp) && clientIpAddress.Equals(allowedIp))
|
||||
{
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
src/Umbraco.Core/Services/IBasicAuthService.cs
Normal file
10
src/Umbraco.Core/Services/IBasicAuthService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Net;
|
||||
|
||||
namespace Umbraco.Cms.Core.Services
|
||||
{
|
||||
public interface IBasicAuthService
|
||||
{
|
||||
bool IsBasicAuthEnabled();
|
||||
bool IsIpAllowListed(IPAddress clientIpAddress);
|
||||
}
|
||||
}
|
||||
@@ -40,6 +40,7 @@ namespace Umbraco.Cms.Infrastructure.DependencyInjection
|
||||
builder.Services.AddUnique<IDomainService, DomainService>();
|
||||
builder.Services.AddUnique<IAuditService, AuditService>();
|
||||
builder.Services.AddUnique<ICacheInstructionService, CacheInstructionService>();
|
||||
builder.Services.AddUnique<IBasicAuthService, BasicAuthService>();
|
||||
builder.Services.AddUnique<ITagService, TagService>();
|
||||
builder.Services.AddUnique<IContentService, ContentService>();
|
||||
builder.Services.AddUnique<IUserService, UserService>();
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Services
|
||||
{
|
||||
[TestFixture]
|
||||
public class BasicAuthServiceTests
|
||||
{
|
||||
[TestCase(true, ExpectedResult = true)]
|
||||
[TestCase(false, ExpectedResult = false)]
|
||||
public bool IsBasicAuthEnabled(bool enabled)
|
||||
{
|
||||
var sut = new BasicAuthService(Mock.Of<IOptionsMonitor<BasicAuthSettings>>(_ => _.CurrentValue == new BasicAuthSettings() {Enabled = enabled}));
|
||||
|
||||
return sut.IsBasicAuthEnabled();
|
||||
}
|
||||
|
||||
[TestCase("::1", "1.1.1.1", ExpectedResult = false)]
|
||||
[TestCase("::1", "1.1.1.1, ::1", ExpectedResult = true)]
|
||||
[TestCase("127.0.0.1", "127.0.0.1, ::1", ExpectedResult = true)]
|
||||
[TestCase("127.0.0.1", "", ExpectedResult = false)]
|
||||
public bool IsBasicAuthEnabled(string clientIpAddress, string commaSeperatedAllowlist)
|
||||
{
|
||||
var allowedIPs = commaSeperatedAllowlist.Split(",").Select(x=>x.Trim()).ToArray();
|
||||
var sut = new BasicAuthService(Mock.Of<IOptionsMonitor<BasicAuthSettings>>(_ => _.CurrentValue == new BasicAuthSettings() {AllowedIPs = allowedIPs}));
|
||||
|
||||
return sut.IsIpAllowListed(IPAddress.Parse(clientIpAddress));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security
|
||||
var mgr = new BackOfficeCookieManager(
|
||||
Mock.Of<IUmbracoContextAccessor>(),
|
||||
runtime,
|
||||
new UmbracoRequestPaths(Options.Create(globalSettings), TestHelper.GetHostingEnvironment()));
|
||||
new UmbracoRequestPaths(Options.Create(globalSettings), TestHelper.GetHostingEnvironment()),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest("/umbraco");
|
||||
|
||||
@@ -48,7 +49,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security
|
||||
runtime,
|
||||
new UmbracoRequestPaths(
|
||||
Options.Create(globalSettings),
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco")));
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco")),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest("/umbraco");
|
||||
|
||||
@@ -69,7 +71,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security
|
||||
runtime,
|
||||
new UmbracoRequestPaths(
|
||||
Options.Create(globalSettings),
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")));
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest(remainingTimeoutSecondsPath);
|
||||
Assert.IsTrue(result);
|
||||
@@ -90,7 +93,8 @@ namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Web.BackOffice.Security
|
||||
runtime,
|
||||
new UmbracoRequestPaths(
|
||||
Options.Create(globalSettings),
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")));
|
||||
Mock.Of<IHostingEnvironment>(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")),
|
||||
Mock.Of<IBasicAuthService>());
|
||||
|
||||
var result = mgr.ShouldAuthenticateRequest("/notbackoffice");
|
||||
Assert.IsFalse(result);
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Web.BackOffice.Security;
|
||||
using Umbraco.Extensions;
|
||||
@@ -22,32 +18,28 @@ namespace Umbraco.Cms.Web.Common.Middleware
|
||||
/// </summary>
|
||||
public class BasicAuthAuthenticationMiddleware : IMiddleware
|
||||
{
|
||||
private readonly ILogger<BasicAuthAuthenticationMiddleware> _logger;
|
||||
private readonly IOptionsSnapshot<BasicAuthSettings> _basicAuthSettings;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly IBasicAuthService _basicAuthService;
|
||||
|
||||
public BasicAuthAuthenticationMiddleware(
|
||||
ILogger<BasicAuthAuthenticationMiddleware> logger,
|
||||
IOptionsSnapshot<BasicAuthSettings> basicAuthSettings,
|
||||
IRuntimeState runtimeState)
|
||||
IRuntimeState runtimeState,
|
||||
IBasicAuthService basicAuthService)
|
||||
{
|
||||
_logger = logger;
|
||||
_basicAuthSettings = basicAuthSettings;
|
||||
_runtimeState = runtimeState;
|
||||
_basicAuthService = basicAuthService;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task InvokeAsync(HttpContext context, RequestDelegate next)
|
||||
{
|
||||
var options = _basicAuthSettings.Value;
|
||||
if (!options.Enabled || _runtimeState.Level < RuntimeLevel.Run)
|
||||
if (_runtimeState.Level < RuntimeLevel.Run || !_basicAuthService.IsBasicAuthEnabled())
|
||||
{
|
||||
await next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
var clientIPAddress = context.Connection.RemoteIpAddress;
|
||||
if (IsIpAllowListed(clientIPAddress, options.AllowedIPs))
|
||||
if (_basicAuthService.IsIpAllowListed(clientIPAddress))
|
||||
{
|
||||
await next(context);
|
||||
return;
|
||||
@@ -98,18 +90,7 @@ namespace Umbraco.Cms.Web.Common.Middleware
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsIpAllowListed(IPAddress clientIpAddress, string[] allowlist)
|
||||
{
|
||||
foreach (var allowedIpString in allowlist)
|
||||
{
|
||||
if(IPAddress.TryParse(allowedIpString, out var allowedIp) && clientIpAddress.Equals(allowedIp))
|
||||
{
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void SetUnauthorizedHeader(HttpContext context)
|
||||
{
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
private readonly IRuntimeState _runtime;
|
||||
private readonly string[] _explicitPaths;
|
||||
private readonly UmbracoRequestPaths _umbracoRequestPaths;
|
||||
private readonly IOptionsMonitor<BasicAuthSettings> _basicAuthSettingsMonitor;
|
||||
private readonly IBasicAuthService _basicAuthService;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BackOfficeCookieManager"/> class.
|
||||
@@ -34,8 +34,8 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
IRuntimeState runtime,
|
||||
UmbracoRequestPaths umbracoRequestPaths,
|
||||
IOptionsMonitor<BasicAuthSettings> basicAuthSettings)
|
||||
: this(umbracoContextAccessor, runtime, null, umbracoRequestPaths, basicAuthSettings)
|
||||
IBasicAuthService basicAuthService)
|
||||
: this(umbracoContextAccessor, runtime, null, umbracoRequestPaths, basicAuthService)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -47,13 +47,13 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
IRuntimeState runtime,
|
||||
IEnumerable<string> explicitPaths,
|
||||
UmbracoRequestPaths umbracoRequestPaths,
|
||||
IOptionsMonitor<BasicAuthSettings> basicAuthSettingsMonitor)
|
||||
IBasicAuthService basicAuthService)
|
||||
{
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_runtime = runtime;
|
||||
_explicitPaths = explicitPaths?.ToArray();
|
||||
_umbracoRequestPaths = umbracoRequestPaths;
|
||||
_basicAuthSettingsMonitor = basicAuthSettingsMonitor;
|
||||
_basicAuthService = basicAuthService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -94,7 +94,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_basicAuthSettingsMonitor.CurrentValue.Enabled)
|
||||
if (_basicAuthService.IsBasicAuthEnabled())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
private readonly IIpResolver _ipResolver;
|
||||
private readonly ISystemClock _systemClock;
|
||||
private readonly UmbracoRequestPaths _umbracoRequestPaths;
|
||||
private readonly IBasicAuthService _basicAuthService;
|
||||
private readonly IOptionsMonitor<BasicAuthSettings> _optionsSnapshot;
|
||||
|
||||
/// <summary>
|
||||
@@ -61,7 +62,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
IIpResolver ipResolver,
|
||||
ISystemClock systemClock,
|
||||
UmbracoRequestPaths umbracoRequestPaths,
|
||||
IOptionsMonitor<BasicAuthSettings> optionsSnapshot)
|
||||
IBasicAuthService basicAuthService)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
@@ -74,7 +75,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
_ipResolver = ipResolver;
|
||||
_systemClock = systemClock;
|
||||
_umbracoRequestPaths = umbracoRequestPaths;
|
||||
_optionsSnapshot = optionsSnapshot;
|
||||
_basicAuthService = basicAuthService;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -119,7 +120,7 @@ namespace Umbraco.Cms.Web.BackOffice.Security
|
||||
_umbracoContextAccessor,
|
||||
_runtimeState,
|
||||
_umbracoRequestPaths,
|
||||
_optionsSnapshot
|
||||
_basicAuthService
|
||||
);
|
||||
|
||||
options.Events = new CookieAuthenticationEvents
|
||||
|
||||
Reference in New Issue
Block a user