Skip to content

Commit a4098b5

Browse files
Continue adding TLS support (#29)
* Continue adding TLS support * Part of the fix to #17 * Make `Tests` nullable and fix errors * Add test that uses client cert * Add `SaslMechanism` * Pass SASL mechanism to Amqp ConnectionFactory if it's EXTERNAL * If SaslMechanism.External is used in the builder, set user and password to null * Upgrade NuGet packages * Add EasyNetQ.Management.Client dependency * Add test that connects using client certificate --------- Signed-off-by: Gabriele Santomaggio <[email protected]> Co-authored-by: Gabriele Santomaggio <[email protected]>
1 parent c164e6f commit a4098b5

16 files changed

+295
-116
lines changed

.editorconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ dotnet_style_qualification_for_method = false:suggestion
3535
dotnet_style_qualification_for_event = false:suggestion
3636

3737
# Types: use keywords instead of BCL types, and permit var only when the type is clear
38+
# TODO consider making csharp_style_var_for_built_in_types and csharp_style_var_elsewhere ERRORS
3839
csharp_style_var_for_built_in_types = false:suggestion
3940
csharp_style_var_when_type_is_apparent = false:none
4041
csharp_style_var_elsewhere = false:suggestion

Directory.Packages.props

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
<ItemGroup>
66
<!-- RabbitMQ.Amqp.Client -->
77
<PackageVersion Include="AMQPNetLite.Core" Version="2.4.11" />
8+
<PackageVersion Include="EasyNetQ.Management.Client" Version="3.0.0" />
89
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" />
910
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
1011
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="1.1.1" />
11-
<PackageVersion Include="MinVer" Version="4.3.0" />
12+
<PackageVersion Include="MinVer" Version="5.0.0" />
1213
<!-- Tests -->
13-
<PackageVersion Include="AltCover" Version="8.8.74" />
14-
<PackageVersion Include="xunit" Version="2.8.1" />
15-
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.1" />
14+
<PackageVersion Include="AltCover" Version="8.8.165" />
15+
<PackageVersion Include="xunit" Version="2.9.0" />
16+
<PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
1617
<PackageVersion Include="Xunit.SkippableFact" Version="1.4.13" />
1718
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
1819
<!-- docs/**/*.csproj -->

RabbitMQ.AMQP.Client/IConnectionSettings.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ public interface IConnectionSettings : IEquatable<IConnectionSettings>
99
string Host { get; }
1010
int Port { get; }
1111
string VirtualHost { get; }
12-
string User { get; }
13-
string Password { get; }
12+
string? User { get; }
13+
string? Password { get; }
1414
string Scheme { get; }
1515
string ConnectionName { get; }
1616
string Path { get; }
1717
bool UseSsl { get; }
18+
SaslMechanism SaslMechanism { get; }
1819
ITlsSettings? TlsSettings { get; }
1920
}
2021

RabbitMQ.AMQP.Client/ILifeCycle.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public interface ILifeCycle
2626
{
2727
Task CloseAsync();
2828

29-
public State State { get; }
29+
State State { get; }
3030

31-
public event LifeCycleCallBack ChangeState;
31+
event LifeCycleCallBack ChangeState;
3232
}

RabbitMQ.AMQP.Client/IRecoveryConfiguration.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,6 @@ public interface IBackOffDelayPolicy
6060
/// or when the user wants to disable the backoff delay policy.
6161
/// </summary>
6262
bool IsActive();
63-
63+
6464
int CurrentAttempt { get; }
6565
}

RabbitMQ.AMQP.Client/Impl/AmqpConnection.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.ObjectModel;
33
using Amqp;
44
using Amqp.Framing;
5+
using Amqp.Sasl;
56
using Amqp.Types;
67

78
namespace RabbitMQ.AMQP.Client.Impl;
@@ -232,6 +233,11 @@ void onOpened(Amqp.IConnection connection, Open open1)
232233
}
233234
}
234235

