Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OAuth2 doc changes #1504

Merged
merged 20 commits into from
Jan 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 35 additions & 11 deletions site/management.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,25 +288,32 @@ rabbitmqctl set_user_tags full_access administrator
RabbitMQ can be configured to use [JWT-encoded OAuth 2.0 access tokens](https://github.com/rabbitmq/rabbitmq-auth-backend-oauth2) to authenticate client applications and management UI users. When doing so, the management UI does
not automatically redirect users to authenticate
against the OAuth 2 server, this must be configured separately. Currently,
RabbitMQ has been tested against the following Authorization servers:
**Authorization code flow with PKCE** is tested with the following Authorization servers:

* [UAA](https://github.com/cloudfoundry/uaa)
* [Keycloak](https://www.keycloak.org/)
* [Auth0](https://auth0.com/)
* [Azure](https://docs.microsoft.com/en-us/azure/active-directory/fundamentals/auth-oauth2)

**Important**: from the OAuth 2.0 point of view, the RabbitMQ Management UI is a **public app** which
means it cannot securely store credentials such as the *client_secret*. This means that RabbitMQ does not need to present a client_secret when authenticating users.

It is usually possible to configure the OAuth client as a **public app** with the authorization server that you are using.
If target authorization server only supports a **confidential app** or it requires a *client_secret*,
then a *client_secret* **must** be configured using the `oauth_client_secret` setting.

To redirect users to the UAA server to authenticate, use the following configuration:

<pre class="lang-ini">
management.enable_uaa = true
management.oauth_enabled = true
management.oauth_client_id = rabbit_user_client
management.oauth_client_secret = rabbit_user_client_secret
management.oauth_provider_url = https://my-uaa-server-host:8443/uaa
</pre>

> IMPORTANT: Since RabbitMQ 3.10, RabbitMQ uses `authorization_code` grant type. `implicit` flow has been
deprecated.
> **Important**: Since RabbitMQ 3.10, RabbitMQ uses `authorization_code` grant type. `implicit` flow is deprecated.

> **Important**: `management.oauth_client_secret` is an optional setting. It is only required when the authorization server used requires it

### Allow Basic and OAuth 2 authentication

Expand All @@ -333,7 +340,6 @@ management.disable_basic_auth = true
management.enable_uaa = true
management.oauth_enabled = true
management.oauth_client_id = rabbit_user_client
management.oauth_client_secret = rabbit_user_client_secret
management.oauth_provider_url = https://my-uaa-server-host:8443/uaa
</pre>

Expand All @@ -348,12 +354,6 @@ curl -i --header "authorization: Bearer &lt;token&gt;" http://localhost:15672/ap
This is true for all endpoints except `GET /definitions` and `POST /definitions`. Those
endpoints require the token to be passed in the `token` query string parameter.

### Minimum scope required and how the UI determines the username from the token

At a minimum, RabbitMQ requires the the `openid` scope because it uses some claims in the *id token* to determine the username and to display this username on the top right corner of the management UI. The *id token* is returned by the Authorization server if the `openid` scope is included in the authorization request.

RabbitMQ reads the `user_name` claim from the *id_token*. If the token does not contain the `user_name`, RabbitMQ uses the `sub` claim.

### Configure which scopes RabbitMQ requests to the authorization server

It is possible to configure which OAuth 2.0 scopes RabbitMQ should claim when redirecting the user to the authorization server.
Expand All @@ -373,6 +373,8 @@ such as:
* <*resource_server_id*>`.tag:administrator`
* <*resource_server_id*>`.read:*/*/*`

The scopes are configured using the `management.oauth_scopes` setting. The value must be a space-separated list of scopes.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will a customer/user know what My understanding is you enter a scope followed by a space so: scope1 scope2 scope3

If that is correct then there probably is no need to clarify further, if I can understand more technical people definitely should :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is !! :)

### Configure OpenID Connect Discovery endpoint

By default, RabbitMQ assumes the OpenID Connect Discovery endpoint is at `<management.oauth_provider_url>/.well-known/openid-configuration`. If your endpoint differs, you can set yours via the `management.oauth_metadata_url` setting.
Expand All @@ -395,6 +397,28 @@ For instance, if you configured the CSP header with the value `default-src 'self

In addition to the `connect-src` CSP header, RabbitMQ also needs the CSP directives `unsafe-eval` `unsafe-inline`, otherwise the OAuth 2.0 functionality may not work.

### Identity-Provider initiated logon

By default, the RabbitMQ Management UI uses the OAuth 2.0 **authorization code flow** to authenticate and authorize users.
However, there are scenarios where users preferred to be automatically redirected to RabbitMQ without getting
Copy link
Contributor

@pstack2021 pstack2021 Nov 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add "RabbitMQ" before the words "Management UI" in the first sentence just to be clear what UI it is at all times.

Add the word "the" after "uses" in the first sentence above

involved in additional logon flows. This is common in Web Portals where with a single click, users navigate
straight to a RabbitMQ cluster's management UI with a token obtained under the covers. This is known as
**Identity-Provider initiated logon**.

RabbitMQ exposes a new setting called `management.oauth_initiated_logon_type` whose default value `sp_initiated`.
To enable an **Identity-Provider initiated logon** you set it to `idp_initiated`.

After you set `management.oauth_initiated_logon_type` to `idp_initiated` and
`oauth_enabled: true` and `oauth_provider_url` are configured, the management UI exposes the HTTP endpoint `/login` which accepts `content-type: application/x-www-form-urlencoded` and it expects the JWT token in the `access_token` form field. This is the endpoint where the web portal would redirect users to access the RabbitMQ Management ui.

This is the minimum required configuration for a RabbitMQ cluster configured with `idp_initiated` logon type:

<pre class="lang-ini">
management.oauth_enabled = true
management.oauth_initiated_logon_type = idp_initiated
management.oauth_provider_url = https://my-web-portal
</pre>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps give an example of the above in documentation, thanks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point ! Thanks


Copy link
Contributor

@pstack2021 pstack2021 Nov 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the above be updated to: "After you set management.oauth_initiated_logon_type to idp_initiated and oauth_enabled: true and oauth_provider_url are configured, the management UI exposes the endpoint /login which accepts content-type: application/x-www-form-urlencoded and it expects the JWT token in the access_token form field.

I have no idea what the above means, do we need to explain it in more simple terms? thanks

## <a id="http-api" class="anchor" href="#http-api">HTTP API</a>

Expand Down
13 changes: 0 additions & 13 deletions site/oauth2-examples-azure.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,17 +49,6 @@ When using **Azure AD as OAuth 2.0 server**, your client app (in our case Rabbit

![Azure AD JWKS URI](./img/oauth2/azure-ad-jwks-uri.png)

## Create a secret for your app

Your application needs a **client secret** to prove its identity when requesting a token.

1. Still on the **App registrations** page, in the left-hand menu, click on **Certificates & Secrets**, then select the **Client secrets** tab.

2. In the **Certificates & Secrets** pane, click on **New Client Secret** and, on the right pane that has just opened, enter a description for the secret and choose an expiration time.

3. Click on **Add**.

<g-emoji class="g-emoji" alias="warning" fallback-src="https://github.githubassets.com/images/icons/emoji/unicode/26a0.png">⚠️</g-emoji> **IMPORTANT**: Immediately note the value of the secret (as you won't be able to get it later and you will need it to configure the `rabbitmq_auth_backend_oauth2` on RabbitMQ side).

## Create OAuth 2.0 roles for your app

Expand Down Expand Up @@ -138,7 +127,6 @@ The configuration on Azure side is done. You now have to configure RabbitMQ to u
Update it with the following values (you should have noted these in the previous steps):
* **Tenant ID** associated to the app that you registered in Azure AD
* **Application ID** associated to the app that you registered in Azure AD
* Value of the **secret** you created for your app in Azure AD
* Value of the **jwks_uri** key from `https://login.microsoftonline.com/{TENANT_ID}/v2.0/.well-known/openid-configuration`

<pre class="lang-bash">
Expand All @@ -150,7 +138,6 @@ $ vi rabbitmq.config
{rabbitmq_management, [
{oauth_enabled, true},
{oauth_client_id, "PUT YOUR AZURE AD APPLICATION ID"},
{oauth_client_secret, "PUT YOUR AZURE AD APPLICATION SECRET"},
{oauth_provider_url, "https://login.microsoftonline.com/AZURE_AD_TENANT_ID"}
]},
{rabbitmq_auth_backend_oauth2, [
Expand Down
8 changes: 4 additions & 4 deletions site/oauth2-examples-keycloak.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ rather than `legacy-token-key`.

### Configure Client

For backend applications which uses **Client Credentials flow** you create a **Client** with:
For backend applications which uses **Client Credentials flow**, you can create a **Client** with:

* **Access Type** : `confidential`
* With all the other flows disabled: Standard Flow, Implicit Flow, Direct Access Grants
* **Access Type** : `public`
* Turn off `Standard Flow`, `Implicit Flow`, and `Direct Access Grants`
* With **Service Accounts Enabled** on. If it is not enabled you do not have the tab `Credentials`
Copy link
Contributor

@pstack2021 pstack2021 Nov 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again enable/disable terminology used here which we want to avoid going forward, see the table here for more details: https://source.vmware.com/portal/pages/global-marketing/terminology-changes
For the reference to "disabled" in the 3rd bullet point above, can we change it to "Turn off Standard Flow, Implicit Flow, and Direct Access Grants "

Are: Standard Flow, Implicit Flow, Direct Access Grant UI entities? if so, lets tag them appropriately, I think bold is being used to tag UI entities in OSS RabbitMQ docs right now, please use that here if so, thanks

4th bullet point: Service Accounts Enabled should change to Service Accounts Activated in PHASE 2 of inclusive language updates in code entities, more details about that in this issue: #1551

Also, a suggested reword of the 4th bullet point, how about: Service Accounts Enabled is turned on, if it is not, you won't have the Credentials tab.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We cannot do anything about Service Accounts Enabled because that is exactly how it is called in Keycloak.

* In tab `Credentials` you have the client id secret
* In the `Credentials` tab, you have the `client id`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Credentials tab,......


### Configure Client scopes
Expand Down
2 changes: 1 addition & 1 deletion site/oauth2-examples-oauth0.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ list of users which have this role.

1. From Auth0 dashboard, go to **Settings > List of Valid Keys**, and **Copy Signing Certificate** from the **CURRENTLY USED** signing key.

2. Create `/tmp/certiicate.pem` and paste the certificate.
2. Create `/tmp/certificate.pem` and paste the certificate.

3. Run `openssl x509 -in /tmp/certificate.pem -pubkey -noout > /tmp/public.pem` to extract the public key from the certificate and paste the public key into `rabbitmq.config`.

Expand Down
95 changes: 77 additions & 18 deletions site/oauth2-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ To understand the details of how to configure RabbitMQ with Oauth2, go to the [U

* [Prerequisites to follow this guide](#prerequisites)
* [Getting started with UAA and RabbitMQ](#getting-started-with-uaa-and-rabbitmq)
* [Use Access tokens](#use-access-tokens)
- [Management user accessing the Management UI](#management-user-accessing-the-management-ui)
- [Monitoring agent accessing management REST api](#monitoring-agent-accessing-management-rest-api)
* [Access Management UI using OAuth 2.0 tokens](#access-management-ui)
- [Service-Provider initiated logon](#service-provider-initiated-logon)
- [Identity-Provider initiated logon](#identity-provider-initiated-logon)
* [Access other protocols using OAuth 2.0 tokens](#access-other-protocols)
- [Management REST api](#monitoring-agent-accessing-management-rest-api)
- [AMQP protocol](#amqp-protocol)
- [JMS protocol](#jms-protocol)
- [MQTT protocol](#mqtt-protocol)
Expand Down Expand Up @@ -78,20 +80,26 @@ has to be configured to validate any of the two types of digital signatures.
Given that asymmetrical keys is the most widely used option, you are going to focus on how to
configure RabbitMQ with them.

Run the following 3 commands to get the environment ready to see Oauth 2.0 plugin in action:
Run the following 2 commands to get the environment ready to see Oauth 2.0 plugin in action:

1. `make start-uaa` to get UAA server running
2. `make setup-uaa-users-and-clients` to install uaac client; connect to UAA server and set ups users, group, clients and permissions
3. `make start-rabbitmq` to start RabbitMQ server
2. `make start-rabbitmq` to start RabbitMQ server

The last command starts a RabbitMQ server with [this](https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/main/conf/uaa/rabbitmq.config) configuration file.

## <a id="access-management-ui" class="anchor" href="#access-management-ui">Access Management UI using OAuth 2.0 tokens</a>

## <a id="use-access-tokens" class="anchor" href="#use-oauth-tokens">Use access tokens</a>
The RabbitMQ Management UI can be configured with one of these two login modes:

The following subsections demonstrate how to use access tokens with any messaging protocol and also to access the management ui and rest api.
* [Service-Provider initiated logon](#service-provider-initiated-logon): this is the default and traditional OAuth 2.0 logon mode.
When the user visits the RabbitMQ Management UI, it shows a button with the label `Click here to logon`. When the user clicks it,
the logon process starts by redirecting to the configured **Authorization Server**.
* [Identity-Provider initiated logon](#identity-provider-initiated-logon): this mode is opposite to the previous mode.
The user must first access the RabbitMQ Management's `/login` endpoint with a token. If the token is valid, the user is allowed to access the RabbitMQ Management UI.
This mode is very useful for Web sites which allow users to access the RabbitMQ Management UI with a single click.
The original Web site get a token on user's behalf and redirects the user to the RabbitMQ Management's `/login` endpoint.

### <a id="management-user-accessing-the-management-ui" class="anchor" href="#management-user-accessing-the-management-ui">Management user accessing the Management UI</a>
### <a id="service-provider-initiated-logon" class="anchor" href="#service-provider-initiated-logon">Service-Provider initiated logon</a>

The first time an end user arrives to the management UI, they are redirected to the configured OAuth 2.0 provider to authenticate.
Once they successfully authenticate, the user is redirected back to RabbitMQ
Expand All @@ -117,23 +125,72 @@ UAA has previously been configured and seeded with two users:

Now navigating to the [local node's management UI](http://localhost:15672) and login using any of those two users.

The user displayed by the management ui is not the user name but `rabbitmq_client` which is the
identity of RabbitMQ to work on half of the user.

This is a token issued by UAA for the `rabbit_admin` user thru the redirect flow you just saw above.
It was signed with the symmetric key.

![JWT token](./img/oauth2/admin-token-signed-sym-key.png)

### <a id="monitoring-agent-accessing-management-rest-api" class="anchor" href="#monitoring-agent-accessing-management-rest-api-2">Monitoring agent accessing management REST api</a>
To configure the RabbitMQ Management UI with OAuth 2.0, the following configuration entries are required
in `advanced.config`:

<pre class="lang-erlang">
...
{rabbitmq_management, [
{oauth_enabled, true},
{oauth_client_id, "rabbit_client_code"},
{oauth_provider_url, "http://localhost:8080"},
...
]},
</pre>

### <a id="identity-provider-initiated-logon" class="anchor" href="#identity-provider-initiated-logon">Identity-Provider initiated logon</a>

When RabbitMQ is provided as a service from a web portal, it is easy to navigate to the RabbitMQ Management UI
with a single click. The web portal retrieves a token before taking the user to the RabbitMQ Management UI web page.

<pre class="lang-plain">
[ Idp | WebPortal ] ----&gt; 2. /login [access_token: TOKEN]---- [ RabbitMQ Cluster ]
/|\ | /|\
| +--------+
1. rabbit_admin from a browser 3. validate token
</pre>

How it works, firstly, the `rabbit_admin` user navigates to the web portal and clicks on the hyperlink associated with a RabbitMQ
cluster. Next, the web portal obtains a token and redirects the user to RabbitMQ `/login` endpoint with the token within the HTTP form field `access_token`. Finally,
RabbitMQ validates the token in the http request and if it is valid, it redirects the user to the overview page.

By default, the RabbitMQ Management UI is configured with **service-provider initiated logon**, to configure **Identity-Provider initiated logon**,
add one entry to `advanced.config`. For example:

<pre class="lang-erlang">
...
{rabbitmq_management, [
{oauth_enabled, true},
{oauth_client_id, "rabbit_client_code"},
{oauth_provider_url, "http://localhost:8080"},
{oauth_initiated_logon_type, idp_initiated},
...
]},
</pre>

**Important**: when the user logs out, or its RabbitMQ session expired, or the token expired, the user is directed to the
RabbitMQ Management landing page which has a **Click here to login** button.
The user is never automatically redirected back to the url configured in the `oauth_provider_url`.
It is only when the user clicks **Click here to login** , the user is redirected to the configured url in `oauth_provider_url`.

## <a id="access-other-protocols" class="anchor" href="#access-other-protocols">Access other protocols using OAuth 2.0 tokens</a>

The following subsections demonstrate how to use access tokens with any messaging protocol and also to access the management rest api.

### <a id="monitoring-agent-accessing-management-rest-api" class="anchor" href="#monitoring-agent-accessing-management-rest-api-2">Management REST api</a>

In this scenario a monitoring agent uses RabbitMQ HTTP API to collect monitoring information.
Because it is not an end user, or human, you refer to it as a *service account*.
This *service account* could be our `mgt_api_client` client you created in UAA with the `monitoring` *user tag*.

This *monitoring agent* would use the *client credentials* or *password* grant flow to authenticate (1) with
UAA and get back a JWT token (2). Once it gets the token, it sends (3) a HTTP request
to the RabbitMQ management endpoint passing the JWT token.
to the RabbitMQ management endpoint passing the JWT token within the `Authorization` header as a *Bearer token*.

<pre class="lang-plain">
[ UAA ] [ RabbitMQ ]
Expand All @@ -148,7 +205,7 @@ to the RabbitMQ management endpoint passing the JWT token.
The following command launches the browser with `mgt_api_client` client with a JWT token previously obtained from UAA:

<pre class="lang-bash">
make curl url=http://localhost:15672/api/overview client_id=mgt_api_client secret=mgt_api_client
make curl-uaa url=http://localhost:15672/api/overview client_id=mgt_api_client secret=mgt_api_client
</pre>


Expand Down Expand Up @@ -293,7 +350,7 @@ a message to a mqtt topic ([scopes-for-mqtt.json](jwts/scopes-for-mqtt.json))
it is any "routing-key" because that is translated to a topic/queue.

You are going to publish a mqtt message by running the following command. If you have not run any of the
previous use cases, you need to launch rabbitmq first like this `make start-uaa`.
previous use cases, you need to launch rabbitmq first like this `make start-rabbitmq`.

<pre class="lang-bash">
make start-mqtt-publish TOKEN=$(bin/jwt_token scopes-for-mqtt.json legacy-token-key private.pem public.pem)
Expand Down Expand Up @@ -688,12 +745,14 @@ The following configuration snippets demonstrate these steps:
<pre class="lang-erlang">
[
{rabbitmq_management, [
%% eanble Oauth
{oauth_enabled, true},
%% use UAA
{enable_uaa, true},
%% OAuth 2 identity server client ID
{uaa_client_id, "rabbit_client"},
{oauth_client_id, "rabbit_client"},
%% UAA endpoint location
{uaa_location, "http://localhost:8080/uaa"}
{oauth_provider_url, "http://localhost:8080"}
]},
].
</pre>
Expand Down
Loading