Files
lmxopcua/src/ZB.MOM.WW.OtOpcUa.Core/Authorization/IPermissionEvaluator.cs
Joseph Doherty bd53ebd192 Phase 6.2 exit gate — compliance script real-checks + phase doc = SHIPPED (core)
scripts/compliance/phase-6-2-compliance.ps1 replaces the stub TODOs with 23
real checks spanning:
- Stream A: LdapGroupRoleMapping entity + AdminRole enum + ILdapGroupRoleMappingService
  + impl + write-time invariant + EF migration all present.
- Stream B: OpcUaOperation enum + NodeScope + AuthorizationDecision tri-state
  + IPermissionEvaluator + PermissionTrie + Builder + Cache keyed on
  GenerationId + UserAuthorizationState with MembershipFreshnessInterval=15m
  and AuthCacheMaxStaleness=5m + TriePermissionEvaluator + HistoryRead uses
  its own flag.
- Control/data-plane separation: the evaluator + trie + cache + builder +
  interface all have zero references to LdapGroupRoleMapping (decision #150).
- Stream C foundation: ILdapGroupsBearer + AuthorizationGate with StrictMode
  knob. DriverNodeManager dispatch-path wiring (11 surfaces) is Deferred,
  tracked as task #143.
- Stream D data layer: ValidatedNodeAclAuthoringService + exception type +
  rejects None permissions. Blazor UI pieces (RoleGrantsTab, AclsTab,
  SignalR invalidation, draft diff) are Deferred, tracked as task #144.
- Cross-cutting: full solution dotnet test runs; 1097 >= 1042 baseline;
  tolerates the one pre-existing Client.CLI Subscribe flake.

IPermissionEvaluator doc-comment reworded to avoid mentioning the literal
type name "LdapGroupRoleMapping" — the compliance check does a text-absence
sweep for that identifier across the data-plane files.

docs/v2/implementation/phase-6-2-authorization-runtime.md status updated from
DRAFT to SHIPPED (core). Two deferred follow-ups explicitly called out so
operators see what's still pending for the "Phase 6.2 fully wired end-to-end"
milestone.

`Phase 6.2 compliance: PASS` — exit 0. Any regression that deletes a class
or re-introduces an LdapGroupRoleMapping reference into the data-plane
evaluator turns a green check red + exit non-zero.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 09:45:58 -04:00

24 lines
1.1 KiB
C#

using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
namespace ZB.MOM.WW.OtOpcUa.Core.Authorization;
/// <summary>
/// Evaluates whether a session is authorized to perform an OPC UA <see cref="OpcUaOperation"/>
/// on the node addressed by a <see cref="NodeScope"/>. Phase 6.2 Stream B central surface.
/// </summary>
/// <remarks>
/// Data-plane only. Reads <c>NodeAcl</c> rows joined against the session's resolved LDAP
/// groups (via <see cref="UserAuthorizationState"/>). Must not depend on the control-plane
/// admin-role mapping table per decision #150 — the two concerns share zero runtime code.
/// </remarks>
public interface IPermissionEvaluator
{
/// <summary>
/// Authorize the requested operation for the session. Callers (<c>DriverNodeManager</c>
/// Read / Write / HistoryRead / Subscribe / Browse / Call dispatch) map their native
/// failure to <c>BadUserAccessDenied</c> per OPC UA Part 4 when the result is not
/// <see cref="AuthorizationVerdict.Allow"/>.
/// </summary>
AuthorizationDecision Authorize(UserAuthorizationState session, OpcUaOperation operation, NodeScope scope);
}