using System.Text.Encodings.Web; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Security.Auth; namespace ZB.MOM.WW.OtOpcUa.Security.Tests; public class AutoLoginAuthenticationHandlerTests { private static async Task AuthenticateAsync(string user = "multi-role-test") { var schemeOpts = new StubOptionsMonitor(new AuthenticationSchemeOptions()); var disableOpts = Options.Create(new AuthDisableLoginOptions { DisableLogin = true, User = user }); var handler = new AutoLoginAuthenticationHandler( schemeOpts, NullLoggerFactory.Instance, UrlEncoder.Default, disableOpts); await handler.InitializeAsync( new AuthenticationScheme( CookieAuthenticationDefaults.AuthenticationScheme, null, typeof(AutoLoginAuthenticationHandler)), new DefaultHttpContext()); return await handler.AuthenticateAsync(); } [Fact] public async Task Authenticates_as_configured_user_with_all_roles() { var result = await AuthenticateAsync(); result.Succeeded.ShouldBeTrue(); result.Principal!.Identity!.IsAuthenticated.ShouldBeTrue(); result.Principal.Identity.Name.ShouldBe("multi-role-test"); foreach (var role in DevAuthRoles.All) result.Principal.IsInRole(role).ShouldBeTrue(); // Satisfies the FleetAdmin (Administrator) + DriverOperator (Operator|Administrator) policies. result.Principal.IsInRole("Administrator").ShouldBeTrue(); result.Principal.IsInRole("Operator").ShouldBeTrue(); } [Fact] public async Task Honours_configured_username() { var result = await AuthenticateAsync("custom-dev"); result.Principal!.Identity!.Name.ShouldBe("custom-dev"); } /// /// Minimal stub returning a fixed value for any /// name. The test project does not reference Moq, so the scheme-options monitor the base /// needs is hand-rolled here. /// private sealed class StubOptionsMonitor(T value) : IOptionsMonitor { public T CurrentValue { get; } = value; public T Get(string? name) => CurrentValue; public IDisposable? OnChange(Action listener) => null; } }