mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-24 19:13:02 +08:00
fuzzing
24
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ae34b02938 |
Fuzzing coverage expansion (Full Encoders / Certificates / Network) (#3867)
# Description
Broadens fuzz coverage across the highest-value untrusted-input surfaces
in the stack, refactors the per-area scaffolding so adding a new fuzz
area is a copy-paste-replace operation, and integrates everything into
`UA.slnx`, `Fuzzing/Fuzzing.md`, and `Docs/README.md`.
**Totals**: 143 files, +4961 / −289. Source plan:
`plans/27-fuzzing-coverage-expansion.md` (added in this PR).
### Shared scaffolding (refactor, no behaviour change)
* Extract generic NUnit replay harness from
`Encoders/Fuzz.Tests/EncoderTests.cs` into
`Fuzzing/common/Fuzz.Tests/{FuzzTargetTestsBase,FuzzTargetFunction,TestcaseAsset,TestAssetUtils}.cs`.
* Each area's `Fuzz.Tests` becomes a thin subclass binding its own
`FuzzableCode` type.
* Hardcoded testcase-suffix arrays replaced with `Testcases.*` directory
discovery at runtime.
* New `Fuzzing/scripts/fuzz-menu.ps1`: dynamic target menu enumerating
`FuzzableCode` statics via reflection — no more hardcoded target lists
in `libfuzz.bat` / `aflfuzz.sh`.
### Encoders area hardening
* **Bug fix**: `AflfuzzXmlEncoder` was re-encoding via `JsonEncoder`;
now uses `XmlEncoder` (the `LibfuzzXmlEncoder` variant was already
correct).
* Add idempotent JSON / XML targets mirroring the existing Binary
idempotent pattern.
* Add compact-JSON encoder option coverage (`JsonEncoderOptions.None`
alongside `Verbose`).
* New `FuzzableCode.BuiltInTypes.cs` (48 targets): `NodeId`,
`ExpandedNodeId`, `Variant`, `ExtensionObject`, `DataValue`,
`DiagnosticInfo`, `QualifiedName`, `LocalizedText` × Binary/JSON/XML
decoders.
* Enrich `Encoders.Testcases.cs` seed corpus with `BrowseRequest` +
`WriteRequest`.
* New `Fuzzing/dictionaries/binary.dict`.
### String parsers (folded into Encoders area)
* New `FuzzableCode.Parsers.cs` (12 targets): `NodeId.Parse`,
`ExpandedNodeId.Parse`, `RelativePathFormatter.Parse`,
`QualifiedName.Parse`, `NumericRange.Parse`, `Uuid` round-trip (both
afl-string and libFuzzer-span signatures).
* New `Fuzzing/dictionaries/nodeid.dict`.
### Certificates / CRL / ASN.1 (NEW area)
* New `Fuzzing/Certificates/{Fuzz,Fuzz.Tests,Fuzz.Tools}` referencing
`Opc.Ua.Security.Certificates` + `Opc.Ua.Core`.
* Targets (20 total): `X509CRL(byte[])` → `EnsureDecoded`,
`X509SubjectAltNameExtension` / `X509AuthorityKeyIdentifierExtension` /
`X509CrlNumberExtension` raw-ASN.1 decoders,
`PEMReader.ImportPublicKeysFromPEM` / `ImportRsaPrivateKeyFromPEM`,
`Pkcs10CertificationRequest`, `AsnUtils.ParseX509Blob` + `AsnReader`
sequence/integer helpers.
* `Certificates.Testcases.cs` builds an RSA cert / CRL / CSR with the
existing builders and emits raw DER + PEM seeds.
* New `Fuzzing/dictionaries/asn1.dict` (DER tags, context-class tags,
length-form sentinels, OID prefixes).
### Network area via `Opc.Ua.Bindings.Pcap` (NO Core changes, NEW area)
* New `Fuzzing/Network/{Fuzz,Fuzz.Tests,Fuzz.Tools}`, multi-targeted
`net8.0;net9.0;net10.0` to match the pcap binding matrix (excluded from
net48/net472).
* **Stateless targets**: `OpcUaFrameParser.Process` (TCP segment → UA-SC
chunk splitter), `TcpStreamReassembler.Process` (raw TCP reassembly),
`OfflineSecureChannel.ReadChunk` (UA-SC symmetric decrypt + verify via
`UaSCUaBinaryChannel.ReadSymmetricMessage` → every security profile
covered through the binding), `ServiceCallReassembler.Push` (chunk →
decoded service call).
* **Stateful libFuzzer-only targets**: `MockServerReplay` /
`MockClientReplay` drivers in a separate target list so cheap stateless
targets dominate throughput.
* Deterministic test-only `ChannelKeyMaterial` via
`SecurityPolicies.None`.
* `Network.Testcases.cs` emits synthetic Hello/Ack/Err/Rhe/MSG seeds via
`LoopbackFrameBuilder`. Live handshake recorder is out of scope for this
PR (degraded mode documented).
* `Network.Fuzz` host does **not** instantiate `NicCaptureSource` — the
AFL/libFuzzer process never opens raw sockets.
* New `Fuzzing/dictionaries/uasc.dict` (MSG/OPN/CLO/HEL/ACK/ERR/RHE
magic + chunk-type bytes + security-policy URI prefixes) and `tcp.dict`
(Ethernet/IPv4/TCP framing markers).
### `Opc.Ua.Core` UA-SC parse seam (complements 4a)
* New `Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageParsers.cs` — `internal
static` helpers for the pre-crypto, pre-auth chunk surface NOT covered
by the pcap binding: `TryParseChunkHeader`, `ReadHelloMessage`,
`ReadAcknowledgeMessage`, `ReadErrorMessage`, `ReadReverseHelloMessage`,
`ReadAsymmetricMessageHeader`.
* **No production-code refactor** (Strategy B): the new internal helpers
are an independent parse seam, not a refactor of the entangled private
channel methods. Existing `ProcessHelloMessage` /
`ProcessReverseHelloMessage` / asym-header decode paths are untouched.
Behaviour is byte-identical (verified — Opc.Ua.Core.Tests Tcp subset 7/7
passing).
* Surface via `<InternalsVisibleTo Include="Network.Fuzz" />` (+
matching Tools and Tests entries because the linked
`FuzzableCode.Transport.cs` compiles from all three host projects).
* New `Fuzzing/Network/Fuzz/FuzzableCode.Transport.cs` (12 targets) +
`Fuzzing/Network/Fuzz.Tools/Transport.Testcases.cs` (seeds under
`Testcases.Tcp.*`).
### Integration
* `UA.slnx`: add the 6 new fuzz projects, 4 new shared harness `.cs`
files, 5 new dictionaries, and the new `fuzz-menu.ps1` script — all
under the right `/Fuzzing/<Area>/` solution folders.
* Rewrite `Fuzzing/Fuzzing.md`: areas table, per-area dictionaries,
dynamic target-menu, step-by-step "how to add a new fuzz area" recipe,
Network area's replay-driven seed pipeline + key-material discipline,
pcap binding dependency note.
* Cross-link from `Docs/README.md` to `Fuzzing/Fuzzing.md`.
* Fix `.Order()` → `.OrderBy()` in shared scaffolding
(`.Order(IComparer)` is net7+; the harness compiles on net48/net472 for
the Encoders + Certificates test matrices).
## Verification
| Project | TFM | Tests | Result |
|---|---|---|---|
| `Encoders.Fuzz.Tests` | net10.0 | 4131 | ✅ 0 failed |
| `Certificates.Fuzz.Tests` | net10.0 | 220 | ✅ 0 failed |
| `Network.Fuzz.Tests` | net10.0 | 330 | ✅ 0 failed |
| **Total** | | **4681** | **✅ 0 failed** |
* Full `dotnet build UA.slnx` (all TFMs, including
net48/net472/net8/net9/net10): **0 errors**, warning count unchanged
from baseline.
* `Network.Fuzz` multi-TFM build: **net8.0 + net9.0 + net10.0** all
green.
* `Opc.Ua.Core` build: **0 errors, 0 warnings** after Phase 4b seam
addition.
## Notes for reviewers
* **Base branch**: `channelrefinements2`, not `master`. The pcap binding
(`Stack/Opc.Ua.Bindings.Pcap`) only exists on the channelrefinements
line.
* **Real keylog / key material**: never committed. All Network seed
corpora use deterministic material generated from fixture test
certificates via the binding's own replay helpers.
* **`.der` test assets**: force-added with `git add -f` (consistent with
the existing intentional exception at
`Tests/Opc.Ua.Security.Certificates.Tests/Assets/OPC Foundation Root CA
[...].der`); the repo-wide `*.der` gitignore otherwise excludes them.
* **Out of scope** (documented as fold-ins for future work):
`PcapFileReader` / `PcapNgFileWriter` / `UaKeyLogTextReader` /
`UaKeyLogJsonReader` defensive parser fuzzing; live handshake recorder
for `Network.Testcases.cs`; real loopback replay drivers (current
implementation uses synthetic replay).
## Checklist
- [ ] I have signed the
[CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf)
and read the
[CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md)
doc.
- [x] I have added tests that prove my fix is effective or that my
feature works and increased code coverage.
- [x] I have added all necessary documentation.
- [x] I have verified that my changes do not introduce (new) build or
analyzer warnings.
- [ ] I ran **all** tests locally using the **UA.slnx** solution against
at least .net **framework** and .net **10**, and all passed. _(Fuzz
suites verified on net10.0: 4681/4681 passing. Full UA.slnx build green
on all TFMs. Full repo-wide test run not yet executed on net48 —
pre-existing tests unaffected by these changes; only
`Stack/Opc.Ua.Core/Stack/Tcp/TcpMessageParsers.cs` is new and is gated
behind `<InternalsVisibleTo>`.)_
- [ ] I fixed **all** failing and flaky tests in the CI pipelines and
**all** CodeQL warnings.
- [ ] I have addressed **all** PR feedback received.
|
||
|
|
b2b4dbb13f |
[Server] Part 13 Aggregates compliance fixes, full test coverage and docs (#3863)
# Description Brings the server-side **OPC UA Part 13 (Aggregates) v1.05.07** support to full conformance: fixes the three genuine non-compliances found by a spec review, completes value-validated test coverage for **all 37 standard aggregate functions**, and adds documentation. The existing aggregate engine is a faithful port and was already largely compliant; this PR closes the remaining gaps. ## Compliance fixes - **`TreatUncertainAsBad` default (§4.2.1.2).** The server-default `AggregateConfiguration` (used when a `ReadProcessedDetails` request sets `UseServerCapabilitiesDefaults = true`) now defaults `TreatUncertainAsBad` to **`True`** as the spec mandates, in both `AggregateManager.GetDefaultConfiguration` and the `HistorianDispatcher` fallback. Behavior change noted in `MigrationGuide.md`. - **`AnnotationCount` (§5.4.3.20).** Previously counted raw data values. It now counts **Annotations** per interval, computed in `HistorianDispatcher.DispatchProcessedReadAsync` from `IHistorianAnnotationProvider` (endTime-exclusive bucketing; reverse-time and `ProcessingInterval == 0` handled). Returns `Bad_AggregateNotSupported` when the provider has no annotation history. - **StandardDeviation/Variance use all n Good raw values (§5.4.3.37/.39).** `ComputeStdDev` previously computed over the N−1 sub-regions returned by `GetRegionsInValueSet`, silently dropping the last raw value. It now computes the mean/variance directly over all Good raw values in the interval (UseBounds = None), differing only by the divisor (sample n−1, population n). The population spec-example tests that used to add a duplicate trailing value as a workaround were updated to the natural 5-value datasets matching §A.35/.37. ## Tests - **Calculator coverage is complete for all 37 aggregates** — added `StatusAggregateCalculatorTests` (DurationGood/Bad, PercentGood/Bad, WorstQuality/WorstQuality2), the Min/Max `*2` simple-bound variants (`Minimum2`/`Maximum2`/`Range2`/`MinimumActualTime2`/`MaximumActualTime2`), and `Interpolative`. - **End-to-end integration** in `HistoryClientIntegrationTests` over the live in-process ReferenceServer: value-validated `Average`/`Minimum`/`Maximum` processed reads and an **AnnotationCount** write→read round-trip. - **Dispatcher-level** `AnnotationCount` tests (counts per interval; `Bad_AggregateNotSupported` without an annotation provider). - **Tightened `AggregateBaseTests`**: dropped `allowAnyResult` from `StandardDeviationSample`/`StandardDeviationPopulation`/`NumberOfTransitions` basecases (now deterministic on seeded data after the D3 fix). - **Validation tests** for `AggregateConfiguration` per §4.2.1.2: `PercentDataBad`/`PercentDataGood > 100` and the invalid relationship `PercentDataGood < (100 - PercentDataBad)`. - **Cross-cutting**: reversed time-range test (start > end). ## Verification - Builds: **0 warnings / 0 errors**. - Aggregate + historian dispatcher + History integration suites green on **.NET 10** and **.NET Framework 4.8** (cross-TFM). - Black-box (MCP) check against a standalone `ConsoleReferenceServer`: both `Server.ServerCapabilities.AggregateFunctions` and `HistoryServerCapabilities.AggregateFunctions` advertise all 37 functions (§4.2.2.1). ## Notes / out of scope - AnnotationCount advertisement remains the full standard set with per-node `Bad_AggregateNotSupported`. This is spec-acceptable: §4.2.2.1 lists what the server *can* support; per-node refinement is the optional `HistoricalConfiguration.AggregateFunctions`. Conditional advertisement could be added later as a quality refinement. - A native-vs-framework-fallback parity test would be useful once a third-party `IHistorianProcessedProvider` implementation exists; the bundled `InMemoryHistorianProvider` uses only the framework fallback today. ## Related Issues _No existing tracking issue; this addresses OPC 10000-13 (Part 13, Aggregates) v1.05.07 conformance gaps. Maintainers: please link or open a tracking issue if one is required._ ## Checklist - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. _(Ran the aggregate/historian/integration suites on net48 + net10; full-solution run pending CI.)_ - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. |
||
|
|
81b3c9b371 |
[Server] Implement NodeManagement service set and fix DeleteAddressSpace (#3839)
# Description Adds the OPC UA NodeManagement service set (AddNodes / DeleteNodes / AddReferences / DeleteReferences) to the server SDK and fixes a long-standing shutdown bug where `NodeState.Delete` callbacks never fired on address-space teardown. ### NodeManagement service set (#3736) - New optional `INodeManagementAsyncNodeManager` facet interface (added to `INodeManager.cs` alongside other facets, discovered via `as`, **not** part of the `IAsyncNodeManager` composite). Opt-in per NodeManager via `AllowNodeManagement` — default is `false` so existing NodeManagers preserve binary compatibility. - Dispatcher in `MasterNodeManager` routes: - **AddNodes** by `RequestedNewNodeId.NamespaceIndex` when supplied, otherwise to the parent's owning NodeManager. When the parent's owner is read-only (e.g. `ObjectsFolder` owned by `CoreNodeManager`), the dispatcher falls back to the first opted-in NodeManager so conformance flows work out of the box. - **DeleteNodes** / **AddReferences** / **DeleteReferences** to the owning NodeManager of the target or source node, returning `BadUserAccessDenied` when that NodeManager has not opted in. Cross-NodeManager `AddReference` / `DeleteReference` best-effort mirrors the inverse edge on the target's NodeManager. - `AsyncCustomNodeManager` provides a default implementation: per-item validation, `RequestedNewNodeId` honored, browse-name dedup for both local and cross-NodeManager parents, `DeleteTargetReferences` semantics, and a NodeId allocator fallback when an `INodeIdFactory.New` override returns a null `NodeId` (e.g. parent-based hierarchical naming with no parent attached). - `StandardServer` adds the four service overrides plumbed through `OperationLimits.MaxNodesPerNodeManagement`, audit events, and `OnRequestComplete`; new `ReportAuditAddReferencesEvent` / `ReportAuditDeleteReferencesEvent` helpers in `AuditEvents`. - Quickstarts `ReferenceNodeManager` opts in via `AllowNodeManagement => true`; the legacy partial-class override in `ReferenceServer.NodeManagement.cs` is removed. ### `NodeState.Delete` on shutdown (#3762) - `CustomNodeManager.DeleteAddressSpace` and `AsyncCustomNodeManager.DeleteAddressSpaceAsync` now snapshot root `PredefinedNodes` (skipping children whose parent is in the snapshot to prevent double-fire), invoke `NodeState.Delete(SystemContext)` on each root (which recurses into children and raises `OnBeforeDelete` / `OnAfterDelete` / `NodeStateChangeMasks.Deleted`), and then clear the map. - Derived overrides in Quickstarts `ReferenceNodeManager`, `SampleNodeManager`, and `FileSystemNodeManager` chain to `base` so the callback fires for their nodes too. ### Tests - **21 new dispatcher unit tests** in `Tests/Opc.Ua.Server.Tests/NodeManager/AsyncCustomNodeManagerNodeManagementTests.cs` covering `AllowNodeManagement` default/opt-in, AddNode validation (`BadBrowseNameInvalid`, `BadParentNodeIdInvalid`, `BadNodeIdRejected`, `BadNodeIdExists`, `BadBrowseNameDuplicated`, `BadNodeClassInvalid`), RequestedNewNodeId paths, DeleteNode + `DeleteTargetReferences`, AddReference duplicate detection (`BadDuplicateReferenceNotAllowed`), and DeleteReference (`BadNoMatch`). - **2 new DeleteAddressSpaceAsync tests** in `AsyncCustomNodeManagerTests` verifying `NodeState.Delete` invocation and no double-fire on children. - Updated InformationModel `NodeManagementAddRefTests.AddReferenceBetweenExistingNodesSucceedsAsync` to accept `BadUserAccessDenied` / `BadNotSupported` when the source NM has opted out. - **Full `Opc.Ua.Server.Tests` on net10.0: 1709 passed, 0 failed.** - **All 26 InformationModel `Category=NodeManagement` conformance tests pass** against the reference server (1 skipped where source NM opts out). ### Docs - New [`Docs/NodeManagement.md`](Docs/NodeManagement.md) with architecture, opt-in pattern, dispatch and routing rules, request-handling table, error-code table, audit events, and custom-behavior examples. - `Docs/MigrationGuide.md` gets two new sections — *NodeManagement service set* (downstream migration steps) and *DeleteAddressSpace invokes NodeState.Delete (#3762)* (shutdown behavior change) — with TOC entries. - `Docs/README.md` links the new `NodeManagement.md`. ## Related Issues - Fixes #3736 - Fixes #3762 ## Checklist _Put an `x` in the boxes that apply. You can complete these step by step after opening the PR._ - [ ] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [ ] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [ ] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [ ] I have addressed **all** PR feedback received. |
||
|
|
4756e7c245 |
DI (OPC 10000-100) with samples (Pump, SW Update), fluent API gap closures and model dependency implementation (#3808)
This PR implements the **OPC UA Device Integration (DI, OPC 10000-100)** companion-spec library trio (`Opc.Ua.Di` / `Opc.Ua.Di.Server` / `Opc.Ua.Di.Client`) plus a worked example (`Applications/MinimalPumpServer`) demonstrating the OPC 40223 Pumps companion specification end-to-end with full simulation. It also closes 11 fluent-API gaps in `Opc.Ua.Server.Fluent`, three source-generator bugs, integrates the DI layer into the unified `services.AddOpcUa()` Microsoft.Extensions DI hosting pattern, and adds 250+ new tests. **Worked example — `Applications/MinimalPumpServer/`** - AOT-compatible console host using `Host.CreateApplicationBuilder` + `AddOpcUa()`. - `PumpNodeManager` inherits from `DiNodeManager`; multi-namespace (DI + Machinery + Pumps) via runtime NodeSet2 loading and `ModelLoaderBuilder`. - Demonstrates declarative second-pump creation via `.ConfigureDevicesFor<PumpNodeManager>(...)` and software-package seeding from the same configurator. - Full simulation: pressure, temperatures, power, flow, efficiency, level, cavitation/overheat fault injection, alarm setup, NAMUR-style supervision. **Documentation** - `Docs/Opc.Ua.Di/` — README, DeviceBuilder, Hosting, LockService, SoftwareUpdate, ClientHelpers (6 new developer guides). - `Docs/Opc.Ua.Di/ComplianceMatrix.md` — every DI declaration mapped to In-v1 / Generated / Deferred / Excluded. - `Docs/CompanionSpecLibraries.md` — packaging guide for new companion-spec libraries. - `Docs/FluentApiGaps.md` — historical record of G1–G11. - `Docs/SourceGeneratedNodeManagers.md` updated for richer node managers. - `Docs/plans/StateMachineBuilder.md` — deferred state-machine builder design. |
||
|
|
0000513cde |
Pluggable user-identity provider model (#3807)
# Description Introduces a pluggable user-identity provider model covering all OPC UA Part 6 §6.5 mechanisms (Anonymous, UserName, X509, IssuedToken/JWT) on both client and server, with full `Microsoft.Extensions.DependencyInjection` integration, plus the Part 12 §9 `AuthorizationService` two-phase token-request flow **including refresh-token rotation**, the Part 12 §8 KeyCredential Push model, and a clean provider model for OPC 10000-12 §7.2 `ApplicationSelfAdmin`. The work is split across phase-by-phase commits so it can be reviewed independently; nothing here changes wire-level behaviour or forces existing applications to migrate. ### Documentation All under `Docs/`: - `IdentityProviders.md` — full developer guide: three-layer model, recipes, configuration reference, "what gets auto-wired" matrix, JWS algorithm table, identity-augmenters section, **"Implementing your own provider"** how-to subsections for Entra / OIDC / Windows / AspNetCore (sibling files merged in per review feedback). - `DependencyInjection.md` — `Identity` sections with `appsettings.json` examples, identity-extension matrix, `WithAuthorizationService` + `WithKeyCredentialPush` + `AddIdentityAugmenter` extensions documented. - `RoleBasedUserManagement.md` — claim-criteria callout describing `IIdentityClaims` probe surface. - `AuthorizationService.md` — Architecture diagram + `IAccessTokenProvider` conceptual narrative restored from master; modern `StartRequestToken` / `FinishRequestToken` flow leads; refresh-token recipe added. - `KeyCredentialService.md` — Push model + Pull vs Push vs Bridge decision matrix + Hybrid (Push + Pull) section; explicit experimental warning for the bridge. - `GDS.md` — KeyCredential Push, `StartRequestToken`, `GdsApplicationSelfAdminProvider`, **shipped Refresh-token support with rotation policy and audit semantics** all documented. - `MigrationGuide.md` — User Identity Providers section listing `[Obsolete]` markers + mechanical recipes; SelfAdmin migration via `IIdentityAugmenter`; `EnableRefreshTokens` default note. - `README.md` index entries. ## Checklist - [x] I have signed the [CLA](https://opcfoundation.org/license/cla/ContributorLicenseAgreementv1.0.pdf) and read the [CONTRIBUTING](https://github.com/OPCFoundation/UA-.NETStandard/blob/master/CONTRIBUTING.md) doc. - [x] I have added tests that prove my fix is effective or that my feature works and increased code coverage. - [x] I have added all necessary documentation. - [x] I have verified that my changes do not introduce (new) build or analyzer warnings. - [x] I ran **all** tests locally using the **UA.slnx** solution against at least .net **framework** and .net **10**, and all passed. - [x] I fixed **all** failing and flaky tests in the CI pipelines and **all** CodeQL warnings. - [x] I have addressed **all** PR feedback received. |
||
|
|
01d7162313 |
Part 9 Alarms & Conditions: complete server + client implementation (#3805)
Complete implementation of **OPC UA Part 9 ΓÇö Alarms & Conditions** for
both server and client, **OPC UA Part 16 ΓÇö State Machines** (generic
extensible client + server API), and the supporting infrastructure
(source-generated event records, source-generated ObjectType proxies,
`IAsyncEnumerable` streaming subscriptions, address-space model change
tracking, per-node `INodeCache` invalidation, unified DI integration).
### Server-side (Part 9 complete)
- **`AlarmConditionState`** ΓÇö every Part 9 method wired automatically
in `OnAfterCreate`: `Silence`, `Suppress`/`Suppress2`,
`Unsuppress`/`Unsuppress2`, `RemoveFromService`/`RemoveFromService2`,
`PlaceInService`/`PlaceInService2`, `Reset`/`Reset2`,
`GetGroupMemberships`. Each method generates the spec-mandated audit
event and supports an optional veto-delegate hook.
- **Latched alarms** ΓÇö `ActiveState` reflects real process state;
`LatchedState` persists until explicit `Reset` (with full precondition
validation).
- **Re-alarming** ΓÇö
`ProcessReAlarm`/`ResetReAlarmRepeatCount`/`IsReAlarmEnabled` helpers
(opt-in, no hidden timer).
- **Audible alarms** ΓÇö `UpdateAudibleState` for
`AudibleEnabled`/`AudibleSound`/`SilenceState` lifecycle.
- **Suppression + groups** ΓÇö `AlarmGroup`, `AlarmSuppressionEngine`
(with first-in-group), `AlarmRateTracker` (for `AlarmMetricsType`).
- **Spec-compliance fixes** ΓÇö `SuppressedOrShelved` now includes
`OutOfServiceState`; `GetRetainState` includes `LatchedState`;
`EffectiveDisplayName` composition includes `OutOfServiceState` +
`LatchedState`.
### Client-side Part 9 API
- **`AlarmClient`** ΓÇö typed Part 9 operations. Each method delegates
to the matching source-generated `*TypeClient` proxy
(`ConditionTypeClient`, `AcknowledgeableConditionTypeClient`,
`AlarmConditionTypeClient`, `DialogConditionTypeClient`,
`ShelvedStateMachineTypeClient`) ΓÇö one source of truth for every
method NodeId.
- **Interface hierarchy** — `IConditionOperations` →
`IAcknowledgeableConditionOperations` → `IAlarmOperations` +
`IDialogConditionOperations`.
- **Source-generated event records** ΓÇö new `EventRecordGenerator`
(alongside `ObjectTypeProxyGenerator`) emits `{Type}TypeRecord` per OPC
UA event type: `ConditionTypeRecord` →
`AcknowledgeableConditionTypeRecord` → `AlarmConditionTypeRecord` →
`LimitAlarmTypeRecord`/`ExclusiveLimitAlarmTypeRecord`/… all the way
to vendor subtypes. **Vendor alarm types get records automatically.**
- **`AlarmEventDecoder`** ΓÇö decodes `EventNotification.Fields` into
the most-specific generated record.
- **`AlarmEventFilterBuilder`** ΓÇö fluent builder for Part 9
`EventFilter`s.
- **`ISession.GetAlarmClient(telemetry)`** convenience extension.
### Part 16 state machines (generic, extensible)
- **Client**: extension methods on the source-generated
`StateMachineTypeClient` / `FiniteStateMachineTypeClient` ΓÇö
`GetCurrentStateAsync`, `ObserveFiniteTransitionsAsync`
(`IAsyncEnumerable<FiniteStateSnapshot>`), `WaitForStateAsync`,
`GetAvailableStatesAsync` / `GetAvailableTransitionsAsync`. **Vendor
proxies inherit the API automatically** through the generated
inheritance chain.
- **Server**: `StateMachineBuilder` (fluent: `AddState` /
`AddTransition` / `OnCause` / validation) +
`FluentFiniteStateMachineState` ΓÇö declare a Part 16 state machine
without subclassing the abstract base.
- **Alarms alignment**: `AlarmClient.GetShelvingStateAsync` /
`ObserveShelvingTransitionsAsync` surface the API for every alarm's
`ShelvingState` child.
### IAsyncEnumerable streaming subscription
- **`IStreamingSubscription`** with
`SubscribeDataChangesAsync`/`SubscribeEventsAsync` returning
`IAsyncEnumerable<T>` (Channel-backed).
- **`ManagedSession.DefaultStreaming`** ΓÇö lazy shared subscription;
disposed with the session.
- **Helpers** ΓÇö `TakeUntilAsync`, `WithTimeoutAsync`, `TakeAsync`,
`BufferedAsync` for state-machine waits and bounded observation windows.
- **`AlarmStreamExtensions`** ΓÇö
`SubscribeAlarmsAsync`/`SubscribeConditionsAsync`/`SubscribeDialogsAsync`
returning the source-generated record types.
### Address-space model change tracking
- **Server**: `RaiseGeneralModelChangeEvent` on both `CustomNodeManager`
and `AsyncCustomNodeManager`; `ModelChangeAggregator` (in
`Opc.Ua.Server.NodeManager`, used by every node manager) batches changes
per service call; **auto-emit** from `CreateNode`/`DeleteNode` (opt-out
via `ModelChangeEmissionEnabled = false`).
- **Client**: `IModelChangeTracker` subscribes to
`BaseModelChangeEventType` via the streaming subscription, decodes
`ModelChangeStructureDataType` payloads, invalidates the `INodeCache`
per-node.
- **`INodeCache.InvalidateNode(NodeId)`** ΓÇö new interface member (true
per-node eviction in `NodeCache`).
- **`ManagedSession.EnableModelChangeTrackingAsync()`** +
`ManagedSessionOptions.ModelChangeTracking` +
`ManagedSessionBuilder.WithModelChangeTracking()` fluent method.
### Dependency Injection integration
- **`services.AddOpcUa().AddClient(...).AddAlarms()`** ΓÇö registers
`AlarmClientFactory` so DI-hosted apps can resolve a Part 9 client per
session without `new`-ing one manually.
- Cross-link added to the unified DI surface (`AddServer` / `AddClient`
/ `AddComplexTypes` / `AddGdsServer` / `AddLdsServer` /
`AddWotConServer`).
### Quickstart server modernization
- `Quickstarts.Servers/Alarms/AlarmNodeManager.cs` ported to
`AsyncCustomNodeManager` and demonstrates the new `AlarmGroup` +
`AlarmSuppressionEngine` end-to-end via a writable `MaintenanceMode`
boolean that suppresses every member alarm.
### Documentation
- New: `Docs/AlarmsAndConditions.md`, `Docs/StreamingSubscription.md`,
`Docs/ModelChangeTracking.md`, `Docs/StateMachines.md` ΓÇö full
developer guides.
- Updated: `Docs/DependencyInjection.md` (`AddAlarms()` row + section),
`Docs/README.md` index, `Docs/MigrationGuide.md` (Part 9 / Part 16 /
model change tracking sections covering behavior changes + breaking API
surface).
- Sample: `Applications/ConsoleReferenceClient/AlarmClientSample.cs`.
|
||
|
|
f3928db05b |
Add unified Microsoft.Extensions DI surface across OPC UA libraries (#3803)
Introduces a consistent `Microsoft.Extensions.DependencyInjection`
surface across the OPC UA libraries. Every consumer starts from a single
root entry point and chains feature-specific extension methods on a
unified builder. PubSub is intentionally excluded per the original
scope.
```csharp
services
.AddOpcUa() // Stack/Opc.Ua.Core
.AddServer(o => { /* … */ }) // Libraries/Opc.Ua.Server
.AddNodeManager<MyNodeManagerFactory>()
.Services
.AddOpcUa()
.AddClient(o => { /* … */ }); // Libraries/Opc.Ua.Client
```
Manual non-DI constructors (`new ApplicationInstance(...)`, `new
StandardServer(...)`, `new LdsServer(...)`, `new ManagedSession(...)`,
etc.) remain unchanged — DI is purely additive for users who want the
.NET Generic Host to own application lifetime, logging, and
configuration.
### What ships
| Feature library | Method on `IOpcUaBuilder` | Returns |
|----------------------------------------------|-------------------------------------------|--------------------------|
| `Opc.Ua.Core` (root) | `services.AddOpcUa()` | `IOpcUaBuilder` |
| `Opc.Ua.Configuration` | `builder.AddApplicationInstance()` |
`IOpcUaBuilder` |
| `Opc.Ua.Client` | `builder.AddClient(opt => …)` |
`IOpcUaClientBuilder` |
| `Opc.Ua.Client.ComplexTypes` | `builder.AddComplexTypes()` |
`IOpcUaBuilder` |
| `Opc.Ua.Server` | `builder.AddServer(opt => …)` |
`IOpcUaServerBuilder` |
| `Opc.Ua.Gds.Client.Common` | `builder.AddGdsClient(opt => …)` |
`IGdsClientBuilder` |
| `Opc.Ua.Gds.Server.Common` | `builder.AddGdsServer(opt => …)` |
`IGdsServerBuilder` |
| `Opc.Ua.Lds.Server` | `builder.AddLdsServer(opt => …)` |
`ILdsServerBuilder` |
| `Opc.Ua.WotCon.Server` | `builder.AddWotConServer(opt => …)` |
`IWotConServerBuilder` |
| `Opc.Ua.WotCon.Client` | `builder.AddWotConClient(opt => …)` |
`IOpcUaBuilder` |
### Design highlights
- **Binary-safe inheritance** — `IOpcUaBuilder :
IDependencyInjectionBuilder` so any existing `AddLogging(this
IDependencyInjectionBuilder)` callers keep compiling unchanged.
- **Three options overloads** per feature: `Action<TOptions>`
(AOT-safe), `IConfiguration`, `IConfigurationSection`. The two binding
overloads are annotated `[RequiresUnreferencedCode]` /
`[RequiresDynamicCode]`. Section names follow the `OpcUa:<Feature>`
convention (`OpcUa:Server`, `OpcUa:Client`, `OpcUa:Gds:Server`,
`OpcUa:Lds`, …).
- **Generic Host integration** — each server feature (regular, GDS, LDS)
registers its own `BackgroundService`. Marker singletons throw
`InvalidOperationException` on duplicate `.AddServer()` /
`.AddGdsServer()` / `.AddLdsServer()`. A regular server + GDS + LDS can
coexist in one host; each owns its own `IApplicationInstance` produced
by a shared `IApplicationInstanceFactory` so PKI roots, endpoints, and
certificates don't collide.
- **Registration isolation** — node managers registered under the
regular server via `.AddNodeManager<T>()` are wrapped in
`OpcUaServerNodeManagerRegistration` so they don't bleed into the GDS /
LDS hosted services.
- **WoT Connectivity server** composes on top of the regular server
feature: `.AddServer(...).AddWotConServer(...)` registers
`WotConnectivityNodeManagerFactory` as a server node-manager
registration.
- **Unified telemetry** — `services.AddOpcUa()` registers
`ITelemetryContext` via `TryAddSingleton` using a new
`ServiceProviderTelemetryContext` that resolves the host's
`ILoggerFactory` on first use. User-supplied registrations win.
### Removed pre-release DI surface
The pre-release `services.AddOpcUaServer(...)`,
`services.AddOpcUaClient(...)`, `services.AddOpcUaGdsClient(...)`
extensions are deleted. `IClientBuilder` was renamed to
`IOpcUaClientBuilder`. In-repo callers migrated:
- `Applications/MinimalCalcServer/Program.cs`
- `Applications/MinimalBoilerServer/Program.cs`
- `Tests/Opc.Ua.Client.Tests/ClientBuilder/OpcUaClientBuilderTests.cs`
(renamed from `OpcUaClientServiceCollectionExtensionsTests.cs`)
- Docs (`MigrationGuide.md`, `Sessions.md`,
`SourceGeneratedNodeManagers.md`, README, new
`Docs/DependencyInjection.md`)
### csproj audit
Pruned every redundant `Microsoft.Extensions.*` package reference.
`Opc.Ua.Core` already pulls in `Microsoft.Extensions.Diagnostics` and
`Microsoft.Extensions.Logging`, which transitively expose DI / Options /
Configuration.Abstractions / Options.ConfigurationExtensions to every
downstream library. Only `Microsoft.Extensions.Hosting.Abstractions`
stays explicit on the server libraries (it isn't transitively
available). Also pruned redundant `System.Formats.Asn1` (Bindings.Https)
and `System.Collections.Immutable` (Security.Certificates).
### Tests
50 new tests in eight projects:
| Project | Tests |
|--------------------------------------|-------|
| `Opc.Ua.Core.Tests` | 12 |
| `Opc.Ua.Client.Tests` | 4 |
| `Opc.Ua.Client.ComplexTypes.Tests` | 3 |
| `Opc.Ua.WotCon.Tests` | 6 |
| `Opc.Ua.Lds.Tests` | 5 |
| `Opc.Ua.Gds.Tests` | 6 |
| `Opc.Ua.Server.Tests` (integration) | 10 |
| `Opc.Ua.Aot.Tests` (smoke) | 4 |
| **Total** | **50** |
Combined-host integration tests cover the rubber-duck-driven scenarios:
telemetry-context override across legacy and new entry paths, server +
GDS + LDS coexistence with distinct ports and PKI roots,
duplicate-registration rejection, and node-manager isolation across
features.
### AOT
`dotnet publish Tests/Opc.Ua.Aot.Tests -c Release -r win-x64
--self-contained` reports zero `IL2026` / `IL3050` / `IL2104` warnings
from the new DI surface. All generic registrations carry
`[DynamicallyAccessedMembers(PublicConstructors)]`. AOT consumers stick
to the `Action<TOptions>` overload exclusively; the new
`Tests/Opc.Ua.Aot.Tests/HostingAotTests.cs` smoke fixture exercises this
end-to-end.
|
||
|
|
51bcd4272a |
GDS Part 12 Full Compliance (#3795)
* GDS: Authorization & SecureChannel hardening (Part 12 §6.5, §7.2, §7.6)
* Fix OnGetCertificates self-admin authorization: pass applicationId to
HasAuthorization so ApplicationSelfAdmin can read its own certificates per
OPC 10000-12 §7.6.10 (was rejecting self-admin pull-management callers).
* Fix OnUnregisterApplicationAsync self-admin authorization: also pass
applicationId (was silently failing the self-admin branch).
* OnUpdateApplication: accept ApplicationSelfAdmin and ApplicationAdmin in
addition to DiscoveryAdmin per §6.5.7. Add self-admin role-permission shim.
* OnGetCertificateStatus: accept CertificateAuthorityAdmin / SelfAdmin /
ApplicationAdmin per §7.6.12 (was using AuthenticatedUserOrSelfAdmin which
is more permissive than spec).
* Introduce ApplicationAdmin privilege (Part 12 §7.2):
- Add GdsRole.ApplicationAdmin static privilege.
- Extend GdsRoleBasedIdentity with AdministeredApplicationIds and a new
constructor accepting the list. WithAdditionalRoles preserves it.
- AuthorizationHelper.HasAuthorization recognises the privilege: alone
when no applicationId is supplied (e.g. RegisterApplication) and
membership-tested against AdministeredApplicationIds otherwise.
- HasTrustListAccess honours the ApplicationAdmin privilege for the
administered applications' trust lists.
- New role lists: DiscoveryAdminOrAppAdmin (RegisterApplication),
DiscoveryAdminOrSelfAdminOrAppAdmin (Update/UnregisterApplication),
CertificateAuthorityAdminOrSelfAdminOrAppAdmin (cert management).
* SecureChannel result-code alignment (Part 12 method tables):
- HasAuthenticatedSecureChannel throws BadSecurityModeInsufficient (was
BadUserAccessDenied).
- Adds requireEncryption flag so callers can demand SignAndEncrypt
(used by future StartNewKeyPairRequest/FinishRequest tightening).
- Sign and SignAndEncrypt are now both accepted as 'authenticated'.
* Tests:
- Register the GDS namespace in AuthorizationHelperTests SetUp so
GDS-namespace role NodeIds do not collide on NodeId.Null with
privilege roles.
- Update HasAuthenticatedSecureChannelThrowsForNonSecureChannel to
expect BadSecurityModeInsufficient.
- Add HasAuthenticatedSecureChannelDoesNotThrowForSign and
HasAuthenticatedSecureChannelWithRequireEncryptionThrowsForSign.
- Add ApplicationAdmin coverage: SucceedsForAdministeredApp,
ThrowsForUnmanagedApp, SucceedsForRegisterApplication,
ThrowsWithEmptyAdministeredList.
- Add NewRoleListsAreCorrectlyPopulated regression test.
The framework already enforces SigningRequired/EncryptionRequired via
DefaultAccessRestrictions in OpcUaGdsModel.xml, returning
BadSecurityModeInsufficient at request dispatch time
(MasterNodeManager.ValidateAccessRestrictions). The model declares the
correct restriction on every admin method, so explicit handler-level
checks would be redundant. Verified manually against §6.5.6, §6.5.7,
§6.5.8, §7.6.4-7.6.10 and §7.6.12.
23 Authorization unit tests pass. 181 unit + 420 integration GDS tests
pass on net10.0; build clean on net48 and net10.0.
* GDS: Audit event correctness (Part 12 7.6, 7.9)
* Fix audit-event ordering: emit CertificateRequestedAuditEvent AFTER the
method outcome is known. Previously the event was raised before
authorization with Status=true, so any failed call appeared in audit as
a successful certificate request and any authorization-denied call
generated a misleading 'success' audit trail.
- OnStartNewKeyPairRequest: refactor to try/catch/finally, emit audit
once with auditException reflecting either the captured throw, the
bad ServiceResult, or null on success.
- OnStartSigningRequestAsync: add the audit emission (previously
missing entirely - 7.9.3 requires it) using the same pattern.
* Redact privateKeyPassword from audit InputArguments. The previous
ApplicationsNodeManager.cs:1206-1223 included the raw password string
as a Variant in the audit event payload, leaking the secret into any
downstream audit sink. The password is now replaced with
AuditEvents.RedactedPrivateKeyPassword (placeholder string).
* OnFinishRequestAsync: build the audit InputArguments from only the
actual method inputs (applicationId, requestId) per 7.6.6 method
signature. Previously the implementation appended the returned
Certificate / PrivateKey / IssuerCertificates to InputArguments, which
leaked the returned PrivateKey into audit payloads.
* Raise CertificateRevokedAuditEventType in OnRevokeCertificate on
success and failure per 7.6.9. The event type was defined in the
model (OpcUaGdsModel.xml:543) but never emitted. Refactored
OnRevokeCertificate with try/catch/finally; sync-over-async (.Result)
is preserved here and addressed separately in Track C (c-revoke-async).
* AuditEvents helper:
- New ReportCertificateRevokedAuditEvent extension method, mirroring
the existing CertificateRequested/Delivered helpers, with an
Exception parameter that drives Status (true on success, false on
failure).
- New RedactedPrivateKeyPassword and RedactedPrivateKey constants
documented as the canonical placeholders. Class-level remarks
instruct callers to redact sensitive arguments before invoking the
helpers.
* Tests:
- AuditEventsTests: lock the placeholder values
(RedactedPrivateKeyPassword and RedactedPrivateKey) so they remain
stable for downstream audit-sink filters.
- Existing 181 unit + 420 integration GDS tests pass on net10.0; build
clean on net48 and net10.0.
b-keycred-audit and b-token-audit remain pending pending Track E and F
respectively (KeyCredentialService and AuthorizationService handlers).
* GDS: Directory / Pull Management correctness gaps (Part 12 6.5, 7.6)
* OnRevokeCertificate converted to async OnRevokeCertificateAsync; uses
await instead of sync-over-async .Result, accepts the method-call
cancellation token, and is now wired through OnCallAsync to integrate
with the async dispatch path. RevokeCertificateAsync helper takes an
optional CancellationToken so callers (OnUnregisterApplicationAsync,
OnRevokeCertificateAsync) can forward it.
* OnCheckRevocationStatusAsync now computes the ValidityTime per
OPC 10000-12 7.6.11. The previous implementation always returned
DateTime.MinValue. The new implementation enumerates the CRLs in the
trusted-issuer store and uses the earliest NextUpdate as ValidityTime
when the chain validates. On Bad results (chain validation failed)
ValidityTime remains DateTime.MinValue so callers re-check
immediately.
* OnFinishRequestAsync returns the issuer chain via a new
BuildIssuerCertificateChain helper. The previous implementation
returned only the immediate signing CA, which is incomplete for
multi-tier CAs per OPC 10000-12 7.6.6. The helper uses
ICertificateGroup.Certificates (in-memory) as the X509Chain
ExtraStore and falls back to the immediate issuing CA if chain
building does not yield a chain. The helper is intentionally
synchronous to avoid contending with concurrent SigningRequestAsync /
NewKeyPairRequestAsync writes against the CertificateGroup's
AuthoritiesStore (which caused parameterised PushTest cases to fail
in parallel runs).
* ValidateApplication (ApplicationsDatabaseBase) now enforces the
reverse-connect rules in OPC 10000-12 6.5.5:
- Server / DiscoveryServer DiscoveryUrls must NOT start with the
"rcp+" prefix.
- Client DiscoveryUrls (when non-empty) must all start with "rcp+"
AND ServerCapabilities must include "RCP".
- ClientAndServer must register at least one non-rcp+ Server
DiscoveryUrl; reverse-connect URLs are still permitted alongside
and require the RCP ServerCapability.
Removed the previous blanket rejection of any DiscoveryUrls on
ApplicationType.Client (which contradicted the spec's reverse-connect
registration pattern).
* Tests:
- RegisterApplicationClientWithRcpDiscoveryUrlsAndRcpCapabilityDoesNotThrow
- RegisterApplicationClientWithRcpDiscoveryUrlsAndMissingCapabilityThrows
- RegisterApplicationServerWithRcpDiscoveryUrlThrows
- RegisterApplicationClientAndServerWithMixedUrlsDoesNotThrow
- RegisterApplicationClientAndServerWithOnlyRcpDiscoveryUrlsThrows
All 188 unit + 420 integration GDS tests pass on net10.0; build clean
on net48 and net10.0.
c-redundancy intentionally requires no enforcement: both transparent
(single application with multiple DiscoveryUrls) and non-transparent
(separate applications with NTRS capability) patterns per OPC 10000-12
6.5.6 are admitted by the validator; transparent redundancy is a
registrant convention rather than a server-enforceable invariant.
* Annex D capabilities: Self-advertise the LDS-ME capability identifier
whenever the MulticastExtension is configured. Previously LdsServer
hard-coded ["LDS"] regardless of whether multicast was running, so
FindServersOnNetwork peers could not distinguish LDS from LDS-ME
instances. Refactored the capability computation into a public static
ComputeServerCapabilities(existing, hasMulticast) helper:
- empty input + no multicast -> ["LDS"]
- empty input + multicast -> ["LDS", "LDS-ME"]
- custom seed list with no "LDS" -> "LDS" is appended
- existing "LDS-ME" is not duplicated
OnServerStarting now wires up the multicast layer first so the
capability set reflects the configured topology.
* Annex C / rcp+ reverse-connect preservation: MulticastDiscovery now
carries the OPC 10000-12 6.5.5 rcp+ DiscoveryUrl prefix end-to-end
through mDNS announce / discover.
- TryBuildProfile strips the rcp+ prefix before parsing the
underlying transport URL (Uri parsing on "rcp+opc.tcp://..." is
brittle across runtimes) and emits a dedicated TXT-record key
ReverseConnectTxtKey ("rc") so receivers can reconstruct it
verbatim.
- OnServiceInstanceDiscovered honours the "rc" key when present
and rebuilds the DiscoveryUrl with the rcp+ scheme.
Exposes MulticastDiscovery.OpcUaServiceType,
MulticastDiscovery.ReverseConnectScheme and
MulticastDiscovery.ReverseConnectTxtKey as public constants so
client code and tests can reference the same values used during
registration and discovery.
* RegisterServer2 fallback (4.2.2): verified that LdsServer overrides
both RegisterServerAsync and RegisterServer2Async, so the LDS
accepts both legacy RegisterServer registrations and the modern
RegisterServer2 + MdnsDiscoveryConfiguration path; no code change
required.
* Tests: new LdsServerStaticTests fixture exercising the capability
computation (six matrix cases) and locking in the Annex C / rcp+
constants (one regression test). 195 unit + 420 integration GDS
tests pass on net10.0; build clean on net48 and net10.0.
* Added Opc.Ua.Lds.Server as a ProjectReference of Opc.Ua.Gds.Tests so
the new tests can use the public static surface of LdsServer and
MulticastDiscovery.
* GDS: Push management hardening (Part 12 7.10)
* d-push-client-multitype: Make ServerPushConfigurationClient.ApplicationCertificateType
settable instead of hard-coded to RsaSha256ApplicationCertificateType.
Callers managing ECC, Brainpool or HTTPS certificates can now override
the default before invoking certificate-management methods (or pass an
explicit certificate type to the methods themselves). Removed the
TODO comment that flagged this limitation.
* d-trustlist-ext: Set Writable / UserWritable to true for the
DefaultApplicationGroup / DefaultHttpsGroup / DefaultUserTokenGroup
TrustList instances in the GDS. Per OPC 10000-12 7.8.2.1 a TrustList
that supports CloseAndUpdate / AddCertificate / RemoveCertificate is
writeable; role-based access controls on the individual methods still
enforce who may actually mutate the trust list. The previous values
(false) were misleading to clients browsing the trust-list nodes.
* d-server-cred-audit: Redact the private key from
CertificateUpdateRequestedAuditEventType InputArguments per OPC 10000-12
7.10.3. ConfigurationNodeManager.UpdateCertificateAsync was passing
the raw private-key ByteString into the audit payload, leaking the
secret to any downstream audit sink. The audit payload now uses
Opc.Ua.Server.AuditEvents.RedactedPrivateKey (an empty ByteString)
as the placeholder; the certificate, issuer chain and key format
remain in the payload so administrators can correlate the request.
Also extended Server.ReportCertificateUpdateRequestedAuditEvent with
an optional Exception parameter so callers can raise the event with
Status=false on failure (parity with the GDS-side helpers).
* Build clean on net48 and net10.0. 195 unit + 420 integration GDS
tests pass on net10.0.
Remaining Track D items (d-create-selfsigned, d-confirm-update,
d-managed-apps, d-alarms, d-push-tests) are larger features that
depend on Track H model additions and are not in scope for this
commit; their todos remain pending.
* GDS: Lock in ServerPushConfigurationClient.ApplicationCertificateType behaviour
Adds ServerPushConfigurationClientStaticTests covering the
Track D quick-win (d-push-client-multitype): the property defaults
to RsaSha256ApplicationCertificateType for backwards compatibility
and is now caller-overridable (e.g. for ECC management).
* GDS: Implement CreateSelfSignedCertificate (Part 12 7.10.6)
* Server-side: ConfigurationNodeManager wires the generated
CreateSelfSignedCertificateMethodState.OnCallAsync handler when the
optional method node exists on the ServerConfiguration instance.
The handler:
- Requires SecurityAdmin access (HasApplicationSecureAdminAccess)
- Validates CertificateGroupId / CertificateTypeId via the existing
VerifyGroupAndTypeId helper
- Creates a self-signed certificate using the CertificateFactory
pipeline (RSA with caller-specified key size, or ECC from the
curve mapped by the certificateTypeId)
- Merges DnsNames and IpAddresses into the SAN extension
- Stores the resulting raw data on the existing
CertificateIdentifier so the resolver can materialise it
- Returns the DER-encoded public certificate to the caller
The method is Optional per the spec; servers that load a nodeset
without it simply skip the wire-up (null guard).
* Client-side: IServerPushConfigurationClient extended with
CreateSelfSignedCertificateAsync; ServerPushConfigurationClient
delegates to the generated ServerConfigurationTypeClient proxy
with the standard elevate/revert permission pattern.
* net48 compat: uses new ValueTask<T>(result) instead of
ValueTask.FromResult which is unavailable on .NET Framework 4.8.
|
||
|
|
535d017840 |
Add OPC UA Part 17 (Alias Names) support (#3779)
* Add OPC UA Part 17 (Alias Names) support Server-side: pluggable IAliasNameStore + thread-safe InMemoryAliasNameStore, AliasNameStoreRegistry (live dispatcher, surfaces through optional IAliasNameStoreRegistryProvider on ServerInternalData), AliasNameNodeManager (standalone CustomNodeManager2; defaults to SecurityAdmin-only mutations on SignAndEncrypt channels), AliasNameMethodDispatcher bridging generated typed FindAlias/FindAliasVerbose/Add/Delete *MethodState.OnCallAsync handlers, AliasNameWildcardMatcher (Part 4 §7.40 Like operator with proper escape handling), and a DiagnosticsNodeManager partial that late-binds the standard well-known Aliases (i=23470), TagVariables (i=23479) and Topics (i=23488) FindAlias methods plus Aliases.LastChange through the registry. Client-side: AliasNameClient (OpenStandardAliases/TagVariables/Topics + arbitrary category root) covering all four Part 17 methods, sub-category enumeration and ReadLastChangeAsync. Hardcoded method-id fast-path for standard categories; cached TranslateBrowsePaths resolution for custom ones. Service-level errors map to typed exceptions (UnauthorizedAccessException / NotSupportedException). AliasNameResolver (IAsyncDisposable) gives a name->NodeId cache with forward and reverse lookup; default refresh is Manual with opt-in AutoOnLastChange polling that compares VersionTime on inequality (wrap-safe). Reference server: registers an InMemoryAliasNameStore for the standard TagVariables + Topics categories with sample seeds (TIC101_Setpoint, TIC101_PV, FIC202_Flow, Pump1_Status, Heater_Power, MultiRefAlias, ServerEvents, AuditEvents) so the standard well-known FindAlias methods return data through the DiagnosticsNodeManager late binder. Tests: 45 server-side cases (wildcard matcher, in-memory store, registry, node manager) plus 11 mocked-session client cases and 4 end-to-end integration cases against a live ReferenceServer over a real OPC UA channel. All 60 tests pass; full solution builds clean across net472/net48/netstandard2.1/net8.0/net9.0/net10.0. Docs: Docs/Part17AliasNames.md plus a link from Docs/README.md. |
||
|
|
bd4543e961 |
ManagedSession, Pluggable Subscription engine, and fluent builder + DI (#3730)
- Add new managed session, wrapping session and providing connection management and failover handling - Add new Subscription engine that can act as alternative to current engine, but is based on channels with worker tasks - Add a fluent builder for managed session clients - Replace NodeCache with LruNodeCache, rename ILruNodeCache and LruNodeCache to INodeCache and NodeCache - Update migration guide and document new functionality. |
||
|
|
39fa3030fa |
Add a fluent api for server, a sample and generate node managers to use with it. (#3684)
* Add source-generated NodeManagers and fluent wiring API Adds a fluent INodeManagerBuilder API for wiring per-node callbacks and a model-aware source generator that emits a partial CustomNodeManager2 plus an INodeManagerFactory for each design file. Opt-in is per class via [Opc.Ua.Server.Fluent.NodeManager] on a partial class (recommended) or project-wide via the ModelSourceGeneratorGenerateNodeManager MSBuild property (legacy). The attribute supports NamespaceUri / Design selectors for multi-design projects and a GenerateFactory toggle. Diagnostics MODELGEN010 / MODELGEN011 surface unmatched bindings and non-partial classes. Adds the ConsoleBoilerServer NativeAOT sample driving the new pipeline end-to-end with Microsoft.Extensions.Logging.Console and updated docs in Docs/SourceGeneratedNodeManagers.md. * Add BoilerServer AOT smoke test Verifies the source-generated Boiler.BoilerNodeManagerFactory loads the boiler address space, registers its namespace, and dispatches the fluent OnRead callbacks wired in BoilerNodeManager.Configure.cs. All 3 new tests pass in JIT mode and against the NativeAOT-published binary; total Aot.Tests suite: 71/71 pass. |
||
|
|
fd41681f4b |
Add support to publish OPC UA applications as Native AOT (#3633)
* make most ptojects aot compatible * Remove newtonsoft * Migrate all projects from Mono.Options to System.CommandLine 2.0.5 * Fix array clone * Replace serializers for storage using new attribute driven type geberator * Add new AOT integration tests covering all functional areas * Documentation updates |
||
|
|
c9b211e61e |
Add comprehensive OPC UA Profiles and Facets documentation (#3397)
* Initial plan * Add comprehensive OPC UA Profiles and Facets documentation Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> * Fix URL in Profiles documentation to use current OPC Foundation site Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> |
||
|
|
35db94cb31 |
Add client-based NodeSet2 export functionality (#3400)
* Initial plan * Add client-based nodeset export functionality Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> * Add tests for client-based nodeset export functionality Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> * Add documentation for client-based nodeset export feature Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> |
||
|
|
2960388560 |
Update headers and license files (#3388)
Update license headers to copy right year 2025, replace RCL/GPL headers with MIT, replace the nuget license with MIT (via license expression). |
||
|
|
35e03d9067 |
Add comprehensive documentation for ComplexTypes library (#3373)
* Initial plan * Add comprehensive ComplexTypes documentation Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> * Fix code review issues in ComplexTypes documentation Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> |
||
|
|
e632da21fa |
Add provisioning mode support for certificate provisioning and initial server configuration (#3375)
* Initial plan * Add provisioning mode support to ConsoleReferenceServer Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> * Add provisioning mode test and ServerFixture support Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> * Add provisioning mode documentation Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: romanett <7413710+romanett@users.noreply.github.com> |
||
|
|
35db52a7a6 | Move from .net 9 to .net 10 SDK and build new target framework .net 10 (#3333) | ||
|
|
493da5d5be |
Extend ServerConfiguration & GDS Server for ECC (#2817)
* update ServerConfiguration Node to support multiple Application Certificates. Trust List Support for User Certificates & Https Certificates * GDS ready for ECC Step1 * fix test * fix build * ensure hash algorithm is set * update configurations to new format, fix minor ecc bugs * implicitly set certificate type of certificate identifier extend CertificateFactory to allow Revocation with ECC Issuer Certificate * Revert "update configurations to new format, fix minor ecc bugs" This reverts commit |
||
|
|
65f245d360 |
Remove winforms sample projects from main repo (#2626)
* remove winforms sample projects from main repo, can be found now in the samples repo! see --> https://github.com/OPCFoundation/UA-.NETStandard-Samples/tree/master/Samples |
||
|
|
8a1df6d3dc |
[Client] Fix UserIdentity for CertificateIdentifer & add parameter for console reference client to specify UserCertificate (#2624)
- Fix the UserIdentity constructor to load the private key of a provided certificateIdenifier. - make UserIdentity constructor throw a ServiceResultException when a Certificate with no private key is specified. - extend console reference client with two new parameters: -uc Thumbprint of a user certifiate located in the TrustedUserCertificatesStore -ucp Password of the private key of the user certificate - add documentation for console reference client |
||
|
|
6d85d8007b |
document role based user mangement (#2528)
* document role based user mangement |
||
|
|
343f7b0fbc |
Add custom test targets to the build process, support for .NET 8. (#2410)
The goal is to reduce the overall number of builds, stop using end of life platforms in the build pipeline and to support build of future/deprecated build targets in a custom build step, which is also triggered weekly in the ci builds. In addition: - added a doc which describes the release and versioning strategy of this project - produce the Nuget packges with .NET 8 assemblies. - produce a Docker build based on a .NET 8 based container. - add custom test targets to test outdated platforms. Need a manual step to enable for VS or command line. - bug fixes: the latest move to an alternate crypto library for Bouncy Castle, which is only used for the GDS support and .NET Framework 4.6.2./netstandard2.0, revealed already a few issues which were previously not found. - only .NET8/.NET6/.NET Framework 4.8 are tested in Pull requests. Remaining builds in weekly scheduled builds. |
||
|
|
7d9be41cf5 |
Doc updates and fixes for .368 preview, ref server improvements (#1695)
- Doc, docs, docs updates for new 368 support - fix a missing null pointer check when ConditionRefresh is run - Ref server: move NodeManager factory API to StandardServer, decoupling the NodeManager implementation from Ref server - Ref server: add shadow mode flag, to allow to map a docker configuration in a mapped folder. - Ref server: sample batch files how to run Github CR and local docker images - Improve some misleading 'delete application certificate' log messages. |