mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-29 07:07:24 +08:00
ecc-testing-fixes
15
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
49305d9085 |
V2 subscription engine close gap for test and feature parity with classic engine (#3824)
# Description V2 subscription engine feature parity round to make the classic engine eligible for deprecation. Splits the test surface so the classic and V2 engines can evolve independently, ports the gaps the classic-engine integration tests had been exercising, and lands the public V2 API additions needed to close them. - Splits `Tests/Opc.Ua.Subscriptions.Tests` into a classic (`Opc.Ua.Subscriptions.Classic.Tests`) and a V2 (`Opc.Ua.Subscriptions.Tests`) project to shrink CI time and let the two engines diverge cleanly. - Adds the V2 public-surface gaps required by the test ports (`Subscription.ServerId` on the class, `SetSubscriptionDurableAsync`, `SendInitialValuesOnTransfer`, unified `OnSubscriptionStateChangedAsync` handler callback, per-item `ConditionRefreshAsync`, fluent `LoadSubscriptionsAsync(Stream, …)` and `Subscription.Snapshot()` / `RestoreAsync()` for save/load + transfer). - Lands handler-centric design (no `PublishingStopped` property handlers maintain derived state); always-sequential per-subscription delivery documented + tested. - **Adds short and long haul stability tests for the V2 `ManagedSession` + subscription engine. Closes #3744** (see "Issue #3744 Haul tests" below). - **Migrates SubscriptionStateSnapshot / MonitoredItemStateSnapshot to `[DataType]` source-generator codecs**. - `SubscriptionDurableV2Tests.cs` 5 V2 ports of the classic durable test patterns. - `V2FollowUpCoverageTests.cs` handler state-change callback, fluent stream-based `LoadSubscriptionsAsync`, `SendInitialValuesOnTransfer`, snapshot edge cases (empty / `DataChangeFilter` round-trip / concurrent mutation). - `SubscriptionFailoverV2Tests.cs` forced channel-break with and without `WithTransferSubscriptionsOnRecreate`. - `MonitoredItemConditionRefreshLiveV2Tests.cs` — live `ConditionRefresh` against the reference server's event source; asserts `RefreshStart` / `RefreshEnd` events flow through the handler. ## Fixes - #3744 Haul tests (V2 ManagedSession + subscription engine) `Tests/Opc.Ua.Sessions.Tests/ManagedSessionStabilityTest.cs` adds the short/long haul coverage requested by [#3744](https://github.com/OPCFoundation/UA-.NETStandard/issues/3744) plus the bonus fault-injection variant: | Test | Duration | Category | Purpose | |---|---|---|---| | `ShortHaulManagedSessionV2Async` | 2 minutes | `ManagedSessionHaul` (`[Explicit]`) | Quick local sanity check of the V2 monotonicity contract. | | `LongHaulManagedSessionV2Async` | 90 minutes (configurable via `TEST_DURATION_MINUTES`) | `ManagedSessionHaul` (`[Explicit]`) | Long-running V2 stability + monotonicity. | | `LongHaulManagedSessionWithFaultInjectionV2Async` | 90 minutes (configurable) + fault every `FAULT_INJECTION_INTERVAL_SECONDS` (default 60s) | `ManagedSessionHaul` (`[Explicit]`) | **Bonus** — force-closes the subscriber transport channel periodically; verifies V2 manager transfers/recreates the subscription and continues monotonic delivery across reconnects. | **Pattern.** A writer `ManagedSession` increments a `uint32` counter and writes it into `Scalar_Static_Mass_UInt32_UInt32_00` every 250ms. A subscriber `ManagedSession` runs a V2 subscription with a single monitored item on the same node. `MonotonicCounterHandler` asserts each received sample is *strictly greater than* the previous one. V2 `ISubscriptionNotificationHandler` per-subscription ordering guarantee. Skipped values (sampling rate < write rate) are tolerated; duplicates and reorderings are violations. |
||
|
|
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. |
||
|
|
5ff968fcfb |
Test project reorganization follow up (#3810)
### Test project reorganization
Splits the integration- vs unit-test boundary along **project
boundaries**
and introduces a runtime-tier split for subscription tests so the
mainline
CI no longer drags in stress / durable suites.
**New projects:**
- `Opc.Ua.Stress.Tests` ΓÇö cross-area stress tier (designed to
absorb
session / channel / pub-sub stress in future). Seeded with the 6
subscription stress classes (`SubscriptionDepthTests`,
`SubscriptionBasicDepthTests`, `MonitoredItemDepthTests`,
`SubscriptionTransferDepthTests`, `SubscriptionPublishTooManyTests`,
`SubscriptionMultipleTests`). **Excluded from mainline CI; runs
nightly.**
- `Opc.Ua.Subscriptions.Durable.Tests` ΓÇö durable-subscription tier
(needs `DurableSubscriptionsEnabled` + storage-backed lifetime).
Receives `SubscriptionDurableTests` plus the migrated
`DurableSubscriptionTest` and `DurableSubscriptionTestDebug`.
**Excluded from mainline CI; runs nightly.**
- `Opc.Ua.Features.Tests` ΓÇö cross-feature integration tier.
Receives the
`[OneTimeSetUp]`-bootstraps-its-own-server integrations for AliasNames
(Part 17), Roles (Part 18), FileSystem (Part 5 §C / Part 20), and
NodeCache. Also absorbs the misplaced
`Tests/Opc.Ua.History.Tests/FileSystemTests.cs`.
**Client.Tests cleanup (~28 files moved):**
- `Opc.Ua.Sessions.Tests` (existing) gains 10 session integration files
plus the 4 session benchmark files inline (`LoadTest`,
`RequestHeaderTest`, `TraceableRequestHeaderTest`,
`SecurityPolicyBenchmarks`).
- `Opc.Ua.Subscriptions.Tests` (existing) gains 4 subscription
integration files plus `PooledNotificationBenchmarks` inline.
- `Opc.Ua.Client.ComplexTypes.Tests` (existing) gains all
`ComplexTypes/*` integration files. The Client.Tests copy of
`TypeSystemClientTest.cs` (a stale near-duplicate) is removed.
- Benchmarks **stay inline** as `[Test]` + BenchmarkDotNet dual-use; no
new benchmark project (per the approved plan).
**CI pipeline:**
- `.azurepipelines/test.yml` now filters
`TestCategory!=LongRunning&TestCategory!=Stress` on the mainline run.
- `-ExcludeFileName` now accepts a comma-separated list. The mainline
matrix excludes the 3 nightly-tier project files alongside the
existing `Opc.Ua.Aot.Tests.csproj`.
- `get-matrix.ps1` enhanced to support multi-pattern excludes.
`InternalsVisibleTo` extended on `Opc.Ua.Client` and `Opc.Ua.Server` to
grant the new test projects access. All affected projects build clean
(`0 Error`) for `net10.0`.
### Fix 8 skipped tests flagged as suspected bugs
Triage of every `[Ignore]` / `[Explicit]` test in `Tests/**` surfaced 8
entries labelled as suspected production bugs. After inspection:
- **1 real production bug** ΓÇö the
`CancellationTokenSource.CancelAsync`
polyfill for netstandard2.0 / netfx was running cancellation callbacks
inline on the caller's thread, deadlocking dispose paths
(`SubscriptionManager.DisposeAsync`, etc.) when a callback awaits on
the caller's `SynchronizationContext`. Fixed at the polyfill root by
hoisting `Cancel()` onto the ThreadPool via `Task.Run`, matching real
.NET 8+ semantics. Caveat (deferred `IsCancellationRequested`
transition) documented inline; all in-repo callers use
`await cts.CancelAsync()` so the deviation is invisible. Test
`DrainAsyncWaitsForInFlightPublishToCompleteAsync` un-ignored ΓÇö
verified passes on net48 (943 ms) and net10.0 (1 s).
- **2 flaky tests stabilized** ΓÇö both
`ValidateMetaDataUpdateTimeNonZeroIsSentPeriodically` (MQTT JSON &
UADP) now use `Stopwatch.GetTimestamp()` instead of `DateTime.Now`,
compute deviation against the **median** interval (not the configured
cadence, so a startup hiccup doesn't skew the run), and use a
proportional `max(interval / 4, 50 ms)` tolerance. `[Ignore]` removed,
`[Category("LongRunning")]` retained.
- **1 mis-labelled "bug"** ΓÇö
`UnorderedMessagesWouldBeLostForSequentialPublishingAsync` asserts the
*documented* lossy trade-off of strict sequential publishing.
`[Explicit]`
removed and renamed to
`OldMessagesAbandonedAfterRepublishTimeoutInSequentialModeAsync`; it's
now a CI-verified regression test for the WAI behavior.
- **4 false positives** ΓÇö `JsonEncoderTestsOld.cs` (16 kLOC) was
excluded from compilation via `<Compile Remove>` and never reached the
runner. The 4 `[Ignore("ProductionBugSuspected")]` markers inside were
orphaned source from a previous JsonEncoder API. Active coverage lives
in `JsonEncoderTests.cs` and `JsonValidationData` fixtures. Deleted
the orphan file and the now-redundant `<Compile Remove>` line.
|
||
|
|
eb40a59566 |
More format and diagnostic fixes (#3780)
Drive the solution to zero warnings / zero errors with analyzers on, promote the consistently-fixed rules to error, and lock in coverage on the only line of new logic. |
||
|
|
14e995c1d0 |
Restructure test projects for faster CI (#3767)
Rebalance the heavy test projects of the OPC UA .NET Standard stack so CI test execution can run cleanly in parallel.
### New test projects (Tests/Opc.Ua.<X>.Tests/)
| Project | Files | Sources |
|---|---:|---|
| Opc.Ua.Sessions.Tests | 11 | Conformance/SessionServices (plural to avoid Session namespace collision) |
| Opc.Ua.Subscriptions.Tests | 25 | SubscriptionServices + MonitoredItemServices |
| Opc.Ua.History.Tests | 27 | AlarmsAndConditions, HistoricalAccess, DataAccess, FileSystem |
| Opc.Ua.Lds.Tests | 15 | Discovery, DiscoveryServices, Miscellaneous |
| Opc.Ua.Core.Security.Tests | 39 | Security, Auditing |
| Opc.Ua.InformationModel.Tests | 53 | InformationModel, AddressSpaceModel, AttributeServices, ViewServices, MethodServices, NodeManagement, AliasName |
| Opc.Ua.Core.Encoders.Tests | 11 | Encoder tests extracted from Core.Tests |
| Opc.Ua.Gds.Tests (existing) | +5 | new GDS tests |
### New helper class libraries (Tests/Opc.Ua.<X>.TestFramework/ + Tests/Opc.Ua.Test.Common/)
* Opc.Ua.Client.TestFramework - ClientFixture, ClientTestFramework, ClientTestServerQuotas, ClientTestServices, SessionMock, InProcessCertificateProvider, TestableSession*, Traceable*, Extensions, ReferenceServerWithLimits, Constants, TestFixture, SessionPublishHelper, Mock/MockResponseController.
* Opc.Ua.Server.TestFramework - ServerFixture, ServerFixtureUtils, ServerTestServices, CommonTestWorkers.
* Opc.Ua.Core.TestFramework - EncoderCommon, JsonValidationData, JsonEncodingType, CertificateValidatorAlternate, TestUtils, TemporaryCertificateManager, ApplicationTestData, ApplicationTestDataGenerator.
* Opc.Ua.Test.Common - Logging.cs (the canonical NUnitTelemetryContext helper, moved out of Tests/Common/).
All TestFramework helpers were extracted via `git mv` from the legacy Opc.Ua.Client.Tests / Opc.Ua.Server.Tests / Opc.Ua.Core.Tests projects (no copy-paste).
### Server-side production-code fixes
1. `MasterNodeManager.ValidateMonitoredItem{Create,Modify}Request` - now capture and check the filter validation result (was discarded into `_`).
2. `MasterNodeManager.ReadAsync` - assign `value = values[ii] = value.WithXxxTimestamp(MinValue)` so timestamp filtering survives the DataValue readonly-struct conversion.
3. `ApplicationsDatabaseBase.{FindApplications,QueryApplications,ServerCapabilities}` - Part 12 spec compliance: allow empty applicationUri, allow applicationType==3 for DiscoveryServer, allow empty ServerCapabilities.
4. `LinqApplicationsDatabase.{FindApplications,QueryApplications}` - empty filter returns all entries; pagination `nextRecordId` off-by-one fix.
### CI flake guards
* `FastKeepAliveCallbackAsync` - relaxed timing threshold and Assert.Ignore on slow CI runners.
* `SecurityCertValidationTests` - Assert.Ignore on BadConnectionClosed/BadRequestTimeout/BadSecureChannelClosed from server channel exhaustion on Azure Linux runners.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
||
|
|
889572472f |
Convert DataValue from class to readonly struct for further GC relief (#3796)
Convert `DataValue` from a mutable reference type (`class`) to a `readonly struct` to eliminate per-allocation GC pressure on every attribute read, subscription publish, and history sample. ### Key API changes (user-visible) | Before | After | Pattern | |---|---|---| | `class DataValue` | `readonly struct DataValue : INullable` | Foundation | | `Equals(DataValue?)` / `operator ==(DataValue?, DataValue?)` | `Equals(DataValue)` / `operator ==(DataValue, DataValue)` | Value semantics | | `IEncoder.WriteDataValue(string?, DataValue?)` | `IEncoder.WriteDataValue(string?, DataValue)` | Non-nullable wire API | | `IDecoder.ReadDataValue(...) -> DataValue?` | `IDecoder.ReadDataValue(...) -> DataValue` | Same | | `IDataChangeMonitoredItemQueue.PeekLast/Oldest()` | `TryPeekLastValue/Oldest(out DataValue)` | TryGet pattern | | `IAggregateCalculator.GetProcessedValue(bool)` | `TryGetProcessedValue(bool, out DataValue)` | Same | | `IUaPubSubDataStore.ReadPublishedDataItem(...)` | `TryReadPublishedDataItem(NodeId, uint, out DataValue)` | Same | | `Dictionary<uint, DataValue?>` (NodeCacheContext) | `Dictionary<uint, DataValue>` | Default + IsNull | | `IHistoryDataSource.FirstRaw/NextRaw` | `TryFirstRaw/TryNextRaw(out DataValue)` | TryGet pattern | | `NodeState.ReadAttribute(... DataValue)` | `NodeState.ReadAttribute(... ref DataValue)` | Sync mutation via ref | | `NodeState.ReadAttributeAsync(... DataValue)` | `NodeState.ReadAttributeAsync(...) -> ValueTask<(ServiceResult, DataValue)>` | Async return tuple | | `obj as DataValue` (heterogeneous Dictionary<string, object>) | `obj is DataValue dv ? dv : default(DataValue)` | Safe struct cast | | `Assert.That(dv, Is.Not.Null)` (tests) | `Assert.That(dv.IsNull, Is.False)` | Struct test pattern | | `[Obsolete] Value` setter, all property setters | Removed; use ctor or `With*()` | Immutability | | `[DataContract]` + `[DataMember]` | Removed; surrogate via `SerializableDataValue` + `DataValueSurrogateProvider` | Serialization | ### Wire format Wire format is **byte-identical** to the previous class-based implementation across binary / JSON / XML encoders. Default DataValue (`.IsNull == true`) is treated as the equivalent of the old null reference (writes JSON `null`, binary `byte 0`, XML omitted element). ### Why TryGet pattern (instead of leaving `DataValue?`) For methods that previously returned `DataValue?` to signal "no value available" (queue peek, aggregate result, data store lookup, history navigation), the conversion to `bool TryGet(out DataValue)` matches BCL conventions (`Dictionary.TryGetValue`, `Queue.TryPeek`, `Int32.TryParse`) and gives the caller an explicit "may be absent" affordance without `Nullable<DataValue>` overhead. ### Breaking changes summary - `DataValue` is now a `readonly struct` - boxing/unboxing semantics change for callers using `object`-typed APIs. - `IEncoder.WriteDataValue` / `IDecoder.ReadDataValue` / `ReadDataValueArray` interface signatures lose the `Nullable` wrapper. - `IDataChangeMonitoredItemQueue.PeekLastValue` / `PeekOldestValue` -> `TryPeekLastValue` / `TryPeekOldestValue` (out parameter). - `IAggregateCalculator.GetProcessedValue` -> `TryGetProcessedValue` (out parameter). - `IUaPubSubDataStore.ReadPublishedDataItem` -> `TryReadPublishedDataItem` (out parameter). - `NodeState.ReadAttribute` takes `ref DataValue`; `ReadAttributeAsync` returns `ValueTask<(ServiceResult, DataValue)>`. - `DataValue` property setters removed (use constructor + `With*` mutators). |
||
|
|
239a40b183 |
GC reduction via IPooledEncodeable activator pooling (#3793)
* GC reduction via IPooledEncodeable activator pooling
Add opt-in activator-level pooling for IEncodeable instances decoded
during V2 subscription publish dispatch. The design replaces the
earlier IAllocator-on-IServiceMessageContext approach (which had a
cross-contamination hazard for non-publish decodes) with a clean
factory-based model where pooling lives on the encodeable activator.
New public API:
- IPooledEncodeable : IEncodeable - opt-in marker with Reuse() method
- PooledEncodeableType<T> : EncodeableType<T> - activator base with
BoundedObjectPool<T> (lock-free, no new package dependency)
- ISubscriptionManager.PoolNotifications { get; set; }
- ManagedSessionOptions.PoolNotifications { get; init; }
- ManagedSessionBuilder.WithPoolNotifications(bool)
Source-gen:
- All concrete non-abstract structure types (including service
request/response types) are generated with PooledEncodeableType<T>
activators and IPooledEncodeable.Reuse() bodies by default
- Derived types use 'new' to hide inherited Reuse/ClearPooledSentinel
so each concrete type routes through its own activator's pool
- No changes to external design XML files (UA Core Services.xml etc.)
- poolable selection is hardcoded in the generator
Benchmarks (MonitoredItemNotification, 1000 ops):
- Allocations: 128 KB -> 408 B (~315x reduction)
- Gen0 collections: 29.75 -> 0.09 per 1000 ops
No interface changes to IEncodeable, IDecoder, IServiceMessageContext,
or ISubscriptionNotificationHandler. Handlers retain by copy when
pooling is enabled.
Call IPooledEncodeable.Reuse() on decoded IServiceRequest and
IServiceResponse after the server is done with them:
- TcpTransportListener.OnRequestReceivedAsync: reuse both request
and response in a finally block after ProcessRequestAsync +
SendResponse complete
- EndpointBase.InvokeServiceAsync (HTTPS path): same pattern after
ProcessRequestAsync + BinaryEncoder.EncodeMessage
Walk acknowledged, overflow-evicted, and disposed NotificationMessage
objects and call IPooledEncodeable.Reuse() on their notification
payloads (MonitoredItemNotification, DataChangeNotification,
EventFieldList, EventNotificationList).
Insertion points in Subscription.cs:
- Acknowledge(): after RemoveAt from m_sentMessages
- InnerPublish() overflow: before RemoveRange/Clear on m_sentMessages
- Dispose(): before m_sentMessages.Clear()
- InnerPublish() unsent-message overflow: before RemoveRange on
the messages list
Replace new T() with XxxActivator.Instance.CreateInstance() for all
server-side notification payload types so instances are rented from
the activator pool instead of heap-allocated:
New static helper ReuseNotificationPayloads() walks the
NotificationMessage.NotificationData, extracts DataChangeNotification
and EventNotificationList via TryGetValue, iterates their items, and
calls Reuse() on each pooled payload.
|
||
|
|
296a904f34 |
Add full OPC UA Part 18 (Role management) support (#3778)
* role management compliant with OPC UA Part 18 Server-side: - New IRoleManager / RoleManager with spec-correct status codes (Bad_AlreadyExists, Bad_NodeIdUnknown, Bad_RequestNotAllowed, Bad_NotFound) for every mutator per Part 18 4.2 / 4.4. - Pre-populate default identities for the three reserved well-known roles per Part 18 4.3 (Anonymous, AuthenticatedUser, TrustedApplication). - Reject mutations on reserved roles with Bad_RequestNotAllowed. - Validate IdentityMappingRuleType per Part 18 4.4.3 (empty criteria for Anonymous/AuthenticatedUser/TrustedApplication; upper-case hex for Thumbprint; Name=Value grammar for X509Subject). - Honour Part 18 4.4.2 default-field-as-wildcard EndpointType comparisons; tighten TrustedApplication/Application rules to require trusted certificate + signed channel. - Introduce CustomConfiguration flag per Part 18 4.4.1. - Add IRoleManager.RoleConfigurationChanged event raised after every successful mutation per Part 18 4.4.1. - Make RoleEntry an immutable snapshot. Address-space binding (typed proxies): - RoleStateBinding switched from stringly-typed OnCallMethod2 plumbing to the source-generated typed proxies (RoleSetState, RoleState, AddRoleMethodState, AddIdentityMethodState, ...). - DiagnosticsNodeManager.AddBehaviourToPredefinedNodeAsync upgrades passive BaseObjectState nodes of RoleSetType / RoleType to the typed RoleSetState / RoleState proxies at predefined-node load time. - New RoleAuthorizationGate.CheckAdmin centralizes SecurityAdmin role plus SignAndEncrypt enforcement per Part 18 4.2 / 4.4 / 5.2. - Bound writable ApplicationsExclude / EndpointsExclude / CustomConfiguration with the same auth gate. - Raise RoleMappingRuleChangedAuditEventType from every successful mutator (Part 18 4.5) via the existing AuditEvents helper. Client library: - New Opc.Ua.Client.Roles.RoleManagementClient + IRoleManagementClient + RoleInfo + SessionRoleExtensions.OpenRoleManagementClient. - Covers list / read / add / remove role, identity, application, endpoint operations plus Set*Exclude via Write Service. Tests: - New RoleManagerTests.cs - 37 NUnit tests for pre-populated roles, reserved-role immutability, spec-correct status codes, criteria validation, ResolveGrantedRoles, exclude semantics, CustomConfiguration, AddRole well-known NodeId reuse, and RoleConfigurationChanged event. Documentation: - Rewrite Docs/RoleBasedUserManagement.md as a Part 18 compliance reference (status-code matrix, client examples, known limitations). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Add Part 18 5 UserManagement implementation Server-side: - New IUserManagement interface (Opc.Ua.Server.UserManagement) modelling Part 18 5.2.1 surface: PasswordLength, PasswordOptions, PasswordRestrictions, SnapshotUsers, AddUser, ModifyUser, RemoveUser, ChangePassword, MustChangePassword, IsUserActive, UserDeactivated event. - Default UserManagement implementation wraps the existing IUserDatabase and stores per-user UserConfigurationMask + description in memory. Validates passwords against PasswordLength + character-class flags from PasswordOptions; honours Part 18 5.2 result codes (Bad_AlreadyExists, Bad_NotFound, Bad_OutOfRange, Bad_NotSupported, Bad_ConfigurationError, Bad_InvalidSelfReference, Bad_IdentityTokenInvalid). - ChangePassword clears the MustChangePassword bit on success. - New UserManagementBinding wires the typed source-generated proxies (UserManagementState, AddUserMethodState, ModifyUserMethodState, RemoveUserMethodState, ChangePasswordMethodState) - typed OnCallAsync delegates everywhere; admin gate via RoleAuthorizationGate.CheckAdmin; ChangePassword gated via RoleAuthorizationGate.CheckSelfUserName; closes active sessions for deactivated users via ISessionManager. - ConfigurationNodeManager.AddBehaviourToPredefinedNodeAsync upgrades the passive UserManagement object to the typed UserManagementState proxy at predefined-node load time; CreateServerConfiguration invokes UserManagementBinding.Bind when an IUserManagement was injected. - IServerInternal gains UserManagement getter + SetUserManagement injector. Tests: - New Tests/Opc.Ua.Server.Tests/UserManagementTests.cs - 18 NUnit tests covering AddUser happy path, duplicate / password-length / config-flag validation, RemoveUser non-existent / self-reference / NoDelete, ModifyUser self-disable / disable-other UserDeactivated event, ChangePassword happy path / same-as-old / wrong-old / MustChangePassword bit clearing / NoChangeByUser rejection, IsUserActive on disabled vs active users. Documentation: - Update Docs/RoleBasedUserManagement.md with a User Management section including the spec result-code matrix, example wiring code, and reduce known limitations - UserManagement is no longer a limitation. |
||
|
|
70b4498db8 |
Certificate manager and ref counted certificate type (#3688)
* New certificate and secrete abstraction with certificate infrastructure and certificate/secret stores. * leak testing for certificate resources to validate new ref counting in every test assembly * Migration guide updated and documentation added for all * Remove IDisposable from Nodestate and UserIdentity. * UserCertificateTokenHandler now just points into certificate registry/stores, no dispose required * Fix CA2000 warnings and cleanup of other diagnostics, increase warning levels in .editorconfig |
||
|
|
13612c03b9 | Fix CreateInstanceOf<X> access restrictions emission and PrioritizedChannel polyfill TryRead bug (#3747) | ||
|
|
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. |
||
|
|
84161c120c |
[Client] Fixed excessive tasks spawning during session connection loss (#3707)
Added checks for Session.KeepAliveStopped before trying to execute Publish for subscriptions. |
||
|
|
26a0b21881 |
Replace session state encoder with IEncodable generation using source generators (#3673)
* Replace SessionStateEncoder with IEncodeable on session/subscription models - Source-gen [DataType]/[DataTypeField] on: MonitoredItemOptions, MonitoredItemState, SubscriptionOptions, SubscriptionState (auto-generated Encode/Decode/IsEqual/Clone) - Manual IEncodeable on: SessionOptions, SessionState, SessionConfiguration (ConfiguredEndpoint and IUserIdentity require manual encoding) - Delete SessionStateEncoder.cs (488 lines removed) - Remove [DataContract]/[DataMember]/[KnownType]/[CollectionDataContract] attributes - Remove JsonSerializerContext classes - Change init -> set, byte[] -> ByteString, DateTime -> DateTimeUtc - MonitoredItems: ArrayOf<MonitoredItemState> with StructureHandling.Inline - Subscriptions: ArrayOf<SubscriptionState> * Source generator: support partial init properties with backing fields Add IsInitOnly detection to the [DataType] source generator so that partial properties with init-only setters can be used in IEncodeable types. For each init-only partial property, the generator: - Emits a private backing field (__PropertyName) - Emits the partial property implementation (get => __field; init => __field = value) - Uses the backing field in Decode() instead of the property - Skips simple init-only fields in Clone() (record 'with' already copies them) Detection uses both IPropertySymbol.SetMethod.IsInitOnly and syntax-tree fallback (SyntaxKind.InitAccessorDeclaration) for partial definitions. * docs: add partial init properties and session state migration sections - SourceGeneratedDataTypes.md: new 'Partial Init Properties' section documenting backing field generation for init-only partial properties - MigrationGuide.md: new 'Session State Persistence' section covering |
||
|
|
6c8c1a6d29 | Enable dispose analyzers CA2000 and CA2213 and fix all issues (#3670) | ||
|
|
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 |