Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion source/Halibut.Tests/Transport/SecureClientFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public async Task SecureClientClearsPoolWhenAllConnectionsCorrupt()
Params = new object[] { "Fred" }
};

var tcpConnectionFactory = new TcpConnectionFactory(Certificates.Octopus, halibutTimeoutsAndLimits, new StreamFactory());
var tcpConnectionFactory = new TcpConnectionFactory(Certificates.Octopus, halibutTimeoutsAndLimits, new StreamFactory(), NoOpSecureConnectionObserver.Instance);
var secureClient = new SecureListeningClient(GetProtocol, endpoint, Certificates.Octopus, log, connectionManager, tcpConnectionFactory);
ResponseMessage response = null!;

Expand Down
3 changes: 2 additions & 1 deletion source/Halibut.Tests/Transport/SecureListenerFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ public async Task SecureListenerDoesNotCreateHundredsOfIoEventsPerSecondOnWindow
(_, _) => UnauthorizedClientConnectResponse.BlockConnection,
timeoutsAndLimits,
new StreamFactory(),
NoOpConnectionsObserver.Instance
NoOpConnectionsObserver.Instance,
NoOpSecureConnectionObserver.Instance
);

var idleAverage = CollectCounterValues(opsPerSec)
Expand Down
12 changes: 9 additions & 3 deletions source/Halibut/HalibutRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class HalibutRuntime : IHalibutRuntime
readonly IRpcObserver rpcObserver;
readonly TcpConnectionFactory tcpConnectionFactory;
readonly IConnectionsObserver connectionsObserver;
readonly ISecureConnectionObserver secureConnectionObserver;
readonly IActiveTcpConnectionsLimiter activeTcpConnectionsLimiter;
readonly IControlMessageObserver controlMessageObserver;

Expand All @@ -59,7 +60,9 @@ internal HalibutRuntime(
IStreamFactory streamFactory,
IRpcObserver rpcObserver,
IConnectionsObserver connectionsObserver,
IControlMessageObserver controlMessageObserver)
IControlMessageObserver controlMessageObserver,
ISecureConnectionObserver secureConnectionObserver
)
{
this.serverCertificate = serverCertificate;
this.trustProvider = trustProvider;
Expand All @@ -73,10 +76,11 @@ internal HalibutRuntime(
invoker = new ServiceInvoker(serviceFactory);
TimeoutsAndLimits = halibutTimeoutsAndLimits;
this.connectionsObserver = connectionsObserver;
this.secureConnectionObserver = secureConnectionObserver;
this.controlMessageObserver = controlMessageObserver;

connectionManager = new ConnectionManagerAsync();
this.tcpConnectionFactory = new TcpConnectionFactory(serverCertificate, TimeoutsAndLimits, streamFactory);
this.tcpConnectionFactory = new TcpConnectionFactory(serverCertificate, TimeoutsAndLimits, streamFactory, secureConnectionObserver);
activeTcpConnectionsLimiter = new ActiveTcpConnectionsLimiter(TimeoutsAndLimits);
}

Expand Down Expand Up @@ -130,7 +134,9 @@ public int Listen(IPEndPoint endpoint)
HandleUnauthorizedClientConnect,
TimeoutsAndLimits,
streamFactory,
connectionsObserver);
connectionsObserver,
secureConnectionObserver
);

