Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BACKPORT #6038] SSL Configuration fails even EnbleSsl property is set to false #6043

Merged
merged 6 commits into from
Jul 18, 2022
Merged
Show file tree
Hide file tree
Changes from 3 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
154 changes: 124 additions & 30 deletions src/core/Akka.Remote.Tests/Transport/DotNettySslSupportSpec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
//-----------------------------------------------------------------------

using System;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Akka.Actor;
using Akka.Configuration;
using Akka.TestKit;
Expand All @@ -21,7 +24,7 @@ public class DotNettySslSupportSpec : AkkaSpec
#region Setup / Config

// valid to 01/01/2037
private static readonly string ValidCertPath = "Resources/akka-validcert.pfx";
private const string ValidCertPath = "Resources/akka-validcert.pfx";

private const string Password = "password";

Expand Down Expand Up @@ -52,6 +55,32 @@ private static Config TestConfig(string certPath, string password)
}");
}

private static Config TestConfig(bool enableSsl, string certPath, string password)
{
var config = ConfigurationFactory.ParseString(@"
akka {
loglevel = DEBUG
actor.provider = ""Akka.Remote.RemoteActorRefProvider,Akka.Remote""
remote {
dot-netty.tcp {
port = 0
hostname = ""127.0.0.1""
enable-ssl = """ + enableSsl.ToString().ToLowerInvariant() + @"""
log-transport = true
}
}
}");
return !enableSsl
? config
: config.WithFallback(@"akka.remote.dot-netty.tcp.ssl {
suppress-validation = """ + enableSsl.ToString().ToLowerInvariant() + @"""
certificate {
path = """ + certPath + @"""
password = """ + password + @"""
}
}");
}

private static Config TestThumbprintConfig(string thumbPrint)
{
var config = ConfigurationFactory.ParseString(@"
Expand Down Expand Up @@ -80,35 +109,47 @@ private static Config TestThumbprintConfig(string thumbPrint)
}");
}

private ActorSystem sys2;
private Address address1;
private Address address2;
private ActorSystem _sys2;
private Address _address1;
private Address _address2;

private ActorPath echoPath;
private ActorPath _echoPath;

private void Setup(string certPath, string password)
{
sys2 = ActorSystem.Create("sys2", TestConfig(certPath, password));
InitializeLogger(sys2);
_sys2 = ActorSystem.Create("sys2", TestConfig(certPath, password));
InitializeLogger(_sys2);

var echo = _sys2.ActorOf(Props.Create<Echo>(), "echo");

_address1 = RARP.For(Sys).Provider.DefaultAddress;
_address2 = RARP.For(_sys2).Provider.DefaultAddress;
_echoPath = new RootActorPath(_address2) / "user" / "echo";
}

private void Setup(bool enableSsl, string certPath, string password)
{
_sys2 = ActorSystem.Create("sys2", TestConfig(enableSsl, certPath, password));
InitializeLogger(_sys2);

var echo = sys2.ActorOf(Props.Create<Echo>(), "echo");
var echo = _sys2.ActorOf(Props.Create<Echo>(), "echo");

address1 = RARP.For(Sys).Provider.DefaultAddress;
address2 = RARP.For(sys2).Provider.DefaultAddress;
echoPath = new RootActorPath(address2) / "user" / "echo";
_address1 = RARP.For(Sys).Provider.DefaultAddress;
_address2 = RARP.For(_sys2).Provider.DefaultAddress;
_echoPath = new RootActorPath(_address2) / "user" / "echo";
}

private void SetupThumbprint(string certPath, string password)
{
InstallCert();
sys2 = ActorSystem.Create("sys2", TestThumbprintConfig(Thumbprint));
InitializeLogger(sys2);
_sys2 = ActorSystem.Create("sys2", TestThumbprintConfig(Thumbprint));
InitializeLogger(_sys2);

var echo = sys2.ActorOf(Props.Create<Echo>(), "echo");
var echo = _sys2.ActorOf(Props.Create<Echo>(), "echo");

address1 = RARP.For(Sys).Provider.DefaultAddress;
address2 = RARP.For(sys2).Provider.DefaultAddress;
echoPath = new RootActorPath(address2) / "user" / "echo";
_address1 = RARP.For(Sys).Provider.DefaultAddress;
_address2 = RARP.For(_sys2).Provider.DefaultAddress;
_echoPath = new RootActorPath(_address2) / "user" / "echo";
}

#endregion
Expand All @@ -123,7 +164,7 @@ public DotNettySslSupportSpec(ITestOutputHelper output) : base(TestConfig(ValidC


[Fact]
public void Secure_transport_should_be_possible_between_systems_sharing_the_same_certificate()
public async Task Secure_transport_should_be_possible_between_systems_sharing_the_same_certificate()
{
// skip this test due to linux/mono certificate issues
if (IsMono) return;
Expand All @@ -132,15 +173,15 @@ public void Secure_transport_should_be_possible_between_systems_sharing_the_same

var probe = CreateTestProbe();

AwaitAssert(() =>
await AwaitAssertAsync(async () =>
{
Sys.ActorSelection(echoPath).Tell("hello", probe.Ref);
Sys.ActorSelection(_echoPath).Tell("hello", probe.Ref);
probe.ExpectMsg("hello", TimeSpan.FromSeconds(3));
}, TimeSpan.FromSeconds(30), TimeSpan.FromMilliseconds(100));
}

[Fact]
public void Secure_transport_should_be_possible_between_systems_using_thumbprint()
[Fact(Skip = "Racy in Azure AzDo CI/CD")]
public async Task Secure_transport_should_be_possible_between_systems_using_thumbprint()
{
// skip this test due to linux/mono certificate issues
if (IsMono) return;
Expand All @@ -150,11 +191,11 @@ public void Secure_transport_should_be_possible_between_systems_using_thumbprint

var probe = CreateTestProbe();

Within(TimeSpan.FromSeconds(12), () =>
await WithinAsync(TimeSpan.FromSeconds(12), async () =>
{
AwaitAssert(() =>
await AwaitAssertAsync(() =>
{
Sys.ActorSelection(echoPath).Tell("hello", probe.Ref);
Sys.ActorSelection(_echoPath).Tell("hello", probe.Ref);
probe.ExpectMsg("hello", TimeSpan.FromMilliseconds(100));
}, TimeSpan.FromSeconds(3), TimeSpan.FromMilliseconds(100));
});
Expand All @@ -173,20 +214,62 @@ public void Secure_transport_should_NOT_be_possible_between_systems_using_SSL_an
var probe = CreateTestProbe();
Assert.Throws<RemoteTransportException>(() =>
{
Sys.ActorSelection(echoPath).Tell("hello", probe.Ref);
Sys.ActorSelection(_echoPath).Tell("hello", probe.Ref);
probe.ExpectNoMsg();
});
}

#region helper classes / methods
[Fact]
public async Task If_EnableSsl_configuration_is_true_but_not_valid_certificate_is_provided_than_ArgumentNullException_should_be_thrown()
{
// skip this test due to linux/mono certificate issues
if (IsMono) return;

var aggregateException = await Assert.ThrowsAsync<AggregateException>(async () =>
{
Setup(true, null, Password);
});

var realException = GetInnerMostException<ArgumentNullException>(aggregateException);
Assert.NotNull(realException);
Assert.Equal("Path to SSL certificate was not found (by default it can be found under `akka.remote.dot-netty.tcp.ssl.certificate.path`) (Parameter 'certificatePath')", realException.Message);
}

[Fact]
public async Task If_EnableSsl_configuration_is_true_but_not_valid_certificate_password_is_provided_than_WindowsCryptographicException_should_be_thrown()
{
// skip this test due to linux/mono certificate issues
if (IsMono) return;

var aggregateException = await Assert.ThrowsAsync<AggregateException>(async () =>
{
Setup(true, ValidCertPath, null);
});

var realException = GetInnerMostException<CryptographicException>(aggregateException);
Assert.NotNull(realException);
// TODO: this error message is not correct, but wanted to keep this assertion here in case someone else
// wants to fix it in the future.
//Assert.Equal("The specified network password is not correct.", realException.Message);
}

[Theory]
[InlineData(ValidCertPath, null)]
[InlineData(null, Password)]
[InlineData(null, null)]
[InlineData(ValidCertPath, Password)]
public void If_EnableSsl_configuration_is_false_than_no_exception_should_be_thrown_even_no_cert_detail_were_provided(string certPath, string password)
{
Setup(false, certPath, password);
}

#region helper classes / methods
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
Shutdown(sys2, TimeSpan.FromSeconds(3));
Shutdown(_sys2, TimeSpan.FromSeconds(3));
}

}
Expand Down Expand Up @@ -217,7 +300,18 @@ private void RemoveCert()
}
}

public class Echo : ReceiveActor
private T GetInnerMostException<T>(Exception ex) where T : Exception
{
Exception currentEx = ex;
while (currentEx.InnerException != null)
{
currentEx = currentEx.InnerException;
}

return currentEx as T;
}

private class Echo : ReceiveActor
{
public Echo()
{
Expand All @@ -227,4 +321,4 @@ public Echo()

#endregion
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ public static DotNettyTransportSettings Create(Config config)

var batchWriterSettings = new BatchWriterSettings(config.GetConfig("batching"));

var enableSsl = config.GetBoolean("enable-ssl", false);

return new DotNettyTransportSettings(
transportMode: transportMode == "tcp" ? TransportMode.Tcp : TransportMode.Udp,
enableSsl: config.GetBoolean("enable-ssl", false),
enableSsl: enableSsl,
connectTimeout: config.GetTimeSpan("connection-timeout", TimeSpan.FromSeconds(15)),
hostname: host,
publicHostname: !string.IsNullOrEmpty(publicHost) ? publicHost : host,
Expand All @@ -87,7 +89,7 @@ public static DotNettyTransportSettings Create(Config config)
serverSocketWorkerPoolSize: ComputeWorkerPoolSize(config.GetConfig("server-socket-worker-pool")),
clientSocketWorkerPoolSize: ComputeWorkerPoolSize(config.GetConfig("client-socket-worker-pool")),
maxFrameSize: ToNullableInt(config.GetByteSize("maximum-frame-size", null)) ?? 128000,
ssl: config.HasPath("ssl") ? SslSettings.Create(config.GetConfig("ssl")) : SslSettings.Empty,
ssl: config.HasPath("ssl") && enableSsl ? SslSettings.Create(config.GetConfig("ssl")) : SslSettings.Empty,
dnsUseIpv6: config.GetBoolean("dns-use-ipv6", false),
tcpReuseAddr: ResolveTcpReuseAddrOption(config.GetString("tcp-reuse-addr", "off-for-windows")),
tcpKeepAlive: config.GetBoolean("tcp-keepalive", true),
Expand Down