feat(auth): cut ScadaBridge over to ZB.MOM.WW.Auth.Ldap; nest+rename Ldap config; roles+sitescope via IGroupRoleMapper (Task 1.2/1.4)

This commit is contained in:
Joseph Doherty
2026-06-02 01:04:34 -04:00
parent 9230afa25f
commit ac34dac479
31 changed files with 647 additions and 1132 deletions
@@ -122,6 +122,49 @@ public class ScadaBridgeGroupRoleMapperTests
Assert.True(scope.IsSystemWideDeployment);
Assert.Empty(scope.PermittedSiteIds);
}
[Fact]
public async Task MapAsync_EmptyGroups_ReturnsNoRoles_AndNonNullScope()
{
// Reviewer-requested empty-groups case (Task 1.2): a user that resolves to NO
// groups must map to NO roles and a non-null, not-system-wide Scope with no
// permitted sites — so the login endpoint can build a roleless principal (which
// every authorization policy then denies) without NRE-ing on Scope. This is the
// post-cutover home for the donor's "no mapped groups" outcome, now that the
// shared LDAP service fail-closes a zero-GROUP LDAP result before it ever reaches
// the mapper.
var repo = new FakeSecurityRepository(
new List<LdapGroupMapping> { Mapping(1, "SCADA-Admins", Roles.Admin) },
new Dictionary<int, IReadOnlyList<SiteScopeRule>>());
var sut = new ScadaBridgeGroupRoleMapper(new RoleMapper(repo));
var mapping = await sut.MapAsync(Array.Empty<string>(), CancellationToken.None);
Assert.Empty(mapping.Roles);
var scope = Assert.IsType<RoleMappingResult>(mapping.Scope);
Assert.Empty(scope.Roles);
Assert.False(scope.IsSystemWideDeployment);
Assert.Empty(scope.PermittedSiteIds);
}
[Fact]
public async Task MapAsync_GroupsMatchNoMapping_ReturnsNoRoles()
{
// A user WITH groups that match no configured LDAP-group→role mapping likewise
// yields zero roles (not an error) — the mapper is the authoritative empty-roles
// boundary now that the LDAP service no longer admits zero-group successes.
var repo = new FakeSecurityRepository(
new List<LdapGroupMapping> { Mapping(1, "SCADA-Admins", Roles.Admin) },
new Dictionary<int, IReadOnlyList<SiteScopeRule>>());
var sut = new ScadaBridgeGroupRoleMapper(new RoleMapper(repo));
var mapping = await sut.MapAsync(new[] { "some-unmapped-group" }, CancellationToken.None);
Assert.Empty(mapping.Roles);
var scope = Assert.IsType<RoleMappingResult>(mapping.Scope);
Assert.Empty(scope.PermittedSiteIds);
Assert.False(scope.IsSystemWideDeployment);
}
}
#endregion