Skip to content

Commit 37d593d

Browse files
committed
* Add AcceptablePolicyErrors to TlsSettings
* Move TLS tests to their own file.
1 parent 64564b2 commit 37d593d

File tree

6 files changed

+225
-127
lines changed

6 files changed

+225
-127
lines changed

RabbitMQ.AMQP.Client/IConnectionSettings.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,25 @@ public interface ITlsSettings
3535
/// <summary>
3636
/// Supported protocols to use.
3737
/// </summary>
38-
SslProtocols Protocols { get; }
38+
SslProtocols Protocols { get; set; }
39+
40+
/// <summary>
41+
/// Acceptable TLS/SSL errors when connecting.
42+
/// </summary>
43+
SslPolicyErrors AcceptablePolicyErrors { get; set; }
3944

4045
/// <summary>
4146
/// Specifies whether certificate revocation should be performed during handshake.
4247
/// </summary>
43-
bool CheckCertificateRevocation { get; }
48+
bool CheckCertificateRevocation { get; set; }
4449

4550
/// <summary>
4651
/// Gets or sets a certificate validation callback to validate remote certificate.
4752
/// </summary>
48-
RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get; }
53+
RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get; set; }
4954

5055
/// <summary>
5156
/// Gets or sets a local certificate selection callback to select the certificate which should be used for authentication.
5257
/// </summary>
53-
LocalCertificateSelectionCallback? LocalCertificateSelectionCallback { get; }
58+
LocalCertificateSelectionCallback? LocalCertificateSelectionCallback { get; set; }
5459
}

RabbitMQ.AMQP.Client/Impl/AmqpConnection.cs

Lines changed: 28 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,6 @@
77

88
namespace RabbitMQ.AMQP.Client.Impl;
99

