Skip to content

Commit decdd5c

Browse files
committed
Add more tests for OAuth2
Signed-off-by: Gabriele Santomaggio <[email protected]>
1 parent 86bba8b commit decdd5c

File tree

6 files changed

+70
-76
lines changed

6 files changed

+70
-76
lines changed

.ci/ubuntu/cluster/rmq/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ COPY --chown=rabbitmq:rabbitmq --chmod=0644 enabled_plugins /etc/rabbitmq/enable
1212
COPY --chown=rabbitmq:rabbitmq rabbitmq-env.conf /etc/rabbitmq/rabbitmq-env.conf
1313
COPY --chown=rabbitmq:rabbitmq rabbitmq.conf /etc/rabbitmq/rabbitmq.conf
1414
COPY --chown=rabbitmq:rabbitmq advanced.config /etc/rabbitmq/advanced.config
15+
COPY --chown=rabbitmq:rabbitmq definitions.json /etc/rabbitmq/definitions.json
1516

1617
EXPOSE 4369 5671 5672 15672 15692 25672 35672-35682
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"rabbit_version":"4.1.0-beta.4","rabbitmq_version":"4.1.0-beta.4","product_name":"RabbitMQ","product_version":"4.1.0-beta.4","rabbitmq_definition_format":"cluster","original_cluster_name":"rabbit@rabbitmq-amqp-go-client-rabbitmq","explanation":"Definitions of cluster 'rabbit@rabbitmq-amqp-go-client-rabbitmq'","users":[{"name":"guest","password_hash":"5AXVjnnJAKWzGy8L/t9vhOi5iZ4j2wwUA9aI0QoOgBYPXmGS","hashing_algorithm":"rabbit_password_hashing_sha256","tags":["administrator"],"limits":{}},{"name":"user_1","password_hash":"k91LVmfv+JsXCihK+BiwURDo2otPX4wRtX4vErArkhRq/kkJ","hashing_algorithm":"rabbit_password_hashing_sha256","tags":["administrator"],"limits":{}},{"name":"O=client,CN=localhost","password_hash":"n3z/QaCVGTgelie+hmxw7//jYQmtERIVOQj+tw47AoPVAsCh","hashing_algorithm":"rabbit_password_hashing_sha256","tags":["administrator"],"limits":{}}],"vhosts":[{"name":"vhost_user_1","description":"","metadata":{"description":"","tags":[],"default_queue_type":"classic"},"tags":[],"default_queue_type":"classic"},{"name":"/","description":"Default virtual host","metadata":{"description":"Default virtual host","tags":[],"default_queue_type":"classic"},"tags":[],"default_queue_type":"classic"},{"name":"tls","description":"","metadata":{"description":"","tags":[],"default_queue_type":"classic"},"tags":[],"default_queue_type":"classic"}],"permissions":[{"user":"O=client,CN=localhost","vhost":"/","configure":".*","write":".*","read":".*"},{"user":"guest","vhost":"/","configure":".*","write":".*","read":".*"},{"user":"O=client,CN=localhost","vhost":"tls","configure":".*","write":".*","read":".*"},{"user":"guest","vhost":"vhost_user_1","configure":".*","write":".*","read":".*"},{"user":"guest","vhost":"tls","configure":".*","write":".*","read":".*"},{"user":"user_1","vhost":"vhost_user_1","configure":".*","write":".*","read":".*"}],"topic_permissions":[],"parameters":[],"global_parameters":[{"name":"cluster_tags","value":[]},{"name":"internal_cluster_id","value":"rabbitmq-cluster-id-A5bx3jtkxi8ukG64KRkw8g"}],"policies":[],"queues":[],"exchanges":[],"bindings":[]}

.ci/ubuntu/cluster/rmq/rabbitmq.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ cluster_formation.classic_config.nodes.2 = [email protected]
3333
auth_backends.1 = internal
3434
auth_backends.2 = rabbit_auth_backend_oauth2
3535

36+
load_definitions = /etc/rabbitmq/definitions.json

RabbitMQ.AMQP.Client/ConnectionSettings.cs

