diff --git a/src/AVEVA.Historian.Client/Wcf/HistorianWcfTagClient.cs b/src/AVEVA.Historian.Client/Wcf/HistorianWcfTagClient.cs index e126298..118bb3f 100644 --- a/src/AVEVA.Historian.Client/Wcf/HistorianWcfTagClient.cs +++ b/src/AVEVA.Historian.Client/Wcf/HistorianWcfTagClient.cs @@ -1,6 +1,7 @@ using System.Net; using System.Runtime.CompilerServices; using System.ServiceModel; +using System.ServiceModel.Channels; using AVEVA.Historian.Client.Models; using AVEVA.Historian.Client.Wcf.Contracts; @@ -281,17 +282,38 @@ internal static class HistorianWcfTagClient { ValidateSupportedAuth(options); + // The browse/metadata code uses the legacy Open2-V1 buffer, which carries + // its own auth blob. That buffer is only valid against the WCF transport that + // negotiates Windows security at the channel level (`/Hist-Integrated`) or + // against the cert binding (which trusts the channel-level cert identity). + // For LocalPipe and RemoteTcpIntegrated the original behaviour stays — + // hit the Integrated endpoint with the Windows transport binding. Only + // RemoteTcpCertificate gets the cert binding here, so browse/metadata + // works from a Linux client over the cert transport. + (Binding historyBinding, EndpointAddress historyEndpoint) = options.Transport switch + { + HistorianTransport.RemoteTcpCertificate => ( + HistorianWcfBindingFactory.CreateMdasNetTcpCertificateBinding(options.RequestTimeout), + HistorianWcfBindingFactory.CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.HistoryCertificate, options.ServerDnsIdentity)), + _ => ( + HistorianWcfBindingFactory.CreateMdasNetTcpWindowsBinding(options.RequestTimeout), + HistorianWcfBindingFactory.CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.HistoryIntegrated)), + }; + ChannelFactory? historyFactory = null; IHistoryServiceContract2? historyChannel = null; - ChannelFactory? retrievalFactory = null; - IRetrievalServiceContract2? retrievalChannel = null; + ChannelFactory? retrievalFactory = null; + IRetrievalServiceContract2? retrievalChannel = null; try { - historyFactory = new ChannelFactory( - HistorianWcfBindingFactory.CreateMdasNetTcpWindowsBinding(options.RequestTimeout), - HistorianWcfBindingFactory.CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.HistoryIntegrated)); - historyFactory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation; - ApplyWindowsCredential(historyFactory, options); + historyFactory = new ChannelFactory(historyBinding, historyEndpoint); + HistorianWcfClientCredentialsHelper.Configure(historyFactory, options); + if (options.Transport != HistorianTransport.RemoteTcpCertificate) + { + // Windows transport-security only applies to the integrated-auth binding. + historyFactory.Credentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation; + ApplyWindowsCredential(historyFactory, options); + } historyFactory.Open(); historyChannel = historyFactory.CreateChannel(); @@ -310,6 +332,7 @@ internal static class HistorianWcfTagClient retrievalFactory = new ChannelFactory( HistorianWcfBindingFactory.CreateMdasNetTcpBinding(options.RequestTimeout), HistorianWcfBindingFactory.CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.Retrieval)); + HistorianWcfClientCredentialsHelper.Configure(retrievalFactory, options); retrievalFactory.Open(); retrievalChannel = retrievalFactory.CreateChannel();