Skip to content

Commit b23c3cd

Browse files
committed
Restore DotNettySslSetupSpec and add mutual TLS Setup API test
- Restored DotNettySslSetupSpec which tests SSL configuration via Setup API - This is distinct from HOCON-based configuration tested in DotNettySslSupportSpec - Added test for configuring mutual TLS via DotNettySslSetup - Enhanced TestActorSystemSetup to support mutual authentication parameter
1 parent 7a7f3ca commit b23c3cd

File tree

1 file changed

+174
-0
lines changed

1 file changed

+174
-0
lines changed
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
//-----------------------------------------------------------------------
2+
// <copyright file="DotNettySslSetupSpec.cs" company="Akka.NET Project">
3+
// Copyright (C) 2009-2022 Lightbend Inc. <http://www.lightbend.com>
4+
// Copyright (C) 2013-2025 .NET Foundation <https://github.com/akkadotnet/akka.net>
5+
// </copyright>
6+
//-----------------------------------------------------------------------
7+
8+
using System;
9+
using System.Security.Cryptography.X509Certificates;
10+
using System.Threading.Tasks;
11+
using Akka.Actor;
12+
using Akka.Actor.Setup;
13+
using Akka.Configuration;
14+
using Akka.Remote.Transport.DotNetty;
15+
using Akka.TestKit;
16+
using Xunit;
17+
using Xunit.Abstractions;
18+
using static Akka.Util.RuntimeDetector;
19+
20+
namespace Akka.Remote.Tests.Transport
21+
{
22+
public class DotNettySslSetupSpec : AkkaSpec
23+
{
24+
#region Setup / Config
25+
26+
// valid to 01/01/2037
27+
private const string ValidCertPath = "Resources/akka-validcert.pfx";
28+
29+
private const string Password = "password";
30+
31+
private static ActorSystemSetup TestActorSystemSetup(bool enableSsl, bool requireMutualAuth = false)
32+
{
33+
var setup = ActorSystemSetup.Empty
34+
.And(BootstrapSetup.Create()
35+
.WithConfig(ConfigurationFactory.ParseString($@"
36+
akka {{
37+
loglevel = DEBUG
38+
actor.provider = ""Akka.Remote.RemoteActorRefProvider,Akka.Remote""
39+
remote {{
40+
dot-netty.tcp {{
41+
port = 0
42+
hostname = ""127.0.0.1""
43+
enable-ssl = ""{enableSsl.ToString().ToLowerInvariant()}""
44+
log-transport = true
45+
}}
46+
}}
47+
}}")));
48+
49+
if (!enableSsl)
50+
return setup;
51+
52+
var certificate = new X509Certificate2(ValidCertPath, Password, X509KeyStorageFlags.DefaultKeySet);
53+
// Use the new constructor that supports mutual auth configuration
54+
return setup.And(new DotNettySslSetup(certificate, true, requireMutualAuth));
55+
}
56+
57+
private ActorSystem _sys2;
58+
private ActorPath _echoPath;
59+
60+
private void Setup(bool enableSsl)
61+
{
62+
_sys2 = ActorSystem.Create("sys2", TestActorSystemSetup(enableSsl));
63+
InitializeLogger(_sys2);
64+
65+
_sys2.ActorOf(Props.Create<Echo>(), "echo");
66+
67+
var address = RARP.For(_sys2).Provider.DefaultAddress;
68+
_echoPath = new RootActorPath(address) / "user" / "echo";
69+
}
70+
71+
#endregion
72+
73+
public DotNettySslSetupSpec(ITestOutputHelper output) : base(TestActorSystemSetup(true), output)
74+
{
75+
}
76+
77+
#if !NET471
78+
[Fact]
79+
public async Task Secure_transport_should_be_possible_between_systems_sharing_the_same_certificate()
80+
{
81+
// skip this test due to linux/mono certificate issues
82+
if (IsMono) return;
83+
84+
Setup(true);
85+
86+
var probe = CreateTestProbe();
87+
88+
await AwaitAssertAsync(async () =>
89+
{
90+
Sys.ActorSelection(_echoPath).Tell("hello", probe.Ref);
91+
await probe.ExpectMsgAsync("hello", TimeSpan.FromSeconds(3));
92+
}, TimeSpan.FromSeconds(30), TimeSpan.FromMilliseconds(100));
93+
}
94+
#endif
95+
96+
#if !NET471
97+
[Fact]
98+
public async Task Mutual_TLS_should_be_configurable_via_Setup_API()
99+
{
100+
// skip this test due to linux/mono certificate issues
101+
if (IsMono) return;
102+
103+
// Create a system with mutual TLS enabled via Setup API
104+
var setupWithMutualTls = ActorSystemSetup.Empty
105+
.And(BootstrapSetup.Create()
106+
.WithConfig(ConfigurationFactory.ParseString(@"
107+
akka {
108+
loglevel = DEBUG
109+
actor.provider = ""Akka.Remote.RemoteActorRefProvider,Akka.Remote""
110+
remote.dot-netty.tcp {
111+
port = 0
112+
hostname = ""127.0.0.1""
113+
enable-ssl = true
114+
log-transport = true
115+
}
116+
}")))
117+
.And(new DotNettySslSetup(
118+
new X509Certificate2(ValidCertPath, Password, X509KeyStorageFlags.DefaultKeySet),
119+
suppressValidation: true,
120+
requireMutualAuthentication: true));
121+
122+
var sys3 = ActorSystem.Create("sys3", setupWithMutualTls);
123+
try
124+
{
125+
InitializeLogger(sys3);
126+
sys3.ActorOf(Props.Create<Echo>(), "echo");
127+
128+
// System should start successfully with mutual TLS
129+
await Task.Delay(TimeSpan.FromSeconds(1));
130+
Assert.False(sys3.WhenTerminated.IsCompleted);
131+
132+
// Verify the transport settings have mutual TLS enabled
133+
var transport = RARP.For(sys3).Provider.Transport;
134+
Assert.NotNull(transport);
135+
}
136+
finally
137+
{
138+
await ShutdownAsync(sys3);
139+
}
140+
}
141+
#endif
142+
143+
[Fact]
144+
public async Task Secure_transport_should_NOT_be_possible_between_systems_using_SSL_and_one_not_using_it()
145+
{
146+
Setup(false);
147+
148+
var probe = CreateTestProbe();
149+
await Assert.ThrowsAsync<RemoteTransportException>(async () =>
150+
{
151+
Sys.ActorSelection(_echoPath).Tell("hello", probe.Ref);
152+
await probe.ExpectNoMsgAsync();
153+
});
154+
}
155+
156+
#region helper classes / methods
157+
158+
protected override void AfterAll()
159+
{
160+
base.AfterAll();
161+
Shutdown(_sys2, TimeSpan.FromSeconds(3));
162+
}
163+
164+
private class Echo : ReceiveActor
165+
{
166+
public Echo()
167+
{
168+
Receive<string>(str => Sender.Tell(str));
169+
}
170+
}
171+
172+
#endregion
173+
}
174+
}

0 commit comments

Comments
 (0)