From d13faea35bc900160e26795c12cdb5d3c0dd41f9 Mon Sep 17 00:00:00 2001 From: Cristian Pogacean Date: Fri, 8 May 2020 13:49:46 +0200 Subject: [PATCH] Hotfix/certificates (#423) * unifying opc ua certificates handling * added PkiRoot config * fixed tests in build pipeline * consistently use the Dns.GetHostName() * pki certificate stores everywhere * cleanup IClientServicesConfig Co-authored-by: Marc Schier --- .gitignore | 2 +- .../Serializers/Extensions/VariantValueEx.cs | 4 +- .../src/Server/GatewayServer.cs | 42 +-- .../src/IClientServicesConfig.cs | 66 ----- .../src/IServerFactory.cs | 2 +- .../src/Runtime/ClientServicesConfig.cs | 76 ------ ...icesConfig2.cs => ClientServicesConfig.cs} | 6 +- .../src/Runtime/Default/SecurityConfig.cs | 13 +- .../src/Runtime/Extensions/OpcConfigEx.cs | 52 ++-- .../Runtime/Extensions/SecurityConfigEx.cs | 3 +- ...cesConfig2.cs => IClientServicesConfig.cs} | 2 +- .../src/Runtime/ISecurityConfig.cs | 5 + .../src/Services/ClientServices.cs | 245 +----------------- .../src/Services/DefaultSessionManager.cs | 6 +- .../src/Services/ServerConsoleHost.cs | 44 ++-- ...rosoft.Azure.IIoT.OpcUa.Testing.Cli.csproj | 6 +- .../cli/Program.cs | 5 +- .../src/Fixtures/BaseServerFixture.cs | 31 ++- .../src/Runtime/TestClientServicesConfig.cs | 61 +++-- .../src/Servers/ServerFactory.cs | 38 +-- ...osoft.Azure.IIoT.Modules.Diagnostic.csproj | 6 +- ...rosoft.Azure.IIoT.Modules.Discovery.csproj | 6 +- .../src/Runtime/Config.cs | 52 +++- .../cli/Program.cs | 2 +- .../src/Runtime/Config.cs | 9 +- .../src/Runtime/LegacyCliConfigKeys.cs | 6 +- ...osoft.Azure.IIoT.Modules.OpcUa.Twin.csproj | 6 +- .../src/Runtime/Config.cs | 56 +--- .../Microsoft.Azure.IIoT.Services.All.csproj | 6 +- ...re.IIoT.Services.OpcUa.Twin.Gateway.csproj | 8 +- .../tests/TestStartup.cs | 7 +- .../tests/TestStartup.cs | 1 - 32 files changed, 285 insertions(+), 589 deletions(-) delete mode 100644 components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IClientServicesConfig.cs delete mode 100644 components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ClientServicesConfig.cs rename components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/{ClientServicesConfig2.cs => ClientServicesConfig.cs} (93%) rename components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/{IClientServicesConfig2.cs => IClientServicesConfig.cs} (93%) diff --git a/.gitignore b/.gitignore index 8fe2c66045..81a981b19d 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ /**/obj/** /**/.vs /**/bin/** +/**/pki/** /**/csx/** /**/ecf/** /**/*.log @@ -36,4 +37,3 @@ *.cache CodeCoverage coverage.cobertura.xml - diff --git a/common/src/Microsoft.Azure.IIoT.Abstractions/src/Serializers/Extensions/VariantValueEx.cs b/common/src/Microsoft.Azure.IIoT.Abstractions/src/Serializers/Extensions/VariantValueEx.cs index a023d4dd2b..2d9b4d253b 100644 --- a/common/src/Microsoft.Azure.IIoT.Abstractions/src/Serializers/Extensions/VariantValueEx.cs +++ b/common/src/Microsoft.Azure.IIoT.Abstractions/src/Serializers/Extensions/VariantValueEx.cs @@ -31,7 +31,7 @@ public static bool IsNull(this VariantValue value) { /// public static T GetValueOrDefault(this Dictionary dict, string key, T defaultValue) { - if (dict != null && dict.TryGetValue(key, out var token)) { + if (dict != null && dict.TryGetValue(key, out var token) && token != null) { try { return token.ConvertTo(); } @@ -52,7 +52,7 @@ public static T GetValueOrDefault(this Dictionary dict, /// public static T? GetValueOrDefault(this Dictionary dict, string key, T? defaultValue) where T : struct { - if (dict != null && dict.TryGetValue(key, out var token)) { + if (dict != null && dict.TryGetValue(key, out var token) && token != null) { try { // Handle enumerations serialized as string if (typeof(T).IsEnum && diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Gateway/src/Server/GatewayServer.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Gateway/src/Server/GatewayServer.cs index f5e8849d02..147dd45d1d 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Gateway/src/Server/GatewayServer.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Gateway/src/Server/GatewayServer.cs @@ -15,8 +15,8 @@ namespace Microsoft.Azure.IIoT.OpcUa.Gateway.Server { using Microsoft.Azure.IIoT.OpcUa.Twin; using Microsoft.Azure.IIoT.OpcUa.History.Models; using Microsoft.Azure.IIoT.OpcUa.History; - using Microsoft.Azure.IIoT.Auth.Server; using Microsoft.Azure.IIoT.Auth; + using Microsoft.Azure.IIoT.Serializers; using Serilog; using Opc.Ua; using Opc.Ua.Configuration; @@ -27,10 +27,12 @@ namespace Microsoft.Azure.IIoT.OpcUa.Gateway.Server { using System.Collections.Generic; using System.Diagnostics; using System.Linq; + using System.Net; + using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using System.Text; - using Microsoft.Azure.IIoT.Serializers; + /// /// Gateway server controller implementation @@ -1597,33 +1599,33 @@ internal void OnRequestComplete(RequestContextModel context) { /// private async Task InitAsync() { var config = new ApplicationConfiguration { - ApplicationName = "Opc UA Gateway Server", + // TODO provide proper naming here + ApplicationName = "Microsoft.Azure.IIoT.Gateway", ApplicationType = Opc.Ua.ApplicationType.ClientAndServer, ApplicationUri = - $"urn:{Utils.GetHostName()}:Microsoft:OpcGatewayServer", - ProductUri = "http://opcfoundation.org/UA/SampleServer", + $"urn:{Dns.GetHostName()}:Microsoft:Azure.IIoT.Gateway", + ProductUri = "https://www.github.com/Azure/Industrial-IoT", SecurityConfiguration = new SecurityConfiguration { ApplicationCertificate = new CertificateIdentifier { - StoreType = "Directory", - StorePath = - "OPC Foundation/CertificateStores/MachineDefault", - SubjectName = "Opc UA Gateway Server" + StoreType = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? + "X509Store" : "Directory", + StorePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? + "CurrentUser\\UA_MachineDefault" : + "pki/own", + SubjectName = "Microsoft.Azure.IIoT.Gateway" }, TrustedPeerCertificates = new CertificateTrustList { StoreType = "Directory", - StorePath = - "OPC Foundation/CertificateStores/UA Applications", + StorePath = "pki/trusted", }, TrustedIssuerCertificates = new CertificateTrustList { StoreType = "Directory", - StorePath = - "OPC Foundation/CertificateStores/UA Certificate Authorities", + StorePath = "pki/issuers", }, RejectedCertificateStore = new CertificateTrustList { StoreType = "Directory", - StorePath = - "OPC Foundation/CertificateStores/RejectedCertificates", + StorePath = "pki/rejected" }, AutoAcceptUntrustedCertificates = false }, @@ -1686,8 +1688,7 @@ private async Task InitAsync() { await config.CertificateValidator.Update(config.SecurityConfiguration); // Use existing certificate, if it is there. - var cert = await config.SecurityConfiguration.ApplicationCertificate - .Find(true); + var cert = config.SecurityConfiguration.ApplicationCertificate.Certificate; if (cert == null) { // Create cert #pragma warning disable IDE0067 // Dispose objects before losing scope @@ -1702,12 +1703,11 @@ private async Task InitAsync() { CertificateFactory.defaultHashSize, false, null, null); #pragma warning restore IDE0067 // Dispose objects before losing scope - } - - if (cert != null) { + config.SecurityConfiguration.ApplicationCertificate.Certificate = cert; - config.ApplicationUri = Utils.GetApplicationUriFromCertificate(cert); + await config.CertificateValidator.UpdateCertificate(config.SecurityConfiguration); } + config.ApplicationUri = Utils.GetApplicationUriFromCertificate(cert); var application = new ApplicationInstance(config); diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IClientServicesConfig.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IClientServicesConfig.cs deleted file mode 100644 index c08f9e663b..0000000000 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IClientServicesConfig.cs +++ /dev/null @@ -1,66 +0,0 @@ -// ------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License (MIT). See License.txt in the repo root for license information. -// ------------------------------------------------------------ - -namespace Microsoft.Azure.IIoT.OpcUa.Protocol { - using System; - - /// - /// Client Services configuration - /// - public interface IClientServicesConfig { - - /// - /// application's certificate store type: Directory or X509Store - /// - string AppCertStoreType { get; } - - /// - /// root path of the pki security folder - /// - string PkiRootPath { get; } - - /// - /// Path to the folder storing the application's certificate - /// - string OwnCertPath { get; } - - /// - /// Path to the folder storing the application's trusted certificates - /// - string TrustedCertPath { get; } - - /// - /// Path of the folder to store the trueste issuer (CA) certificates - /// - string IssuerCertPath { get; } - - /// - /// Path of the folder to store the rejected certificates - /// - /// - string RejectedCertPath { get; } - - /// - /// flag to force automatically acceptance of untrusted certificates - /// - bool AutoAcceptUntrustedCertificates { get; } - - /// - /// the default store path for the windows X509 certificates store in case - /// X509Store store type is used - /// - string OwnCertX509StorePathDefault { get; } - - /// - /// Default session timeout for client - /// - TimeSpan? DefaultSessionTimeout { get; } - - /// - /// Default operation timeout - /// - TimeSpan? OperationTimeout { get; } - } -} diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IServerFactory.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IServerFactory.cs index 1476409001..364277e761 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IServerFactory.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/IServerFactory.cs @@ -17,6 +17,6 @@ public interface IServerFactory { /// /// ApplicationConfiguration CreateServer(IEnumerable ports, - out ServerBase server); + string pkiRootPath, out ServerBase server); } } diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ClientServicesConfig.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ClientServicesConfig.cs deleted file mode 100644 index f8cac2b176..0000000000 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ClientServicesConfig.cs +++ /dev/null @@ -1,76 +0,0 @@ -// ------------------------------------------------------------ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License (MIT). See License.txt in the repo root for license information. -// ------------------------------------------------------------ - -namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Runtime { - using Microsoft.Azure.IIoT.Utils; - using Microsoft.Extensions.Configuration; - using System; - using System.Runtime.InteropServices; - - /// - /// Client's application configuration implementation - /// - public class ClientServicesConfig : ConfigBase, IClientServicesConfig { - -#pragma warning disable CS1591 // Missing XML comment for publicly visible type or member - public const string AppCertStoreTypeKey = "AppCertStoreType"; - public const string PkiRootPathKey = "PkiRootPath"; - public const string OwnCertPathKey = "OwnCertPath"; - public const string TrustedCertPathKey = "TrustedCertPath"; - public const string IssuerCertPathKey = "IssuerCertPath"; - public const string RejectedCertPathKey = "RejectedCertPath"; - public const string AutoAcceptKey = "AutoAccept"; - public const string OwnCertX509StorePathDefaultKey = "OwnCertX509StorePathDefault"; - public const string SessionTimeoutKey = "SessionTimeout"; - public const string OperationTimeoutKey = "OperationTimeout"; -#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member - - /// - public string AppCertStoreType => GetStringOrDefault(AppCertStoreTypeKey, - () => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? - "X509Store" : "Directory"); - /// - public string PkiRootPath => - GetStringOrDefault(PkiRootPathKey, - () => "pki"); - /// - public string OwnCertPath => - GetStringOrDefault(OwnCertPathKey, - () => PkiRootPath + "/own"); - /// - public string TrustedCertPath => - GetStringOrDefault(TrustedCertPathKey, - () => PkiRootPath + "/trusted"); - /// - public string IssuerCertPath => - GetStringOrDefault(IssuerCertPathKey, - () => PkiRootPath + "/issuer"); - /// - public string RejectedCertPath => - GetStringOrDefault(RejectedCertPathKey, - () => PkiRootPath + "/rejected"); - /// - public string OwnCertX509StorePathDefault => - GetStringOrDefault(OwnCertX509StorePathDefaultKey, - () => "CurrentUser\\UA_MachineDefault"); - /// - public bool AutoAcceptUntrustedCertificates => - GetBoolOrDefault(AutoAcceptKey); - /// - public TimeSpan? DefaultSessionTimeout => - GetDurationOrNull(SessionTimeoutKey); - /// - public TimeSpan? OperationTimeout => - GetDurationOrNull(OperationTimeoutKey); - - /// - /// Configuration constructor - /// - /// - public ClientServicesConfig(IConfiguration configuration = null) : - base(configuration) { - } - } -} diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig2.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig.cs similarity index 93% rename from components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig2.cs rename to components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig.cs index cac4daa7c2..894137dcb4 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig2.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/ClientServicesConfig.cs @@ -12,7 +12,7 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Runtime { /// /// Default client configuration /// - public class ClientServicesConfig2 : ConfigBase, IClientServicesConfig2, ISecurityConfig, ITransportQuotaConfig { + public class ClientServicesConfig : ConfigBase, IClientServicesConfig, ISecurityConfig, ITransportQuotaConfig { /// /// Configuration @@ -49,6 +49,8 @@ public class ClientServicesConfig2 : ConfigBase, IClientServicesConfig2, ISecuri public uint MaxKeepAliveCount => (uint)GetIntOrDefault(MaxKeepAliveCountKey, () => 5); + /// + public string PkiRootPath => _security.PkiRootPath; /// public CertificateInfo ApplicationCertificate => _security.ApplicationCertificate; @@ -84,7 +86,7 @@ public class ClientServicesConfig2 : ConfigBase, IClientServicesConfig2, ISecuri public int SecurityTokenLifetime => _transport.SecurityTokenLifetime; /// - public ClientServicesConfig2(IConfiguration configuration = null) : base(configuration) { + public ClientServicesConfig(IConfiguration configuration = null) : base(configuration) { _security = new SecurityConfig(configuration); _transport = new TransportQuotaConfig(configuration); } diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/SecurityConfig.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/SecurityConfig.cs index d216dd38ac..ee1869f60a 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/SecurityConfig.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Default/SecurityConfig.cs @@ -17,6 +17,7 @@ public class SecurityConfig : ConfigBase, ISecurityConfig { /// Configuration /// #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member + public const string PkiRootPathKey = "PkiRootPath"; public const string ApplicationCertificateStorePathKey = "ApplicationCertificateStorePath"; public const string ApplicationCertificateStoreTypeKey = "ApplicationCertificateStoreType"; public const string ApplicationCertificateSubjectNameKey = "ApplicationCertificateSubjectName"; @@ -31,11 +32,15 @@ public class SecurityConfig : ConfigBase, ISecurityConfig { public const string MinimumCertificateKeySizeKey = "MinimumCertificateKeySize"; #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member + /// + public string PkiRootPath => + GetStringOrDefault(PkiRootPathKey, () => "pki"); + /// public CertificateInfo ApplicationCertificate => new CertificateInfo { StorePath = GetStringOrDefault(ApplicationCertificateStorePathKey, () => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? - "CurrentUser\\My" : "/pki/own"), + "CurrentUser\\UA_MachineDefault" : $"{PkiRootPath}/own"), StoreType = GetStringOrDefault(ApplicationCertificateStoreTypeKey, () => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "X509Store" : "Directory"), @@ -45,19 +50,19 @@ public class SecurityConfig : ConfigBase, ISecurityConfig { /// public CertificateStore TrustedIssuerCertificates => new CertificateStore { - StorePath = GetStringOrDefault(TrustedIssuerCertificatesPathKey, () => "/pki/trusted"), + StorePath = GetStringOrDefault(TrustedIssuerCertificatesPathKey, () => $"{PkiRootPath}/issuers"), StoreType = GetStringOrDefault(TrustedIssuerCertificatesTypeKey, () => "Directory"), }; /// public CertificateStore TrustedPeerCertificates => new CertificateStore { - StorePath = GetStringOrDefault(TrustedPeerCertificatesPathKey, () => "/pki/trusted"), + StorePath = GetStringOrDefault(TrustedPeerCertificatesPathKey, () => $"{PkiRootPath}/trusted"), StoreType = GetStringOrDefault(TrustedPeerCertificatesTypeKey, () => "Directory"), }; /// public CertificateStore RejectedCertificateStore => new CertificateStore { - StorePath = GetStringOrDefault(RejectedCertificateStorePathKey, () => "/pki/trusted"), + StorePath = GetStringOrDefault(RejectedCertificateStorePathKey, () => $"{PkiRootPath}/rejected"), StoreType = GetStringOrDefault(RejectedCertificateStoreTypeKey, () => "Directory"), }; diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/OpcConfigEx.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/OpcConfigEx.cs index 192e885233..a1fb2e2de0 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/OpcConfigEx.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/OpcConfigEx.cs @@ -4,9 +4,11 @@ // ------------------------------------------------------------ namespace Microsoft.Azure.IIoT.OpcUa.Protocol { + using Opc.Ua; using System; + using System.Linq; + using System.Threading.Tasks; using System.Security.Cryptography.X509Certificates; - using Opc.Ua; /// /// Configuration extensions @@ -20,8 +22,8 @@ public static class OpcConfigEx { /// /// /// - public static ApplicationConfiguration ToApplicationConfiguration( - this IClientServicesConfig2 opcConfig, bool createSelfSignedCertIfNone, + public static async Task ToApplicationConfigurationAsync( + this IClientServicesConfig opcConfig, bool createSelfSignedCertIfNone, CertificateValidationEventHandler handler) { if (string.IsNullOrWhiteSpace(opcConfig.ApplicationName)) { throw new ArgumentNullException(nameof(opcConfig.ApplicationName)); @@ -40,20 +42,28 @@ public static ApplicationConfiguration ToApplicationConfiguration( applicationConfiguration.CertificateValidator.CertificateValidation += handler; - X509Certificate2 certificate = null; + var configuredSubject = applicationConfiguration.SecurityConfiguration + .ApplicationCertificate.SubjectName; + applicationConfiguration.SecurityConfiguration.ApplicationCertificate.SubjectName = + applicationConfiguration.ApplicationName; + await applicationConfiguration.CertificateValidator + .Update(applicationConfiguration.SecurityConfiguration); - // use existing certificate, if it is there - certificate = applicationConfiguration.SecurityConfiguration.ApplicationCertificate.Find(true).Result; + // use existing certificate, if present + var certificate = applicationConfiguration.SecurityConfiguration + .ApplicationCertificate.Certificate; // create a self signed certificate if there is none if (certificate == null && createSelfSignedCertIfNone) { certificate = CertificateFactory.CreateCertificate( - applicationConfiguration.SecurityConfiguration.ApplicationCertificate.StoreType, - applicationConfiguration.SecurityConfiguration.ApplicationCertificate.StorePath, + applicationConfiguration.SecurityConfiguration + .ApplicationCertificate.StoreType, + applicationConfiguration.SecurityConfiguration + .ApplicationCertificate.StorePath, null, applicationConfiguration.ApplicationUri, applicationConfiguration.ApplicationName, - applicationConfiguration.ApplicationName, + configuredSubject, null, CertificateFactory.defaultKeySize, DateTime.UtcNow - TimeSpan.FromDays(1), @@ -61,17 +71,29 @@ public static ApplicationConfiguration ToApplicationConfiguration( CertificateFactory.defaultHashSize ); - // update security information - applicationConfiguration.SecurityConfiguration.ApplicationCertificate.Certificate = - certificate ?? + if (certificate == null) { throw new Exception( "OPC UA application certificate can not be created! Cannot continue without it!"); - //await applicationConfiguration.CertificateValidator.UpdateCertificate( - //applicationConfiguration.SecurityConfiguration).ConfigureAwait(false); + } + + applicationConfiguration.SecurityConfiguration + .ApplicationCertificate.Certificate = certificate; + try { + // copy the certificate *public key only* into the trusted certificates list + using (ICertificateStore trustedStore = applicationConfiguration + .SecurityConfiguration.TrustedPeerCertificates.OpenStore()) { + using (var publicKey = new X509Certificate2(certificate.RawData)) { + trustedStore.Add(publicKey.YieldReturn()); + } + } + } + catch { } + // update security information + await applicationConfiguration.CertificateValidator.UpdateCertificate( + applicationConfiguration.SecurityConfiguration); } applicationConfiguration.ApplicationUri = Utils.GetApplicationUriFromCertificate(certificate); - return applicationConfiguration; } } diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/SecurityConfigEx.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/SecurityConfigEx.cs index a4a9ec44b5..6ca0a7e495 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/SecurityConfigEx.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/Extensions/SecurityConfigEx.cs @@ -50,7 +50,8 @@ public static SecurityConfiguration ToSecurityConfiguration(this ISecurityConfig AutoAcceptUntrustedCertificates = securityConfig.AutoAcceptUntrustedCertificates, RejectSHA1SignedCertificates = securityConfig.RejectSha1SignedCertificates, MinimumCertificateKeySize = securityConfig.MinimumCertificateKeySize, - ApplicationCertificate = securityConfig.ApplicationCertificate.ToCertificateIdentifier() + ApplicationCertificate = securityConfig.ApplicationCertificate.ToCertificateIdentifier(), + AddAppCertToTrustedStore = true }; return securityConfiguration; diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig2.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig.cs similarity index 93% rename from components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig2.cs rename to components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig.cs index aa5b43b7ab..0a65e9b9a3 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig2.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/IClientServicesConfig.cs @@ -8,7 +8,7 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol { /// /// Client services configuration /// - public interface IClientServicesConfig2 : ITransportQuotaConfig, ISecurityConfig { + public interface IClientServicesConfig : ITransportQuotaConfig, ISecurityConfig { /// /// Application name diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ISecurityConfig.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ISecurityConfig.cs index 29b7cc2a00..407174e5ef 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ISecurityConfig.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Runtime/ISecurityConfig.cs @@ -11,6 +11,11 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol { /// public interface ISecurityConfig { + /// + /// PkiRootPath + /// + string PkiRootPath { get; } + /// /// Certificate /// diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ClientServices.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ClientServices.cs index f8cf48bee5..7b7a921695 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ClientServices.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ClientServices.cs @@ -5,7 +5,6 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Services { using Microsoft.Azure.IIoT.OpcUa.Protocol.Models; - using Microsoft.Azure.IIoT.OpcUa.Protocol.Runtime; using Microsoft.Azure.IIoT.OpcUa.Registry.Models; using Microsoft.Azure.IIoT.OpcUa.Core.Models; using Microsoft.Azure.IIoT.OpcUa.Registry; @@ -20,10 +19,9 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Services { using System.Collections.Generic; using System.Diagnostics; using System.Linq; - using System.Runtime.InteropServices; + using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; - using System.Security.Cryptography.X509Certificates; /// /// Opc ua stack based service client @@ -34,32 +32,19 @@ public class ClientServices : IClientHost, IEndpointServices, IEndpointDiscovery /// /// Create client host services /// + /// /// /// - public ClientServices(ILogger logger, TimeSpan? maxOpTimeout = null) : - this(logger, new ClientServicesConfig(), maxOpTimeout) { - } - - /// - /// Create client host services - /// - /// - /// - /// - public ClientServices(ILogger logger, IClientServicesConfig configuration, + public ClientServices(ILogger logger, IClientServicesConfig clientConfig, TimeSpan? maxOpTimeout = null) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); - _configuration = configuration ?? - throw new ArgumentNullException(nameof(configuration)); + _clientConfig = clientConfig ?? + throw new ArgumentNullException(nameof(clientConfig)); _maxOpTimeout = maxOpTimeout; - + _appConfig = _clientConfig.ToApplicationConfigurationAsync(true, VerifyCertificate).Result; // Create discovery config and client certificate - _appConfig = CreateApplicationConfiguration( - TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(30)); - InitApplicationSecurityAsync().Wait(); - _timer = new Timer(_ => OnTimer(), null, kEvictionCheck, Timeout.InfiniteTimeSpan); } @@ -423,222 +408,6 @@ private void EvictIfInactive(ConnectionIdentifier id) { } } - /// - /// Create application configuration for client - /// - /// - private ApplicationConfiguration CreateApplicationConfiguration( - TimeSpan operationTimeout, TimeSpan sessionTimeout) { - - // mitigation for bug in .NET Core 2.1 - var effectiveAppCertStoreType = _configuration.AppCertStoreType; - var effectiveOwnCertPath = _configuration.OwnCertPath; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - effectiveAppCertStoreType = CertificateStoreType.X509Store; - effectiveOwnCertPath = _configuration.OwnCertX509StorePathDefault; - } - - var applicationConfiguration = new ApplicationConfiguration { - ApplicationName = "Azure IIoT OPC Twin Client Services", - ApplicationType = Opc.Ua.ApplicationType.Client, - ApplicationUri = "urn:" + Utils.GetHostName() + ":Azure:IIoTOpcTwin", - CertificateValidator = new CertificateValidator(), - SecurityConfiguration = new SecurityConfiguration { - ApplicationCertificate = new CertificateIdentifier { - StoreType = effectiveAppCertStoreType, - StorePath = effectiveOwnCertPath, - SubjectName = "Azure IIoT OPC Twin" - }, - TrustedPeerCertificates = new CertificateTrustList { - StoreType = CertificateStoreType.Directory, - StorePath = _configuration.TrustedCertPath - }, - TrustedIssuerCertificates = new CertificateTrustList { - StoreType = CertificateStoreType.Directory, - StorePath = _configuration.IssuerCertPath - }, - RejectedCertificateStore = new CertificateTrustList { - StoreType = CertificateStoreType.Directory, - StorePath = _configuration.RejectedCertPath - }, - NonceLength = 32, - AutoAcceptUntrustedCertificates = _configuration.AutoAcceptUntrustedCertificates, - RejectSHA1SignedCertificates = false, - AddAppCertToTrustedStore = false, - MinimumCertificateKeySize = 1024 - }, - TransportConfigurations = new TransportConfigurationCollection(), - TransportQuotas = TransportQuotaConfigEx.DefaultTransportQuotas(), - ClientConfiguration = new ClientConfiguration { - DefaultSessionTimeout = (int)sessionTimeout.TotalMilliseconds - } - }; - applicationConfiguration.TransportQuotas.OperationTimeout = (int)operationTimeout.TotalMilliseconds; - return applicationConfiguration; - } - - /// - /// Initialize the OPC UA Application's security configuration - /// - /// - private async Task InitApplicationSecurityAsync() { - - // update certificates validator - _appConfig.CertificateValidator.CertificateValidation += - new CertificateValidationEventHandler(VerifyCertificate); - await _appConfig.CertificateValidator - .Update(_appConfig).ConfigureAwait(false); - - // lookup for an existing certificate in the configured store - var ownCertificate = await _appConfig.SecurityConfiguration - .ApplicationCertificate.Find(true).ConfigureAwait(false); - if (ownCertificate == null) { - // - // Work around windows issue and lookup application certificate also on - // directory if configured. This is needed for container persistence. - // - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && - _configuration.AppCertStoreType == CertificateStoreType.Directory) { - - // Use x509 store instead of directory for private cert. - var ownCertificateIdentifier = new CertificateIdentifier { - StoreType = _configuration.AppCertStoreType, - StorePath = _configuration.OwnCertPath, - SubjectName = _appConfig.SecurityConfiguration - .ApplicationCertificate.SubjectName - }; - ownCertificate = await ownCertificateIdentifier.Find(true) - .ConfigureAwait(false); - if ((ownCertificate != null) && !ownCertificate.Verify()) { - try { - _logger.Warning("Found malformed own certificate {Thumbprint}, " + - "{Subject} in the store - deleting it...", - ownCertificate.Thumbprint, ownCertificate.Subject); - ownCertificateIdentifier.RemoveFromStore(ownCertificate); - } - catch (Exception ex) { - _logger.Information(ex, - "Failed to remove malformed own certificate"); - } - ownCertificate = null; - } - } - } - - if (ownCertificate == null) { - - _logger.Information("Application own certificate not found. " + - "Creating a new self-signed certificate with default settings..."); - ownCertificate = CertificateFactory.CreateCertificate( - _appConfig.SecurityConfiguration.ApplicationCertificate.StoreType, - _appConfig.SecurityConfiguration.ApplicationCertificate.StorePath, - null, - _appConfig.ApplicationUri, _appConfig.ApplicationName, - _appConfig.SecurityConfiguration.ApplicationCertificate.SubjectName, - null, CertificateFactory.defaultKeySize, - DateTime.UtcNow - TimeSpan.FromDays(1), - CertificateFactory.defaultLifeTime, CertificateFactory.defaultHashSize, - false, null, null); - - _appConfig.SecurityConfiguration.ApplicationCertificate.Certificate = - ownCertificate; - _logger.Information( - "New application certificate with {Thumbprint}, {Subject} created", - ownCertificate.Thumbprint, ownCertificate.SubjectName.Name); - } - else { - _logger.Information("Application certificate with {Thumbprint}, {Subject} " + - "found in the certificate store", - ownCertificate.Thumbprint, ownCertificate.SubjectName.Name); - } - // Set the Certificate as the newly created certificate - await SetOwnCertificateAsync(ownCertificate); - if (_appConfig.SecurityConfiguration.AutoAcceptUntrustedCertificates) { - _logger.Warning( - "WARNING: Automatically accepting certificates. This is a security risk."); - } - } - - /// - /// set a new application instance certificate - /// - /// - private async Task SetOwnCertificateAsync(X509Certificate2 newCertificate) { - - if (newCertificate == null || !newCertificate.HasPrivateKey) { - throw new ArgumentException("Empty or invalid certificate"); - } - - // attempt to replace the old certificate from the various trust lists - var oldCertificate = _appConfig.SecurityConfiguration - .ApplicationCertificate.Certificate; - if (oldCertificate?.Thumbprint != newCertificate.Thumbprint) { - return; - } - - _logger.Information( - "Setting new application certificate {Thumbprint}, {Subject}...", - newCertificate.Thumbprint, newCertificate.SubjectName.Name); - - // copy the certificate, public key only into the trusted certificates list - using (var publicKey = new X509Certificate2(newCertificate.RawData)) { - var trustList = - _appConfig.SecurityConfiguration.TrustedPeerCertificates; - if (oldCertificate != null) { - trustList.Remove(oldCertificate.YieldReturn()); - } - trustList.Add(newCertificate.YieldReturn()); - } - - // add the certificate to the own store - try { - var applicationCertificate = _appConfig.SecurityConfiguration - .ApplicationCertificate; - _logger.Information( - "Adding own certificate to configured certificate store"); - // Remove old and add new - if (oldCertificate != null) { - applicationCertificate.RemoveFromStore(oldCertificate); - } - applicationCertificate.AddToStore(newCertificate, true); - } - catch (Exception ex) { - _logger.Warning(ex, - "Failed adding own certificate into configured certificate store."); - } - - // - // Work around windows issue and persist application certificate also on - // directory if configured. This is needed for container persistence. - // - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && - _configuration.AppCertStoreType == CertificateStoreType.Directory) { - var applicationCertificate = new CertificateIdentifier { - StoreType = CertificateStoreType.Directory, - StorePath = _configuration.OwnCertPath, - SubjectName = newCertificate.SubjectName.Name - }; - try { - _logger.Information( - "Persisting own certificate into directory certificate store..."); - // Remove old and add new - if (oldCertificate != null) { - applicationCertificate.RemoveFromStore(oldCertificate); - } - applicationCertificate.AddToStore(newCertificate, true); - } - catch (Exception ex) { - _logger.Warning(ex, - "Failed adding own certificate to directory certificate store."); - } - } - - _appConfig.SecurityConfiguration.ApplicationCertificate - .Certificate = newCertificate; - await _appConfig.CertificateValidator.UpdateCertificate( - _appConfig.SecurityConfiguration); - } - /// /// Default event handler to validate certificates and handle auto accept. /// @@ -751,7 +520,7 @@ public void Dispose() { private const int kMaxDiscoveryAttempts = 3; private readonly ILogger _logger; private readonly TimeSpan? _maxOpTimeout; - private readonly IClientServicesConfig _configuration; + private readonly IClientServicesConfig _clientConfig; private readonly ApplicationConfiguration _appConfig; private readonly Dictionary _clients = new Dictionary(); diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/DefaultSessionManager.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/DefaultSessionManager.cs index 438213304c..523e11de04 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/DefaultSessionManager.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/DefaultSessionManager.cs @@ -32,7 +32,7 @@ public class DefaultSessionManager : ISessionManager { /// /// /// - public DefaultSessionManager(IClientServicesConfig2 clientConfig, ILogger logger) { + public DefaultSessionManager(IClientServicesConfig clientConfig, ILogger logger) { _logger = logger; _clientConfig = clientConfig; _lock = new SemaphoreSlim(1, 1); @@ -110,7 +110,7 @@ void OnValidate(CertificateValidator sender, CertificateValidationEventArgs e) { } }; - var applicationConfiguration = _clientConfig.ToApplicationConfiguration( + var applicationConfiguration = await _clientConfig.ToApplicationConfigurationAsync( true, OnValidate); var endpointConfiguration = _clientConfig.ToEndpointConfiguration(); @@ -403,7 +403,7 @@ public static EndpointIdentifier GetEndpointId(SessionClient session) { } private readonly ILogger _logger; - private readonly IClientServicesConfig2 _clientConfig; + private readonly IClientServicesConfig _clientConfig; private readonly Dictionary _sessions = new Dictionary(); private readonly SemaphoreSlim _lock; diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ServerConsoleHost.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ServerConsoleHost.cs index 14ef550c8b..c20d02acca 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ServerConsoleHost.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Protocol/src/Services/ServerConsoleHost.cs @@ -12,7 +12,6 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Services { using System.Threading; using System.Threading.Tasks; using System.Security.Cryptography.X509Certificates; - using System.Runtime.InteropServices; /// /// Console host for servers @@ -21,7 +20,8 @@ public class ServerConsoleHost : IServerHost { /// public X509Certificate2 Certificate { get; private set; } - + /// + public string PkiRootPath { get; set; } /// public bool AutoAccept { get; set; } @@ -70,7 +70,7 @@ public async Task StartAsync(IEnumerable ports) { await _lock.WaitAsync(); try { if (_server == null) { - await StartServerInternalAsync(ports); + await StartServerInternalAsync(ports, PkiRootPath); return; } } @@ -97,24 +97,19 @@ public void Dispose() { /// Start server /// /// + /// /// - private async Task StartServerInternalAsync(IEnumerable ports) { + private async Task StartServerInternalAsync(IEnumerable ports, string pkiRootPath) { ApplicationInstance.MessageDlg = new DummyDialog(); - var config = _factory.CreateServer(ports, out _server); + var config = _factory.CreateServer(ports, pkiRootPath, out _server); _logger.Information("Server created..."); config = ApplicationInstance.FixupAppConfig(config); - - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - config.SecurityConfiguration.ApplicationCertificate.StoreType = - CertificateStoreType.X509Store; - config.SecurityConfiguration.ApplicationCertificate.StorePath = - "CurrentUser\\UA_MachineDefault"; - } _logger.Information("Validate configuration..."); await config.Validate(ApplicationType.Server); + config.SecurityConfiguration.AutoAcceptUntrustedCertificates = AutoAccept; config.CertificateValidator = new CertificateValidator(); config.CertificateValidator.CertificateValidation += (v, e) => { if (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted) { @@ -126,10 +121,8 @@ private async Task StartServerInternalAsync(IEnumerable ports) { _logger.Information("Initialize certificate validation..."); await config.CertificateValidator.Update(config.SecurityConfiguration); + var cert = config.SecurityConfiguration.ApplicationCertificate.Certificate; - // Use existing certificate, if it is there. - var cert = await config.SecurityConfiguration.ApplicationCertificate - .Find(true); if (cert == null) { _logger.Information("Creating new certificate in {path}...", config.SecurityConfiguration.ApplicationCertificate.StorePath); @@ -143,15 +136,12 @@ private async Task StartServerInternalAsync(IEnumerable ports) { null, CertificateFactory.defaultKeySize, DateTime.UtcNow - TimeSpan.FromDays(1), CertificateFactory.defaultLifeTime, - CertificateFactory.defaultHashSize, - false, null, null); + CertificateFactory.defaultHashSize); #pragma warning restore IDE0067 // Dispose objects before losing scope - } - - if (cert != null) { config.SecurityConfiguration.ApplicationCertificate.Certificate = cert; - config.ApplicationUri = Utils.GetApplicationUriFromCertificate(cert); + await config.CertificateValidator.UpdateCertificate(config.SecurityConfiguration); } + config.ApplicationUri = Utils.GetApplicationUriFromCertificate(cert); var application = new ApplicationInstance(config); @@ -159,12 +149,18 @@ private async Task StartServerInternalAsync(IEnumerable ports) { var haveAppCertificate = await application.CheckApplicationInstanceCertificate(false, 0); if (!haveAppCertificate) { - _logger.Error("Failed validating certificate!"); + _logger.Error("Failed validating own certificate!"); throw new Exception("Application instance certificate invalid!"); } - // Set certificate - Certificate = cert; + // Set Certificate + try { + // just take the public key + Certificate = new X509Certificate2(config.SecurityConfiguration.ApplicationCertificate.Certificate.RawData); + } + catch { + Certificate = config.SecurityConfiguration.ApplicationCertificate.Certificate; + } _logger.Information("Starting server ..."); // start the server. diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Microsoft.Azure.IIoT.OpcUa.Testing.Cli.csproj b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Microsoft.Azure.IIoT.OpcUa.Testing.Cli.csproj index e6ee1323af..8eddaee437 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Microsoft.Azure.IIoT.OpcUa.Testing.Cli.csproj +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Microsoft.Azure.IIoT.OpcUa.Testing.Cli.csproj @@ -4,9 +4,9 @@ netcoreapp3.1 - - - + + + diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Program.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Program.cs index ec0de9f331..27f7fda913 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Program.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/cli/Program.cs @@ -32,6 +32,7 @@ namespace Microsoft.Azure.IIoT.OpcUa.Cli { using System.IO; using System.IO.Compression; using System.Linq; + using System.Net; using System.Runtime.Loader; using System.Text; using System.Threading; @@ -62,7 +63,7 @@ public static void Main(string[] args) { var op = Op.None; var endpoint = new EndpointModel(); string fileName = null; - var host = Utils.GetHostName(); + var host = Dns.GetHostName(); var ports = new List(); try { for (var i = 0; i < args.Length; i++) { @@ -622,7 +623,7 @@ public ServerWrapper(EndpointModel endpoint, StackLogger logger) { _cts = new CancellationTokenSource(); if (endpoint.Url == null) { _server = RunSampleServerAsync(_cts.Token, logger.Logger); - endpoint.Url = "opc.tcp://" + Utils.GetHostName() + + endpoint.Url = "opc.tcp://" + Dns.GetHostName() + ":51210/UA/SampleServer"; } else { diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Fixtures/BaseServerFixture.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Fixtures/BaseServerFixture.cs index 741027ec03..966dfd7c5a 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Fixtures/BaseServerFixture.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Fixtures/BaseServerFixture.cs @@ -35,6 +35,11 @@ public abstract class BaseServerFixture : IDisposable { /// public X509Certificate2 Certificate => _serverHost.Certificate; + /// + /// Cert folder + /// + public string PkiRootPath { get; private set; } + /// /// Logger /// @@ -50,7 +55,7 @@ public abstract class BaseServerFixture : IDisposable { /// public static int StartPort { set => _nextPort = value; } - /// + /// /// Create fixture /// protected BaseServerFixture(IEnumerable nodes) { @@ -62,15 +67,18 @@ protected BaseServerFixture(IEnumerable nodes) { _client = new Lazy(() => { return new ClientServices(Logger, _config); }, false); - _serverHost = new ServerConsoleHost( - new ServerFactory(Logger, nodes) { - LogStatus = false - }, Logger) { - AutoAccept = true - }; + PkiRootPath = Path.Combine(Directory.GetCurrentDirectory(), "pki", + Guid.NewGuid().ToByteArray().ToBase16String()); var port = Interlocked.Increment(ref _nextPort); for (var i = 0; i < 200; i++) { // Retry 200 times try { + _serverHost = new ServerConsoleHost( + new ServerFactory(Logger, nodes) { + LogStatus = false + }, Logger) { + PkiRootPath = PkiRootPath, + AutoAccept = true + }; Logger.Information("Starting server host on {port}...", port); _serverHost.StartAsync(new int[] { port }).Wait(); @@ -90,17 +98,16 @@ public void Dispose() { Logger.Information("Disposing server and client fixture..."); _serverHost.Dispose(); // Clean up all created certificates - var certFolder = Path.Combine(Directory.GetCurrentDirectory(), "OPC Foundation"); - if (Directory.Exists(certFolder)) { + if (Directory.Exists(PkiRootPath)) { Logger.Information("Server disposed - cleaning up server certificates..."); - Try.Op(() => Directory.Delete(certFolder, true)); + Try.Op(() => Directory.Delete(PkiRootPath, true)); } if (_client.IsValueCreated) { Logger.Information("Disposing client..."); Task.Run(() => _client.Value.Dispose()).Wait(); - Logger.Information("Client disposed - cleaning up client certificates..."); - _config?.Dispose(); } + Logger.Information("Client disposed - cleaning up client certificates..."); + _config?.Dispose(); Logger.Information("Server and client fixture disposed."); } diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Runtime/TestClientServicesConfig.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Runtime/TestClientServicesConfig.cs index e653839892..bc5e1bb5bf 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Runtime/TestClientServicesConfig.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Runtime/TestClientServicesConfig.cs @@ -5,50 +5,69 @@ namespace Microsoft.Azure.IIoT.OpcUa.Testing.Runtime { using Microsoft.Azure.IIoT.OpcUa.Protocol; + using Microsoft.Azure.IIoT.OpcUa.Protocol.Runtime; using Microsoft.Azure.IIoT.Utils; using System; using System.IO; - using System.Runtime.InteropServices; /// /// Client's application configuration implementation /// public class TestClientServicesConfig : IClientServicesConfig, IDisposable { - /// - /// Pki root - /// - public const string Pki = "pki"; - /// - public string AppCertStoreType => - RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? - "X509Store" : "Directory"; - + public string PkiRootPath { get;} + /// + public string ApplicationName => _opc.ApplicationName; + /// + public string ApplicationUri => _opc.ApplicationUri; + /// + public string ProductUri => _opc.ProductUri; + /// + public uint DefaultSessionTimeout => _opc.DefaultSessionTimeout; + /// + public int KeepAliveInterval => _opc.KeepAliveInterval; + /// + public uint MaxKeepAliveCount => _opc.MaxKeepAliveCount; /// - public string PkiRootPath { get; } + public int MinSubscriptionLifetime => _opc.MinSubscriptionLifetime; /// - public string OwnCertPath => Path.Combine(PkiRootPath, "own"); + public CertificateInfo ApplicationCertificate => _opc.ApplicationCertificate; /// - public string TrustedCertPath => Path.Combine(PkiRootPath, "trusted"); + public bool AutoAcceptUntrustedCertificates { get; private set; } /// - public string IssuerCertPath => Path.Combine(PkiRootPath, "issuer"); + public ushort MinimumCertificateKeySize => _opc.MinimumCertificateKeySize; /// - public string RejectedCertPath => Path.Combine(PkiRootPath, "rejected"); + public CertificateStore RejectedCertificateStore => _opc.RejectedCertificateStore; /// - public string OwnCertX509StorePathDefault => "CurrentUser\\UA_MachineDefault"; + public bool RejectSha1SignedCertificates => _opc.RejectSha1SignedCertificates; /// - public bool AutoAcceptUntrustedCertificates { get; } + public CertificateStore TrustedIssuerCertificates => _opc.TrustedIssuerCertificates; /// - public TimeSpan? DefaultSessionTimeout => null; + public CertificateStore TrustedPeerCertificates => _opc.TrustedPeerCertificates; /// - public TimeSpan? OperationTimeout => null; + public int ChannelLifetime => _opc.ChannelLifetime; + /// + public int MaxArrayLength => _opc.MaxArrayLength; + /// + public int MaxBufferSize => _opc.MaxBufferSize; + /// + public int MaxByteStringLength => _opc.MaxByteStringLength; + /// + public int MaxMessageSize => _opc.MaxMessageSize; + /// + public int MaxStringLength => _opc.MaxStringLength; + /// + public int OperationTimeout => _opc.OperationTimeout; + /// + public int SecurityTokenLifetime => _opc.SecurityTokenLifetime; /// public TestClientServicesConfig(bool autoAccept = false) { AutoAcceptUntrustedCertificates = autoAccept; - PkiRootPath = Path.Combine(Directory.GetCurrentDirectory(), Pki, + PkiRootPath = Path.Combine(Directory.GetCurrentDirectory(), "pki", Guid.NewGuid().ToByteArray().ToBase16String()); + _opc = new ClientServicesConfig(); } /// @@ -57,5 +76,7 @@ public void Dispose() { Try.Op(() => Directory.Delete(PkiRootPath, true)); } } + + private readonly ClientServicesConfig _opc; } } diff --git a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Servers/ServerFactory.cs b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Servers/ServerFactory.cs index 394313ec97..4dceb3c381 100644 --- a/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Servers/ServerFactory.cs +++ b/components/opc-ua/src/Microsoft.Azure.IIoT.OpcUa.Testing/src/Servers/ServerFactory.cs @@ -11,10 +11,12 @@ namespace Microsoft.Azure.IIoT.OpcUa.Protocol.Sample { using System; using System.Collections.Generic; using System.Linq; + using System.Net; using System.Threading; using System.Threading.Tasks; using System.Xml; using System.IdentityModel.Selectors; + using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; /// @@ -60,10 +62,10 @@ public ServerFactory(ILogger logger) : } /// - public ApplicationConfiguration CreateServer(IEnumerable ports, + public ApplicationConfiguration CreateServer(IEnumerable ports, string applicationName, out ServerBase server) { server = new Server(LogStatus, _nodes, _logger); - return Server.CreateServerConfiguration(ports); + return Server.CreateServerConfiguration(ports, applicationName); } /// @@ -88,7 +90,7 @@ public Server(bool logStatus, IEnumerable nodes, /// /// public static ApplicationConfiguration CreateServerConfiguration( - IEnumerable ports) { + IEnumerable ports, string pkiRootPath) { var extensions = new List { new MemoryBuffer.MemoryBufferConfiguration { Buffers = new MemoryBuffer.MemoryBufferInstanceCollection { @@ -107,39 +109,41 @@ public static ApplicationConfiguration CreateServerConfiguration( /// ... }; + if (string.IsNullOrEmpty(pkiRootPath)) { + pkiRootPath = "pki"; + } return new ApplicationConfiguration { ApplicationName = "UA Core Sample Server", ApplicationType = ApplicationType.Server, - ApplicationUri = - $"urn:{Utils.GetHostName()}:OPCFoundation:CoreSampleServer", - + ApplicationUri = $"urn:{Dns.GetHostName()}:OPCFoundation:CoreSampleServer", Extensions = new XmlElementCollection( extensions.Select(XmlElementEx.SerializeObject)), ProductUri = "http://opcfoundation.org/UA/SampleServer", SecurityConfiguration = new SecurityConfiguration { ApplicationCertificate = new CertificateIdentifier { - StoreType = "Directory", - StorePath = - "OPC Foundation/CertificateStores/MachineDefault", - SubjectName = "UA Core Sample Server" + StoreType = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? + CertificateStoreType.X509Store : + CertificateStoreType.Directory, + StorePath = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? + "CurrentUser\\UA_MachineDefault" : + $"{pkiRootPath}/own", + SubjectName = "UA Core Sample Server", }, TrustedPeerCertificates = new CertificateTrustList { StoreType = "Directory", - StorePath = - "OPC Foundation/CertificateStores/UA Applications", + StorePath = $"{pkiRootPath}/trusted", }, TrustedIssuerCertificates = new CertificateTrustList { StoreType = "Directory", - StorePath = - "OPC Foundation/CertificateStores/UA Certificate Authorities", + StorePath = $"{pkiRootPath}/issuer", }, RejectedCertificateStore = new CertificateTrustList { StoreType = "Directory", - StorePath = - "OPC Foundation/CertificateStores/RejectedCertificates", + StorePath = $"{pkiRootPath}/rejected", }, - AutoAcceptUntrustedCertificates = false + AutoAcceptUntrustedCertificates = true, + AddAppCertToTrustedStore = true }, TransportConfigurations = new TransportConfigurationCollection(), TransportQuotas = TransportQuotaConfigEx.DefaultTransportQuotas(), diff --git a/modules/src/Microsoft.Azure.IIoT.Modules.Diagnostic/src/Microsoft.Azure.IIoT.Modules.Diagnostic.csproj b/modules/src/Microsoft.Azure.IIoT.Modules.Diagnostic/src/Microsoft.Azure.IIoT.Modules.Diagnostic.csproj index c7c976a90e..e7bc401bc0 100644 --- a/modules/src/Microsoft.Azure.IIoT.Modules.Diagnostic/src/Microsoft.Azure.IIoT.Modules.Diagnostic.csproj +++ b/modules/src/Microsoft.Azure.IIoT.Modules.Diagnostic/src/Microsoft.Azure.IIoT.Modules.Diagnostic.csproj @@ -8,9 +8,9 @@ - - - + + + diff --git a/modules/src/Microsoft.Azure.IIoT.Modules.Discovery/src/Microsoft.Azure.IIoT.Modules.Discovery.csproj b/modules/src/Microsoft.Azure.IIoT.Modules.Discovery/src/Microsoft.Azure.IIoT.Modules.Discovery.csproj index f35c7fdc9f..5db35ae0c3 100644 --- a/modules/src/Microsoft.Azure.IIoT.Modules.Discovery/src/Microsoft.Azure.IIoT.Modules.Discovery.csproj +++ b/modules/src/Microsoft.Azure.IIoT.Modules.Discovery/src/Microsoft.Azure.IIoT.Modules.Discovery.csproj @@ -8,9 +8,9 @@ - - - + + + diff --git a/modules/src/Microsoft.Azure.IIoT.Modules.Discovery/src/Runtime/Config.cs b/modules/src/Microsoft.Azure.IIoT.Modules.Discovery/src/Runtime/Config.cs index a22796bb4e..eb0578f46f 100644 --- a/modules/src/Microsoft.Azure.IIoT.Modules.Discovery/src/Runtime/Config.cs +++ b/modules/src/Microsoft.Azure.IIoT.Modules.Discovery/src/Runtime/Config.cs @@ -6,6 +6,8 @@ namespace Microsoft.Azure.IIoT.Modules.Discovery.Runtime { using Microsoft.Azure.IIoT.Module.Framework; using Microsoft.Azure.IIoT.Module.Framework.Client; + using Microsoft.Azure.IIoT.OpcUa.Protocol; + using Microsoft.Azure.IIoT.OpcUa.Protocol.Runtime; using Microsoft.Azure.IIoT.Hub.Module.Client.Runtime; using Microsoft.Azure.IIoT.Diagnostics; using Microsoft.Extensions.Configuration; @@ -13,7 +15,7 @@ namespace Microsoft.Azure.IIoT.Modules.Discovery.Runtime { /// /// Wraps a configuration root /// - public class Config : DiagnosticsConfig, IModuleConfig { + public class Config : DiagnosticsConfig, IModuleConfig, IClientServicesConfig{ /// public string EdgeHubConnectionString => _module.EdgeHubConnectionString; @@ -23,6 +25,52 @@ public class Config : DiagnosticsConfig, IModuleConfig { public bool EnableMetrics => _module.EnableMetrics; /// public TransportOption Transport => _module.Transport; + /// + public string ApplicationName => _opc.ApplicationName; + /// + public string ApplicationUri => _opc.ApplicationUri; + /// + public string ProductUri => _opc.ProductUri; + /// + public uint DefaultSessionTimeout => _opc.DefaultSessionTimeout; + /// + public int KeepAliveInterval => _opc.KeepAliveInterval; + /// + public uint MaxKeepAliveCount => _opc.MaxKeepAliveCount; + /// + public int MinSubscriptionLifetime => _opc.MinSubscriptionLifetime; + /// + public string PkiRootPath => _opc.PkiRootPath; + /// + public CertificateInfo ApplicationCertificate => _opc.ApplicationCertificate; + /// + public bool AutoAcceptUntrustedCertificates => _opc.AutoAcceptUntrustedCertificates; + /// + public ushort MinimumCertificateKeySize => _opc.MinimumCertificateKeySize; + /// + public CertificateStore RejectedCertificateStore => _opc.RejectedCertificateStore; + /// + public bool RejectSha1SignedCertificates => _opc.RejectSha1SignedCertificates; + /// + public CertificateStore TrustedIssuerCertificates => _opc.TrustedIssuerCertificates; + /// + public CertificateStore TrustedPeerCertificates => _opc.TrustedPeerCertificates; + /// + public int ChannelLifetime => _opc.ChannelLifetime; + /// + public int MaxArrayLength => _opc.MaxArrayLength; + /// + public int MaxBufferSize => _opc.MaxBufferSize; + /// + public int MaxByteStringLength => _opc.MaxByteStringLength; + /// + public int MaxMessageSize => _opc.MaxMessageSize; + /// + public int MaxStringLength => _opc.MaxStringLength; + /// + public int OperationTimeout => _opc.OperationTimeout; + /// + public int SecurityTokenLifetime => _opc.SecurityTokenLifetime; /// /// Configuration constructor @@ -31,8 +79,10 @@ public class Config : DiagnosticsConfig, IModuleConfig { public Config(IConfiguration configuration) : base(configuration) { _module = new ModuleConfig(configuration); + _opc = new ClientServicesConfig(configuration); } + private readonly ClientServicesConfig _opc; private readonly ModuleConfig _module; } } diff --git a/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/cli/Program.cs b/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/cli/Program.cs index a2e52f8a73..1595b85ad1 100644 --- a/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/cli/Program.cs +++ b/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/cli/Program.cs @@ -260,7 +260,7 @@ private class ServerWrapper : IDisposable { public ServerWrapper(ILogger logger) { _cts = new CancellationTokenSource(); _server = RunSampleServerAsync(_cts.Token, logger); - EndpointUrl = "opc.tcp://" + Opc.Ua.Utils.GetHostName() + + EndpointUrl = "opc.tcp://" + Dns.GetHostName() + ":51210/UA/SampleServer"; } diff --git a/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/src/Runtime/Config.cs b/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/src/Runtime/Config.cs index f31539f1e1..5ffe37a207 100644 --- a/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/src/Runtime/Config.cs +++ b/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/src/Runtime/Config.cs @@ -15,8 +15,7 @@ namespace Microsoft.Azure.IIoT.Modules.OpcUa.Publisher.Runtime { /// /// Wraps a configuration root /// - public class Config : DiagnosticsConfig, IModuleConfig, IClientServicesConfig2, - ISecurityConfig, ITransportQuotaConfig { + public class Config : DiagnosticsConfig, IModuleConfig, IClientServicesConfig{ /// public string EdgeHubConnectionString => _module.EdgeHubConnectionString; @@ -41,6 +40,8 @@ public class Config : DiagnosticsConfig, IModuleConfig, IClientServicesConfig2, /// public int MinSubscriptionLifetime => _opc.MinSubscriptionLifetime; /// + public string PkiRootPath => _opc.PkiRootPath; + /// public CertificateInfo ApplicationCertificate => _opc.ApplicationCertificate; /// public bool AutoAcceptUntrustedCertificates => _opc.AutoAcceptUntrustedCertificates; @@ -77,11 +78,11 @@ public class Config : DiagnosticsConfig, IModuleConfig, IClientServicesConfig2, /// public Config(IConfiguration configuration) : base(configuration) { - _opc = new ClientServicesConfig2(configuration); + _opc = new ClientServicesConfig(configuration); _module = new ModuleConfig(configuration); } - private readonly ClientServicesConfig2 _opc; + private readonly ClientServicesConfig _opc; private readonly ModuleConfig _module; } } diff --git a/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/src/Runtime/LegacyCliConfigKeys.cs b/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/src/Runtime/LegacyCliConfigKeys.cs index d07ceb025a..09c941006f 100644 --- a/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/src/Runtime/LegacyCliConfigKeys.cs +++ b/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Publisher/src/Runtime/LegacyCliConfigKeys.cs @@ -115,17 +115,17 @@ public static class LegacyCliConfigKeys { /// /// Key for the OPC Session creation timeout in seconds. /// - public const string OpcSessionCreationTimeout = ClientServicesConfig2.DefaultSessionTimeoutKey; + public const string OpcSessionCreationTimeout = ClientServicesConfig.DefaultSessionTimeoutKey; /// /// Key for the OPC Keep Alive Interval in seconds. /// - public const string OpcKeepAliveIntervalInSec = ClientServicesConfig2.KeepAliveIntervalKey; + public const string OpcKeepAliveIntervalInSec = ClientServicesConfig.KeepAliveIntervalKey; /// /// Key for the disconnect thresholt for missed keep alive signals. /// - public const string OpcKeepAliveDisconnectThreshold = ClientServicesConfig2.MaxKeepAliveCountKey; + public const string OpcKeepAliveDisconnectThreshold = ClientServicesConfig.MaxKeepAliveCountKey; /// /// Key for the flag to trust own certificate. diff --git a/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin.csproj b/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin.csproj index 7974199d15..ebaaa58c3e 100644 --- a/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin.csproj +++ b/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin.csproj @@ -8,9 +8,9 @@ - - - + + + diff --git a/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin/src/Runtime/Config.cs b/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin/src/Runtime/Config.cs index b6384985e1..b4aa788f72 100644 --- a/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin/src/Runtime/Config.cs +++ b/modules/src/Microsoft.Azure.IIoT.Modules.OpcUa.Twin/src/Runtime/Config.cs @@ -11,14 +11,11 @@ namespace Microsoft.Azure.IIoT.Modules.OpcUa.Twin.Runtime { using Microsoft.Azure.IIoT.Hub.Module.Client.Runtime; using Microsoft.Azure.IIoT.Diagnostics; using Microsoft.Extensions.Configuration; - using System.Runtime.InteropServices; - using System; /// /// Wraps a configuration root /// - public class Config : DiagnosticsConfig, IModuleConfig, IClientServicesConfig2, - ISecurityConfig, ITransportQuotaConfig, IClientServicesConfig { + public class Config : DiagnosticsConfig, IModuleConfig, IClientServicesConfig{ /// public string EdgeHubConnectionString => _module.EdgeHubConnectionString; @@ -43,6 +40,8 @@ public class Config : DiagnosticsConfig, IModuleConfig, IClientServicesConfig2, /// public int MinSubscriptionLifetime => _opc.MinSubscriptionLifetime; /// + public string PkiRootPath => _opc.PkiRootPath; + /// public CertificateInfo ApplicationCertificate => _opc.ApplicationCertificate; /// public bool AutoAcceptUntrustedCertificates => _opc.AutoAcceptUntrustedCertificates; @@ -73,51 +72,6 @@ public class Config : DiagnosticsConfig, IModuleConfig, IClientServicesConfig2, /// public int SecurityTokenLifetime => _opc.SecurityTokenLifetime; - /// - /// ClientServicesConfig - /// - private const string kAppCertStoreType = "AppCertStoreType"; - private const string kPkiRootPath = "PkiRootPath"; - private const string kOwnCertPath = "OwnCertPath"; - private const string kTrustedCertPath = "TrustedCertPath"; - private const string kIssuerCertPath = "IssuerCertPath"; - private const string kRejectedCertPath = "RejectedCertPath"; - private const string kAutoAccept = "AutoAccept"; - private const string kOwnCertX509StorePathDefault = "OwnCertX509StorePathDefault"; - private const string kSessionTimeout = "SessionTimeout"; - private const string kOperationTimeout = "OperationTimeout"; - - /// - public string AppCertStoreType => GetStringOrDefault(kAppCertStoreType, - () => RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "X509Store" : "Directory"); - /// - public string PkiRootPath => - GetStringOrDefault(kPkiRootPath, () => "pki"); - /// - public string OwnCertPath => - GetStringOrDefault(kOwnCertPath, () => PkiRootPath + "/own"); - /// - public string TrustedCertPath => - GetStringOrDefault(kTrustedCertPath, () => PkiRootPath + "/trusted"); - /// - public string IssuerCertPath => - GetStringOrDefault(kIssuerCertPath, () => PkiRootPath + "/issuer"); - /// - public string RejectedCertPath => - GetStringOrDefault(kRejectedCertPath, () => PkiRootPath + "/rejected"); - /// - public string OwnCertX509StorePathDefault => - GetStringOrDefault(kOwnCertX509StorePathDefault, () => "CurrentUser\\UA_MachineDefault"); - /// - bool IClientServicesConfig.AutoAcceptUntrustedCertificates => - GetBoolOrDefault(kAutoAccept, () => false); - /// - TimeSpan? IClientServicesConfig.DefaultSessionTimeout => - GetDurationOrNull(kSessionTimeout); - /// - TimeSpan? IClientServicesConfig.OperationTimeout => - GetDurationOrNull(kOperationTimeout); - /// /// Configuration constructor /// @@ -125,10 +79,10 @@ public class Config : DiagnosticsConfig, IModuleConfig, IClientServicesConfig2, public Config(IConfiguration configuration) : base(configuration) { _module = new ModuleConfig(configuration); - _opc = new ClientServicesConfig2(configuration); + _opc = new ClientServicesConfig(configuration); } - private readonly ClientServicesConfig2 _opc; + private readonly ClientServicesConfig _opc; private readonly ModuleConfig _module; } } diff --git a/services/src/Microsoft.Azure.IIoT.Services.All/src/Microsoft.Azure.IIoT.Services.All.csproj b/services/src/Microsoft.Azure.IIoT.Services.All/src/Microsoft.Azure.IIoT.Services.All.csproj index a791bd29fc..37e0dbcae7 100644 --- a/services/src/Microsoft.Azure.IIoT.Services.All/src/Microsoft.Azure.IIoT.Services.All.csproj +++ b/services/src/Microsoft.Azure.IIoT.Services.All/src/Microsoft.Azure.IIoT.Services.All.csproj @@ -4,9 +4,9 @@ true - - - + + + diff --git a/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.Gateway/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.Gateway.csproj b/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.Gateway/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.Gateway.csproj index d406c23269..87b8635b54 100644 --- a/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.Gateway/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.Gateway.csproj +++ b/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.Gateway/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.Gateway.csproj @@ -4,10 +4,10 @@ true - - - - + + + + diff --git a/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.History/tests/TestStartup.cs b/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.History/tests/TestStartup.cs index 222479b8cb..c7a5842904 100644 --- a/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.History/tests/TestStartup.cs +++ b/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin.History/tests/TestStartup.cs @@ -9,9 +9,9 @@ namespace Microsoft.Azure.IIoT.Services.OpcUa.Twin.History { using Microsoft.Azure.IIoT.OpcUa.Edge.Control.Services; using Microsoft.Azure.IIoT.OpcUa.Edge.Export; using Microsoft.Azure.IIoT.OpcUa.Protocol.Services; + using Microsoft.Azure.IIoT.OpcUa.Testing.Runtime; using Microsoft.Azure.IIoT.Hub.Client; using Microsoft.Azure.IIoT.Auth; - using Microsoft.Azure.IIoT.Auth.Models; using Microsoft.Azure.IIoT.Utils; using Microsoft.Extensions.Hosting; using Microsoft.AspNetCore.Hosting; @@ -19,10 +19,9 @@ namespace Microsoft.Azure.IIoT.Services.OpcUa.Twin.History { using Autofac; using Autofac.Extensions.Hosting; using System; + using System.Collections.Generic; using System.Net.Http; using System.Text; - using System.Threading.Tasks; - using System.Collections.Generic; /// /// Startup class for tests @@ -46,6 +45,8 @@ public override void ConfigureContainer(ContainerBuilder builder) { .AsImplementedInterfaces().SingleInstance(); builder.RegisterType() .AsImplementedInterfaces().SingleInstance(); + builder.RegisterType() + .AsImplementedInterfaces().SingleInstance(); builder.RegisterType() .AsImplementedInterfaces(); builder.RegisterType>() diff --git a/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin/tests/TestStartup.cs b/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin/tests/TestStartup.cs index 4932768ebd..35e76874bb 100644 --- a/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin/tests/TestStartup.cs +++ b/services/src/Microsoft.Azure.IIoT.Services.OpcUa.Twin/tests/TestStartup.cs @@ -11,7 +11,6 @@ namespace Microsoft.Azure.IIoT.Services.OpcUa.Twin { using Microsoft.Azure.IIoT.OpcUa.Testing.Runtime; using Microsoft.Azure.IIoT.OpcUa.Core.Models; using Microsoft.Azure.IIoT.Hub.Client; - using Microsoft.Azure.IIoT.Auth.Models; using Microsoft.Azure.IIoT.Auth; using Microsoft.Azure.IIoT.Utils; using Microsoft.Azure.IIoT.Serializers.NewtonSoft;