Skip to content

Commit 588d5d6

Browse files
authored
Modernize AkkaSpec and Akka.Remote DotNetty transport settings (#6854)
* Modernize AkkaSpec and Akka.Remote DotNetty transport settings * Update API approval list
1 parent 12a5434 commit 588d5d6

File tree

10 files changed

+465
-321
lines changed

10 files changed

+465
-321
lines changed

src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveRemote.DotNet.verified.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,4 +855,13 @@ namespace Akka.Remote.Transport
855855
public Akka.Actor.Address Recipient { get; }
856856
public Akka.Actor.Address Sender { get; }
857857
}
858+
}
859+
namespace Akka.Remote.Transport.DotNetty
860+
{
861+
public sealed class DotNettySslSetup : Akka.Actor.Setup.Setup
862+
{
863+
public DotNettySslSetup(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, bool suppressValidation) { }
864+
public System.Security.Cryptography.X509Certificates.X509Certificate2 Certificate { get; }
865+
public bool SuppressValidation { get; }
866+
}
858867
}

src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveRemote.Net.verified.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,4 +855,13 @@ namespace Akka.Remote.Transport
855855
public Akka.Actor.Address Recipient { get; }
856856
public Akka.Actor.Address Sender { get; }
857857
}
858+
}
859+
namespace Akka.Remote.Transport.DotNetty
860+
{
861+
public sealed class DotNettySslSetup : Akka.Actor.Setup.Setup
862+
{
863+
public DotNettySslSetup(System.Security.Cryptography.X509Certificates.X509Certificate2 certificate, bool suppressValidation) { }
864+
public System.Security.Cryptography.X509Certificates.X509Certificate2 Certificate { get; }
865+
public bool SuppressValidation { get; }
866+
}
858867
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
//-----------------------------------------------------------------------
2+
// <copyright file="DotNettySslSupportSpec.cs" company="Akka.NET Project">
3+
// Copyright (C) 2013-2023 .NET Foundation <https://github.com/akkadotnet/akka.net>
4+
// </copyright>
5+
//-----------------------------------------------------------------------
6+
7+
using System;
8+
using System.Security.Cryptography.X509Certificates;
9+
using System.Threading.Tasks;
10+
using Akka.Actor;
11+
using Akka.Actor.Setup;
12+
using Akka.Configuration;
13+
using Akka.Remote.Transport.DotNetty;
14+
using Akka.TestKit;
15+
using Xunit;
16+
using Xunit.Abstractions;
17+
using static Akka.Util.RuntimeDetector;
18+
19+
namespace Akka.Remote.Tests.Transport
20+
{
21+
public class DotNettySslSetupSpec : AkkaSpec
22+
{
23+
#region Setup / Config
24+
25+
// valid to 01/01/2037
26+
private const string ValidCertPath = "Resources/akka-validcert.pfx";
27+
28+
private const string Password = "password";
29+
30+
private static ActorSystemSetup TestActorSystemSetup(bool enableSsl)
31+
{
32+
var setup = ActorSystemSetup.Empty
33+
.And(BootstrapSetup.Create()
34+
.WithConfig(ConfigurationFactory.ParseString($@"
35+
akka {{
36+
loglevel = DEBUG
37+
actor.provider = ""Akka.Remote.RemoteActorRefProvider,Akka.Remote""
38+
remote {{
39+
dot-netty.tcp {{
40+
port = 0
41+
hostname = ""127.0.0.1""
42+
enable-ssl = ""{enableSsl.ToString().ToLowerInvariant()}""
43+
log-transport = true
44+
}}
45+
}}
46+
}}")));
47+
48+
if (!enableSsl)
49+
return setup;
50+
51+
var certificate = new X509Certificate2(ValidCertPath, Password, X509KeyStorageFlags.DefaultKeySet);
52+
return setup.And(new DotNettySslSetup(certificate, true));
53+
}
54+
55+
private ActorSystem _sys2;
56+
private ActorPath _echoPath;
57+
58+
private void Setup(bool enableSsl)
59+
{
60+
_sys2 = ActorSystem.Create("sys2", TestActorSystemSetup(enableSsl));
61+
InitializeLogger(_sys2);
62+
63+
_sys2.ActorOf(Props.Create<Echo>(), "echo");
64+
65+
var address = RARP.For(_sys2).Provider.DefaultAddress;
66+
_echoPath = new RootActorPath(address) / "user" / "echo";
67+
}
68+
69+
#endregion
70+
71+
public DotNettySslSetupSpec(ITestOutputHelper output) : base(TestActorSystemSetup(true), output)
72+
{
73+
}
74+
75+
[Fact]
76+
public async Task Secure_transport_should_be_possible_between_systems_sharing_the_same_certificate()
77+
{
78+
// skip this test due to linux/mono certificate issues
79+
if (IsMono) return;
80+
81+
Setup(true);
82+
83+
var probe = CreateTestProbe();
84+
85+
await AwaitAssertAsync(async () =>
86+
{
87+
Sys.ActorSelection(_echoPath).Tell("hello", probe.Ref);
88+
await probe.ExpectMsgAsync("hello", TimeSpan.FromSeconds(3));
89+
}, TimeSpan.FromSeconds(30), TimeSpan.FromMilliseconds(100));
90+
}
91+
92+
[Fact]
93+
public async Task Secure_transport_should_NOT_be_possible_between_systems_using_SSL_and_one_not_using_it()
94+
{
95+
Setup(false);
96+
97+
var probe = CreateTestProbe();
98+
await Assert.ThrowsAsync<RemoteTransportException>(async () =>
99+
{
100+
Sys.ActorSelection(_echoPath).Tell("hello", probe.Ref);
101+
await probe.ExpectNoMsgAsync();
102+
});
103+
}
104+
105+
#region helper classes / methods
106+
107+
protected override void AfterAll()
108+
{
109+
base.AfterAll();
110+
Shutdown(_sys2, TimeSpan.FromSeconds(3));
111+
}
112+
113+
private class Echo : ReceiveActor
114+
{
115+
public Echo()
116+
{
117+
Receive<string>(str => Sender.Tell(str));
118+
}
119+
}
120+
121+
#endregion
122+
}
123+
}

src/core/Akka.Remote/Akka.Remote.csproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
<GenerateDocumentationFile>true</GenerateDocumentationFile>
88
</PropertyGroup>
99
<ItemGroup>
10-
<EmbeddedResource Include="Configuration\Remote.conf"/>
11-
<ProjectReference Include="..\Akka\Akka.csproj"/>
10+
<EmbeddedResource Include="Configuration\Remote.conf" />
11+
<ProjectReference Include="..\Akka\Akka.csproj" />
1212
</ItemGroup>
1313
<ItemGroup>
14-
<PackageReference Include="DotNetty.Handlers" Version="0.6.0"/>
15-
<PackageReference Include="Google.Protobuf" Version="$(ProtobufVersion)"/>
14+
<PackageReference Include="DotNetty.Handlers" Version="0.6.0" />
15+
<PackageReference Include="Google.Protobuf" Version="$(ProtobufVersion)" />
1616
</ItemGroup>
1717
<PropertyGroup>
1818
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>

src/core/Akka.Remote/AkkaProtocolSettings.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,9 @@ public AkkaProtocolSettings(Config config)
5151
// backwards compatibility with the existing dot-netty.tcp.connection-timeout
5252
var enabledTransports = config.GetStringList("akka.remote.enabled-transports", new string[] { });
5353
if (enabledTransports.Contains("akka.remote.dot-netty.tcp"))
54-
HandshakeTimeout = config.GetTimeSpan("akka.remote.dot-netty.tcp.connection-timeout", null);
55-
else if (enabledTransports.Contains("akka.remote.dot-netty.ssl"))
56-
HandshakeTimeout = config.GetTimeSpan("akka.remote.dot-netty.ssl.connection-timeout", null);
54+
HandshakeTimeout = config.GetTimeSpan("akka.remote.dot-netty.tcp.connection-timeout", TimeSpan.FromSeconds(15), allowInfinite:false);
5755
else
58-
HandshakeTimeout = config.GetTimeSpan("akka.remote.handshake-timeout", TimeSpan.FromSeconds(20), allowInfinite:false);
56+
HandshakeTimeout = config.GetTimeSpan("akka.remote.handshake-timeout", TimeSpan.FromSeconds(15), allowInfinite:false);
5957
}
6058
}
6159
}

src/core/Akka.Remote/Configuration/Remote.conf

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -352,9 +352,6 @@ akka {
352352
trttl = "Akka.Remote.Transport.ThrottlerProvider,Akka.Remote"
353353
}
354354

355-
# necessary to keep backwards compatibility
356-
helios.tcp.transport-class = "Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote.Transport.Helios"
357-
358355
### Default configuration for the DotNetty based transport drivers
359356

360357
dot-netty.tcp {
@@ -481,10 +478,10 @@ akka {
481478
# Sets the size of the connection backlog
482479
backlog = 4096
483480

484-
# Enables the TCP_NODELAY flag, i.e. disables Nagle’s algorithm
481+
# Enables the TCP_NODELAY flag, i.e. disables Nagle's algorithm
485482
tcp-nodelay = on
486483

487-
# Enables TCP Keepalive, subject to the O/S kernel’s configuration
484+
# Enables TCP Keepalive, subject to the O/S kernel's configuration
488485
tcp-keepalive = on
489486

490487
# Enables SO_REUSEADDR, which determines when an ActorSystem can open
@@ -524,48 +521,45 @@ akka {
524521
pool-size-max = 2
525522
}
526523

527-
524+
ssl {
525+
certificate {
526+
# Valid certificate path required
527+
path = ""
528+
# Valid certificate password required
529+
password = ""
530+
# Default key storage flag is "default-key-set"
531+
# Available flags include:
532+
# default-key-set | exportable | machine-key-set | persist-key-set | user-key-set | user-protected
533+
# flags = [ "default-key-set" ]
534+
535+
# To use a Thumbprint instead of a file, set this to true
536+
# And specify a thumbprint and it's storage location below
537+
use-thumbprint-over-file = false
538+
539+
# Valid Thumbprint required (if use-thumbprint-over-file is true)
540+
# A typical thumbprint is a format similar to: "45df32e258c92a7abf6c112e54912ab15bbb9eb0"
541+
# On Windows machines, The thumbprint for an installed certificate can be located
542+
# By using certlm.msc and opening the certificate under the 'Details' tab.
543+
thumbprint = ""
544+
545+
# The Store name. Under windows The most common option is "My", which indicates the personal store.
546+
# See System.Security.Cryptography.X509Certificates.StoreName for other common values.
547+
store-name = ""
548+
549+
# Valid options : local-machine or current-user
550+
# current-user indicates a certificate stored under the user's account
551+
# local-machine indicates a certificate stored at an operating system level (potentially shared by users)
552+
store-location = "current-user"
553+
}
554+
suppress-validation = false
555+
}
528556
}
529557

530558
dot-netty.udp = ${akka.remote.dot-netty.tcp}
531559
dot-netty.udp {
532560
transport-protocol = udp
533561
}
534562

535-
dot-netty.ssl = ${akka.remote.dot-netty.tcp}
536-
dot-netty.ssl = {
537-
certificate {
538-
# Valid certificate path required
539-
path = ""
540-
# Valid certificate password required
541-
password = ""
542-
# Default key storage flag is "default-key-set"
543-
# Available flags include:
544-
# default-key-set | exportable | machine-key-set | persist-key-set | user-key-set | user-protected
545-
# flags = [ "default-key-set" ]
546-
547-
# To use a Thumbprint instead of a file, set this to true
548-
# And specify a thumprint and it's storage location below
549-
use-thumbprint-over-file = false
550-
551-
# Valid Thumprint required (if use-thumbprint-over-file is true)
552-
# A typical thumbprint is a format similar to: "45df32e258c92a7abf6c112e54912ab15bbb9eb0"
553-
# On Windows machines, The thumprint for an installed certificate can be located
554-
# By using certlm.msc and opening the certificate under the 'Details' tab.
555-
thumbprint = ""
556-
557-
# The Store name. Under windows The most common option is "My", which indicates the personal store.
558-
# See System.Security.Cryptography.X509Certificates.StoreName for other common values.
559-
store-name = ""
560-
561-
# Valid options : local-machine or current-user
562-
# current-user indicates a certificate stored under the user's account
563-
# local-machine indicates a certificate stored at an operating system level (potentially shared by users)
564-
store-location = "current-user"
565-
}
566-
suppress-validation = false
567-
}
568-
569563
### Default configuration for the failure injector transport adapter
570564

571565
gremlin {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
//-----------------------------------------------------------------------
2+
// <copyright file="SslSetup.cs" company="Akka.NET Project">
3+
// Copyright (C) 2013-2023 .NET Foundation <https://github.com/akkadotnet/akka.net>
4+
// </copyright>
5+
//-----------------------------------------------------------------------
6+
7+
using System.Security.Cryptography.X509Certificates;
8+
using Akka.Actor.Setup;
9+
10+
namespace Akka.Remote.Transport.DotNetty;
11+
12+
public sealed class DotNettySslSetup: Setup
13+
{
14+
public DotNettySslSetup(X509Certificate2 certificate, bool suppressValidation)
15+
{
16+
Certificate = certificate;
17+
SuppressValidation = suppressValidation;
18+
}
19+
20+
public X509Certificate2 Certificate { get; }
21+
public bool SuppressValidation { get; }
22+
23+
internal SslSettings Settings => new SslSettings(Certificate, SuppressValidation);
24+
}

src/core/Akka.Remote/Transport/DotNetty/DotNettyTransport.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,13 +131,17 @@ protected DotNettyTransport(ActorSystem system, Config config)
131131
System = system;
132132
Config = config;
133133

134+
// Helios compatibility
134135
if (system.Settings.Config.HasPath("akka.remote.helios.tcp"))
135136
{
136-
var heliosFallbackConfig = system.Settings.Config.GetConfig("akka.remote.helios.tcp");
137+
var heliosFallbackConfig = system.Settings.Config.GetConfig("akka.remote.helios.tcp")
138+
.WithFallback("transport-class = \"Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote.Transport.Helios\"");
137139
config = heliosFallbackConfig.WithFallback(config);
138140
}
139141

140-
Settings = DotNettyTransportSettings.Create(config);
142+
var setup = system.Settings.Setup.Get<DotNettySslSetup>();
143+
var sslSettings = setup.HasValue ? setup.Value.Settings : null;
144+
Settings = DotNettyTransportSettings.Create(config, sslSettings);
141145
Log = Logging.GetLogger(System, GetType());
142146
_serverEventLoopGroup = new MultithreadEventLoopGroup(Settings.ServerSocketWorkerPoolSize);
143147
_clientEventLoopGroup = new MultithreadEventLoopGroup(Settings.ClientSocketWorkerPoolSize);

0 commit comments

Comments
 (0)