Skip to content

Commit

Permalink
Fix channel factory to use root ca if provided
Browse files Browse the repository at this point in the history
  • Loading branch information
w1am committed Oct 23, 2024
1 parent 09fcaa6 commit 5670139
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 142 deletions.
53 changes: 31 additions & 22 deletions src/EventStore.Client/ChannelFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
using TChannel = Grpc.Net.Client.GrpcChannel;

namespace EventStore.Client {

internal static class ChannelFactory {
private const int MaxReceiveMessageLength = 17 * 1024 * 1024;

Expand Down Expand Up @@ -38,14 +38,8 @@ public static TChannel CreateChannel(EventStoreClientSettings settings, EndPoint

#if NET48
static HttpMessageHandler CreateHandler(EventStoreClientSettings settings) {
if (settings.CreateHttpMessageHandler != null) {
if (settings.CreateHttpMessageHandler is not null)
return settings.CreateHttpMessageHandler.Invoke();
}

var certificate = settings.ConnectivitySettings.ClientCertificate ??
settings.ConnectivitySettings.TlsCaFile;

var configureClientCert = settings.ConnectivitySettings is { Insecure: false } && certificate != null;

var handler = new WinHttpHandler {
TcpKeepAliveEnabled = true,
Expand All @@ -56,41 +50,56 @@ static HttpMessageHandler CreateHandler(EventStoreClientSettings settings) {

if (settings.ConnectivitySettings.Insecure) return handler;

if (configureClientCert) {
handler.ClientCertificates.Add(certificate!);
}
if (settings.ConnectivitySettings.ClientCertificate is not null)
handler.ClientCertificates.Add(settings.ConnectivitySettings.ClientCertificate);

if (!settings.ConnectivitySettings.TlsVerifyCert) {
handler.ServerCertificateValidationCallback = delegate { return true; };
} else if (settings.ConnectivitySettings.TlsCaFile is not null) {
handler.ServerCertificateValidationCallback= (sender, certificate, chain, errors) => {
if (chain is null) return false;
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
chain.ChainPolicy.ExtraStore.Add(settings.ConnectivitySettings.TlsCaFile);
return chain.Build(certificate);
};
}

return handler;
}
#else
static HttpMessageHandler CreateHandler(EventStoreClientSettings settings) {
if (settings.CreateHttpMessageHandler != null) {
if (settings.CreateHttpMessageHandler is not null)
return settings.CreateHttpMessageHandler.Invoke();
}

var certificate = settings.ConnectivitySettings.ClientCertificate ??
settings.ConnectivitySettings.TlsCaFile;

var configureClientCert = settings.ConnectivitySettings is { Insecure: false } && certificate != null;

var handler = new SocketsHttpHandler {
KeepAlivePingDelay = settings.ConnectivitySettings.KeepAliveInterval,
KeepAlivePingTimeout = settings.ConnectivitySettings.KeepAliveTimeout,
EnableMultipleHttp2Connections = true,
EnableMultipleHttp2Connections = true
};

if (settings.ConnectivitySettings.Insecure) return handler;
if (settings.ConnectivitySettings.Insecure)
return handler;

if (configureClientCert) {
handler.SslOptions.ClientCertificates = new X509CertificateCollection { certificate! };
if (settings.ConnectivitySettings.ClientCertificate is not null) {
handler.SslOptions.ClientCertificates = new X509CertificateCollection {
settings.ConnectivitySettings.ClientCertificate
};
}

if (!settings.ConnectivitySettings.TlsVerifyCert) {
handler.SslOptions.RemoteCertificateValidationCallback = delegate { return true; };
} else if (settings.ConnectivitySettings.TlsCaFile is not null) {
handler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => {
if (certificate is not X509Certificate2 peerCertificate || chain is null) return false;
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.DisableCertificateDownloads = true;
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(settings.ConnectivitySettings.TlsCaFile);
return chain.Build(peerCertificate);
};
}

return handler;
Expand Down
46 changes: 30 additions & 16 deletions src/EventStore.Client/EventStoreClientSettings.ConnectionString.cs
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,8 @@ private static EventStoreClientSettings CreateSettings(

#if NET48
HttpMessageHandler CreateDefaultHandler() {
var certificate = settings.ConnectivitySettings.ClientCertificate ??
settings.ConnectivitySettings.TlsCaFile;

var configureClientCert = settings.ConnectivitySettings is { Insecure: false } && certificate != null;
if (settings.CreateHttpMessageHandler is not null)
return settings.CreateHttpMessageHandler.Invoke();

var handler = new WinHttpHandler {
TcpKeepAliveEnabled = true,
Expand All @@ -249,37 +247,53 @@ HttpMessageHandler CreateDefaultHandler() {

if (settings.ConnectivitySettings.Insecure) return handler;

if (configureClientCert) {
handler.ClientCertificates.Add(certificate!);
}
if (settings.ConnectivitySettings.ClientCertificate is not null)
handler.ClientCertificates.Add(settings.ConnectivitySettings.ClientCertificate);

if (!settings.ConnectivitySettings.TlsVerifyCert) {
handler.ServerCertificateValidationCallback = delegate { return true; };
} else if (settings.ConnectivitySettings.TlsCaFile is not null) {
handler.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => {
if (chain is null) return false;
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
chain.ChainPolicy.ExtraStore.Add(settings.ConnectivitySettings.TlsCaFile);
return chain.Build(certificate);
};
}

return handler;
}
#else
HttpMessageHandler CreateDefaultHandler() {
var certificate = settings.ConnectivitySettings.ClientCertificate ??
settings.ConnectivitySettings.TlsCaFile;

var configureClientCert = settings.ConnectivitySettings is { Insecure: false } && certificate != null;

var handler = new SocketsHttpHandler {
KeepAlivePingDelay = settings.ConnectivitySettings.KeepAliveInterval,
KeepAlivePingTimeout = settings.ConnectivitySettings.KeepAliveTimeout,
EnableMultipleHttp2Connections = true,
EnableMultipleHttp2Connections = true
};

if (settings.ConnectivitySettings.Insecure) return handler;
if (settings.ConnectivitySettings.Insecure)
return handler;

if (configureClientCert) {
handler.SslOptions.ClientCertificates = [certificate!];
if (settings.ConnectivitySettings.ClientCertificate is not null) {
handler.SslOptions.ClientCertificates = new X509CertificateCollection {
settings.ConnectivitySettings.ClientCertificate
};
}

if (!settings.ConnectivitySettings.TlsVerifyCert) {
handler.SslOptions.RemoteCertificateValidationCallback = delegate { return true; };
} else if (settings.ConnectivitySettings.TlsCaFile is not null) {
handler.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => {
if (certificate is not X509Certificate2 peerCertificate || chain is null) return false;
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.DisableCertificateDownloads = true;
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(settings.ConnectivitySettings.TlsCaFile);
return chain.Build(peerCertificate);
};
}

return handler;
Expand Down
49 changes: 34 additions & 15 deletions src/EventStore.Client/HttpFallback.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,33 @@ internal HttpFallback(EventStoreClientSettings settings) {
if (!settings.ConnectivitySettings.Insecure) {
handler.ClientCertificateOptions = ClientCertificateOption.Manual;

if (settings.ConnectivitySettings.TlsCaFile != null)
handler.ClientCertificates.Add(settings.ConnectivitySettings.TlsCaFile);

if (settings.ConnectivitySettings.ClientCertificate != null)
if (settings.ConnectivitySettings.ClientCertificate is not null)
handler.ClientCertificates.Add(settings.ConnectivitySettings.ClientCertificate);

if (!settings.ConnectivitySettings.TlsVerifyCert)
if (!settings.ConnectivitySettings.TlsVerifyCert) {
handler.ServerCertificateCustomValidationCallback = delegate { return true; };
} else if (settings.ConnectivitySettings.TlsCaFile is not null) {
#if NET48
handler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, errors) => {
if (chain is null) return false;
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
chain.ChainPolicy.ExtraStore.Add(settings.ConnectivitySettings.TlsCaFile);
return chain.Build(certificate);
};
#else
handler.ServerCertificateCustomValidationCallback = (sender, certificate, chain, errors) => {
if (certificate is null || chain is null) return false;
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.DisableCertificateDownloads = true;
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
chain.ChainPolicy.CustomTrustStore.Add(settings.ConnectivitySettings.TlsCaFile);
return chain.Build(certificate);
};
#endif
}
}

_httpClient = new HttpClient(handler);
Expand All @@ -45,9 +64,9 @@ internal async Task<T> HttpGetAsync<T>(string path, ChannelInfo channelInfo, Tim
UserCredentials? userCredentials, Action onNotFound, CancellationToken cancellationToken) {

var request = CreateRequest(path, HttpMethod.Get, channelInfo, userCredentials);

var httpResult = await HttpSendAsync(request, onNotFound, deadline, cancellationToken).ConfigureAwait(false);

#if NET
var json = await httpResult.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
#else
Expand All @@ -66,26 +85,26 @@ internal async Task HttpPostAsync(string path, string query, ChannelInfo channel
UserCredentials? userCredentials, Action onNotFound, CancellationToken cancellationToken) {

var request = CreateRequest(path, query, HttpMethod.Post, channelInfo, userCredentials);

await HttpSendAsync(request, onNotFound, deadline, cancellationToken).ConfigureAwait(false);
}

private async Task<HttpResponseMessage> HttpSendAsync(HttpRequestMessage request, Action onNotFound,
TimeSpan? deadline, CancellationToken cancellationToken) {

if (!deadline.HasValue) {
return await HttpSendAsync(request, onNotFound, cancellationToken).ConfigureAwait(false);
return await HttpSendAsync(request, onNotFound, cancellationToken).ConfigureAwait(false);
}

using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
cts.CancelAfter(deadline.Value);

return await HttpSendAsync(request, onNotFound, cts.Token).ConfigureAwait(false);
}

async Task<HttpResponseMessage> HttpSendAsync(HttpRequestMessage request, Action onNotFound,
CancellationToken cancellationToken) {

var httpResult = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
if (httpResult.IsSuccessStatusCode) {
return httpResult;
Expand All @@ -107,7 +126,7 @@ private HttpRequestMessage CreateRequest(string path, HttpMethod method, Channel

private HttpRequestMessage CreateRequest(string path, string query, HttpMethod method, ChannelInfo channelInfo,
UserCredentials? credentials) {

var uriBuilder = new UriBuilder($"{_addressScheme}://{channelInfo.Channel.Target}") {
Path = path,
Query = query
Expand All @@ -119,7 +138,7 @@ private HttpRequestMessage CreateRequest(string path, string query, HttpMethod m
if (credentials != null) {
httpRequest.Headers.Add(Constants.Headers.Authorization, credentials.ToString());
}

return httpRequest;
}

Expand Down
89 changes: 0 additions & 89 deletions test/EventStore.Client.Plugins.Tests/ClientCertificate.cs

This file was deleted.

Loading

0 comments on commit 5670139

Please sign in to comment.