Closes task #121 (partial — creation-time gate; decision #153 per-item revocation stamp is a follow-up). Before this commit a session could subscribe to any node via CreateMonitoredItems, even nodes where Read was denied — the subscription would surface BadUserAccessDenied on each data-change read, but the client saw a successful CreateMonitoredItems response and held the subscription open, wasting resources and leaking the address-space shape through the item metadata. New override on DriverNodeManager.CreateMonitoredItems: - Pre-iterates itemsToCreate, gates each through AuthorizationGate with OpcUaOperation.CreateMonitoredItems at the target node's scope. - For denied slots: sets errors[i] = new ServiceResult( StatusCodes.BadUserAccessDenied). The OPC Foundation base stack honours pre-populated non-success errors and skips item creation for those slots — the subscription never holds a handle to a denied node. - Preserves prior errors (e.g. BadNodeIdUnknown) — first diagnosis wins. - Non-string-identifier references (stack-synthesized numeric ids) bypass the gate. Extracted the pure filter logic into GateMonitoredItemCreateRequests(items, errors, identity, gate, scopeResolver) — static internal, unit-testable without the OPC UA server stack. Tests — 6 new in MonitoredItemGatingTests.cs (gate-null no-op, denied-gets-BadUserAccessDenied, allowed-passes, mixed-batch-denies- per-item, pre-populated-error-preserved, numeric-id-bypass). Server.Tests 263 → 269. Known follow-ups: - Per-item (AuthGenerationId, MembershipVersion) stamp (decision #153) for detecting revocation mid-subscription — needs subscription-layer plumbing. - TransferSubscriptions not yet wired (same pattern, smaller scope). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.7 KiB
5.7 KiB