236+
if (_connectionSettings.SaslMechanism == SaslMechanism.External)
237+
{
238+
cf.SASL.Profile = SaslProfile.External;
239+
}
240+
235241
try
236242
{
237243
_nativeConnection = await cf.CreateAsync(_connectionSettings.Address, open: open, onOpened: onOpened)

RabbitMQ.AMQP.Client/Impl/AmqpManagement.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,8 +388,8 @@ public override string ToString()
388388

389389
return info;
390390
}
391-
392-
391+
392+
393393
internal void ChangeStatus(State newState, Error? error)
394394
{
395395
OnNewStatus(newState, error);

RabbitMQ.AMQP.Client/Impl/ConnectionSettings.cs

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ public class ConnectionSettingBuilder
1010
// TODO: maybe add the event "LifeCycle" to the builder
1111
private string _host = "localhost";
1212
private int _port = -1; // Note: -1 means use the defalt for the scheme
13-
private string _user = "guest";
14-
private string _password = "guest";
13+
private string? _user = "guest";
14+
private string? _password = "guest";
1515
private string _scheme = "AMQP";
16-
private string _connection = "AMQP.NET";
16+
private string _connectionName = "AMQP.NET";
1717
private string _virtualHost = "/";
18+
private SaslMechanism _saslMechanism = Client.SaslMechanism.Plain;
1819
private IRecoveryConfiguration _recoveryConfiguration = Impl.RecoveryConfiguration.Create();
1920

20-
2121
private ConnectionSettingBuilder()
2222
{
2323
}
@@ -27,7 +27,6 @@ public static ConnectionSettingBuilder Create()
2727
return new ConnectionSettingBuilder();
2828
}
2929

30-
3130
public ConnectionSettingBuilder Host(string host)
3231
{
3332
_host = host;
@@ -52,16 +51,15 @@ public ConnectionSettingBuilder Password(string password)
5251
return this;
5352
}
5453

55-
5654
public ConnectionSettingBuilder Scheme(string scheme)
5755
{
5856
_scheme = scheme;
5957
return this;
6058
}
6159

62-
public ConnectionSettingBuilder ConnectionName(string connection)
60+
public ConnectionSettingBuilder ConnectionName(string connectionName)
6361
{
64-
_connection = connection;
62+
_connectionName = connectionName;
6563
return this;
6664
}
6765

@@ -71,6 +69,18 @@ public ConnectionSettingBuilder VirtualHost(string virtualHost)
7169
return this;
7270
}
7371

72+
public ConnectionSettingBuilder SaslMechanism(SaslMechanism saslMechanism)
73+
{
74+
_saslMechanism = saslMechanism;
75+
if (_saslMechanism == Client.SaslMechanism.External)
76+
{
77+
_user = null;
78+
_password = null;
79+
}
80+
81+
return this;
82+
}
83+
7484
public ConnectionSettingBuilder RecoveryConfiguration(IRecoveryConfiguration recoveryConfiguration)
7585
{
7686
_recoveryConfiguration = recoveryConfiguration;
@@ -81,7 +91,10 @@ public ConnectionSettings Build()
8191
{
8292
var c = new ConnectionSettings(_host, _port, _user,
8393
_password, _virtualHost,
84-
_scheme, _connection) { RecoveryConfiguration = (RecoveryConfiguration)_recoveryConfiguration };
94+
_scheme, _connectionName, _saslMechanism)
95+
{
96+
RecoveryConfiguration = (RecoveryConfiguration)_recoveryConfiguration
97+
};
8598

8699
return c;
87100
}
@@ -96,6 +109,7 @@ public class ConnectionSettings : IConnectionSettings
96109
private readonly string _connectionName = "";
97110
private readonly string _virtualHost = "/";
98111
private readonly ITlsSettings? _tlsSettings;
112+
private readonly SaslMechanism _saslMechanism = SaslMechanism.Plain;
99113

100114
public ConnectionSettings(string address, ITlsSettings? tlsSettings = null)
101115
{
@@ -109,15 +123,16 @@ public ConnectionSettings(string address, ITlsSettings? tlsSettings = null)
109123
}
110124

