Lands the integration seam between the Server project's OPC UA stack and the Core.Authorization evaluator. Actual DriverNodeManager dispatch-path wiring (Read/Write/HistoryRead/Browse/Call/Subscribe/Alarm surfaces) lands in the follow-up PR on this branch — covered by Task #143 below. Server.Security additions: - ILdapGroupsBearer — marker interface a custom IUserIdentity implements to expose its resolved LDAP group DNs. Parallel to the existing IRoleBearer (admin roles) — control/data-plane separation per decision #150. - AuthorizationGate — stateless bridge between Opc.Ua.IUserIdentity and IPermissionEvaluator. IsAllowed(identity, operation, scope) materializes a UserAuthorizationState from the identity's LDAP groups, delegates to the evaluator, and returns a single bool the dispatch paths use to decide whether to surface BadUserAccessDenied. - StrictMode knob controls fail-open-during-transition vs fail-closed: - strict=false (default during rollout) — null identity, identity without ILdapGroupsBearer, or NotGranted outcome all return true so older deployments without ACL data keep working. - strict=true (production target) — any of the above returns false. The appsetting `Authorization:StrictMode = true` flips deployments over once their ACL data is populated. Tests (9 new in Server.Tests/AuthorizationGateTests): - Null identity — strict denies, lax allows. - Identity without LDAP groups — strict denies, lax allows. - LDAP group with matching grant allows. - LDAP group without grant — strict denies. - Wrong operation denied (Read-only grant, WriteOperate requested). - BuildSessionState returns materialized state with LDAP groups + null when identity doesn't carry them. Full solution dotnet test: 1087 passing (Phase 6.1 = 1042, Phase 6.2 A = +9, B = +27, C foundation = +9 = 1087). Pre-existing Client.CLI Subscribe flake unchanged. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
21 lines
999 B
C#
21 lines
999 B
C#
namespace ZB.MOM.WW.OtOpcUa.Server.Security;
|
|
|
|
/// <summary>
|
|
/// Minimal interface an <see cref="Opc.Ua.IUserIdentity"/> exposes so the Phase 6.2
|
|
/// authorization evaluator can read the session's resolved LDAP group DNs without a
|
|
/// hard dependency on any specific identity subtype. Implemented by OtOpcUaServer's
|
|
/// role-based identity; tests stub it to drive the evaluator under different group
|
|
/// memberships.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Control/data-plane separation (decision #150): Admin UI role routing consumes
|
|
/// <see cref="IRoleBearer.Roles"/> via <c>LdapGroupRoleMapping</c>; the OPC UA data-path
|
|
/// evaluator consumes <see cref="LdapGroups"/> directly against <c>NodeAcl</c>. The two
|
|
/// are sourced from the same directory query at sign-in but never cross.
|
|
/// </remarks>
|
|
public interface ILdapGroupsBearer
|
|
{
|
|
/// <summary>Fully-qualified LDAP group DNs the user is a member of.</summary>
|
|
IReadOnlyList<string> LdapGroups { get; }
|
|
}
|