mirror of
https://github.com/OPCFoundation/UA-.NETStandard.git
synced 2026-10-21 17:16:16 +08:00
d552634258
Closes #4510. ## Summary OPC UA Part 6 feeds the **raw** ECDH shared secret into HKDF. .NET Framework only exposes `ECDiffieHellman.DeriveKeyMaterial`, which always hashes it, so the ECC SecureChannel and user-token policies were unavailable on `net48` (`SecurityPolicies.GetInfo` returned `null`). This adds a BouncyCastle polyfill for just that primitive: - **`Opc.Ua.Security.Certificates/Org.BouncyCastle/EcdhRawAgreement.cs`** (`net48` only): an internal `DeriveRawSecretAgreement(this ECDiffieHellman, ECDiffieHellmanPublicKey)` extension using `ECDHBasicAgreement`. It returns the X coordinate padded to the field size, exactly like the .NET 8 BCL method. Keys stay CNG keys; ECDSA signatures and HKDF stay on the platform — only the agreement step is managed code. The point is validated (on curve, not infinity) and mismatched curves are rejected. - Because the extension mirrors the .NET 8 signature, `Nonce.GenerateSecret` now has one code path on every target. - `SupportsRawEccSecretAgreement()` is removed; the CBC-based ECC policies (`ECC_nistP256`, `ECC_nistP384`, `ECC_brainpoolP256r1`, `ECC_brainpoolP384r1`) are offered on every target (still subject to OS curve support). - BouncyCastle was already a `net48` dependency of `Opc.Ua.Security.Certificates`; no new package. (Only `net48` is downlevel now — `netstandard2.1`/`net472` from the issue text are no longer targets.) **Not in scope:** the `_AesGcm` / `_ChaChaPoly` ECC variants (and PubSub DTLS) still need .NET 8 because .NET Framework has no AEAD ciphers — follow-up stacked on this branch. ## Docs `EccProfiles.md` (Known limitations), `migrate/2.0.x/certificates.md`, `ProductionChecklist.md`, `Profiles.md`, `WhatsNewIn2.0.md`. Calls out that on `net48` the agreement step does not run in a FIPS/validated module. ## Tests (local) | Suite | Result | |---|---| | `Opc.Ua.Core.Tests` full, net48 | 5956 passed, 0 failed | | `EccInteropTests` net48 vs 1.5.378 peer (net8.0, native raw ECDH) | 26 passed; 28 skipped (AEAD + curve25519/448) — all four CBC curves, both directions, UserName tokens, token renewal | | `Opc.Ua.Sessions.Tests` ECC filter, net48 | 52 passed, 0 failed | | Server `SessionCoverageTests`/`EphemeralNonce*`, Configuration builder tests, net48 | all pass | | Nonce/ECC/EncryptedSecret + session tests, net10.0 | all pass | New tests: symmetric agreement on all four curves; on net48 an oracle against CNG (`SHA256(raw) == DeriveKeyFromHash`); curve mismatch and off-curve rejection. Tests that asserted the old net48 limitation were updated. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2443 lines
105 KiB
C#
2443 lines
105 KiB
C#
/* ========================================================================
|
|
* Copyright (c) 2005-2025 The OPC Foundation, Inc. All rights reserved.
|
|
*
|
|
* OPC Foundation MIT License 1.00
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use,
|
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following
|
|
* conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* The complete license agreement can be found here:
|
|
* http://opcfoundation.org/License/MIT/1.00/
|
|
* ======================================================================*/
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading.Tasks;
|
|
using NUnit.Framework;
|
|
using Opc.Ua.Tests;
|
|
|
|
#pragma warning disable CA2007 // Consider calling ConfigureAwait on the awaited task
|
|
|
|
namespace Opc.Ua.Configuration.Tests
|
|
{
|
|
/// <summary>
|
|
/// Tests for the ApplicationConfigurationBuilder fluent API.
|
|
/// </summary>
|
|
[TestFixture]
|
|
[Category("ApplicationConfigurationBuilder")]
|
|
[SetCulture("en-us")]
|
|
[SetUICulture("en-us")]
|
|
[Parallelizable]
|
|
public class ApplicationConfigurationBuilderTests
|
|
{
|
|
public const string ApplicationName = "UA Builder Test";
|
|
public const string ApplicationUri = "urn:localhost:opcfoundation.org:BuilderTest";
|
|
public const string ProductUri = "http://opcfoundation.org/UA/BuilderTest";
|
|
public const string SubjectName = "CN=UA Builder Test, O=OPC Foundation, C=US, S=Arizona";
|
|
public const string EndpointUrl = "opc.tcp://localhost:52000";
|
|
|
|
[SetUp]
|
|
public void SetUp()
|
|
{
|
|
m_pkiRoot = Path.GetTempPath() + Path.GetRandomFileName() + Path.DirectorySeparatorChar;
|
|
}
|
|
|
|
[TearDown]
|
|
public void TearDown()
|
|
{
|
|
try
|
|
{
|
|
Directory.Delete(m_pkiRoot, true);
|
|
}
|
|
catch
|
|
{
|
|
// best effort cleanup
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task BuildReturnsBuilderWithCorrectApplicationConfigurationAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
IApplicationConfigurationBuilderTypes builder = appInstance.Build(ApplicationUri, ProductUri);
|
|
|
|
Assert.That(builder, Is.Not.Null);
|
|
Assert.That(appInstance.ApplicationConfiguration, Is.Not.Null);
|
|
Assert.That(appInstance.ApplicationConfiguration.ApplicationName, Is.EqualTo(ApplicationName));
|
|
Assert.That(appInstance.ApplicationConfiguration.ApplicationUri, Is.EqualTo(ApplicationUri));
|
|
Assert.That(appInstance.ApplicationConfiguration.ProductUri, Is.EqualTo(ProductUri));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task BuildSetsDefaultTransportQuotasAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri);
|
|
|
|
Assert.That(appInstance.ApplicationConfiguration!.TransportQuotas, Is.Not.Null);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsClientSetsClientConfigurationAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient();
|
|
|
|
Assert.That(appInstance.ApplicationConfiguration!.ClientConfiguration, Is.Not.Null);
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.Client));
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration.ApplicationType,
|
|
Is.EqualTo(ApplicationType.Client));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsClientFromServerTypeSetsClientAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.Server
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient();
|
|
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.Client));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerFromClientTypeSetsServerAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.Client
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl]);
|
|
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.Server));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerThenClientSetsClientAndServerWithBothConfigsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AsClient();
|
|
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.ClientAndServer));
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ApplicationType,
|
|
Is.EqualTo(ApplicationType.ClientAndServer));
|
|
Assert.That(appInstance.ApplicationConfiguration.ClientConfiguration, Is.Not.Null);
|
|
Assert.That(appInstance.ApplicationConfiguration.ServerConfiguration, Is.Not.Null);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerThenClientSetsClientAndServerAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AsClient();
|
|
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.ClientAndServer));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsClientFromDiscoveryServerThrowsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.DiscoveryServer
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
Assert.Throws<ArgumentException>(() =>
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient());
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerFromDiscoveryServerThrowsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.DiscoveryServer
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
Assert.Throws<ArgumentException>(() =>
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl]));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerSetsBaseAddressesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
const string endpoint1 = "opc.tcp://localhost:51000";
|
|
const string endpoint2 = "opc.tcp://localhost:51001";
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([endpoint1, endpoint2]);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.BaseAddresses.Count,
|
|
Is.EqualTo(2));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerSetsAlternateBaseAddressesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
string[] alternates = ["opc.tcp://myhost:51000"];
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl], alternates);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.AlternateBaseAddresses.Count,
|
|
Is.EqualTo(1));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerDisablesLdsRegistrationByDefaultAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl]);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxRegistrationInterval,
|
|
Is.Zero);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerInitializesEmptyPoliciesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl]);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies.Count,
|
|
Is.Zero);
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration.ServerConfiguration.UserTokenPolicies.Count,
|
|
Is.Zero);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationWithSubjectNameSetsDefaultsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig, Is.Not.Null);
|
|
Assert.That(secConfig.ApplicationCertificate, Is.Not.Null);
|
|
Assert.That(secConfig.ApplicationCertificate.SubjectName, Is.Not.Null.And.Not.Empty);
|
|
Assert.That(secConfig.TrustedPeerCertificates, Is.Not.Null);
|
|
Assert.That(secConfig.TrustedIssuerCertificates, Is.Not.Null);
|
|
Assert.That(secConfig.TrustedHttpsCertificates, Is.Not.Null);
|
|
Assert.That(secConfig.HttpsIssuerCertificates, Is.Not.Null);
|
|
Assert.That(secConfig.TrustedUserCertificates, Is.Not.Null);
|
|
Assert.That(secConfig.UserIssuerCertificates, Is.Not.Null);
|
|
Assert.That(secConfig.RejectedCertificateStore, Is.Not.Null);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationSetsSecureDefaultsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig.AutoAcceptUntrustedCertificates, Is.False);
|
|
Assert.That(secConfig.AddAppCertToTrustedStore, Is.False);
|
|
Assert.That(secConfig.RejectSHA1SignedCertificates, Is.True);
|
|
Assert.That(secConfig.RejectUnknownRevocationStatus, Is.True);
|
|
Assert.That(secConfig.SuppressNonceValidationErrors, Is.False);
|
|
Assert.That(secConfig.SendCertificateChain, Is.True);
|
|
Assert.That(secConfig.MinimumCertificateKeySize, Is.EqualTo(CertificateFactory.DefaultKeySize));
|
|
Assert.That(secConfig.MaxRejectedCertificates, Is.EqualTo(5));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationWithCertIdListSetsSecureDefaultsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(certs, m_pkiRoot);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig.ApplicationCertificates.Count, Is.GreaterThan(0));
|
|
Assert.That(secConfig.AutoAcceptUntrustedCertificates, Is.False);
|
|
Assert.That(secConfig.SendCertificateChain, Is.True);
|
|
Assert.That(secConfig.MaxRejectedCertificates, Is.EqualTo(5));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationStoresSetsAllStoresAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
string appRoot = Path.Combine(m_pkiRoot, "own");
|
|
string trustedRoot = Path.Combine(m_pkiRoot, "trusted");
|
|
string issuerRoot = Path.Combine(m_pkiRoot, "issuer");
|
|
string rejectedRoot = Path.Combine(m_pkiRoot, "rejected");
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfigurationStores(
|
|
SubjectName,
|
|
appRoot,
|
|
trustedRoot,
|
|
issuerRoot,
|
|
rejectedRoot);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig.ApplicationCertificate, Is.Not.Null);
|
|
Assert.That(secConfig.TrustedPeerCertificates, Is.Not.Null);
|
|
Assert.That(secConfig.TrustedIssuerCertificates, Is.Not.Null);
|
|
Assert.That(secConfig.RejectedCertificateStore, Is.Not.Null);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationStoresWithoutRejectedRootUsesDefaultAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
string appRoot = Path.Combine(m_pkiRoot, "own");
|
|
string trustedRoot = Path.Combine(m_pkiRoot, "trusted");
|
|
string issuerRoot = Path.Combine(m_pkiRoot, "issuer");
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfigurationStores(
|
|
SubjectName,
|
|
appRoot,
|
|
trustedRoot,
|
|
issuerRoot);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig.RejectedCertificateStore, Is.Not.Null);
|
|
Assert.That(secConfig.RejectedCertificateStore.StorePath, Is.Not.Null.And.Not.Empty);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationUserStoreConfiguresUserStoresAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
string appRoot = Path.Combine(m_pkiRoot, "own");
|
|
string trustedRoot = Path.Combine(m_pkiRoot, "trusted");
|
|
string issuerRoot = Path.Combine(m_pkiRoot, "issuer");
|
|
string userTrusted = Path.Combine(m_pkiRoot, "trustedUser");
|
|
string userIssuer = Path.Combine(m_pkiRoot, "issuerUser");
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfigurationStores(SubjectName, appRoot, trustedRoot, issuerRoot)
|
|
.AddSecurityConfigurationUserStore(userTrusted, userIssuer);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig.TrustedUserCertificates, Is.Not.Null);
|
|
Assert.That(secConfig.UserIssuerCertificates, Is.Not.Null);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationHttpsStoreConfiguresHttpsStoresAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
string appRoot = Path.Combine(m_pkiRoot, "own");
|
|
string trustedRoot = Path.Combine(m_pkiRoot, "trusted");
|
|
string issuerRoot = Path.Combine(m_pkiRoot, "issuer");
|
|
string httpsTrusted = Path.Combine(m_pkiRoot, "trustedHttps");
|
|
string httpsIssuer = Path.Combine(m_pkiRoot, "issuerHttps");
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfigurationStores(SubjectName, appRoot, trustedRoot, issuerRoot)
|
|
.AddSecurityConfigurationHttpsStore(httpsTrusted, httpsIssuer);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig.TrustedHttpsCertificates, Is.Not.Null);
|
|
Assert.That(secConfig.HttpsIssuerCertificates, Is.Not.Null);
|
|
// both stores live under the roots that were passed in (the
|
|
// trusted store used to be derived from the store type).
|
|
Assert.That(secConfig.TrustedHttpsCertificates.StorePath, Does.StartWith(httpsTrusted));
|
|
Assert.That(secConfig.HttpsIssuerCertificates.StorePath, Does.StartWith(httpsIssuer));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetHiResClockDisabledSetsPropertyAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetHiResClockDisabled(true);
|
|
|
|
Assert.That(appInstance.ApplicationConfiguration!.DisableHiResClock, Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetTransportQuotasReplacesQuotasAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
var quotas = new TransportQuotas { OperationTimeout = 42000 };
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetTransportQuotas(quotas);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.OperationTimeout,
|
|
Is.EqualTo(42000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetOperationTimeoutSetsValueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetOperationTimeout(15000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.OperationTimeout,
|
|
Is.EqualTo(15000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetMaxStringLengthSetsValueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetMaxStringLength(1_000_000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.MaxStringLength,
|
|
Is.EqualTo(1_000_000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetMaxByteStringLengthSetsValueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetMaxByteStringLength(2_000_000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.MaxByteStringLength,
|
|
Is.EqualTo(2_000_000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetMaxArrayLengthSetsValueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetMaxArrayLength(5000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.MaxArrayLength,
|
|
Is.EqualTo(5000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetMaxMessageSizeSetsValueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetMaxMessageSize(8_000_000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.MaxMessageSize,
|
|
Is.EqualTo(8_000_000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetMaxBufferSizeSetsValueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetMaxBufferSize(65536);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.MaxBufferSize,
|
|
Is.EqualTo(65536));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetChannelLifetimeSetsValueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetChannelLifetime(600_000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.ChannelLifetime,
|
|
Is.EqualTo(600_000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetSecurityTokenLifetimeSetsValueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetSecurityTokenLifetime(3_600_000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.SecurityTokenLifetime,
|
|
Is.EqualTo(3_600_000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetMaxEncodingNestingLevelsSetsValueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetMaxEncodingNestingLevels(128);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.MaxEncodingNestingLevels,
|
|
Is.EqualTo(128));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SetMaxDecoderRecoveriesSetsValueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.SetMaxDecoderRecoveries(10);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.TransportQuotas!.MaxDecoderRecoveries,
|
|
Is.EqualTo(10));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SecurityOptionsSetAutoAcceptUntrustedCertificatesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetAutoAcceptUntrustedCertificates(true);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.SecurityConfiguration.AutoAcceptUntrustedCertificates,
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SecurityOptionsSetAddAppCertToTrustedStoreAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetAddAppCertToTrustedStore(true);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.SecurityConfiguration.AddAppCertToTrustedStore,
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SecurityOptionsSetRejectSHA1SignedCertificatesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetRejectSHA1SignedCertificates(false);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.SecurityConfiguration.RejectSHA1SignedCertificates,
|
|
Is.False);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SecurityOptionsSetRejectUnknownRevocationStatusAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetRejectUnknownRevocationStatus(false);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.SecurityConfiguration.RejectUnknownRevocationStatus,
|
|
Is.False);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SecurityOptionsSetUseValidatedCertificatesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetUseValidatedCertificates(true);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.SecurityConfiguration.UseValidatedCertificates,
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SecurityOptionsSetSuppressNonceValidationErrorsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetSuppressNonceValidationErrors(true);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.SecurityConfiguration.SuppressNonceValidationErrors,
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SecurityOptionsSetSendCertificateChainAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetSendCertificateChain(false);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.SecurityConfiguration.SendCertificateChain,
|
|
Is.False);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SecurityOptionsSetMinimumCertificateKeySizeAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetMinimumCertificateKeySize(4096);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.SecurityConfiguration.MinimumCertificateKeySize,
|
|
Is.EqualTo(4096));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SecurityOptionsSetMaxRejectedCertificatesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetMaxRejectedCertificates(100);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.SecurityConfiguration.MaxRejectedCertificates,
|
|
Is.EqualTo(100));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task SecurityOptionsSetApplicationCertificatesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.SetApplicationCertificates(certs);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.SecurityConfiguration.ApplicationCertificates.Count,
|
|
Is.GreaterThan(0));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// The certificate identifier overload of AddSecurityConfiguration must accept an
|
|
/// identifier which does not name a certificate type, the same way the obsolete
|
|
/// subject name overload does. See https://github.com/OPCFoundation/UA-.NETStandard/issues/4315.
|
|
/// </summary>
|
|
[Test]
|
|
public async Task AddSecurityConfigurationWithoutCertificateTypeKeepsTheCertificateAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.Client
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
ApplicationConfiguration configuration = await appInstance
|
|
.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(
|
|
[
|
|
new CertificateIdentifier
|
|
{
|
|
StoreType = CertificateStoreType.Directory,
|
|
StorePath = Path.Combine(m_pkiRoot, "own"),
|
|
SubjectName = SubjectName
|
|
// CertificateType deliberately not set
|
|
}
|
|
],
|
|
m_pkiRoot)
|
|
.SetAutoAcceptUntrustedCertificates(true)
|
|
.CreateAsync().ConfigureAwait(false);
|
|
|
|
SecurityConfiguration securityConfiguration = configuration.SecurityConfiguration;
|
|
Assert.That(securityConfiguration.ApplicationCertificates, Has.Count.EqualTo(1));
|
|
Assert.That(
|
|
securityConfiguration.ApplicationCertificates[0].CertificateType,
|
|
Is.EqualTo(ObjectTypeIds.RsaSha256ApplicationCertificateType));
|
|
Assert.That(
|
|
securityConfiguration.SupportedSecurityPolicies.ToArray(),
|
|
Contains.Item(SecurityPolicies.Basic256Sha256));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddUnsecurePolicyNoneAddsPolicyWhenTrueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddUnsecurePolicyNone();
|
|
|
|
ArrayOf<ServerSecurityPolicy> policies = appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies;
|
|
Assert.That(policies.Count, Is.EqualTo(1));
|
|
Assert.That(policies[0].SecurityMode, Is.EqualTo(MessageSecurityMode.None));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddUnsecurePolicyNoneSkipsWhenFalseAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddUnsecurePolicyNone(false);
|
|
|
|
ArrayOf<ServerSecurityPolicy> policies = appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies;
|
|
Assert.That(policies.Count, Is.Zero);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSignPoliciesAddsPoliciesWhenTrueAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddSignPolicies();
|
|
|
|
ArrayOf<ServerSecurityPolicy> policies = appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies;
|
|
Assert.That(policies.Count, Is.GreaterThan(0));
|
|
Assert.That(
|
|
policies.ToList().All(p => p.SecurityMode >= MessageSecurityMode.Sign),
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSignPoliciesSkipsWhenFalseAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddSignPolicies(false);
|
|
|
|
ArrayOf<ServerSecurityPolicy> policies = appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies;
|
|
Assert.That(policies.Count, Is.Zero);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSignAndEncryptPoliciesAddsPoliciesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddSignAndEncryptPolicies();
|
|
|
|
ArrayOf<ServerSecurityPolicy> policies = appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies;
|
|
Assert.That(policies.Count, Is.GreaterThan(0));
|
|
Assert.That(
|
|
policies.ToList().All(p => p.SecurityMode == MessageSecurityMode.SignAndEncrypt),
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSignAndEncryptPoliciesSkipsWhenFalseAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddSignAndEncryptPolicies(false);
|
|
|
|
ArrayOf<ServerSecurityPolicy> policies = appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies;
|
|
Assert.That(policies.Count, Is.Zero);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddEccSignPoliciesAddsPoliciesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddEccSignPolicies();
|
|
|
|
ArrayOf<ServerSecurityPolicy> policies = appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies;
|
|
Assert.That(policies.Count, Is.GreaterThan(0));
|
|
Assert.That(
|
|
policies.ToList().All(p => p.SecurityMode == MessageSecurityMode.Sign),
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddEccSignAndEncryptPoliciesAddsPoliciesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddEccSignAndEncryptPolicies();
|
|
|
|
ArrayOf<ServerSecurityPolicy> policies = appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies;
|
|
Assert.That(policies.Count, Is.GreaterThan(0));
|
|
Assert.That(
|
|
policies.ToList().All(p => p.SecurityMode == MessageSecurityMode.SignAndEncrypt),
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddPolicyWithValidParametersAddsPolicyAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddPolicy(MessageSecurityMode.SignAndEncrypt, SecurityPolicies.Basic256Sha256);
|
|
|
|
ArrayOf<ServerSecurityPolicy> policies = appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies;
|
|
Assert.That(policies.Count, Is.EqualTo(1));
|
|
Assert.That(policies[0].SecurityMode, Is.EqualTo(MessageSecurityMode.SignAndEncrypt));
|
|
Assert.That(policies[0].SecurityPolicyUri, Is.EqualTo(SecurityPolicies.Basic256Sha256));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddPolicyWithNoneModeThrowsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
Assert.Throws<ArgumentException>(() =>
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddPolicy(MessageSecurityMode.None, SecurityPolicies.None));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddPolicyWithNoneUriThrowsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
Assert.Throws<ArgumentException>(() =>
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddPolicy(MessageSecurityMode.Sign, SecurityPolicies.None));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddPolicyWithInvalidUriThrowsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
Assert.Throws<ArgumentException>(() =>
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddPolicy(MessageSecurityMode.Sign, "not-a-valid-policy-uri"));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddDuplicatePolicyDoesNotDuplicateAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddPolicy(MessageSecurityMode.SignAndEncrypt, SecurityPolicies.Basic256Sha256)
|
|
.AddPolicy(MessageSecurityMode.SignAndEncrypt, SecurityPolicies.Basic256Sha256);
|
|
|
|
ArrayOf<ServerSecurityPolicy> policies = appInstance.ApplicationConfiguration!.ServerConfiguration!.SecurityPolicies;
|
|
Assert.That(policies.Count, Is.EqualTo(1));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddUserTokenPolicyByTypeAddsPoliciesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddUserTokenPolicy(UserTokenType.Anonymous)
|
|
.AddUserTokenPolicy(UserTokenType.UserName);
|
|
|
|
ArrayOf<UserTokenPolicy> tokenPolicies = appInstance.ApplicationConfiguration!.ServerConfiguration!.UserTokenPolicies;
|
|
Assert.That(tokenPolicies.Count, Is.EqualTo(2));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddUserTokenPolicyWithObjectAddsPolicyAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
var policy = new UserTokenPolicy(UserTokenType.Certificate)
|
|
{
|
|
SecurityPolicyUri = SecurityPolicies.Basic256Sha256
|
|
};
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddUserTokenPolicy(policy);
|
|
|
|
ArrayOf<UserTokenPolicy> tokenPolicies = appInstance.ApplicationConfiguration!.ServerConfiguration!.UserTokenPolicies;
|
|
Assert.That(tokenPolicies.Count, Is.EqualTo(1));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddUserTokenPolicyWithNullThrowsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
Assert.Throws<ArgumentNullException>(() =>
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddUserTokenPolicy(null!));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMinRequestThreadCountAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMinRequestThreadCount(5);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MinRequestThreadCount,
|
|
Is.EqualTo(5));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxRequestThreadCountAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxRequestThreadCount(100);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxRequestThreadCount,
|
|
Is.EqualTo(100));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxQueuedRequestCountAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxQueuedRequestCount(200);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxQueuedRequestCount,
|
|
Is.EqualTo(200));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetDiagnosticsEnabledAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetDiagnosticsEnabled(true);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.DiagnosticsEnabled,
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxSessionCountAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxSessionCount(500);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxSessionCount,
|
|
Is.EqualTo(500));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxChannelCountAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxChannelCount(300);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxChannelCount,
|
|
Is.EqualTo(300));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMinSessionTimeoutAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMinSessionTimeout(1000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MinSessionTimeout,
|
|
Is.EqualTo(1000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxSessionTimeoutAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxSessionTimeout(60000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxSessionTimeout,
|
|
Is.EqualTo(60000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxFailedAuthenticationAttemptsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxFailedAuthenticationAttempts(0);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxFailedAuthenticationAttempts,
|
|
Is.Zero);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetContinuationPointsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxBrowseContinuationPoints(10)
|
|
.SetMaxQueryContinuationPoints(20)
|
|
.SetMaxHistoryContinuationPoints(30);
|
|
|
|
ServerConfiguration srv = appInstance.ApplicationConfiguration!.ServerConfiguration!;
|
|
Assert.That(srv!.MaxBrowseContinuationPoints, Is.EqualTo(10));
|
|
Assert.That(srv.MaxQueryContinuationPoints, Is.EqualTo(20));
|
|
Assert.That(srv.MaxHistoryContinuationPoints, Is.EqualTo(30));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxRequestAgeAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxRequestAge(600_000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxRequestAge,
|
|
Is.EqualTo(600_000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetPublishingIntervalsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMinPublishingInterval(50)
|
|
.SetMaxPublishingInterval(60000)
|
|
.SetPublishingResolution(100);
|
|
|
|
ServerConfiguration srv = appInstance.ApplicationConfiguration!.ServerConfiguration!;
|
|
Assert.That(srv!.MinPublishingInterval, Is.EqualTo(50));
|
|
Assert.That(srv.MaxPublishingInterval, Is.EqualTo(60000));
|
|
Assert.That(srv.PublishingResolution, Is.EqualTo(100));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetSubscriptionLifetimes()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMinSubscriptionLifetime(1000)
|
|
.SetMaxSubscriptionLifetime(3_600_000);
|
|
|
|
ServerConfiguration srv = appInstance.ApplicationConfiguration!.ServerConfiguration!;
|
|
Assert.That(srv!.MinSubscriptionLifetime, Is.EqualTo(1000));
|
|
Assert.That(srv.MaxSubscriptionLifetime, Is.EqualTo(3_600_000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetQueueSizesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxMessageQueueSize(500)
|
|
.SetMaxNotificationQueueSize(1000)
|
|
.SetMaxNotificationsPerPublish(2000)
|
|
.SetMaxEventQueueSize(3000);
|
|
|
|
ServerConfiguration srv = appInstance.ApplicationConfiguration!.ServerConfiguration!;
|
|
Assert.That(srv!.MaxMessageQueueSize, Is.EqualTo(500));
|
|
Assert.That(srv.MaxNotificationQueueSize, Is.EqualTo(1000));
|
|
Assert.That(srv.MaxNotificationsPerPublish, Is.EqualTo(2000));
|
|
Assert.That(srv.MaxEventQueueSize, Is.EqualTo(3000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMinSupportedSamplingIntervalAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMinSupportedSamplingInterval(100);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MinSupportedSamplingInterval,
|
|
Is.EqualTo(100.0));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetAvailableSamplingRatesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
ArrayOf<SamplingRateGroup> rates =
|
|
[
|
|
new SamplingRateGroup(100, 100, 10)
|
|
];
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetAvailableSamplingRates(rates);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.AvailableSamplingRates.Count,
|
|
Is.EqualTo(1));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetRegistrationEndpointAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
var endpoint = new EndpointDescription("opc.tcp://localhost:4840");
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetRegistrationEndpoint(endpoint);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.RegistrationEndpoint,
|
|
Is.Not.Null);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxRegistrationIntervalAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxRegistrationInterval(30000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxRegistrationInterval,
|
|
Is.EqualTo(30000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetNodeManagerSaveFileAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetNodeManagerSaveFile("nodemanager.xml");
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.NodeManagerSaveFile,
|
|
Is.EqualTo("nodemanager.xml"));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxPublishRequestCountAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxPublishRequestCount(50);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxPublishRequestCount,
|
|
Is.EqualTo(50));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxSubscriptionCountAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxSubscriptionCount(200);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxSubscriptionCount,
|
|
Is.EqualTo(200));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsAddServerProfileAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
const string profile = "http://opcfoundation.org/UA-Profile/Server/StandardUA";
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddServerProfile(profile);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.ServerProfileArray.ToList(),
|
|
Does.Contain(profile));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetShutdownDelayAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetShutdownDelay(5);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.ShutdownDelay,
|
|
Is.EqualTo(5));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsAddServerCapabilitiesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddServerCapabilities("DA")
|
|
.AddServerCapabilities("HA");
|
|
|
|
var capabilities = appInstance.ApplicationConfiguration!.ServerConfiguration!.ServerCapabilities.ToList();
|
|
Assert.That(capabilities, Does.Contain("DA"));
|
|
Assert.That(capabilities, Does.Contain("HA"));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetSupportedPrivateKeyFormatsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
var formats = new List<string> { "PEM", "PFX" }.ToArrayOf();
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetSupportedPrivateKeyFormats(formats);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.SupportedPrivateKeyFormats.Count,
|
|
Is.EqualTo(2));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxTrustListSizeAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxTrustListSize(65536);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxTrustListSize,
|
|
Is.EqualTo(65536));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMultiCastDnsEnabledAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMultiCastDnsEnabled(true);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MultiCastDnsEnabled,
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetReverseConnectAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
var reverseConnect = new ReverseConnectServerConfiguration();
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetReverseConnect(reverseConnect);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.ReverseConnect,
|
|
Is.Not.Null);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetOperationLimitsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
var limits = new OperationLimits { MaxNodesPerRead = 100 };
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetOperationLimits(limits);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.OperationLimits,
|
|
Is.Not.Null);
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration.ServerConfiguration.OperationLimits.MaxNodesPerRead,
|
|
Is.EqualTo(100));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetAuditingEnabledAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetAuditingEnabled(true);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.AuditingEnabled,
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetHttpsMutualTlsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetHttpsMutualTls(true);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.HttpsMutualTls,
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetDurableSubscriptionsEnabledAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetDurableSubscriptionsEnabled(true);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.DurableSubscriptionsEnabled,
|
|
Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxDurableNotificationQueueSizeAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxDurableNotificationQueueSize(5000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxDurableNotificationQueueSize,
|
|
Is.EqualTo(5000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxDurableEventQueueSizeAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxDurableEventQueueSize(3000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxDurableEventQueueSize,
|
|
Is.EqualTo(3000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ServerOptionsSetMaxDurableSubscriptionLifetimeAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.SetMaxDurableSubscriptionLifetime(720);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ServerConfiguration!.MaxDurableSubscriptionLifetimeInHours,
|
|
Is.EqualTo(720));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ClientOptionsSetDefaultSessionTimeoutAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.SetDefaultSessionTimeout(30000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ClientConfiguration!.DefaultSessionTimeout,
|
|
Is.EqualTo(30000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ClientOptionsAddWellKnownDiscoveryUrlsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddWellKnownDiscoveryUrls("opc.tcp://localhost:4840");
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ClientConfiguration!.WellKnownDiscoveryUrls.Count,
|
|
Is.EqualTo(1));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ClientOptionsAddDiscoveryServerAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
var discovery = new EndpointDescription("opc.tcp://localhost:4840");
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddDiscoveryServer(discovery);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ClientConfiguration!.DiscoveryServers.Count,
|
|
Is.EqualTo(1));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ClientOptionsSetEndpointCacheFilePathAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.SetEndpointCacheFilePath("endpoints.xml");
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ClientConfiguration!.EndpointCacheFilePath,
|
|
Is.EqualTo("endpoints.xml"));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ClientOptionsSetMinSubscriptionLifetimeAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
IApplicationConfigurationBuilderClientOptions clientBuilder =
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient();
|
|
clientBuilder.SetMinSubscriptionLifetime(5000);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ClientConfiguration!.MinSubscriptionLifetime,
|
|
Is.EqualTo(5000));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ClientOptionsSetReverseConnectAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
var reverseConnect = new ReverseConnectClientConfiguration();
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.SetReverseConnect(reverseConnect);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ClientConfiguration!.ReverseConnect,
|
|
Is.Not.Null);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task ClientOptionsSetClientOperationLimitsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
var limits = new OperationLimits { MaxNodesPerRead = 50 };
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.SetClientOperationLimits(limits);
|
|
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration!.ClientConfiguration!.OperationLimits,
|
|
Is.Not.Null);
|
|
Assert.That(
|
|
appInstance.ApplicationConfiguration.ClientConfiguration.OperationLimits.MaxNodesPerRead,
|
|
Is.EqualTo(50));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task CreateAsyncWithServerTypeAndNoServerConfigThrowsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.Server
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri);
|
|
|
|
// Directly access builder to bypass fluent chain - ServerConfig is null
|
|
var builder = new ApplicationConfigurationBuilder(appInstance);
|
|
Assert.ThrowsAsync<ArgumentException>(async () =>
|
|
await builder.CreateAsync().ConfigureAwait(false));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task CreateAsyncWithClientTypeAndNoClientConfigThrowsAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.Client
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri);
|
|
|
|
// Directly access builder to bypass fluent chain - ClientConfig is null
|
|
var builder = new ApplicationConfigurationBuilder(appInstance);
|
|
Assert.ThrowsAsync<ArgumentException>(async () =>
|
|
await builder.CreateAsync().ConfigureAwait(false));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task CreateAsyncForClientCreatesValidConfigAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
ApplicationConfiguration config = await appInstance
|
|
.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(certs, m_pkiRoot)
|
|
.CreateAsync()
|
|
.ConfigureAwait(false);
|
|
|
|
Assert.That(config, Is.Not.Null);
|
|
Assert.That(config.ClientConfiguration, Is.Not.Null);
|
|
Assert.That(config.SecurityConfiguration, Is.Not.Null);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task CreateAsyncForServerAddsDefaultUserTokenPolicyAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
ApplicationConfiguration config = await appInstance
|
|
.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddSecurityConfiguration(certs, m_pkiRoot)
|
|
.CreateAsync()
|
|
.ConfigureAwait(false);
|
|
|
|
Assert.That(config.ServerConfiguration!.UserTokenPolicies.Count, Is.GreaterThan(0));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task CreateAsyncForServerAddsDefaultSecurityPoliciesAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
ApplicationConfiguration config = await appInstance
|
|
.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AddSecurityConfiguration(certs, m_pkiRoot)
|
|
.CreateAsync()
|
|
.ConfigureAwait(false);
|
|
|
|
Assert.That(config.ServerConfiguration!.SecurityPolicies.Count, Is.GreaterThan(0));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void CreateDefaultApplicationCertificatesReturnsMultipleCerts()
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
// RSA + ECC P256 + ECC P384 at minimum, plus Brainpool on non-macOS
|
|
Assert.That(certs.Count, Is.GreaterThanOrEqualTo(3));
|
|
|
|
// verify first cert is RSA SHA256
|
|
Assert.That(
|
|
certs[0].CertificateType,
|
|
Is.EqualTo(ObjectTypeIds.RsaSha256ApplicationCertificateType));
|
|
}
|
|
|
|
[Test]
|
|
public void CreateDefaultApplicationCertificatesIncludesBrainpoolOnNonMacOS()
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
if (!RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
|
|
{
|
|
Assert.That(certs.Count, Is.GreaterThanOrEqualTo(5));
|
|
}
|
|
else
|
|
{
|
|
Assert.That(certs.Count, Is.EqualTo(3));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void CreateDefaultApplicationCertificatesSetsStoreTypeAndPath()
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
foreach (CertificateIdentifier cert in certs)
|
|
{
|
|
Assert.That(cert.StoreType, Is.EqualTo(CertificateStoreType.Directory));
|
|
Assert.That(cert.StorePath, Is.EqualTo(m_pkiRoot));
|
|
Assert.That(cert.SubjectName, Is.EqualTo(SubjectName));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public void CreateDefaultApplicationCertificatesWithNullStoreType()
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(SubjectName);
|
|
|
|
Assert.That(certs.Count, Is.GreaterThanOrEqualTo(3));
|
|
Assert.That(certs[0].StoreType, Is.Null);
|
|
Assert.That(certs[0].StorePath, Is.Null);
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationWithDefaultPkiRootAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig, Is.Not.Null);
|
|
Assert.That(secConfig.ApplicationCertificate, Is.Not.Null);
|
|
Assert.That(secConfig.ApplicationCertificate.StorePath, Is.Not.Null.And.Not.Empty);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationWithCertIdListAndDefaultPkiRootAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(certs);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig, Is.Not.Null);
|
|
Assert.That(secConfig.TrustedPeerCertificates.StorePath, Is.Not.Null.And.Not.Empty);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task FullClientAndServerBuilderFlowAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
ApplicationConfiguration config = await appInstance
|
|
.Build(ApplicationUri, ProductUri)
|
|
.SetOperationTimeout(10000)
|
|
.SetMaxStringLength(500_000)
|
|
.SetMaxByteStringLength(1_000_000)
|
|
.SetMaxArrayLength(10_000)
|
|
.SetMaxMessageSize(4_000_000)
|
|
.SetMaxBufferSize(65536)
|
|
.SetChannelLifetime(300_000)
|
|
.SetSecurityTokenLifetime(3_600_000)
|
|
.SetMaxEncodingNestingLevels(64)
|
|
.SetMaxDecoderRecoveries(5)
|
|
.AsServer([EndpointUrl], ["opc.tcp://althost:51000"])
|
|
.AddUnsecurePolicyNone()
|
|
.AddSignPolicies()
|
|
.AddSignAndEncryptPolicies()
|
|
.AddEccSignPolicies()
|
|
.AddEccSignAndEncryptPolicies()
|
|
.AddUserTokenPolicy(UserTokenType.Anonymous)
|
|
.AddUserTokenPolicy(UserTokenType.UserName)
|
|
.SetDiagnosticsEnabled(true)
|
|
.SetMaxSessionCount(100)
|
|
.SetMaxChannelCount(50)
|
|
.SetMinSessionTimeout(1000)
|
|
.SetMaxSessionTimeout(60000)
|
|
.SetMaxBrowseContinuationPoints(10)
|
|
.SetMaxQueryContinuationPoints(10)
|
|
.SetMaxHistoryContinuationPoints(10)
|
|
.SetMaxRequestAge(600_000)
|
|
.SetMinPublishingInterval(50)
|
|
.SetMaxPublishingInterval(30000)
|
|
.SetPublishingResolution(50)
|
|
.SetMinSubscriptionLifetime(1000)
|
|
.SetMaxSubscriptionLifetime(3_600_000)
|
|
.SetMaxMessageQueueSize(100)
|
|
.SetMaxNotificationQueueSize(1000)
|
|
.SetMaxNotificationsPerPublish(5000)
|
|
.SetMinSupportedSamplingInterval(100)
|
|
.SetMaxEventQueueSize(10000)
|
|
.SetMaxRegistrationInterval(30000)
|
|
.SetNodeManagerSaveFile("nodes.xml")
|
|
.SetMaxPublishRequestCount(20)
|
|
.SetMaxSubscriptionCount(100)
|
|
.AddServerProfile("http://opcfoundation.org/UA-Profile/Server/StandardUA")
|
|
.SetShutdownDelay(5)
|
|
.AddServerCapabilities("DA")
|
|
.SetMaxTrustListSize(65536)
|
|
.SetMultiCastDnsEnabled(false)
|
|
.SetAuditingEnabled(true)
|
|
.SetHttpsMutualTls(false)
|
|
.SetDurableSubscriptionsEnabled(true)
|
|
.SetMaxDurableNotificationQueueSize(5000)
|
|
.SetMaxDurableEventQueueSize(3000)
|
|
.SetMaxDurableSubscriptionLifetime(720)
|
|
.AsClient()
|
|
.SetDefaultSessionTimeout(30000)
|
|
.AddWellKnownDiscoveryUrls("opc.tcp://localhost:4840")
|
|
.SetEndpointCacheFilePath("endpoints.xml")
|
|
.AddSecurityConfiguration(certs, m_pkiRoot)
|
|
.SetAutoAcceptUntrustedCertificates(true)
|
|
.SetAddAppCertToTrustedStore(true)
|
|
.SetMinimumCertificateKeySize(1024)
|
|
.SetRejectSHA1SignedCertificates(false)
|
|
.SetRejectUnknownRevocationStatus(false)
|
|
.SetSendCertificateChain(true)
|
|
.SetSuppressNonceValidationErrors(true)
|
|
.SetMaxRejectedCertificates(10)
|
|
.SetUseValidatedCertificates(true)
|
|
.SetHiResClockDisabled(false)
|
|
.CreateAsync()
|
|
.ConfigureAwait(false);
|
|
|
|
Assert.That(config, Is.Not.Null);
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.ClientAndServer));
|
|
Assert.That(config.ClientConfiguration, Is.Not.Null);
|
|
Assert.That(config.ServerConfiguration, Is.Not.Null);
|
|
Assert.That(config.SecurityConfiguration, Is.Not.Null);
|
|
Assert.That(config.TransportQuotas!.OperationTimeout, Is.EqualTo(10000));
|
|
Assert.That(config.ServerConfiguration.DiagnosticsEnabled, Is.True);
|
|
Assert.That(config.ServerConfiguration.DurableSubscriptionsEnabled, Is.True);
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsClientIdempotentWhenAlreadyClientAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.Client
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient();
|
|
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.Client));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsClientIdempotentWhenAlreadyClientAndServerAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.ClientAndServer
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient();
|
|
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.ClientAndServer));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerIdempotentWhenAlreadyServerAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.Server
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl]);
|
|
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.Server));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerIdempotentWhenAlreadyClientAndServerAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.ClientAndServer
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl]);
|
|
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.ClientAndServer));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsServerFromClientTypeAfterClientSelectedSetsClientAndServerAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.Client
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AsClient();
|
|
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.ClientAndServer));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AsClientAfterServerSelectedSetsClientAndServerAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry)
|
|
{
|
|
ApplicationName = ApplicationName,
|
|
ApplicationType = ApplicationType.Server
|
|
};
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsServer([EndpointUrl])
|
|
.AsClient();
|
|
|
|
Assert.That(appInstance.ApplicationType, Is.EqualTo(ApplicationType.ClientAndServer));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationWithSeparateRejectedRootAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
string rejectedRoot = Path.Combine(m_pkiRoot, "rejected");
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot, null, rejectedRoot);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig.RejectedCertificateStore, Is.Not.Null);
|
|
Assert.That(secConfig.RejectedCertificateStore.StorePath, Does.Contain("rejected"));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationWithSeparateAppRootAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
string appRoot = Path.Combine(m_pkiRoot, "app");
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot, appRoot);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig.ApplicationCertificate, Is.Not.Null);
|
|
Assert.That(secConfig.ApplicationCertificate.StorePath, Does.Contain("app"));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddSecurityConfigurationWithCertIdListAndSeparateRejectedRootAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
string rejectedRoot = Path.Combine(m_pkiRoot, "rejected");
|
|
|
|
ArrayOf<CertificateIdentifier> certs =
|
|
ApplicationConfigurationBuilder.CreateDefaultApplicationCertificates(
|
|
SubjectName,
|
|
CertificateStoreType.Directory,
|
|
m_pkiRoot);
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(certs, m_pkiRoot, rejectedRoot);
|
|
|
|
SecurityConfiguration secConfig = appInstance.ApplicationConfiguration!.SecurityConfiguration;
|
|
Assert.That(secConfig.RejectedCertificateStore!.StorePath, Does.Contain("rejected"));
|
|
}
|
|
}
|
|
|
|
[Test]
|
|
public async Task AddExtensionWithEncodeableAddsExtensionAsync()
|
|
{
|
|
ITelemetryContext telemetry = NUnitTelemetryContext.Create();
|
|
var appInstance = new ApplicationInstance(telemetry) { ApplicationName = ApplicationName };
|
|
await using (appInstance.ConfigureAwait(false))
|
|
{
|
|
var qualifiedName = new System.Xml.XmlQualifiedName("OperationLimits", Namespaces.OpcUa);
|
|
var limits = new OperationLimits { MaxNodesPerRead = 42 };
|
|
|
|
appInstance.Build(ApplicationUri, ProductUri)
|
|
.AsClient()
|
|
.AddSecurityConfiguration(SubjectName, m_pkiRoot)
|
|
.AddExtension(qualifiedName, limits);
|
|
|
|
OperationLimits extension = appInstance.ApplicationConfiguration!.ParseExtension<OperationLimits>(qualifiedName)!;
|
|
Assert.That(extension, Is.Not.Null);
|
|
Assert.That(extension.MaxNodesPerRead, Is.EqualTo(42));
|
|
}
|
|
}
|
|
|
|
private string m_pkiRoot;
|
|
}
|
|
}
|