listeners.DoWithExclusiveAccess(l =>
{
Expand Down
12 changes: 11 additions & 1 deletion source/Halibut/HalibutRuntimeBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class HalibutRuntimeBuilder
IStreamFactory? streamFactory;
IRpcObserver? rpcObserver;
IConnectionsObserver? connectionsObserver;
ISecureConnectionObserver? secureConnectionObserver;
IControlMessageObserver? controlMessageObserver;
MessageStreamWrappers queueMessageStreamWrappers = new();

Expand All @@ -43,6 +44,12 @@ public HalibutRuntimeBuilder WithConnectionsObserver(IConnectionsObserver connec
return this;
}

public HalibutRuntimeBuilder WithSecureConnectionObserver(ISecureConnectionObserver secureConnectionsObserver)
{
this.secureConnectionObserver = secureConnectionsObserver;
return this;
}

internal HalibutRuntimeBuilder WithStreamFactory(IStreamFactory streamFactory)
{
this.streamFactory = streamFactory;
Expand Down Expand Up @@ -175,6 +182,7 @@ public HalibutRuntime Build()

var streamFactory = this.streamFactory ?? new StreamFactory();
var connectionsObserver = this.connectionsObserver ?? NoOpConnectionsObserver.Instance;
var secureConnectionObserver = this.secureConnectionObserver ?? NoOpSecureConnectionObserver.Instance;
var rpcObserver = this.rpcObserver ?? new NoRpcObserver();
var controlMessageObserver = this.controlMessageObserver ?? new NoOpControlMessageObserver();

Expand All @@ -191,7 +199,9 @@ public HalibutRuntime Build()
streamFactory,
rpcObserver,
connectionsObserver,
controlMessageObserver);
controlMessageObserver,
secureConnectionObserver
);

if (onUnauthorizedClientConnect is not null)
{
Expand Down
22 changes: 22 additions & 0 deletions source/Halibut/Transport/Observability/ConnectionDirection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// 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.

namespace Halibut.Transport.Observability
{
public enum ConnectionDirection
{
Incoming,
Outgoing
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// 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.Observability
{
public interface ISecureConnectionObserver
{
public void SecureConnectionEstablished(SecureConnectionInfo secureConnectionInfo);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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.

namespace Halibut.Transport.Observability
{
public class NoOpSecureConnectionObserver : ISecureConnectionObserver
{
static NoOpSecureConnectionObserver? singleInstance;
public static NoOpSecureConnectionObserver Instance => singleInstance ??= new NoOpSecureConnectionObserver();
public void SecureConnectionEstablished(SecureConnectionInfo secureConnectionInfo)
{
}
}
}
52 changes: 52 additions & 0 deletions source/Halibut/Transport/Observability/SecureConnectionInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// 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.Observability
{
public struct SecureConnectionInfo
{
SecureConnectionInfo(
SslProtocols sslProtocols,
ConnectionDirection connectionDirection,
string thumbprint
)
{
SslProtocols = sslProtocols;
ConnectionDirection = connectionDirection;
Thumbprint = thumbprint;
}

public SslProtocols SslProtocols { get; }
public ConnectionDirection ConnectionDirection { get; }
public string Thumbprint { get; }

public static SecureConnectionInfo CreateIncoming(
SslProtocols sslProtocols,
string thumbprint
)
{
return new SecureConnectionInfo(sslProtocols, ConnectionDirection.Incoming, thumbprint);
}

public static SecureConnectionInfo CreateOutgoing(
SslProtocols sslProtocols,
string thumbprint
)
{
return new(sslProtocols, ConnectionDirection.Outgoing, thumbprint);
}
}
}
7 changes: 6 additions & 1 deletion source/Halibut/Transport/SecureListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class SecureListener : IAsyncDisposable
readonly HalibutTimeoutsAndLimits halibutTimeoutsAndLimits;
readonly IStreamFactory streamFactory;
readonly IConnectionsObserver connectionsObserver;
readonly ISecureConnectionObserver secureConnectionObserver;
ILog log;
TcpListener listener;
Thread? backgroundThread;
Expand All @@ -67,7 +68,9 @@ public SecureListener(
Func<string, string, UnauthorizedClientConnectResponse> unauthorizedClientConnect,
HalibutTimeoutsAndLimits halibutTimeoutsAndLimits,
IStreamFactory streamFactory,
IConnectionsObserver connectionsObserver)
IConnectionsObserver connectionsObserver,
ISecureConnectionObserver secureConnectionObserver
)
{
this.endPoint = endPoint;
this.serverCertificate = serverCertificate;
Expand All @@ -81,6 +84,7 @@ public SecureListener(
this.halibutTimeoutsAndLimits = halibutTimeoutsAndLimits;
this.streamFactory = streamFactory;
this.connectionsObserver = connectionsObserver;
this.secureConnectionObserver = secureConnectionObserver;
this.cts = new CancellationTokenSource();
this.cancellationToken = cts.Token;

Expand Down Expand Up @@ -336,6 +340,7 @@ await ssl
{
connectionAuthorizedAndObserved = true;
connectionsObserver.ConnectionAccepted(true);
secureConnectionObserver.SecureConnectionEstablished(SecureConnectionInfo.CreateIncoming(ssl.SslProtocol, thumbprint));
tcpClientManager.AddActiveClient(thumbprint, client);
errorEventType = EventType.Error;
await ExchangeMessages(ssl).ConfigureAwait(false);
Expand Down
39 changes: 35 additions & 4 deletions source/Halibut/Transport/SslConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,47 @@
using System;
using System.Security.Authentication;

namespace Halibut.Transport
{
public static class SslConfiguration
{
public static SslProtocols SupportedProtocols
static SslProtocols GetSupportedProtocols()
{
#if NETFRAMEWORK
// Net48 tests has issues establishing a common algorithm when we allow system default
var supportedProtocolMode = "legacy";
#else
var supportedProtocolMode = Environment.GetEnvironmentVariable("HALIBUT_SUPPORTED_SSL_PROTOCOLS")?.ToLowerInvariant();
#endif


if (supportedProtocolMode == "legacy")
{
#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
get => SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
// See https://learn.microsoft.com/en-us/dotnet/fundamentals/syslib-diagnostics/syslib0039
// TLS 1.0 and 1.1 are obsolete from .NET 7
return SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13;
#pragma warning restore SYSLIB0039
}

if (supportedProtocolMode == "system")
{
return SslProtocols.None;
}

if (supportedProtocolMode == "modern")
{
return SslProtocols.Tls12 | SslProtocols.Tls13;
}

if (supportedProtocolMode == "tls1.3")
{
return SslProtocols.Tls13;
}

return SslProtocols.None;
}

public static SslProtocols SupportedProtocols { get; } = GetSupportedProtocols();
}
}
11 changes: 10 additions & 1 deletion source/Halibut/Transport/TcpConnectionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Threading;
using System.Threading.Tasks;
using Halibut.Diagnostics;
using Halibut.Transport.Observability;
using Halibut.Transport.Protocol;
using Halibut.Transport.Proxy;
using Halibut.Transport.Streams;
Expand All @@ -20,12 +21,19 @@ public class TcpConnectionFactory : IConnectionFactory
readonly X509Certificate2 clientCertificate;
readonly HalibutTimeoutsAndLimits halibutTimeoutsAndLimits;
readonly IStreamFactory streamFactory;
readonly ISecureConnectionObserver secureConnectionObserver;

public TcpConnectionFactory(X509Certificate2 clientCertificate, HalibutTimeoutsAndLimits halibutTimeoutsAndLimits, IStreamFactory streamFactory)
public TcpConnectionFactory(
X509Certificate2 clientCertificate,
HalibutTimeoutsAndLimits halibutTimeoutsAndLimits,
IStreamFactory streamFactory,
ISecureConnectionObserver secureConnectionObserver
)
{
this.clientCertificate = clientCertificate;
this.halibutTimeoutsAndLimits = halibutTimeoutsAndLimits;
this.streamFactory = streamFactory;
this.secureConnectionObserver = secureConnectionObserver;
}

public async Task<IConnection> EstablishNewConnectionAsync(ExchangeProtocolBuilder exchangeProtocolBuilder, ServiceEndPoint serviceEndpoint, ILog log, CancellationToken cancellationToken)
Expand Down Expand Up @@ -60,6 +68,7 @@ await ssl.AuthenticateAsClientAsync(
await ssl.FlushAsync(cancellationToken);

log.Write(EventType.Security, "Secure connection established. Server at {0} identified by thumbprint: {1}, using protocol {2}", client.Client.RemoteEndPoint, serviceEndpoint.RemoteThumbprint, ssl.SslProtocol.ToString());
secureConnectionObserver.SecureConnectionEstablished(SecureConnectionInfo.CreateOutgoing(ssl.SslProtocol, serviceEndpoint.RemoteThumbprint ?? "Unknown"));

return new SecureConnection(client, ssl, exchangeProtocolBuilder, halibutTimeoutsAndLimits, log);
}
Expand Down