Files
UA-.NETStandard/tests/Opc.Ua.Configuration.Tests/ApplicationConfigurationBuilderTests.cs
e7bb1859f4 Add AllowUnencryptedUserNameTokens client security option (#4910)
# Description

Session.OpenValidateIdentity rejected a UserName identity whenever the
effective token policy was None and the channel was not SignAndEncrypt.
The check was hard-coded and failed before anything was sent, so for
example legacy PLC devices that only offer an unencrypted UserName
policy could not be logged into.
The previous v1.5.x UA.NET stack did allow to setup non-encrypted
connections, but it is understandable that the usage of encrypted
authentication is preferred at default.

This PR adds a SecurityConfiguration.AllowUnencryptedUserNameTokens
(default false). When set to true, the session is able to send the
password in plain text and logs a warning in this scenario. The flag is
exposed in code, through the configuration builder, and in the XML
configuration.

Adds builder, XML round-trip, and client session tests, plus docs.

## Related Issues

- Fixes #4909

## Checklist

_Put an `x` in the boxes that apply. You can complete these step by step
after opening the PR._

- [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.

---------

Co-authored-by: Marc Schier <marcschier@users.noreply.github.com>
Co-authored-by: Marc <marcschier@hotmail.com>
2026-10-28 15:05:15 +01:00

2463 lines
106 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.AllowUnencryptedUserNameTokens, 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 SecurityOptionsSetAllowUnencryptedUserNameTokensAsync()
{
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)
.SetAllowUnencryptedUserNameTokens(true);
Assert.That(
appInstance.ApplicationConfiguration!.SecurityConfiguration.AllowUnencryptedUserNameTokens,
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);
await 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);
await 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)
.SetAllowUnencryptedUserNameTokens(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;
}
}