feat(security): wire Security:Auth:DisableLogin into AddOtOpcUaAuth
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
@@ -11,6 +12,7 @@ using ZB.MOM.WW.Auth.AspNetCore;
|
||||
using ZB.MOM.WW.Auth.Abstractions.Roles;
|
||||
using ZB.MOM.WW.OtOpcUa.Configuration;
|
||||
using ZB.MOM.WW.OtOpcUa.Security.Audit;
|
||||
using ZB.MOM.WW.OtOpcUa.Security.Auth;
|
||||
using ZB.MOM.WW.OtOpcUa.Security.Jwt;
|
||||
using ZB.MOM.WW.OtOpcUa.Security.Ldap;
|
||||
|
||||
@@ -36,6 +38,7 @@ public static class ServiceCollectionExtensions
|
||||
services.AddOptions<JwtOptions>().Bind(configuration.GetSection(JwtOptions.SectionName));
|
||||
services.AddOptions<OtOpcUaCookieOptions>().Bind(configuration.GetSection(OtOpcUaCookieOptions.SectionName));
|
||||
services.AddOptions<LdapOptions>().Bind(configuration.GetSection(LdapOptions.SectionName));
|
||||
services.AddOptions<AuthDisableLoginOptions>().Bind(configuration.GetSection(AuthDisableLoginOptions.SectionName));
|
||||
|
||||
services.AddSingleton<JwtTokenService>();
|
||||
|
||||
@@ -69,8 +72,32 @@ public static class ServiceCollectionExtensions
|
||||
.PersistKeysToDbContext<OtOpcUaConfigDbContext>()
|
||||
.SetApplicationName("OtOpcUa");
|
||||
|
||||
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
|
||||
.AddCookie(o =>
|
||||
var disableLogin = configuration
|
||||
.GetSection(AuthDisableLoginOptions.SectionName)
|
||||
.GetValue<bool>(nameof(AuthDisableLoginOptions.DisableLogin));
|
||||
|
||||
var authBuilder = services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
if (disableLogin)
|
||||
{
|
||||
// DEV/TEST ONLY: replace the cookie handler with an always-succeeding handler registered
|
||||
// UNDER the cookie scheme name, so FallbackPolicy + FleetAdmin + DriverOperator (which all
|
||||
// name this scheme) authenticate through it and pass with all roles — zero policy changes.
|
||||
authBuilder.AddScheme<AuthenticationSchemeOptions, AutoLoginAuthenticationHandler>(
|
||||
CookieAuthenticationDefaults.AuthenticationScheme, _ => { });
|
||||
|
||||
// Loud, once-at-first-resolve warning (mirrors the cookie RequireHttps warning idiom below).
|
||||
services.AddOptions<AuthDisableLoginOptions>()
|
||||
.PostConfigure<ILoggerFactory>((opts, lf) =>
|
||||
{
|
||||
lf.CreateLogger("ZB.MOM.WW.OtOpcUa.Security").LogWarning(
|
||||
"AdminUI LOGIN DISABLED (Security:Auth:DisableLogin=true) — every request is " +
|
||||
"authenticated as '{User}' with FULL permissions ({Roles}). Dev/test only; never " +
|
||||
"enable in production.", opts.User, string.Join(",", DevAuthRoles.All));
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
authBuilder.AddCookie(o =>
|
||||
{
|
||||
// Static fields only — Name / ExpireTimeSpan / SecurePolicy / SlidingExpiration /
|
||||
// HttpOnly / SameSite are applied from OtOpcUaCookieOptions via ZbCookieDefaults
|
||||
@@ -80,6 +107,7 @@ public static class ServiceCollectionExtensions
|
||||
// No OnRedirectToLogin / OnRedirectToAccessDenied overrides — let the framework's
|
||||
// built-in IsAjaxRequest heuristic do its thing (302 for browsers, 401 for AJAX).
|
||||
});
|
||||
}
|
||||
|
||||
// Externalised cookie config — mirrors ScadaBridge's PostConfigure pattern. Fixes a
|
||||
// pre-existing latent bug where OtOpcUaCookieOptions was bound but ignored.
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Security;
|
||||
using ZB.MOM.WW.OtOpcUa.Security.Auth;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Security.Tests;
|
||||
|
||||
public class AddOtOpcUaAuthWiringTests
|
||||
{
|
||||
private static async Task<Type> CookieHandlerTypeAsync(bool disableLogin)
|
||||
{
|
||||
var config = new ConfigurationBuilder().AddInMemoryCollection(new Dictionary<string, string?>
|
||||
{
|
||||
["Security:Auth:DisableLogin"] = disableLogin ? "true" : "false",
|
||||
}).Build();
|
||||
|
||||
var services = new ServiceCollection();
|
||||
services.AddLogging();
|
||||
services.AddOtOpcUaAuth(config);
|
||||
|
||||
await using var sp = services.BuildServiceProvider();
|
||||
var provider = sp.GetRequiredService<IAuthenticationSchemeProvider>();
|
||||
var scheme = await provider.GetSchemeAsync(CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
return scheme!.HandlerType;
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task DisableLogin_true_registers_autologin_handler_for_cookie_scheme()
|
||||
=> (await CookieHandlerTypeAsync(true)).ShouldBe(typeof(AutoLoginAuthenticationHandler));
|
||||
|
||||
[Fact]
|
||||
public async Task DisableLogin_false_registers_cookie_handler()
|
||||
=> (await CookieHandlerTypeAsync(false)).ShouldBe(typeof(CookieAuthenticationHandler));
|
||||
}
|
||||
Reference in New Issue
Block a user