10-
internal class Visitor(AmqpManagement management) : IVisitor
11-
{
12-
private AmqpManagement Management { get; } = management;
13-
14-
public async Task VisitQueues(IEnumerable<QueueSpec> queueSpec)
15-
{
16-
foreach (QueueSpec spec in queueSpec)
17-
{
18-
Trace.WriteLine(TraceLevel.Information, $"Recovering queue {spec.Name}");
19-
try
20-
{
21-
await Management.Queue(spec).Declare()
22-
.ConfigureAwait(false);
23-
}
24-
catch (Exception e)
25-
{
26-
Trace.WriteLine(TraceLevel.Error,
27-
$"Error recovering queue {spec.Name}. Error: {e}. Management Status: {Management}");
28-
}
29-
}
30-
}
31-
}
32-
3310
/// <summary>
3411
/// AmqpConnection is the concrete implementation of <see cref="IConnection"/>
3512
/// It is a wrapper around the AMQP.Net Lite <see cref="Connection"/> class
@@ -38,7 +15,7 @@ public class AmqpConnection : AbstractLifeCycle, IConnection
3815
{
3916
private const string ConnectionNotRecoveredCode = "CONNECTION_NOT_RECOVERED";
4017
private const string ConnectionNotRecoveredMessage = "Connection not recovered";
41-
private readonly SemaphoreSlim _semaphoreClose = new(1, 1);
18+
private readonly SemaphoreSlim _semaphoreClose = new(1, 1); // TODO this needs to be Disposed
4219

4320
// The native AMQP.Net Lite connection
4421
private Connection? _nativeConnection;
@@ -55,7 +32,7 @@ private void ChangeEntitiesStatus(State state, Error? error)
5532

5633
private void ChangePublishersStatus(State state, Error? error)
5734
{
58-
foreach (var publisher1 in Publishers.Values)
35+
foreach (IPublisher publisher1 in Publishers.Values)
5936
{
6037
var publisher = (AmqpPublisher)publisher1;
6138
publisher.ChangeStatus(state, error);
@@ -64,7 +41,7 @@ private void ChangePublishersStatus(State state, Error? error)
6441

6542
private void ChangeConsumersStatus(State state, Error? error)
6643
{
67-
foreach (var consumer1 in Consumers.Values)
44+
foreach (IConsumer consumer1 in Consumers.Values)
6845
{
6946
var consumer = (AmqpConsumer)consumer1;
7047
consumer.ChangeStatus(state, error);
@@ -79,7 +56,7 @@ private async Task ReconnectEntities()
7956

8057
private async Task ReconnectPublishers()
8158
{
82-
foreach (var publisher1 in Publishers.Values)
59+
foreach (IPublisher publisher1 in Publishers.Values)
8360
{
8461
var publisher = (AmqpPublisher)publisher1;
8562
await publisher.Reconnect().ConfigureAwait(false);
@@ -88,7 +65,7 @@ private async Task ReconnectPublishers()
8865

8966
private async Task ReconnectConsumers()
9067
{
91-
foreach (var consumer1 in Consumers.Values)
68+
foreach (IConsumer consumer1 in Consumers.Values)
9269
{
9370
var consumer = (AmqpConsumer)consumer1;
9471
await consumer.Reconnect().ConfigureAwait(false);
@@ -419,7 +396,6 @@ public IPublisherBuilder PublisherBuilder()
419396
return publisherBuilder;
420397
}
421398

422-
423399
public override async Task CloseAsync()
424400
{
425401
await _semaphoreClose.WaitAsync()
@@ -459,10 +435,32 @@ await ConnectionCloseTaskCompletionSource.Task.WaitAsync(TimeSpan.FromSeconds(10
459435
OnNewStatus(State.Closed, null);
460436
}
461437

462-
463438
public override string ToString()
464439
{
465440
string info = $"AmqpConnection{{ConnectionSettings='{_connectionSettings}', Status='{State.ToString()}'}}";
466441
return info;
467442
}
468443
}
444+
445+
internal class Visitor(AmqpManagement management) : IVisitor
446+
{
447+
private AmqpManagement Management { get; } = management;
448+
449+
public async Task VisitQueues(IEnumerable<QueueSpec> queueSpec)
450+
{
451+
foreach (QueueSpec spec in queueSpec)
452+
{
453+
Trace.WriteLine(TraceLevel.Information, $"Recovering queue {spec.Name}");
454+
try
455+
{
456+
await Management.Queue(spec).Declare()
457+
.ConfigureAwait(false);
458+
}
459+
catch (Exception e)
460+
{
461+
Trace.WriteLine(TraceLevel.Error,
462+
$"Error recovering queue {spec.Name}. Error: {e}. Management Status: {Management}");
463+
}
464+
}
465+
}
466+
}

RabbitMQ.AMQP.Client/Impl/ConnectionSettings.cs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -358,40 +358,34 @@ public override string ToString()
358358
public class TlsSettings : ITlsSettings
359359
{
360360
internal const SslProtocols DefaultSslProtocols = SslProtocols.None;
361-
362-
private readonly SslProtocols _protocols;
363-
private readonly X509CertificateCollection _clientCertificates;
364-
private readonly bool _checkCertificateRevocation = false;
365-
private readonly RemoteCertificateValidationCallback? _remoteCertificateValidationCallback;
366-
private readonly LocalCertificateSelectionCallback? _localCertificateSelectionCallback;
361+
private readonly X509CertificateCollection _clientCertificates = new X509CertificateCollection();
367362

368363
public TlsSettings() : this(DefaultSslProtocols)
369364
{
370365
}
371366

372367
public TlsSettings(SslProtocols protocols)
373368
{
374-
_protocols = protocols;
375-
_clientCertificates = new X509CertificateCollection();
376-
_remoteCertificateValidationCallback = trustEverythingCertValidationCallback;
377-
_localCertificateSelectionCallback = null;
369+
Protocols = protocols;
370+
RemoteCertificateValidationCallback = trustEverythingCertValidationCallback;
371+
LocalCertificateSelectionCallback = null;
378372
}
379373

380-
public SslProtocols Protocols => _protocols;
374+
public SslProtocols Protocols { get; set; }
375+
376+
public SslPolicyErrors AcceptablePolicyErrors { get; set; } = SslPolicyErrors.None;
381377

382378
public X509CertificateCollection ClientCertificates => _clientCertificates;
383379

384-
public bool CheckCertificateRevocation => _checkCertificateRevocation;
380+
public bool CheckCertificateRevocation { get; set; } = false;
385381

386-
public RemoteCertificateValidationCallback? RemoteCertificateValidationCallback
387-
=> _remoteCertificateValidationCallback;
382+
public RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get; set; }
388383

389-
public LocalCertificateSelectionCallback? LocalCertificateSelectionCallback
390-
=> _localCertificateSelectionCallback;
384+
public LocalCertificateSelectionCallback? LocalCertificateSelectionCallback { get; set; }
391385

392-
private static bool trustEverythingCertValidationCallback(object sender, X509Certificate? certificate,
386+
private bool trustEverythingCertValidationCallback(object sender, X509Certificate? certificate,
393387
X509Chain? chain, SslPolicyErrors sslPolicyErrors)
394388
{
395-
return true;
389+
return (sslPolicyErrors & ~AcceptablePolicyErrors) == SslPolicyErrors.None;
396390
}
397391
}

RabbitMQ.AMQP.Client/PublicAPI.Unshipped.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,11 +416,17 @@ RabbitMQ.AMQP.Client.Impl.RecoveryConfiguration.IsActivate() -> bool
416416
RabbitMQ.AMQP.Client.Impl.RecoveryConfiguration.IsTopologyActive() -> bool
417417
RabbitMQ.AMQP.Client.Impl.RecoveryConfiguration.Topology(bool activated) -> RabbitMQ.AMQP.Client.IRecoveryConfiguration!
418418
RabbitMQ.AMQP.Client.Impl.TlsSettings
419+
RabbitMQ.AMQP.Client.Impl.TlsSettings.AcceptablePolicyErrors.get -> System.Net.Security.SslPolicyErrors
420+
RabbitMQ.AMQP.Client.Impl.TlsSettings.AcceptablePolicyErrors.set -> void
419421
RabbitMQ.AMQP.Client.Impl.TlsSettings.CheckCertificateRevocation.get -> bool
422+
RabbitMQ.AMQP.Client.Impl.TlsSettings.CheckCertificateRevocation.set -> void
420423
RabbitMQ.AMQP.Client.Impl.TlsSettings.ClientCertificates.get -> System.Security.Cryptography.X509Certificates.X509CertificateCollection!
421424
RabbitMQ.AMQP.Client.Impl.TlsSettings.LocalCertificateSelectionCallback.get -> System.Net.Security.LocalCertificateSelectionCallback?
425+
RabbitMQ.AMQP.Client.Impl.TlsSettings.LocalCertificateSelectionCallback.set -> void
422426
RabbitMQ.AMQP.Client.Impl.TlsSettings.Protocols.get -> System.Security.Authentication.SslProtocols
427+
RabbitMQ.AMQP.Client.Impl.TlsSettings.Protocols.set -> void
423428
RabbitMQ.AMQP.Client.Impl.TlsSettings.RemoteCertificateValidationCallback.get -> System.Net.Security.RemoteCertificateValidationCallback?
429+
RabbitMQ.AMQP.Client.Impl.TlsSettings.RemoteCertificateValidationCallback.set -> void
424430
RabbitMQ.AMQP.Client.Impl.TlsSettings.TlsSettings() -> void
425431
RabbitMQ.AMQP.Client.Impl.TlsSettings.TlsSettings(System.Security.Authentication.SslProtocols protocols) -> void
426432
RabbitMQ.AMQP.Client.Impl.Utils
@@ -485,11 +491,17 @@ RabbitMQ.AMQP.Client.IStreamSpecification.MaxAge(System.TimeSpan maxAge) -> Rabb
485491
RabbitMQ.AMQP.Client.IStreamSpecification.MaxSegmentSizeBytes(RabbitMQ.AMQP.Client.ByteCapacity! maxSegmentSize) -> RabbitMQ.AMQP.Client.IStreamSpecification!
486492
RabbitMQ.AMQP.Client.IStreamSpecification.Queue() -> RabbitMQ.AMQP.Client.IQueueSpecification!
487493
RabbitMQ.AMQP.Client.ITlsSettings
494+
RabbitMQ.AMQP.Client.ITlsSettings.AcceptablePolicyErrors.get -> System.Net.Security.SslPolicyErrors
495+
RabbitMQ.AMQP.Client.ITlsSettings.AcceptablePolicyErrors.set -> void
488496
RabbitMQ.AMQP.Client.ITlsSettings.CheckCertificateRevocation.get -> bool
497+
RabbitMQ.AMQP.Client.ITlsSettings.CheckCertificateRevocation.set -> void
489498
RabbitMQ.AMQP.Client.ITlsSettings.ClientCertificates.get -> System.Security.Cryptography.X509Certificates.X509CertificateCollection!
490499
RabbitMQ.AMQP.Client.ITlsSettings.LocalCertificateSelectionCallback.get -> System.Net.Security.LocalCertificateSelectionCallback?
500+
RabbitMQ.AMQP.Client.ITlsSettings.LocalCertificateSelectionCallback.set -> void
491501
RabbitMQ.AMQP.Client.ITlsSettings.Protocols.get -> System.Security.Authentication.SslProtocols
502+
RabbitMQ.AMQP.Client.ITlsSettings.Protocols.set -> void
492503
RabbitMQ.AMQP.Client.ITlsSettings.RemoteCertificateValidationCallback.get -> System.Net.Security.RemoteCertificateValidationCallback?
504+
RabbitMQ.AMQP.Client.ITlsSettings.RemoteCertificateValidationCallback.set -> void
493505
RabbitMQ.AMQP.Client.ITopologyListener
494506
RabbitMQ.AMQP.Client.ITopologyListener.Clear() -> void
495507
RabbitMQ.AMQP.Client.ITopologyListener.QueueCount() -> int

Tests/ConnectionTests.cs

Lines changed: 1 addition & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
using System;
2-
using System.IO;
3-
using System.Security.Cryptography.X509Certificates;
4-
using System.Threading.Tasks;
5-
using EasyNetQ.Management.Client;
6-
using EasyNetQ.Management.Client.Model;
1+
using System.Threading.Tasks;
72
using RabbitMQ.AMQP.Client;
83
using RabbitMQ.AMQP.Client.Impl;
94
using Xunit;
@@ -78,75 +73,6 @@ public void ValidateBuilderWithSslOptions()
7873
Assert.Equal("amqps", connectionSettings.Scheme);
7974
}
8075

81-
[Fact]
82-
public async Task ConnectUsingTlsAndUserPassword()
83-
{
84-
ConnectionSettings connectionSettings = ConnectionSettingBuilder.Create()
85-
.Host("localhost")
86-
.Scheme("amqps")
87-
.Build();
88-
89-
Assert.True(connectionSettings.UseSsl);
90-
Assert.Equal("localhost", connectionSettings.Host);
91-
Assert.Equal(5671, connectionSettings.Port);
92-
Assert.Equal("guest", connectionSettings.User);
93-
Assert.Equal("guest", connectionSettings.Password);
94-
Assert.Equal("/", connectionSettings.VirtualHost);
95-
Assert.Equal("amqps", connectionSettings.Scheme);
96-
97-
IConnection connection = await AmqpConnection.CreateAsync(connectionSettings);
98-
Assert.Equal(State.Open, connection.State);
99-
await connection.CloseAsync();
100-
Assert.Equal(State.Closed, connection.State);
101-
}
102-
103-
[Fact]
104-
public async Task ConnectUsingTlsAndClientCertificate()
105-
{
106-
string cwd = Directory.GetCurrentDirectory();
107-
108-
string clientCertFile = Path.GetFullPath(Path.Join(cwd, "../../../../.ci/certs/client_localhost.p12"));
109-
if (false == File.Exists(clientCertFile))
110-
{
111-
clientCertFile = Path.GetFullPath(Path.Join(cwd, "../../../../../.ci/certs/client_localhost.p12"));
112-
}
113-
Assert.True(File.Exists(clientCertFile));
114-
115-
var cert = new X509Certificate2(clientCertFile, "grapefruit");
116-
string userName = cert.Subject.Trim().Replace(" ", string.Empty);
117-
118-
var managementUri = new Uri("http://localhost:15672");
119-
using var managementClient = new ManagementClient(managementUri, "guest", "guest");
120-
var userInfo = new UserInfo(null, null, []);
121-
await managementClient.CreateUserAsync(userName, userInfo);
122-
123-
var permissionInfo = new PermissionInfo();
124-
await managementClient.CreatePermissionAsync("/", userName, permissionInfo);
125-
126-
ConnectionSettings connectionSettings = ConnectionSettingBuilder.Create()
127-
.Host("localhost")
128-
.Scheme("amqps")
129-
.SaslMechanism(SaslMechanism.External)
130-
.Build();
131-
132-
Assert.NotNull(connectionSettings.TlsSettings);
133-
connectionSettings.TlsSettings.ClientCertificates.Add(cert);
134-
135-
Assert.True(connectionSettings.UseSsl);
136-
Assert.Equal("localhost", connectionSettings.Host);
137-
Assert.Equal(5671, connectionSettings.Port);
138-
Assert.Null(connectionSettings.User);
139-
Assert.Null(connectionSettings.Password);
140-
Assert.Equal("/", connectionSettings.VirtualHost);
141-
Assert.Equal("amqps", connectionSettings.Scheme);
142-
Assert.Equal(SaslMechanism.External, connectionSettings.SaslMechanism);
143-
144-
IConnection connection = await AmqpConnection.CreateAsync(connectionSettings);
145-
Assert.Equal(State.Open, connection.State);
146-
await connection.CloseAsync();
147-
Assert.Equal(State.Closed, connection.State);
148-
}
149-
15076
[Fact]
15177
public async Task RaiseErrorsIfTheParametersAreNotValid()
15278
{

0 commit comments

Comments
 (0)