111125
public ConnectionSettings(string host, int port,
112-
string user, string password,
126+
string? user, string? password,
113127
string virtualHost, string scheme, string connectionName,
114-
ITlsSettings? tlsSettings = null)
128+
SaslMechanism saslMechanism, ITlsSettings? tlsSettings = null)
115129
{
116130
_address = new Address(host: host, port: port,
117131
user: user, password: password,
118132
path: "/", scheme: scheme);
119133
_connectionName = connectionName;
120134
_virtualHost = virtualHost;
135+
_saslMechanism = saslMechanism;
121136
_tlsSettings = tlsSettings;
122137

123138
if (_address.UseSsl && _tlsSettings == null)
@@ -129,12 +144,13 @@ public ConnectionSettings(string host, int port,
129144
public string Host => _address.Host;
130145
public int Port => _address.Port;
131146
public string VirtualHost => _virtualHost;
132-
public string User => _address.User;
133-
public string Password => _address.Password;
147+
public string? User => _address.User;
148+
public string? Password => _address.Password;
134149
public string Scheme => _address.Scheme;
135150
public string ConnectionName => _connectionName;
136151
public string Path => _address.Path;
137152
public bool UseSsl => _address.UseSsl;
153+
public SaslMechanism SaslMechanism => _saslMechanism;
138154

139155
public ITlsSettings? TlsSettings => _tlsSettings;
140156

@@ -279,7 +295,7 @@ public static BackOffDelayPolicy Create()
279295
{
280296
return new BackOffDelayPolicy();
281297
}
282-
298+
283299
public static BackOffDelayPolicy Create(int maxAttempt)
284300
{
285301
return new BackOffDelayPolicy(maxAttempt);

RabbitMQ.AMQP.Client/RabbitMQ.AMQP.Client.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
<None Include="$(MSBuildThisFileDirectory)..\LICENSE" Pack="true" Visible="false" PackagePath="" />
2525
<None Include="$(MSBuildThisFileDirectory)..\LICENSE-APACHE2" Pack="true" Visible="false" PackagePath="" />
2626
<None Include="$(MSBuildThisFileDirectory)..\LICENSE-MPL-RabbitMQ" Pack="true" Visible="false" PackagePath="" />
27-
<Folder Include="Metrics/" />
2827
<InternalsVisibleTo Include="Tests" />
2928
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
3029
</ItemGroup>

RabbitMQ.AMQP.Client/SaslMechanism.cs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
namespace RabbitMQ.AMQP.Client
2+
{
3+
public class SaslMechanism : IEquatable<SaslMechanism>
4+
{
5+
public static readonly SaslMechanism Plain = new("PLAIN");
6+
public static readonly SaslMechanism External = new("EXTERNAL");
7+
8+
private readonly string _saslMechanism;
9+
10+
private SaslMechanism(string saslMechanism)
11+
{
12+
_saslMechanism = saslMechanism;
13+
}
14+
15+
public string Mechanism => _saslMechanism;
16+
17+
public override bool Equals(object? obj)
18+
{
19+
if (obj is null)
20+
{
21+
return false;
22+
}
23+
24+
if (obj is not SaslMechanism)
25+
{
26+
return false;
27+
}
28+
29+
if (Object.ReferenceEquals(this, obj))
30+
{
31+
return true;
32+
}
33+
34+
return GetHashCode() == obj.GetHashCode();
35+
}
36+
37+
public bool Equals(SaslMechanism? other)
38+
{
39+
if (other is null)
40+
{
41+
return false;
42+
}
43+
44+
if (Object.ReferenceEquals(this, other))
45+
{
46+
return true;
47+
}
48+
49+
return GetHashCode() == other.GetHashCode();
50+
}
51+
52+
public override int GetHashCode()
53+
{
54+
return _saslMechanism.GetHashCode();
55+
}
56+
}
57+
}

Tests/ConnectionRecoveryTests.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,10 +60,10 @@ public async Task NormalCloseTheStatusShouldBeCorrectAndErrorNull(bool activeRec
6060
ConnectionSettingBuilder.Create().ConnectionName(connectionName).RecoveryConfiguration(
6161
RecoveryConfiguration.Create().Activated(activeRecovery).Topology(false)).Build());
6262

63-
var completion = new TaskCompletionSource();
63+
TaskCompletionSource completion = new TaskCompletionSource();
6464
var listFromStatus = new List<State>();
6565
var listToStatus = new List<State>();
66-
var listError = new List<Error>();
66+
var listError = new List<Error?>();
6767
connection.ChangeState += (sender, from, to, error) =>
6868
{
6969
listFromStatus.Add(from);
@@ -103,14 +103,14 @@ public async Task NormalCloseTheStatusShouldBeCorrectAndErrorNull(bool activeRec
103103
public async Task UnexpectedCloseTheStatusShouldBeCorrectAndErrorNotNull()
104104
{
105105
const string connectionName = "unexpected-close-connection-name";
106-
var connection = await AmqpConnection.CreateAsync(
106+
IConnection connection = await AmqpConnection.CreateAsync(
107107
ConnectionSettingBuilder.Create().ConnectionName(connectionName).RecoveryConfiguration(
108108
RecoveryConfiguration.Create().Activated(true).Topology(false)
109109
.BackOffDelayPolicy(new FakeFastBackOffDelay())).Build());
110110
var resetEvent = new ManualResetEvent(false);
111111
var listFromStatus = new List<State>();
112112
var listToStatus = new List<State>();
113-
var listError = new List<Error>();
113+
var listError = new List<Error?>();
114114
connection.ChangeState += (sender, previousState, currentState, error) =>
115115
{
116116
listFromStatus.Add(previousState);
@@ -170,7 +170,10 @@ public async Task OverrideTheBackOffWithBackOffDisabled()
170170
{
171171
listFromStatus.Add(previousState);
172172
listToStatus.Add(currentState);
173-
listError.Add(error);
173+
if (error is not null)
174+
{
175+
listError.Add(error);
176+
}
174177
if (listError.Count >= 4)
175178
{
176179
resetEvent.Set();

0 commit comments

Comments
 (0)