feat(auth): cut OtOpcUa over to ZB.MOM.WW.Auth.Ldap; preserve DevStubMode; route roles via IGroupRoleMapper (Task 1.2/1.4)
This commit is contained in:
@@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using ZB.MOM.WW.OtOpcUa.Configuration.Services;
|
||||
using ZB.MOM.WW.Auth.Abstractions.Roles;
|
||||
using ZB.MOM.WW.OtOpcUa.Security.Jwt;
|
||||
using ZB.MOM.WW.OtOpcUa.Security.Ldap;
|
||||
|
||||
@@ -43,7 +43,7 @@ public static class AuthEndpoints
|
||||
private static async Task<IResult> LoginAsync(
|
||||
HttpContext http,
|
||||
ILdapAuthService ldap,
|
||||
ILdapGroupRoleMappingService roleMappings,
|
||||
IGroupRoleMapper<string> roleMapper,
|
||||
CancellationToken ct)
|
||||
{
|
||||
var isForm = http.Request.HasFormContentType;
|
||||
@@ -87,18 +87,25 @@ public static class AuthEndpoints
|
||||
return Results.Redirect("/login" + qs);
|
||||
}
|
||||
|
||||
// Role resolution now lives behind the shared IGroupRoleMapper<string> seam
|
||||
// (OtOpcUaGroupRoleMapper): it applies the appsettings GroupToRole baseline AND merges
|
||||
// system-wide DB grants from the user's LDAP groups. result.Roles is empty on the real
|
||||
// LDAP path (the library returns groups, not roles); it is only pre-populated on the
|
||||
// DevStub success path (FleetAdmin) — union that pre-resolved set in so the dev grant
|
||||
// survives the move to the mapper.
|
||||
IReadOnlyList<string> roles = result.Roles;
|
||||
try
|
||||
{
|
||||
var dbRows = await roleMappings.GetByGroupsAsync(result.Groups, ct);
|
||||
roles = RoleMapper.Merge(result.Roles, dbRows);
|
||||
var mapping = await roleMapper.MapAsync(result.Groups, ct);
|
||||
roles = Union(result.Roles, mapping.Roles);
|
||||
}
|
||||
catch (Exception ex) when (ex is not OperationCanceledException)
|
||||
{
|
||||
// A DB hiccup must never block sign-in — fall back to the appsettings baseline roles.
|
||||
// A DB hiccup (or any mapper fault) must never block sign-in — fall back to the
|
||||
// pre-resolved baseline roles (empty on the real path, FleetAdmin under DevStub).
|
||||
http.RequestServices.GetService<ILoggerFactory>()?
|
||||
.CreateLogger("ZB.MOM.WW.OtOpcUa.Security.AuthEndpoints")
|
||||
.LogWarning(ex, "DB role-map lookup failed for {User}; using appsettings baseline roles", username);
|
||||
.LogWarning(ex, "Role-map lookup failed for {User}; using pre-resolved baseline roles", username);
|
||||
}
|
||||
|
||||
var claims = new List<Claim>
|
||||
@@ -119,6 +126,21 @@ public static class AuthEndpoints
|
||||
return Results.Redirect(string.IsNullOrWhiteSpace(returnUrl) ? "/" : returnUrl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Case-insensitive set-union of two role lists, preserving the de-duplication semantics the
|
||||
/// legacy <c>RoleMapper.Merge</c> applied. Used to fold any pre-resolved roles (the DevStub
|
||||
/// FleetAdmin grant) into the mapper-resolved set.
|
||||
/// </summary>
|
||||
/// <param name="first">The first role set (pre-resolved baseline).</param>
|
||||
/// <param name="second">The second role set (mapper output).</param>
|
||||
private static IReadOnlyList<string> Union(IReadOnlyList<string> first, IReadOnlyList<string> second)
|
||||
{
|
||||
var roles = new HashSet<string>(first, StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var role in second)
|
||||
roles.Add(role);
|
||||
return [.. roles];
|
||||
}
|
||||
|
||||
private static IResult Ping(HttpContext http) =>
|
||||
http.User.Identity?.IsAuthenticated == true ? Results.Ok() : Results.Unauthorized();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user