Add HistorianClientOptions.ServerDnsIdentity for cert-binding overrides
When the server cert's CN/SAN doesn't match the URL host (typical for installer-generated AVEVA Historian certs that claim DNS=localhost even when reached over a LAN IP), WCF rejects the channel with "Identity check failed for outgoing message". Set ServerDnsIdentity to whatever the cert claims (often "localhost") to satisfy the check. The endpoint address for the cert binding is constructed with a DnsEndpointIdentity when the option is non-null. Default null. Pairs with AllowUntrustedServerCertificate so a Linux client can talk to a self-signed dev Historian over RemoteTcpCertificate. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,4 +38,15 @@ public sealed class HistorianClientOptions
|
||||
/// server's identity matters.
|
||||
/// </summary>
|
||||
public bool AllowUntrustedServerCertificate { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the expected DNS identity in the endpoint address — set this to
|
||||
/// whatever DNS name the server's certificate actually claims (often
|
||||
/// <c>localhost</c> on installer-generated AVEVA Historian certificates) when
|
||||
/// connecting via IP address or a hostname that doesn't match the cert SAN/CN.
|
||||
/// Without this override WCF rejects the channel with
|
||||
/// "Identity check failed for outgoing message". Has no effect on transports
|
||||
/// that don't validate a server certificate.
|
||||
/// </summary>
|
||||
public string? ServerDnsIdentity { get; init; }
|
||||
}
|
||||
|
||||
@@ -144,19 +144,22 @@ internal static class HistorianWcfBindingFactory
|
||||
CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.Retrieval)),
|
||||
HistorianTransport.RemoteTcpCertificate => (
|
||||
CreateMdasNetTcpCertificateBinding(timeout),
|
||||
CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.HistoryCertificate),
|
||||
CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.HistoryCertificate, options.ServerDnsIdentity),
|
||||
CreateMdasNetTcpBinding(timeout),
|
||||
CreateEndpointAddress(options.Host, options.Port, HistorianWcfServiceNames.Retrieval)),
|
||||
_ => throw new NotSupportedException($"Transport {options.Transport} is not supported.")
|
||||
};
|
||||
}
|
||||
|
||||
public static EndpointAddress CreateEndpointAddress(string host, int port, string serviceName)
|
||||
public static EndpointAddress CreateEndpointAddress(string host, int port, string serviceName, string? dnsIdentity = null)
|
||||
{
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(host);
|
||||
ArgumentException.ThrowIfNullOrWhiteSpace(serviceName);
|
||||
|
||||
return new EndpointAddress($"{Scheme}://{host}:{port}/{serviceName}");
|
||||
Uri uri = new($"{Scheme}://{host}:{port}/{serviceName}");
|
||||
return string.IsNullOrWhiteSpace(dnsIdentity)
|
||||
? new EndpointAddress(uri)
|
||||
: new EndpointAddress(uri, new DnsEndpointIdentity(dnsIdentity));
|
||||
}
|
||||
|
||||
public static EndpointAddress CreatePipeEndpointAddress(string host, string serviceName)
|
||||
|
||||
Reference in New Issue
Block a user