Skip to content

Commit

Permalink
Merge pull request #109 from rabbitmq/oauth2
Browse files Browse the repository at this point in the history
Start support for OAuth 2 token retrieval and refresh
  • Loading branch information
acogoluegnes authored Dec 20, 2024
2 parents 7595674 + 380f2f5 commit a74b948
Show file tree
Hide file tree
Showing 35 changed files with 2,440 additions and 144 deletions.
1 change: 1 addition & 0 deletions ci/start-broker.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ wait_for_message() {

make -C "${PWD}"/tls-gen/basic

rm -rf rabbitmq-configuration
mkdir -p rabbitmq-configuration/tls
cp -R "${PWD}"/tls-gen/basic/result/* rabbitmq-configuration/tls
chmod o+r rabbitmq-configuration/tls/*
Expand Down
25 changes: 23 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,18 @@
<slf4j.version>1.7.36</slf4j.version>
<netty4.version>4.1.116.Final</netty4.version>
<netty4.iouring.version>0.0.25.Final</netty4.iouring.version>
<netty5.version>5.0.0.Alpha5</netty5.version>
<micrometer.version>1.14.2</micrometer.version>
<gson.version>2.11.0</gson.version>
<logback.version>1.2.13</logback.version>
<junit.jupiter.version>5.11.4</junit.jupiter.version>
<assertj.version>3.27.0</assertj.version>
<mockito.version>5.14.2</mockito.version>
<jqwik.version>1.9.2</jqwik.version>
<amqp-client.version>5.22.0</amqp-client.version>
<micrometer-tracing-test.version>1.4.1</micrometer-tracing-test.version>
<micrometer-docs-generator.version>1.0.4</micrometer-docs-generator.version>
<jose4j.version>0.9.6</jose4j.version>
<commons-lang3.version>3.17.0</commons-lang3.version>
<bouncycastle.version>1.79</bouncycastle.version>
<maven.compiler.plugin.version>3.13.0</maven.compiler.plugin.version>
<maven.dependency.plugin.version>3.8.1</maven.dependency.plugin.version>
<maven-surefire-plugin.version>3.5.2</maven-surefire-plugin.version>
Expand Down Expand Up @@ -140,6 +141,13 @@
</dependency>
<!-- End of QPid dependencies -->

<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>${gson.version}</version>
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
Expand Down Expand Up @@ -244,6 +252,19 @@
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>${bouncycastle.version}</version>
<scope>test</scope>
</dependency>

</dependencies>

Expand Down
29 changes: 29 additions & 0 deletions src/docs/asciidoc/usage.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,35 @@ include::{test-examples}/Api.java[tag=subscription-listener]
<4> Get the message offset
<5> Store the offset in the external store after processing

=== OAuth 2 Support

The client can authenticate against an OAuth 2 server like https://github.com/cloudfoundry/uaa[UAA].
It uses the https://tools.ietf.org/html/rfc6749#section-4.4[OAuth 2 Client Credentials flow].
The https://www.rabbitmq.com/docs/oauth2[OAuth 2 plugin] must be enabled on the server side and configured to use the same OAuth 2 server as the client.

How to retrieve the OAuth 2 token can be globally configured at the environment level:

.Configuring OAuth 2 token retrieval
[source,java,indent=0]
--------
include::{test-examples}/Api.java[tag=oauth2]
--------
<1> Access the OAuth 2 configuration
<2> Set the token endpoint URI
<3> Authenticate the client application
<4> Set the grant type
<5> Set optional parameters (depends on the OAuth 2 server)
<6> Set the SSL context (e.g. to verify and trust the identity of the OAuth 2 server)
<7> The token can be shared across the environment connections

The environment retrieves tokens and uses them to create AMQP connections.
It also takes care of refreshing the tokens before they expire and of re-authenticating existing connections so the broker does not close them when their token expires.

The environment uses the same token for all the connections it maintains by default, but this can be changed by setting the `shared` flag to `false`.
With `shared = false`, each connection will have its own OAuth 2 token.

The OAuth 2 configuration can be set at the environment level but also at the connection level.

=== Metrics Collection

The library provides the {javadoc-url}/com/rabbitmq/client/amqp/metrics/MetricsCollector.html[`MetricsCollector`] abstraction to collect metrics.
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/com/rabbitmq/client/amqp/ConnectionSettings.java
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,17 @@ public interface ConnectionSettings<T> {
*/
Affinity<? extends T> affinity();

/**
* OAuth 2 settings.
*
* <p>OAuth 2 requires RabbitMQ 4.1 or more.
*
* @return OAuth 2 settings
* @see OAuth2Settings
* @since 0.4.0
*/
OAuth2Settings<? extends T> oauth2();

/**
* TLS settings.
*
Expand Down
133 changes: 133 additions & 0 deletions src/main/java/com/rabbitmq/client/amqp/OAuth2Settings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
// Copyright (c) 2024 Broadcom. All Rights Reserved.
// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// If you have any questions regarding licensing, please contact us at
// info@rabbitmq.com.
package com.rabbitmq.client.amqp;

import javax.net.ssl.SSLContext;

/**
* Configuration to retrieve a token using the <a
* href="https://tools.ietf.org/html/rfc6749#section-4.4">OAuth 2 Client Credentials flow</a>.
*
* <p>OAuth 2 requires RabbitMQ 4.1 or more.
*
* @param <T> the type of object returned by methods, usually the object itself
* @since 0.4.0
*/
public interface OAuth2Settings<T> {

/**
* Set the URI to access to get the token.
*
* <p>TLS is supported by providing a <code>HTTPS</code> URI and setting a {@link SSLContext}. See
* {@link #tls()} for more information. <em>Applications in production should always use HTTPS to
* retrieve tokens.</em>
*
* @param uri access URI
* @return OAuth 2 settings
* @see #tls()
* @see TlsSettings#sslContext(SSLContext)
*/
OAuth2Settings<T> tokenEndpointUri(String uri);

/**
* Set the OAuth 2 client ID
*
* <p>The client ID usually identifies the application that requests a token.
*
* @param clientId client ID
* @return OAuth 2 settings
*/
OAuth2Settings<T> clientId(String clientId);

/**
* Set the secret (password) to use to get a token.
*
* @param clientSecret client secret
* @return OAuth 2 settings
*/
OAuth2Settings<T> clientSecret(String clientSecret);

/**
* Set the grant type to use when requesting the token.
*
* <p>The default is <code>client_credentials</code>, but some OAuth 2 servers can use
* non-standard grant types to request tokens with extra-information.
*
* @param grantType grant type
* @return OAuth 2 settings
*/
OAuth2Settings<T> grantType(String grantType);

/**
* Set a parameter to pass in the request.
*
* <p>The OAuth 2 server may require extra parameters to narrow down the identity of the user.
*
* @param name name of the parameter
* @param value value of the parameter
* @return OAuth 2 settings
*/
OAuth2Settings<T> parameter(String name, String value);

/**
* Whether to share the same token between connections.
*
* <p>Default is <true>true</true> (the token is shared between connections).
*
* @param shared flag to share the token between connections
* @return OAuth 2 settings
*/
OAuth2Settings<T> shared(boolean shared);

/**
* TLS configuration for requesting the token.
*
* @return TLS configuration
*/
TlsSettings<? extends T> tls();

/**
* Connection settings.
*
* @return connections settings
*/
T connection();

/**
* TLS settings to request the OAuth 2 token.
*
* @param <T> the type of object returned by methods, usually the object itself
*/
interface TlsSettings<T> {

/**
* {@link SSLContext} for HTTPS requests.
*
* @param sslContext the SSL context
* @return TLS settings
*/
TlsSettings<T> sslContext(SSLContext sslContext);

/**
* Go back to the general OAuth 2 settings.
*
* @return OAuth 2 settings
*/
OAuth2Settings<T> oauth2();
}
}
Loading

0 comments on commit a74b948

Please sign in to comment.