From ef8c2d19198a198596c8e18b22d032ec9f604964 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Tue, 10 Nov 2026 12:48:41 -0500 Subject: [PATCH] docs: clarify aggregate registration and SDK identity ownership --- .../Compatibility/Aggregates/README.md | 4 ++-- .../OpcUaApplicationHost.cs | 14 +++++++------- .../Security/RoleCarryingUserIdentity.cs | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Compatibility/Aggregates/README.md b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Compatibility/Aggregates/README.md index ffb5e45b..3f1ddc0b 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Compatibility/Aggregates/README.md +++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Compatibility/Aggregates/README.md @@ -10,9 +10,9 @@ Representation adaptations: - Nullable reference annotations describe the existing optional bounds/slices; no warning policy is disabled. - Immutable StatusCode methods replace the old setters. NodeId extraction and QualifiedName construction use supported typed APIs. - Removed TypeInfo.Cast/Variant(object, TypeInfo) operations use the SDK 2 typed conversion surface; baseline vectors verify value **types**, values, timestamps and all status bits. -- Interval, quality, sample selection, queue trimming, interpolation and partial-result algorithms remain the baseline algorithms. Factory registration replaces the existing 37 IDs through the public SDK API; it must not add capabilities or duplicate advertised references. +- Interval, quality, sample selection, queue trimming, interpolation and partial-result algorithms remain the baseline algorithms. The server creates a fresh SDK AggregateManager and registers these 37 IDs exactly once through the public API. It must not call the base registration first: replacing an existing factory also adds a duplicate diagnostic node in SDK 2.0.1. No extra capability is advertised. -The isolated `scripts/validation/opcua-aggregate-baseline` process pins only SDK 1.5.378.182 and generates the checked-in golden fixture. It is deliberately outside the solution and does not inherit the candidate package graph. The golden file records the baseline assembly hash, shared inputs and 4,144 outputs/cases across all 37 aggregate IDs, seven datasets, forward/reverse, stepped/sloped interpolation, uncertain-as-bad flags and incremental/partial processing. No baseline binary is loaded by the candidate tests or production host. +The isolated `scripts/validation/opcua-aggregate-baseline` process pins only SDK 1.5.378.182 and generates the checked-in golden fixture. It is deliberately outside the solution and does not inherit the candidate package graph. The golden file records the baseline assembly hash, shared inputs and 6,144 outputs/cases across all 37 aggregate IDs: the original 4,144 cases plus 2,000 numeric-width, nonfinite/conversion, timestamp tie/picosecond and configuration-edge cases. Forward/reverse, stepped/sloped interpolation, uncertain-as-bad flags and incremental/partial processing are retained. The candidate tests exercise the same independent expectations both directly and through the booted runtime manager. Unset SDK 2 FILETIME timestamps map explicitly to the original CLR unset sentinel when observing results. No baseline binary is loaded by the candidate tests or production host. Run the generator with a **new** output path, then compare it with `tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests/Fixtures/opcua-1.5.378.182-aggregates.json`. It refuses to overwrite evidence. Never regenerate expectations from the compatibility implementation. Existing historian parity tests retain their application-specific documented divergences from the baseline SDK, while new compatibility tests check the complete old-calculator output. diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs index e6fa9067..b383df19 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/OpcUaApplicationHost.cs @@ -161,8 +161,8 @@ public sealed class OpcUaQuotaOptions /// Thin facade over the OPC Foundation .NET Standard SDK's application bootstrap. /// Owns the + lifetime, /// builds the programmatically (security profiles + user -/// token policies + PKI stores), starts a , attaches the -/// ImpersonateUser hook for UserName-token authentication via +/// token policies + PKI stores), installs an SDK identity-registry authenticator before +/// the opens its listeners via /// , and publishes the redundancy peer URIs through /// Server.ServerArray. See docs/OpcUaServer.md and docs/security.md. /// @@ -468,7 +468,7 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable private async Task EnsureApplicationCertificateAsync(CancellationToken cancellationToken) { // silent: false → SDK logs cert creation events through its own trace plumbing. - // minimumKeySize/lifetimeInMonths: 0 → use SDK defaults (2048-bit, 12-month lifetime). + // A null lifetime keeps the SDK default (12 months). Key-size policy comes from the configuration. var ok = await _application!.CheckApplicationInstanceCertificatesAsync( false, null, cancellationToken).ConfigureAwait(false); if (!ok) @@ -610,10 +610,10 @@ public sealed class OpcUaApplicationHost : IAsyncDisposable /// /// Anonymous + UserName token policies. UserName tokens are always SDK-encrypted with /// the server certificate (see docs/security.md "UserName token encryption") so the - /// policy works on None endpoints too. The real LDAP-bound validator is wired through - /// on StandardServer.SessionManager.ImpersonateUser - /// (see / ); the Host - /// project supplies the LDAP adapter, and denies all + /// policy works on None endpoints too. The Host supplies API-key authentication through + /// ; installs it in the + /// SDK identity registry before listeners open. retains the + /// application decision seam, and denies all /// UserName logins when none is registered. /// /// Whether the Anonymous policy is advertised. diff --git a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Security/RoleCarryingUserIdentity.cs b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Security/RoleCarryingUserIdentity.cs index 96de455e..f4a26366 100644 --- a/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Security/RoleCarryingUserIdentity.cs +++ b/src/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer/Security/RoleCarryingUserIdentity.cs @@ -4,7 +4,7 @@ using Opc.Ua.Server; namespace ZB.MOM.WW.OtOpcUa.OpcUaServer.Security; /// -/// A that additionally carries the LDAP-resolved roles +/// An SDK identity that additionally carries the application roles resolved for an API key /// () for the authenticated session. The SDK may augment identities with mandatory and dynamically mapped roles. This subtype /// preserves the application identity when those roles are added, so a method /// handler can later recover the roles via