diff --git a/source/Halibut.TestUtils.CompatBinary.SchannelProbe/Halibut.TestUtils.CompatBinary.SchannelProbe.csproj b/source/Halibut.TestUtils.CompatBinary.SchannelProbe/Halibut.TestUtils.CompatBinary.SchannelProbe.csproj
new file mode 100644
index 000000000..34156a448
--- /dev/null
+++ b/source/Halibut.TestUtils.CompatBinary.SchannelProbe/Halibut.TestUtils.CompatBinary.SchannelProbe.csproj
@@ -0,0 +1,23 @@
+
+
+
+ Exe
+ 9.0
+ Halibut.TestUtils.SampleProgram.SchannelProbe
+ enable
+ true
+
+
+
+ net48;net8.0
+
+
+ net8.0
+
+
+
+
+
+
+
+
diff --git a/source/Halibut.TestUtils.CompatBinary.SchannelProbe/Program.cs b/source/Halibut.TestUtils.CompatBinary.SchannelProbe/Program.cs
new file mode 100644
index 000000000..dd623f5d8
--- /dev/null
+++ b/source/Halibut.TestUtils.CompatBinary.SchannelProbe/Program.cs
@@ -0,0 +1,13 @@
+using System.Threading.Tasks;
+using Halibut.TestUtils.SampleProgram.Base;
+
+namespace Halibut.TestUtils.SampleProgram.SchannelProbe
+{
+ public class Program
+ {
+ public static async Task Main()
+ {
+ return await BackwardsCompatProgramBase.Main();
+ }
+ }
+}
diff --git a/source/Halibut.Tests/Halibut.Tests.csproj b/source/Halibut.Tests/Halibut.Tests.csproj
index 602280ad8..d5d3051aa 100644
--- a/source/Halibut.Tests/Halibut.Tests.csproj
+++ b/source/Halibut.Tests/Halibut.Tests.csproj
@@ -31,6 +31,7 @@
+
diff --git a/source/Halibut.Tests/SchannelSessionCacheFixture.cs b/source/Halibut.Tests/SchannelSessionCacheFixture.cs
new file mode 100644
index 000000000..e8369c5e8
--- /dev/null
+++ b/source/Halibut.Tests/SchannelSessionCacheFixture.cs
@@ -0,0 +1,172 @@
+using System;
+using System.Threading.Tasks;
+using FluentAssertions;
+using Halibut.Diagnostics.LogCreators;
+using Halibut.Tests.Support;
+using Halibut.Tests.Support.BackwardsCompatibility;
+using Halibut.Tests.Support.Logging;
+using Halibut.Tests.TestServices.Async;
+using Halibut.Tests.Util;
+using Halibut.TestUtils.Contracts;
+using NUnit.Framework;
+
+namespace Halibut.Tests
+{
+ ///
+ /// Proves that process isolation prevents SChannel session cache collisions.
+ ///
+ /// In-process, a single acting as both TLS server and TLS
+ /// client to localhost with two different certificates can collide in the SChannel session
+ /// cache (Windows). Running the tentacle in a separate process avoids this because the
+ /// SChannel session cache is per-process.
+ ///
+ /// These tests verify that two separate processes — one listening tentacle and one polling
+ /// tentacle — both using the same certificate and both connecting via localhost, can
+ /// simultaneously communicate successfully with an in-process Octopus server.
+ ///
+ [TestFixture]
+ [NonParallelizable]
+ public class SchannelSessionCacheFixture : BaseTest
+ {
+ [Test]
+ public async Task ListeningTentacleInSeparateProcessCanCommunicateWithOctopus()
+ {
+ using var tmpDirectory = new TmpDirectory();
+ var octopusCert = CertificateGenerator.GenerateSelfSignedCertificate(tmpDirectory.FullPath);
+ var tentacleCert = CertificateGenerator.GenerateSelfSignedCertificate(tmpDirectory.FullPath);
+
+ var octopus = new HalibutRuntimeBuilder()
+ .WithServerCertificate(octopusCert.Certificate2)
+ .WithLogFactory(new TestContextLogCreator("Octopus", Logging.LogLevel.Trace).ToCachingLogFactory())
+ .WithHalibutTimeoutsAndLimits(new HalibutTimeoutsAndLimitsForTestsBuilder().Build())
+ .Build();
+
+ await using var _ = new AsyncDisposableAction(async () => await octopus.DisposeAsync());
+
+ octopus.Trust(tentacleCert.Thumbprint);
+
+ using var runningTentacle = await new SchannelProbeBinaryRunner(
+ ServiceConnectionType.Listening,
+ clientListenPort: null,
+ clientCertAndThumbprint: octopusCert,
+ serviceCertAndThumbprint: tentacleCert,
+ logger: Logger).Run();
+
+ runningTentacle.ServiceListenPort.Should().NotBeNull("listening tentacle should have reported its port");
+
+ var serviceUri = new Uri($"https://localhost:{runningTentacle.ServiceListenPort}");
+ var serviceEndPoint = new ServiceEndPoint(serviceUri, tentacleCert.Thumbprint, octopus.TimeoutsAndLimits);
+
+ var echo = octopus.CreateAsyncClient(serviceEndPoint);
+ var result = await echo.SayHelloAsync("world");
+
+ result.Should().Be("world...");
+ }
+
+ [Test]
+ public async Task PollingTentacleInSeparateProcessCanCommunicateWithOctopus()
+ {
+ using var tmpDirectory = new TmpDirectory();
+ var octopusCert = CertificateGenerator.GenerateSelfSignedCertificate(tmpDirectory.FullPath);
+ var tentacleCert = CertificateGenerator.GenerateSelfSignedCertificate(tmpDirectory.FullPath);
+
+ var octopus = new HalibutRuntimeBuilder()
+ .WithServerCertificate(octopusCert.Certificate2)
+ .WithLogFactory(new TestContextLogCreator("Octopus", Logging.LogLevel.Trace).ToCachingLogFactory())
+ .WithHalibutTimeoutsAndLimits(new HalibutTimeoutsAndLimitsForTestsBuilder().Build())
+ .Build();
+
+ await using var _ = new AsyncDisposableAction(async () => await octopus.DisposeAsync());
+
+ octopus.Trust(tentacleCert.Thumbprint);
+ var pollingListenPort = octopus.Listen();
+
+ using var runningTentacle = await new SchannelProbeBinaryRunner(
+ ServiceConnectionType.Polling,
+ clientListenPort: pollingListenPort,
+ clientCertAndThumbprint: octopusCert,
+ serviceCertAndThumbprint: tentacleCert,
+ logger: Logger).Run();
+
+ var serviceUri = new Uri("poll://SQ-TENTAPOLL");
+ var serviceEndPoint = new ServiceEndPoint(serviceUri, tentacleCert.Thumbprint, octopus.TimeoutsAndLimits);
+
+ var echo = octopus.CreateAsyncClient(serviceEndPoint);
+ var result = await echo.SayHelloAsync("world");
+
+ result.Should().Be("world...");
+ }
+
+ [Test]
+ public async Task ListeningAndPollingTentaclesInSeparateProcessesCanSimultaneouslyCommunicateWithOctopus()
+ {
+ using var tmpDirectory = new TmpDirectory();
+ var octopusCert = CertificateGenerator.GenerateSelfSignedCertificate(tmpDirectory.FullPath);
+ // Both tentacles intentionally share the same certificate to maximise the chance of
+ // triggering an SChannel session-cache collision if process isolation were absent.
+ var sharedTentacleCert = CertificateGenerator.GenerateSelfSignedCertificate(tmpDirectory.FullPath);
+
+ var octopus = new HalibutRuntimeBuilder()
+ .WithServerCertificate(octopusCert.Certificate2)
+ .WithLogFactory(new TestContextLogCreator("Octopus", Logging.LogLevel.Trace).ToCachingLogFactory())
+ .WithHalibutTimeoutsAndLimits(new HalibutTimeoutsAndLimitsForTestsBuilder().Build())
+ .Build();
+
+ await using var _ = new AsyncDisposableAction(async () => await octopus.DisposeAsync());
+
+ octopus.Trust(sharedTentacleCert.Thumbprint);
+ var pollingListenPort = octopus.Listen();
+
+ // Start listening tentacle
+ using var listeningTentacle = await new SchannelProbeBinaryRunner(
+ ServiceConnectionType.Listening,
+ clientListenPort: null,
+ clientCertAndThumbprint: octopusCert,
+ serviceCertAndThumbprint: sharedTentacleCert,
+ logger: Logger).Run();
+
+ listeningTentacle.ServiceListenPort.Should().NotBeNull("listening tentacle should have reported its port");
+
+ // Start polling tentacle
+ using var pollingTentacle = await new SchannelProbeBinaryRunner(
+ ServiceConnectionType.Polling,
+ clientListenPort: pollingListenPort,
+ clientCertAndThumbprint: octopusCert,
+ serviceCertAndThumbprint: sharedTentacleCert,
+ logger: Logger).Run();
+
+ var listeningServiceUri = new Uri($"https://localhost:{listeningTentacle.ServiceListenPort}");
+ var listeningEndPoint = new ServiceEndPoint(listeningServiceUri, sharedTentacleCert.Thumbprint, octopus.TimeoutsAndLimits);
+
+ var pollingServiceUri = new Uri("poll://SQ-TENTAPOLL");
+ var pollingEndPoint = new ServiceEndPoint(pollingServiceUri, sharedTentacleCert.Thumbprint, octopus.TimeoutsAndLimits);
+
+ var listeningEcho = octopus.CreateAsyncClient(listeningEndPoint);
+ var pollingEcho = octopus.CreateAsyncClient(pollingEndPoint);
+
+ // Call both simultaneously
+ var listeningTask = listeningEcho.SayHelloAsync("from-listening");
+ var pollingTask = pollingEcho.SayHelloAsync("from-polling");
+
+ var results = await Task.WhenAll(listeningTask, pollingTask);
+
+ results[0].Should().Be("from-listening...");
+ results[1].Should().Be("from-polling...");
+ }
+ }
+
+ class AsyncDisposableAction : IAsyncDisposable
+ {
+ readonly Func action;
+
+ public AsyncDisposableAction(Func action)
+ {
+ this.action = action;
+ }
+
+ public async ValueTask DisposeAsync()
+ {
+ await action();
+ }
+ }
+}
diff --git a/source/Halibut.Tests/Support/BackwardsCompatibility/HalibutTestBinaryPath.cs b/source/Halibut.Tests/Support/BackwardsCompatibility/HalibutTestBinaryPath.cs
index 3860e7173..b7a0675ce 100644
--- a/source/Halibut.Tests/Support/BackwardsCompatibility/HalibutTestBinaryPath.cs
+++ b/source/Halibut.Tests/Support/BackwardsCompatibility/HalibutTestBinaryPath.cs
@@ -9,15 +9,25 @@ public class HalibutTestBinaryPath
public string BinPath(string version)
{
var onDiskVersion = version.Replace(".", "_");
+ var projectName = $"Halibut.TestUtils.CompatBinary.v{onDiskVersion}";
+ return ResolveProjectBinPath(projectName);
+ }
+
+ public string SchannelProbeBinPath()
+ {
+ return ResolveProjectBinPath("Halibut.TestUtils.CompatBinary.SchannelProbe");
+ }
+
+ string ResolveProjectBinPath(string projectName)
+ {
var assemblyDir = new DirectoryInfo(Path.GetDirectoryName(typeof(HalibutTestBinaryRunner).Assembly.Location)!);
var upAt = assemblyDir.Parent!.Parent!.Parent!.Parent!;
- var projectName = $"Halibut.TestUtils.CompatBinary.v{onDiskVersion}";
var executable = Path.Combine(upAt.FullName, projectName, assemblyDir.Parent.Parent.Name, assemblyDir.Parent.Name, assemblyDir.Name, projectName);
executable = AddExeForWindows(executable);
if (!File.Exists(executable))
{
- throw new Exception("Could not executable at path:\n" +
+ throw new Exception("Could not find executable at path:\n" +
executable + "\n" +
$"Did you forget to update the csproj to depend on {projectName}\n" +
"If testing a previously untested version of Halibut a new project may be required.");
@@ -25,7 +35,7 @@ public string BinPath(string version)
return executable;
}
-
+
string AddExeForWindows(string path)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return path + ".exe";
diff --git a/source/Halibut.Tests/Support/BackwardsCompatibility/SchannelProbeBinaryRunner.cs b/source/Halibut.Tests/Support/BackwardsCompatibility/SchannelProbeBinaryRunner.cs
new file mode 100644
index 000000000..ea0248fe7
--- /dev/null
+++ b/source/Halibut.Tests/Support/BackwardsCompatibility/SchannelProbeBinaryRunner.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+using System.Threading;
+using System.Threading.Tasks;
+using CliWrap;
+using Halibut.Logging;
+using Serilog;
+
+namespace Halibut.Tests.Support.BackwardsCompatibility
+{
+ public class SchannelProbeBinaryRunner
+ {
+ readonly ServiceConnectionType serviceConnectionType;
+ readonly int? clientListenPort;
+ readonly CertAndThumbprint clientCertAndThumbprint;
+ readonly CertAndThumbprint serviceCertAndThumbprint;
+ readonly ILogger logger;
+
+ ///
+ /// Launches the SchannelProbe binary as a listening tentacle (server dials it) or a
+ /// polling tentacle (it dials the server). Uses the current version of Halibut.
+ ///
+ public SchannelProbeBinaryRunner(
+ ServiceConnectionType serviceConnectionType,
+ int? clientListenPort,
+ CertAndThumbprint clientCertAndThumbprint,
+ CertAndThumbprint serviceCertAndThumbprint,
+ ILogger logger)
+ {
+ this.serviceConnectionType = serviceConnectionType;
+ this.clientListenPort = clientListenPort;
+ this.clientCertAndThumbprint = clientCertAndThumbprint;
+ this.serviceCertAndThumbprint = serviceCertAndThumbprint;
+ this.logger = logger.ForContext();
+ }
+
+ public async Task Run()
+ {
+ var compatBinaryStayAlive = new CompatBinaryStayAlive(logger);
+
+ var settings = new Dictionary
+ {
+ { "mode", "serviceonly" },
+ { "tentaclecertpath", serviceCertAndThumbprint.CertificatePfxPath },
+ { "octopusthumbprint", clientCertAndThumbprint.Thumbprint },
+ { "halibutloglevel", LogLevel.Info.ToString() },
+ { CompatBinaryStayAlive.StayAliveFilePathEnvVarKey, compatBinaryStayAlive.LockFile },
+ { "WithStandardServices", true.ToString() },
+ { "WithCachingService", false.ToString() },
+ { "WithTentacleServices", false.ToString() },
+ { "ServiceConnectionType", serviceConnectionType.ToString() },
+ };
+
+ if (serviceConnectionType == ServiceConnectionType.Polling && clientListenPort.HasValue)
+ settings.Add("octopusservercommsport", "https://localhost:" + clientListenPort.Value);
+
+ var cts = new CancellationTokenSource();
+ var hasStarted = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously);
+ int? serviceListenPort = null;
+
+ var runningTask = Task.Run(async () =>
+ {
+ try
+ {
+ await Cli.Wrap(new HalibutTestBinaryPath().SchannelProbeBinPath())
+ .WithEnvironmentVariables(settings)
+ .WithStandardOutputPipe(PipeTarget.ToDelegate((line, _) =>
+ {
+ logger.Information(line);
+ if (line.StartsWith("Listening on port: "))
+ serviceListenPort = int.Parse(Regex.Match(line, @"\d+").Value);
+ if (line.Contains("RunningAndReady"))
+ hasStarted.TrySetResult(true);
+ return Task.CompletedTask;
+ }))
+ .WithStandardErrorPipe(PipeTarget.ToDelegate((line, _) =>
+ {
+ logger.Information(line);
+ return Task.CompletedTask;
+ }))
+ .ExecuteAsync(cts.Token);
+ }
+ catch (OperationCanceledException) { }
+ catch (Exception e)
+ {
+ hasStarted.TrySetException(e);
+ throw;
+ }
+ });
+
+ var winner = await Task.WhenAny(runningTask, hasStarted.Task, Task.Delay(TimeSpan.FromSeconds(30)));
+
+ if (winner == runningTask || !hasStarted.Task.IsCompleted)
+ {
+ cts.Cancel();
+ cts.Dispose();
+ compatBinaryStayAlive.Dispose();
+ if (winner == runningTask) await runningTask; // re-throw startup exception
+ throw new Exception("SchannelProbe binary did not start within 30 seconds");
+ }
+
+ return new RunningSchannelProbe(cts, serviceListenPort, compatBinaryStayAlive);
+ }
+
+ public class RunningSchannelProbe : IDisposable
+ {
+ readonly CancellationTokenSource cts;
+ readonly CompatBinaryStayAlive compatBinaryStayAlive;
+
+ public int? ServiceListenPort { get; }
+
+ public RunningSchannelProbe(CancellationTokenSource cts, int? serviceListenPort, CompatBinaryStayAlive compatBinaryStayAlive)
+ {
+ this.cts = cts;
+ this.compatBinaryStayAlive = compatBinaryStayAlive;
+ ServiceListenPort = serviceListenPort;
+ }
+
+ public void Dispose()
+ {
+ cts.Cancel();
+ cts.Dispose();
+ compatBinaryStayAlive.Dispose();
+ }
+ }
+ }
+}
diff --git a/source/Halibut.Tests/Transport/SecureClientFixture.cs b/source/Halibut.Tests/Transport/SecureClientFixture.cs
index d6df4e782..c6aa33f7f 100644
--- a/source/Halibut.Tests/Transport/SecureClientFixture.cs
+++ b/source/Halibut.Tests/Transport/SecureClientFixture.cs
@@ -84,8 +84,7 @@ public async Task SecureClientClearsPoolWhenAllConnectionsCorrupt()
Certificates.Octopus,
halibutTimeoutsAndLimits,
new StreamFactory(),
- NoOpSecureConnectionObserver.Instance,
- SslConfiguration.Default
+ NoOpSecureConnectionObserver.Instance
);
var secureClient = new SecureListeningClient(GetProtocol, endpoint, Certificates.Octopus, log, connectionManager, tcpConnectionFactory);
ResponseMessage response = null!;
diff --git a/source/Halibut.Tests/Transport/SecureListenerFixture.cs b/source/Halibut.Tests/Transport/SecureListenerFixture.cs
index 314daf5ed..69775b77e 100644
--- a/source/Halibut.Tests/Transport/SecureListenerFixture.cs
+++ b/source/Halibut.Tests/Transport/SecureListenerFixture.cs
@@ -74,8 +74,7 @@ public async Task SecureListenerDoesNotCreateHundredsOfIoEventsPerSecondOnWindow
timeoutsAndLimits,
new StreamFactory(),
NoOpConnectionsObserver.Instance,
- NoOpSecureConnectionObserver.Instance,
- SslConfiguration.Default
+ NoOpSecureConnectionObserver.Instance
);
var idleAverage = CollectCounterValues(opsPerSec)
diff --git a/source/Halibut.sln b/source/Halibut.sln
index 05e2e010b..fcb21f36a 100644
--- a/source/Halibut.sln
+++ b/source/Halibut.sln
@@ -41,6 +41,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Halibut.TestUtils.CompatBinary.SchannelProbe", "Halibut.TestUtils.CompatBinary.SchannelProbe\Halibut.TestUtils.CompatBinary.SchannelProbe.csproj", "{4D26A9FA-B316-4BE3-8780-23E9136492DB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -177,6 +179,18 @@ Global
{80042E24-9461-47D1-9AC5-E414E4DBF821}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{80042E24-9461-47D1-9AC5-E414E4DBF821}.Release|x86.ActiveCfg = Release|Any CPU
{80042E24-9461-47D1-9AC5-E414E4DBF821}.Release|x86.Build.0 = Release|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Debug|x86.Build.0 = Debug|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Release|x86.ActiveCfg = Release|Any CPU
+ {4D26A9FA-B316-4BE3-8780-23E9136492DB}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/source/Halibut/HalibutRuntime.cs b/source/Halibut/HalibutRuntime.cs
index 7233b29ec..1588239e0 100644
--- a/source/Halibut/HalibutRuntime.cs
+++ b/source/Halibut/HalibutRuntime.cs
@@ -47,7 +47,6 @@ public class HalibutRuntime : IHalibutRuntime
readonly ISecureConnectionObserver secureConnectionObserver;
readonly IActiveTcpConnectionsLimiter activeTcpConnectionsLimiter;
readonly IControlMessageObserver controlMessageObserver;
- readonly ISslConfigurationProvider sslConfigurationProvider;
internal HalibutRuntime(
IServiceFactory serviceFactory,
@@ -63,8 +62,7 @@ internal HalibutRuntime(
IRpcObserver rpcObserver,
IConnectionsObserver connectionsObserver,
IControlMessageObserver controlMessageObserver,
- ISecureConnectionObserver secureConnectionObserver,
- ISslConfigurationProvider sslConfigurationProvider
+ ISecureConnectionObserver secureConnectionObserver
)
{
this.serverCertificate = serverCertificate;
@@ -81,10 +79,9 @@ ISslConfigurationProvider sslConfigurationProvider
this.connectionsObserver = connectionsObserver;
this.secureConnectionObserver = secureConnectionObserver;
this.controlMessageObserver = controlMessageObserver;
- this.sslConfigurationProvider = sslConfigurationProvider;
connectionManager = new ConnectionManagerAsync();
- tcpConnectionFactory = new TcpConnectionFactory(serverCertificate, TimeoutsAndLimits, streamFactory, secureConnectionObserver, sslConfigurationProvider);
+ tcpConnectionFactory = new TcpConnectionFactory(serverCertificate, TimeoutsAndLimits, streamFactory, secureConnectionObserver);
activeTcpConnectionsLimiter = new ActiveTcpConnectionsLimiter(TimeoutsAndLimits);
}
@@ -139,8 +136,7 @@ public int Listen(IPEndPoint endpoint)
TimeoutsAndLimits,
streamFactory,
connectionsObserver,
- secureConnectionObserver,
- sslConfigurationProvider
+ secureConnectionObserver
);
listeners.DoWithExclusiveAccess(l =>
@@ -256,7 +252,7 @@ public async Task DiscoverAsync(Uri uri, CancellationToken canc
public async Task DiscoverAsync(ServiceEndPoint endpoint, CancellationToken cancellationToken)
{
- var client = new DiscoveryClient(streamFactory, sslConfigurationProvider);
+ var client = new DiscoveryClient(streamFactory);
return await client.DiscoverAsync(endpoint, TimeoutsAndLimits, cancellationToken);
}
diff --git a/source/Halibut/HalibutRuntimeBuilder.cs b/source/Halibut/HalibutRuntimeBuilder.cs
index acd85cc65..6bb3e7313 100644
--- a/source/Halibut/HalibutRuntimeBuilder.cs
+++ b/source/Halibut/HalibutRuntimeBuilder.cs
@@ -32,7 +32,6 @@ public class HalibutRuntimeBuilder
ISecureConnectionObserver? secureConnectionObserver;
IControlMessageObserver? controlMessageObserver;
MessageStreamWrappers queueMessageStreamWrappers = new();
- ISslConfigurationProvider? sslConfigurationProvider;
public HalibutRuntimeBuilder WithQueueMessageStreamWrappers(MessageStreamWrappers queueMessageStreamWrappers)
{
@@ -52,12 +51,6 @@ public HalibutRuntimeBuilder WithSecureConnectionObserver(ISecureConnectionObser
return this;
}
- public HalibutRuntimeBuilder WithSslConfigurationProvider(ISslConfigurationProvider sslConfigurationProvider)
- {
- this.sslConfigurationProvider = sslConfigurationProvider;
- return this;
- }
-
internal HalibutRuntimeBuilder WithStreamFactory(IStreamFactory streamFactory)
{
this.streamFactory = streamFactory;
@@ -193,7 +186,6 @@ public HalibutRuntime Build()
var secureConnectionObserver = this.secureConnectionObserver ?? NoOpSecureConnectionObserver.Instance;
var rpcObserver = this.rpcObserver ?? new NoRpcObserver();
var controlMessageObserver = this.controlMessageObserver ?? new NoOpControlMessageObserver();
- var sslConfigurationProvider = this.sslConfigurationProvider ?? SslConfiguration.Default;
var halibutRuntime = new HalibutRuntime(
serviceFactory,
@@ -209,8 +201,7 @@ public HalibutRuntime Build()
rpcObserver,
connectionsObserver,
controlMessageObserver,
- secureConnectionObserver,
- sslConfigurationProvider
+ secureConnectionObserver
);
if (onUnauthorizedClientConnect is not null)
diff --git a/source/Halibut/Transport/DefaultSslConfigurationProvider.cs b/source/Halibut/Transport/DefaultSslConfigurationProvider.cs
deleted file mode 100644
index ad354eddc..000000000
--- a/source/Halibut/Transport/DefaultSslConfigurationProvider.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2012-2013 Octopus Deploy Pty. Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.Security.Authentication;
-
-namespace Halibut.Transport
-{
- ///
- /// Provides a default implementation of ISslConfigurationProvider that uses the system defaults.
- ///
- public class DefaultSslConfigurationProvider : ISslConfigurationProvider
- {
- public SslProtocols SupportedProtocols => SslProtocols.None;
- }
-}
\ No newline at end of file
diff --git a/source/Halibut/Transport/DiscoveryClient.cs b/source/Halibut/Transport/DiscoveryClient.cs
index a631c32ec..c92280702 100644
--- a/source/Halibut/Transport/DiscoveryClient.cs
+++ b/source/Halibut/Transport/DiscoveryClient.cs
@@ -16,17 +16,10 @@ public class DiscoveryClient
readonly LogFactory logs = new ();
readonly IStreamFactory streamFactory;
- readonly ISslConfigurationProvider sslConfigurationProvider;
public DiscoveryClient(IStreamFactory streamFactory)
- : this(streamFactory, SslConfiguration.Default)
- {
- }
-
- public DiscoveryClient(IStreamFactory streamFactory, ISslConfigurationProvider sslConfigurationProvider)
{
this.streamFactory = streamFactory;
- this.sslConfigurationProvider = sslConfigurationProvider;
}
public async Task DiscoverAsync(ServiceEndPoint serviceEndpoint, HalibutTimeoutsAndLimits halibutTimeoutsAndLimits, CancellationToken cancellationToken)
@@ -52,13 +45,12 @@ public async Task DiscoverAsync(ServiceEndPoint serviceEndpoint
await ssl.AuthenticateAsClientAsync(
serviceEndpoint.BaseUri.Host,
new X509Certificate2Collection(),
- sslConfigurationProvider.SupportedProtocols,
+ SslConfiguration.SupportedProtocols,
false);
#else
await ssl.AuthenticateAsClientEnforcingTimeout(
serviceEndpoint,
new X509Certificate2Collection(),
- sslConfigurationProvider,
cancellationToken
);
#endif
diff --git a/source/Halibut/Transport/ISslConfigurationProvider.cs b/source/Halibut/Transport/ISslConfigurationProvider.cs
deleted file mode 100644
index 952b45e51..000000000
--- a/source/Halibut/Transport/ISslConfigurationProvider.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2012-2013 Octopus Deploy Pty. Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System.Security.Authentication;
-
-namespace Halibut.Transport
-{
- public interface ISslConfigurationProvider
- {
- public SslProtocols SupportedProtocols { get; }
- }
-}
\ No newline at end of file
diff --git a/source/Halibut/Transport/LegacySslConfigurationProvider.cs b/source/Halibut/Transport/LegacySslConfigurationProvider.cs
deleted file mode 100644
index 67c92fa90..000000000
--- a/source/Halibut/Transport/LegacySslConfigurationProvider.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright 2012-2013 Octopus Deploy Pty. Ltd.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-using System;
-using System.Security.Authentication;
-
-namespace Halibut.Transport
-{
- ///
- /// An implementation of ISslConfigurationProvider that uses legacy TLS protocols (1.0 and 1.1)
- /// in addition to modern ones. Protocols are explicitly specified rather than using system
- /// defaults.
- ///
- public class LegacySslConfigurationProvider : ISslConfigurationProvider
- {
-#pragma warning disable SYSLIB0039
- // See https://learn.microsoft.com/en-us/dotnet/fundamentals/syslib-diagnostics/syslib0039
- // TLS 1.0 and 1.1 are obsolete from .NET 7
- public SslProtocols SupportedProtocols => SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
-#pragma warning restore SYSLIB0039
- }
-}
\ No newline at end of file
diff --git a/source/Halibut/Transport/SecureListener.cs b/source/Halibut/Transport/SecureListener.cs
index 6a48bde2a..5132e1a4e 100644
--- a/source/Halibut/Transport/SecureListener.cs
+++ b/source/Halibut/Transport/SecureListener.cs
@@ -49,7 +49,6 @@ public class SecureListener : IAsyncDisposable
readonly IStreamFactory streamFactory;
readonly IConnectionsObserver connectionsObserver;
readonly ISecureConnectionObserver secureConnectionObserver;
- readonly ISslConfigurationProvider sslConfigurationProvider;
ILog log;
TcpListener listener;
Thread? backgroundThread;
@@ -70,8 +69,7 @@ public SecureListener(
HalibutTimeoutsAndLimits halibutTimeoutsAndLimits,
IStreamFactory streamFactory,
IConnectionsObserver connectionsObserver,
- ISecureConnectionObserver secureConnectionObserver,
- ISslConfigurationProvider sslConfigurationProvider
+ ISecureConnectionObserver secureConnectionObserver
)
{
this.endPoint = endPoint;
@@ -87,7 +85,6 @@ ISslConfigurationProvider sslConfigurationProvider
this.streamFactory = streamFactory;
this.connectionsObserver = connectionsObserver;
this.secureConnectionObserver = secureConnectionObserver;
- this.sslConfigurationProvider = sslConfigurationProvider;
this.cts = new CancellationTokenSource();
this.cancellationToken = cts.Token;
@@ -312,7 +309,7 @@ await ssl
.AuthenticateAsServerAsync(
serverCertificate,
true,
- sslConfigurationProvider.SupportedProtocols,
+ SslConfiguration.SupportedProtocols,
false)
.ConfigureAwait(false);
diff --git a/source/Halibut/Transport/SslConfiguration.cs b/source/Halibut/Transport/SslConfiguration.cs
index 254a7c41c..0626651bd 100644
--- a/source/Halibut/Transport/SslConfiguration.cs
+++ b/source/Halibut/Transport/SslConfiguration.cs
@@ -1,12 +1,9 @@
+using System.Security.Authentication;
+
namespace Halibut.Transport
{
public static class SslConfiguration
{
- public static ISslConfigurationProvider Default { get; }
-#if NETFRAMEWORK // .NET4.8 exhibited inconsistent behavior when using the default configuration
- = new LegacySslConfigurationProvider();
-#else
- = new DefaultSslConfigurationProvider();
-#endif
+ public static SslProtocols SupportedProtocols => SslProtocols.None; // None means system defaults
}
}
\ No newline at end of file
diff --git a/source/Halibut/Transport/Streams/SslStreamExtensionMethods.cs b/source/Halibut/Transport/Streams/SslStreamExtensionMethods.cs
index aceddd438..857899c09 100644
--- a/source/Halibut/Transport/Streams/SslStreamExtensionMethods.cs
+++ b/source/Halibut/Transport/Streams/SslStreamExtensionMethods.cs
@@ -13,7 +13,6 @@ internal static async Task AuthenticateAsClientEnforcingTimeout(
this SslStream ssl,
ServiceEndPoint serviceEndpoint,
X509Certificate2Collection clientCertificates,
- ISslConfigurationProvider sslConfigurationProvider,
CancellationToken cancellationToken)
{
using var timeoutCts = new CancellationTokenSource(ssl.ReadTimeout);
@@ -23,7 +22,7 @@ internal static async Task AuthenticateAsClientEnforcingTimeout(
{
TargetHost = serviceEndpoint.BaseUri.Host,
ClientCertificates = clientCertificates,
- EnabledSslProtocols = sslConfigurationProvider.SupportedProtocols,
+ EnabledSslProtocols = SslConfiguration.SupportedProtocols,
CertificateRevocationCheckMode = X509RevocationMode.NoCheck
};
diff --git a/source/Halibut/Transport/TcpConnectionFactory.cs b/source/Halibut/Transport/TcpConnectionFactory.cs
index b61e190e5..10750ee97 100644
--- a/source/Halibut/Transport/TcpConnectionFactory.cs
+++ b/source/Halibut/Transport/TcpConnectionFactory.cs
@@ -22,21 +22,18 @@ public class TcpConnectionFactory : IConnectionFactory
readonly HalibutTimeoutsAndLimits halibutTimeoutsAndLimits;
readonly IStreamFactory streamFactory;
readonly ISecureConnectionObserver secureConnectionObserver;
- readonly ISslConfigurationProvider sslConfigurationProvider;
public TcpConnectionFactory(
X509Certificate2 clientCertificate,
HalibutTimeoutsAndLimits halibutTimeoutsAndLimits,
IStreamFactory streamFactory,
- ISecureConnectionObserver secureConnectionObserver,
- ISslConfigurationProvider sslConfigurationProvider
+ ISecureConnectionObserver secureConnectionObserver
)
{
this.clientCertificate = clientCertificate;
this.halibutTimeoutsAndLimits = halibutTimeoutsAndLimits;
this.streamFactory = streamFactory;
this.secureConnectionObserver = secureConnectionObserver;
- this.sslConfigurationProvider = sslConfigurationProvider;
}
public async Task EstablishNewConnectionAsync(ExchangeProtocolBuilder exchangeProtocolBuilder, ServiceEndPoint serviceEndpoint, ILog log, CancellationToken cancellationToken)
@@ -61,10 +58,10 @@ public async Task EstablishNewConnectionAsync(ExchangeProtocolBuild
await ssl.AuthenticateAsClientAsync(
serviceEndpoint.BaseUri.Host,
new X509Certificate2Collection(clientCertificate),
- sslConfigurationProvider.SupportedProtocols,
+ SslConfiguration.SupportedProtocols,
false);
#else
- await ssl.AuthenticateAsClientEnforcingTimeout(serviceEndpoint, new X509Certificate2Collection(clientCertificate), sslConfigurationProvider, cancellationToken);
+ await ssl.AuthenticateAsClientEnforcingTimeout(serviceEndpoint, new X509Certificate2Collection(clientCertificate), cancellationToken);
#endif
await ssl.WriteAsync(MxLine, 0, MxLine.Length, cancellationToken);