Lines changed: 29 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,11 @@ public class ConnectionSettings : IEquatable<ConnectionSettings>
208208
{
209209
protected Address _address = new("amqp://localhost:5672");
210210
protected string _virtualHost = Consts.DefaultVirtualHost;
211+
private readonly SaslMechanism _saslMechanism = SaslMechanism.Plain;
212+
private readonly OAuth2Options? _oAuth2Options = null;
211213
private readonly string _containerId = string.Empty;
212214
private readonly uint _maxFrameSize = Consts.DefaultMaxFrameSize;
213215
private readonly TlsSettings? _tlsSettings;
214-
private readonly SaslMechanism _saslMechanism = SaslMechanism.Plain;
215216
private readonly IRecoveryConfiguration _recoveryConfiguration = new RecoveryConfiguration();
216217

217218
public ConnectionSettings(Uri uri,
@@ -221,7 +222,7 @@ public ConnectionSettings(Uri uri,
221222
uint? maxFrameSize = null,
222223
TlsSettings? tlsSettings = null,
223224
OAuth2Options? oAuth2Options = null)
224-
: this(containerId, saslMechanism, recoveryConfiguration, maxFrameSize, tlsSettings)
225+
: this(containerId, saslMechanism, recoveryConfiguration, maxFrameSize, tlsSettings, oAuth2Options)
225226
{
226227
(string? user, string? password) = ProcessUserInfo(uri);
227228

@@ -233,22 +234,23 @@ public ConnectionSettings(Uri uri,
233234
throw new ArgumentOutOfRangeException("uri.Scheme", "Uri scheme must be 'amqp' or 'amqps'");
234235
}
235236

236-
_address = new Address(host: uri.Host,
237-
port: uri.Port,
238-
user: user,
239-
password: password,
240-
path: "/",
241-
scheme: scheme);
237+
_address = InitAddress(uri.Host, uri.Port, user, password, scheme);
238+
_tlsSettings = InitTlsSettings();
239+
}
242240

243-
if (oAuth2Options is not null)
241+
protected Address InitAddress(string host, int port, string? user, string? password, string scheme)
242+
{
243+
if (_oAuth2Options is not null)
244244
{
245-
// in case of OAuth2, we need to use plain mechanism
246-
_saslMechanism = SaslMechanism.Plain;
247-
_address = new Address(_address.Host, _address.Port, "", oAuth2Options.Token, _address.Path,
248-
_address.Scheme);
245+
return new Address(host, port, "", _oAuth2Options.Token, "/", scheme);
249246
}
250247

251-
_tlsSettings = InitTlsSettings();
248+
return new Address(host,
249+
port: port,
250+
user: user,
251+
password: password,
252+
path: "/",
253+
scheme: scheme);
252254
}
253255

254256
public ConnectionSettings(string scheme,
@@ -263,33 +265,19 @@ public ConnectionSettings(string scheme,
263265
uint? maxFrameSize = null,
264266
TlsSettings? tlsSettings = null,
265267
OAuth2Options? oAuth2Options = null)
266-
: this(containerId, saslMechanism, recoveryConfiguration, maxFrameSize, tlsSettings)
268+
: this(containerId, saslMechanism, recoveryConfiguration, maxFrameSize, tlsSettings, oAuth2Options)
267269
{
268270
if (false == Utils.IsValidScheme(scheme))
269271
{
270272
throw new ArgumentOutOfRangeException(nameof(scheme), "scheme must be 'amqp' or 'amqps'");
271273
}
272274

273-
_address = new Address(host: host,
274-
port: port,
275-
user: user,
276-
password: password,
277-
path: "/",
278-
scheme: scheme);
279-
275+
_address = InitAddress(host, port, user, password, scheme);
280276
if (virtualHost is not null)
281277
{
282278
_virtualHost = virtualHost;
283279
}
284280

285-
if (oAuth2Options is not null)
286-
{
287-
// in case of OAuth2, we need to use plain mechanism
288-
_saslMechanism = SaslMechanism.Plain;
289-
_address = new Address(_address.Host, _address.Port, "", oAuth2Options.Token, _address.Path,
290-
_address.Scheme);
291-
}
292-
293281
_tlsSettings = InitTlsSettings();
294282
}
295283

@@ -298,7 +286,8 @@ protected ConnectionSettings(
298286
SaslMechanism? saslMechanism = null,
299287
IRecoveryConfiguration? recoveryConfiguration = null,
300288
uint? maxFrameSize = null,
301-
TlsSettings? tlsSettings = null)
289+
TlsSettings? tlsSettings = null,
290+
OAuth2Options? oAuth2Options = null)
302291
{
303292
if (containerId is not null)
304293
{
@@ -310,6 +299,13 @@ protected ConnectionSettings(
310299
_saslMechanism = saslMechanism;
311300
}
312301

302+
if (oAuth2Options is not null)
303+
{
304+
// If OAuth2Options is set, then SaslMechanism must be Plain
305+
_oAuth2Options = oAuth2Options;
306+
_saslMechanism = SaslMechanism.Plain;
307+
}
308+
313309
if (recoveryConfiguration is not null)
314310
{
315311
_recoveryConfiguration = recoveryConfiguration;
@@ -483,7 +479,7 @@ public ClusterConnectionSettings(IEnumerable<Uri> uris,
483479
uint? maxFrameSize = null,
484480
TlsSettings? tlsSettings = null,
485481
OAuth2Options? oAuth2Options = null)
486-
: base(containerId, saslMechanism, recoveryConfiguration, maxFrameSize, tlsSettings)
482+
: base(containerId, saslMechanism, recoveryConfiguration, maxFrameSize, tlsSettings, oAuth2Options)
487483
{
488484
_uris = uris.ToList();
489485
if (_uris.Count == 0)
@@ -525,20 +521,7 @@ public ClusterConnectionSettings(IEnumerable<Uri> uris,
525521
}
526522
}
527523

528-
var address = new Address(host: uri.Host,
529-
port: uri.Port,
530-
user: user,
531-
password: password,
532-
path: "/",
533-
scheme: scheme);
534-
535-
// if (oAuth2Options is not null)
536-
// {
537-
// // in case of OAuth2, we need to use plain mechanism
538-
// _saslMechanism = SaslMechanism.Plain;
539-
// _address = new Address(_address.Host, _address.Port, "", oAuth2Options.Token, _address.Path,
540-
// _address.Scheme);
541-
// }
524+
var address = InitAddress(uri.Host, uri.Port, user, password, scheme);
542525

543526
_uriToAddress[uri] = address;
544527

RabbitMQ.AMQP.Client/PublicAPI.Unshipped.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,11 @@ RabbitMQ.AMQP.Client.ConnectionException.ConnectionException(string! message) ->
6565
RabbitMQ.AMQP.Client.ConnectionException.ConnectionException(string! message, System.Exception! innerException) -> void
6666
RabbitMQ.AMQP.Client.ConnectionSettings
6767
RabbitMQ.AMQP.Client.ConnectionSettings.ConnectionSettings(string! scheme, string! host, int port, string? user = null, string? password = null, string? virtualHost = null, string! containerId = "", RabbitMQ.AMQP.Client.SaslMechanism? saslMechanism = null, RabbitMQ.AMQP.Client.IRecoveryConfiguration? recoveryConfiguration = null, uint? maxFrameSize = null, RabbitMQ.AMQP.Client.TlsSettings? tlsSettings = null, RabbitMQ.AMQP.Client.OAuth2Options? oAuth2Options = null) -> void
68-
RabbitMQ.AMQP.Client.ConnectionSettings.ConnectionSettings(string? containerId = null, RabbitMQ.AMQP.Client.SaslMechanism? saslMechanism = null, RabbitMQ.AMQP.Client.IRecoveryConfiguration? recoveryConfiguration = null, uint? maxFrameSize = null, RabbitMQ.AMQP.Client.TlsSettings? tlsSettings = null) -> void
68+
RabbitMQ.AMQP.Client.ConnectionSettings.ConnectionSettings(string? containerId = null, RabbitMQ.AMQP.Client.SaslMechanism? saslMechanism = null, RabbitMQ.AMQP.Client.IRecoveryConfiguration? recoveryConfiguration = null, uint? maxFrameSize = null, RabbitMQ.AMQP.Client.TlsSettings? tlsSettings = null, RabbitMQ.AMQP.Client.OAuth2Options? oAuth2Options = null) -> void
6969
RabbitMQ.AMQP.Client.ConnectionSettings.ConnectionSettings(System.Uri! uri, string? containerId = null, RabbitMQ.AMQP.Client.SaslMechanism? saslMechanism = null, RabbitMQ.AMQP.Client.IRecoveryConfiguration? recoveryConfiguration = null, uint? maxFrameSize = null, RabbitMQ.AMQP.Client.TlsSettings? tlsSettings = null, RabbitMQ.AMQP.Client.OAuth2Options? oAuth2Options = null) -> void
7070
RabbitMQ.AMQP.Client.ConnectionSettings.ContainerId.get -> string!
7171
RabbitMQ.AMQP.Client.ConnectionSettings.Host.get -> string!
72+
RabbitMQ.AMQP.Client.ConnectionSettings.InitAddress(string! host, int port, string? user, string? password, string! scheme) -> Amqp.Address!
7273
RabbitMQ.AMQP.Client.ConnectionSettings.MaxFrameSize.get -> uint
7374
RabbitMQ.AMQP.Client.ConnectionSettings.Password.get -> string?
7475
RabbitMQ.AMQP.Client.ConnectionSettings.Path.get -> string!

Tests/OAuth2Tests.cs

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@
2121

2222
namespace Tests
2323
{
24-
public class OAuth2Tests(ITestOutputHelper testOutputHelper) : IntegrationTest(testOutputHelper, setupConnectionAndManagement: false)
24+
public class OAuth2Tests(ITestOutputHelper testOutputHelper)
25+
: IntegrationTest(testOutputHelper, setupConnectionAndManagement: false)
2526
{
2627
private const string Base64Key = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGH";
2728

2829
private const string Audience = "rabbitmq";
30+
2931
//
3032
[SkippableFact]
3133
public async Task ConnectToRabbitMqWithOAuth2TokenShouldSuccess()
@@ -46,37 +48,42 @@ public async Task ConnectToRabbitMqWithOAuth2TokenShouldSuccess()
4648
public async Task ConnectToRabbitMqWithOAuth2TokenShouldDisconnectAfterTimeout()
4749
{
4850
Skip.IfNot(IsCluster);
49-
IConnection connection = await AmqpConnection.CreateAsync(
50-
ConnectionSettingsBuilder.Create()
51-
.Host("localhost")
52-
.Port(5672)
53-
.RecoveryConfiguration(new RecoveryConfiguration().Activated(false).Topology(false))
54-
.OAuth2Options(new OAuth2Options(GenerateToken(DateTime.UtcNow.AddMilliseconds(1_000))))
55-
.Build());
56-
57-
Assert.NotNull(connection);
58-
Assert.Equal(State.Open, connection.State);
59-
State? stateFrom = null;
60-
State? stateTo = null;
61-
Error? stateError = null;
62-
TaskCompletionSource<bool> tcs = new();
63-
connection.ChangeState += (sender, from, to, error) =>
51+
var l = new List<ConnectionSettingsBuilder>
6452
{
65-
stateFrom = from;
66-
stateTo = to;
67-
stateError = error;
68-
tcs.SetResult(true);
53+
ConnectionSettingsBuilder.Create().Uris(new List<Uri> { new("amqp://") }),
54+
ConnectionSettingsBuilder.Create().Uri(new Uri("amqp://localhost:5672")),
55+
ConnectionSettingsBuilder.Create().Host("localhost").Port(5672)
6956
};
7057

71-
await tcs.Task;
72-
Assert.NotNull(stateFrom);
73-
Assert.NotNull(stateTo);
74-
Assert.NotNull(stateError);
75-
Assert.NotNull(stateError.ErrorCode);
76-
Assert.Equal(State.Open, stateFrom);
77-
Assert.Equal(State.Closed, stateTo);
78-
Assert.Equal(State.Closed, connection.State);
79-
Assert.Contains(stateError.ErrorCode, "amqp:unauthorized-access");
58+
foreach (ConnectionSettingsBuilder builder in l)
59+
{
60+
IConnection connection = await AmqpConnection.CreateAsync(builder
61+
.RecoveryConfiguration(new RecoveryConfiguration().Activated(false).Topology(false))
62+
.OAuth2Options(new OAuth2Options(GenerateToken(DateTime.UtcNow.AddMilliseconds(1_000)))).Build());
63+
Assert.NotNull(connection);
64+
Assert.Equal(State.Open, connection.State);
65+
State? stateFrom = null;
66+
State? stateTo = null;
67+
Error? stateError = null;
68+
TaskCompletionSource<bool> tcs = new();
69+
connection.ChangeState += (sender, from, to, error) =>
70+
{
71+
stateFrom = from;
72+
stateTo = to;
73+
stateError = error;
74+
tcs.SetResult(true);
75+
};
76+
77+
await tcs.Task;
78+
Assert.NotNull(stateFrom);
79+
Assert.NotNull(stateTo);
80+
Assert.NotNull(stateError);
81+
Assert.NotNull(stateError.ErrorCode);
82+
Assert.Equal(State.Open, stateFrom);
83+
Assert.Equal(State.Closed, stateTo);
84+
Assert.Equal(State.Closed, connection.State);
85+
Assert.Contains(stateError.ErrorCode, "amqp:unauthorized-access");
86+
}
8087
}
8188

8289
private static string GenerateToken(DateTime duration)

0 commit comments

Comments
 (0)