Files
lmxopcua/docs/OpcUaServer.md
Joseph Doherty 3b2defd94f Phase 0 — mechanical rename ZB.MOM.WW.LmxOpcUa.* → ZB.MOM.WW.OtOpcUa.*
Renames all 11 projects (5 src + 6 tests), the .slnx solution file, all source-file namespaces, all axaml namespace references, and all v1 documentation references in CLAUDE.md and docs/*.md (excluding docs/v2/ which is already in OtOpcUa form). Also updates the TopShelf service registration name from "LmxOpcUa" to "OtOpcUa" per Phase 0 Task 0.6.

Preserves runtime identifiers per Phase 0 Out-of-Scope rules to avoid breaking v1/v2 client trust during coexistence: OPC UA `ApplicationUri` defaults (`urn:{GalaxyName}:LmxOpcUa`), server `EndpointPath` (`/LmxOpcUa`), `ServerName` default (feeds cert subject CN), `MxAccessConfiguration.ClientName` default (defensive — stays "LmxOpcUa" for MxAccess audit-trail consistency), client OPC UA identifiers (`ApplicationName = "LmxOpcUaClient"`, `ApplicationUri = "urn:localhost:LmxOpcUaClient"`, cert directory `%LocalAppData%\LmxOpcUaClient\pki\`), and the `LmxOpcUaServer` class name (class rename out of Phase 0 scope per Task 0.5 sed pattern; happens in Phase 1 alongside `LmxNodeManager → GenericDriverNodeManager` Core extraction). 23 LmxOpcUa references retained, all enumerated and justified in `docs/v2/implementation/exit-gate-phase-0.md`.

Build clean: 0 errors, 30 warnings (lower than baseline 167). Tests at strict improvement over baseline: 821 passing / 1 failing vs baseline 820 / 2 (one flaky pre-existing failure passed this run; the other still fails — both pre-existing and unrelated to the rename). `Client.UI.Tests`, `Historian.Aveva.Tests`, `Client.Shared.Tests`, `IntegrationTests` all match baseline exactly. Exit gate compliance results recorded in `docs/v2/implementation/exit-gate-phase-0.md` with all 7 checks PASS or DEFERRED-to-PR-review (#7 service install verification needs Windows service permissions on the reviewer's box).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 13:57:47 -04:00

8.9 KiB

OPC UA Server

The OPC UA server component hosts the Galaxy-backed namespace on a configurable TCP endpoint and exposes deployed System Platform objects and attributes to OPC UA clients.

Configuration

OpcUaConfiguration defines the server endpoint and session settings. All properties have sensible defaults:

Property Default Description
BindAddress 0.0.0.0 IP address or hostname the server binds to
Port 4840 TCP port the server listens on
EndpointPath /LmxOpcUa URI path appended to the base address
ServerName LmxOpcUa Application name presented to clients
GalaxyName ZB Galaxy name used in the namespace URI
MaxSessions 100 Maximum concurrent client sessions
SessionTimeoutMinutes 30 Idle session timeout
AlarmTrackingEnabled false Enables AlarmConditionState nodes for alarm attributes
AlarmFilter.ObjectFilters [] Wildcard template-name patterns that scope alarm tracking to matching objects and their descendants (see Alarm Tracking)

The resulting endpoint URL is opc.tcp://{BindAddress}:{Port}{EndpointPath}, e.g., opc.tcp://0.0.0.0:4840/LmxOpcUa.

The namespace URI follows the pattern urn:{GalaxyName}:LmxOpcUa and is used as the ProductUri. The ApplicationUri can be set independently via OpcUa.ApplicationUri to support redundant deployments where each instance needs a unique identity. When ApplicationUri is null, it defaults to the namespace URI.

Programmatic ApplicationConfiguration

OpcUaServerHost builds the entire ApplicationConfiguration in code. There are no XML configuration files. This keeps deployment simple on factory floor machines where editing XML is error-prone.

The configuration covers:

  • ServerConfiguration -- base address, session limits, security policies, and user token policies
  • SecurityConfiguration -- certificate store paths under %LOCALAPPDATA%\OPC Foundation\pki\, auto-accept enabled
  • TransportQuotas -- 4 MB max message/string/byte-string size, 120-second operation timeout, 1-hour security token lifetime
  • TraceConfiguration -- OPC Foundation SDK tracing is disabled (output path null, trace masks 0); all logging goes through Serilog instead

Security Profiles

The server supports configurable transport security profiles controlled by the Security section in appsettings.json. The default configuration exposes only MessageSecurityMode.None for backward compatibility.

Supported Phase 1 profiles:

Profile Name SecurityPolicy URI MessageSecurityMode
None SecurityPolicy#None None
Basic256Sha256-Sign SecurityPolicy#Basic256Sha256 Sign
Basic256Sha256-SignAndEncrypt SecurityPolicy#Basic256Sha256 SignAndEncrypt

SecurityProfileResolver maps configured profile names to ServerSecurityPolicy instances at startup. Unknown names are skipped with a warning, and an empty or invalid list falls back to None.

For production deployments, configure ["Basic256Sha256-SignAndEncrypt"] or ["None", "Basic256Sha256-SignAndEncrypt"] and set AutoAcceptClientCertificates to false. See the Security Guide for hardening details.

Redundancy

When Redundancy.Enabled = true, LmxOpcUaServer exposes the standard OPC UA redundancy nodes on startup:

  • Server/ServerRedundancy/RedundancySupport — set to Warm or Hot based on configuration
  • Server/ServerRedundancy/ServerUriArray — populated with the configured ServerUris
  • Server/ServiceLevel — computed dynamically from role and runtime health

The ServiceLevel is updated whenever MXAccess connection state changes or Galaxy DB health changes. See Redundancy Guide for full details.

User token policies

UserTokenPolicies are dynamically configured based on the Authentication settings in appsettings.json:

  • An Anonymous user token policy is added when AllowAnonymous is true (the default).
  • A UserName user token policy is added when an authentication provider is configured (LDAP or injected).

Both policies can be active simultaneously, allowing clients to connect with or without credentials.

Session impersonation

When a client presents UserName credentials, the server validates them through IUserAuthenticationProvider. If the provider also implements IRoleProvider (as LdapAuthenticationProvider does), LDAP group membership is resolved once during authentication and mapped to custom OPC UA role NodeIds in a dedicated urn:zbmom:lmxopcua:roles namespace. These role NodeIds are added to the session's RoleBasedIdentity.GrantedRoleIds.

Anonymous sessions receive WellKnownRole_Anonymous. Authenticated sessions receive WellKnownRole_AuthenticatedUser plus any LDAP-derived role NodeIds. Permission checks in LmxNodeManager inspect GrantedRoleIds directly — no username extraction or side-channel cache is needed.

AnonymousCanWrite controls whether anonymous sessions can write, regardless of whether LDAP is enabled.

Certificate handling

On startup, OpcUaServerHost.StartAsync calls CheckApplicationInstanceCertificate(false, minKeySize) to locate or create a self-signed certificate meeting the configured minimum key size (default 2048). The certificate subject defaults to CN={ServerName}, O=ZB MOM, DC=localhost but can be overridden via Security.CertificateSubject. Certificate stores use the directory-based store type under the configured Security.PkiRootPath (default %LOCALAPPDATA%\OPC Foundation\pki\):

Store Path suffix
Own pki/own
Trusted issuers pki/issuer
Trusted peers pki/trusted
Rejected pki/rejected

AutoAcceptUntrustedCertificates is controlled by Security.AutoAcceptClientCertificates (default true). Set to false in production to enforce client certificate trust. When RejectSHA1Certificates is true (default), client certificates signed with SHA-1 are rejected. Certificate validation events are logged for visibility into accepted and rejected client connections.

Server class hierarchy

LmxOpcUaServer extends StandardServer

LmxOpcUaServer inherits from the OPC Foundation StandardServer base class and overrides two methods:

  • CreateMasterNodeManager -- Instantiates LmxNodeManager with the Galaxy namespace URI, the IMxAccessClient for runtime I/O, performance metrics, and an optional IHistorianDataSource (supplied by the runtime-loaded historian plugin, see Historical Data Access). The node manager is wrapped in a MasterNodeManager with no additional core node managers.
  • OnServerStarted -- Configures redundancy, history capabilities, and server capabilities at startup. Called after the server is fully initialized.
  • LoadServerProperties -- Returns server metadata: manufacturer ZB MOM, product LmxOpcUa Server, and the assembly version as the software version.

ServerCapabilities

ConfigureServerCapabilities populates the ServerCapabilities node at startup:

  • ServerProfileArray -- StandardUA2017
  • LocaleIdArray -- en
  • MinSupportedSampleRate -- 100ms
  • MaxBrowseContinuationPoints -- 100
  • MaxHistoryContinuationPoints -- 100
  • MaxArrayLength -- 65535
  • MaxStringLength / MaxByteStringLength -- 4MB
  • OperationLimits -- 1000 nodes per Read/Write/Browse/RegisterNodes/TranslateBrowsePaths/MonitoredItems/HistoryRead; 0 for MethodCall/NodeManagement/HistoryUpdate (not supported)
  • ServerDiagnostics.EnabledFlag -- true (SDK tracks session/subscription counts automatically)

Session tracking

LmxOpcUaServer exposes ActiveSessionCount by querying ServerInternal.SessionManager.GetSessions().Count. OpcUaServerHost surfaces this for status reporting.

Startup and Shutdown

OpcUaServerHost.StartAsync performs the following sequence:

  1. Build ApplicationConfiguration programmatically
  2. Validate the configuration via appConfig.Validate(ApplicationType.Server)
  3. Create ApplicationInstance and check/create the application certificate
  4. Instantiate LmxOpcUaServer and start it via ApplicationInstance.Start

OpcUaServerHost.Stop calls _server.Stop() and nulls both the server and application instance references. The class implements IDisposable, delegating to Stop.

Key source files

  • src/ZB.MOM.WW.OtOpcUa.Host/OpcUa/OpcUaServerHost.cs -- Application lifecycle and programmatic configuration
  • src/ZB.MOM.WW.OtOpcUa.Host/OpcUa/LmxOpcUaServer.cs -- StandardServer subclass and node manager creation
  • src/ZB.MOM.WW.OtOpcUa.Host/OpcUa/SecurityProfileResolver.cs -- Profile-name to ServerSecurityPolicy mapping
  • src/ZB.MOM.WW.OtOpcUa.Host/Configuration/OpcUaConfiguration.cs -- Configuration POCO
  • src/ZB.MOM.WW.OtOpcUa.Host/Configuration/SecurityProfileConfiguration.cs -- Security configuration POCO