Resolve all high-severity architecture review findings
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using ZB.MOM.WW.ScadaBridge.CentralUI.Services;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services;
|
||||
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
using NSubstitute;
|
||||
using ZB.MOM.WW.Auth.Abstractions.Roles;
|
||||
using ZB.MOM.WW.ScadaBridge.CentralUI.Auth;
|
||||
using ZB.MOM.WW.ScadaBridge.Security;
|
||||
|
||||
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Auth;
|
||||
|
||||
public class CircuitRevocationRegressionTests
|
||||
{
|
||||
[Fact]
|
||||
public async Task ExplicitServerAutoLogin_DoesNotRemapSyntheticCookiePrincipal()
|
||||
{
|
||||
var initial = SessionClaimBuilder.Build("developer", "Developer", [],
|
||||
new RoleMappingResult(Roles.All, [], true), DateTimeOffset.UtcNow);
|
||||
var mapper = Substitute.For<IGroupRoleMapper<string>>();
|
||||
mapper.MapAsync(Arg.Any<IReadOnlyList<string>>(), Arg.Any<CancellationToken>())
|
||||
.Returns(new GroupRoleMapping<string>([], Scope: new RoleMappingResult([], [], false)));
|
||||
var services = new ServiceCollection().AddLogging();
|
||||
services.AddSingleton(mapper);
|
||||
services.AddSingleton<TimeProvider>(TimeProvider.System);
|
||||
services.AddSingleton(Options.Create(new SecurityOptions()));
|
||||
services.AddSingleton(Options.Create(new ZB.MOM.WW.ScadaBridge.Security.Auth.AuthDisableLoginOptions { DisableLogin = true }));
|
||||
services.AddScoped<CookieSessionValidator>();
|
||||
services.AddSingleton<IHttpContextAccessor>(new HttpContextAccessor { HttpContext = new DefaultHttpContext { User = initial } });
|
||||
services.AddScoped<AuthenticationStateProvider, CookieAuthenticationStateProvider>();
|
||||
using var provider = services.BuildServiceProvider();
|
||||
using var scope = provider.CreateScope();
|
||||
var auth = scope.ServiceProvider.GetRequiredService<AuthenticationStateProvider>();
|
||||
var state = await auth.GetAuthoritativeStateAsync();
|
||||
Assert.Contains(state.User.Claims, claim => claim.Type == JwtTokenService.RoleClaimType && claim.Value == Roles.Administrator);
|
||||
await mapper.DidNotReceive().MapAsync(Arg.Any<IReadOnlyList<string>>(), Arg.Any<CancellationToken>());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task SameCircuit_RechecksMappingAndScope_AfterGrantRevocation()
|
||||
{
|
||||
var mapping = new RoleMappingResult([Roles.Deployer, Roles.Administrator], ["1"], false);
|
||||
var mapper = Substitute.For<IGroupRoleMapper<string>>();
|
||||
mapper.MapAsync(Arg.Any<IReadOnlyList<string>>(), Arg.Any<CancellationToken>())
|
||||
.Returns(_ => new GroupRoleMapping<string>(mapping.Roles, Scope: mapping));
|
||||
var initial = SessionClaimBuilder.Build("alice", "Alice", ["group"], mapping, DateTimeOffset.UtcNow);
|
||||
var services = new ServiceCollection().AddLogging();
|
||||
services.AddSingleton(mapper);
|
||||
var transaction = Substitute.For<IConfigurationCommandTransaction>();
|
||||
services.AddSingleton(transaction);
|
||||
services.AddScoped<ConfigurationCommandService>();
|
||||
services.AddSingleton<TimeProvider>(TimeProvider.System);
|
||||
services.AddSingleton(Options.Create(new SecurityOptions()));
|
||||
services.AddScoped<CookieSessionValidator>();
|
||||
services.AddSingleton<IHttpContextAccessor>(new HttpContextAccessor { HttpContext = new DefaultHttpContext { User = initial } });
|
||||
services.AddScoped<AuthenticationStateProvider, CookieAuthenticationStateProvider>();
|
||||
using var provider = services.BuildServiceProvider();
|
||||
using var scope = provider.CreateScope();
|
||||
var auth = scope.ServiceProvider.GetRequiredService<AuthenticationStateProvider>();
|
||||
var sites = new SiteScopeService(auth);
|
||||
Assert.True(await sites.IsSiteAllowedAsync(1));
|
||||
mapping = new RoleMappingResult([Roles.Viewer], ["2"], false);
|
||||
var refreshed = await auth.GetAuthenticationStateAsync();
|
||||
Assert.DoesNotContain(Roles.Deployer, refreshed.User.FindAll(JwtTokenService.RoleClaimType).Select(c => c.Value));
|
||||
Assert.False(await sites.IsSiteAllowedAsync(1));
|
||||
Assert.True(await sites.IsSiteAllowedAsync(2));
|
||||
// The already-created circuit facade must deny before starting any save transaction.
|
||||
var commands = scope.ServiceProvider.GetRequiredService<ConfigurationCommandService>();
|
||||
await Assert.ThrowsAsync<UnauthorizedAccessException>(() => commands.ExecuteAsync(new CreateRoleMappingCommand("blocked", Roles.Viewer)));
|
||||
await transaction.DidNotReceive().ExecuteAsync(Arg.Any<Func<IServiceProvider, Task<object?>>>());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user