Skip to content

Commit 83bde59

Browse files
Merge pull request #2091 from rabbitmq/support-scope-aliases-in-cuttlefish-style
4.1: OAuth 2: support scope aliases in rabbitmq.conf
2 parents d13f6b9 + 4ce0b26 commit 83bde59

File tree

7 files changed

+134
-129
lines changed

7 files changed

+134
-129
lines changed

docs/oauth2-examples-okta.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,11 +186,14 @@ This is totally optional but it can save you time.
186186

187187
## Configure RabbitMQ to use Okta as OAuth 2.0 Authentication Backend
188188

189-
The configuration on Okta side is done. You now have to configure RabbitMQ to use the resources you just created. You took note of the following values:
189+
The configuration on the Okta side is now done. The next step is to configure RabbitMQ
190+
to use the resources created earlier.
190191

191-
- **okta_client_app_ID** associated to the okta app that you registered in okta for rabbitMQ.
192-
- **okta-Issuer** associated to the **default Authorization server**.
193-
- **okta-Metadata-URI** associated to the **default Authorization server**.
192+
The following values will be necessary during the next steps:
193+
194+
* **okta_client_app_ID**: the Okta app registered above to be used with RabbitMQ
195+
* **okta-Issuer**: the **default Authorization server**
196+
* **okta-Metadata-URI**: the **default Authorization server**
194197

195198
Clone [rabbitmq.conf.tmpl](https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/tree/next/conf/okta/rabbitmq.conf.tmpl) as `rabbitmq.conf` (in the same folder as `rabbitmq.conf.tmpl`).
196199
There is a second configuration file, [advanced.config](https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/tree/next/conf/okta/advanced.config),
@@ -205,6 +208,15 @@ or `{okta-issuer}/.well-known/openid-configuration`
205208
4. Else you need to determine the path that follows the uri in `{okta-issuer}` and update
206209
`auth_oauth2.discovery_endpoint_path` accordingly. For instance, if **okta-Metadata-URI** is `{okta-issuer}/some-other-endpoint`, you update `auth_oauth2.discovery_endpoint_path` with the value `some-other-endpoint`.
207210

211+
The mapping of the roles configured in Okta, such as `monitoring` and `admin`, are configured
212+
at the bottom of the `rabbitmq.conf` file. For example:
213+
214+
```ini
215+
#...
216+
auth_oauth2.scope_aliases.admin = okta.read:*/* okta.write:*/* okta.configure:*/* okta.tag:administrator
217+
auth_oauth2.scope_aliases.monitoring = okta.tag:management okta.read:*/
218+
#...
219+
```
208220

209221
### About OpenId Discovery Endpoint
210222

docs/oauth2-examples/index.md

Lines changed: 32 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -528,116 +528,59 @@ make curl-with-token URL=http://localhost:15672/api/overview TOKEN=$(bin/jwt_tok
528528

529529
### Using Scope Aliases {#using-scope-aliases}
530530

531-
*Custom scopes*? are any scope whose format is not compliant with RabbitMQ format.
532-
For instance, `api://rabbitmq:Read.All` is one of the custom scopes you will use in this use case.
531+
This example demonstrates how to use custom scopes with RabbitMQ.
533532

534-
#### How to Configure RabbitMQ to Use a Custom Scope Mapping
533+
**UAA** identity provider has been configured with two clients (`producer_with_roles`
534+
and `consumer_with_roles`) with the following custom scopes:
535535

536-
See below a sample RabbitMQ configuration where you map `api://rabbitmq:Read.All`
537-
custom scope to `rabbitmq.read:*/*` RabbitMQ scope.
536+
`producer_with_roles` with
537+
- `api://rabbitmq:producer`.
538538

539-
``` erl
540-
{rabbitmq_auth_backend_oauth2, [
541-
%%...,
542-
{scope_aliases, #{
543-
<<"api://rabbitmq:Read.All">> => [<<"rabbitmq.read:*/*">>],
544-
...
545-
},
546-
%%...
547-
]}
548-
```
549-
550-
Additionally, you can map a custom scope to many RabbitMQ scopes. For instance below you
551-
are mapping the role `api://rabbitmq:producer` to 3 RabbitMQ scopes which grants
552-
`read`, `write` and `configure` access on any resource and on any vhost:
553-
554-
``` erl
555-
{rabbitmq_auth_backend_oauth2, [
556-
%% ...,
557-
558-
{scope_aliases, #{
559-
<<"api://rabbitmq:producer">> => [
560-
<<"rabbitmq.read:*/*">>,
561-
<<"rabbitmq.write:*/*">>,
562-
<<"rabbitmq.configure:*/*">>
563-
]
564-
}},
565-
%% ...
566-
]}
567-
```
568-
569-
#### Scopes Aliases in JWT Tokens
539+
`consumer_with_roles` with
540+
- `api://rabbitmq:Read.All`.
541+
- `api://rabbitmq:Write.All`.
542+
- `api://rabbitmq:Configure.All`.
543+
- `api://rabbitmq:Administrator`.
570544

571-
If you do not configure RabbitMQ OAuth 2.0 plugin with `extra_scopes_source`, RabbitMQ
572-
expects the `scope` token's field to carry *custom scopes*. For instance, below you have a sample JWT
573-
token where the custom scopes are in the `scope` field :
545+
For more information about scope aliases, check out
546+
the [section](./oauth2#scope-aliases) that explains it in more detail.
574547

575-
```javascript
576-
{
577-
"sub": "producer",
578-
"scope": [
579-
"api://rabbitmq:producer",
580-
"api://rabbitmq:Administrator"
581-
],
582-
"aud": [
583-
"rabbitmq"
584-
]
585-
}
586-
```
548+
#### How to Configure Scope Aliases
587549

588-
Now, let's say you do configure RabbitMQ OAuth 2.0 plugin with `extra_scopes_source` as shown below:
550+
This is the configuration required to map those custom scopes to RabbitMQ scopes.
589551

552+
:::tip
553+
Since RabbitMQ 4.1, it is possible to configure **scope aliases** using the [ini-like](./configure#config-file) configuration style. Earlier versions only supported
554+
the legacy Erlang-style.
555+
:::
590556

591557
```ini
592-
# ...
593-
auth_oauth2.resource_server_id = rabbitmq
594-
auth_oauth2.additional_scopes_key = roles
595-
# ...
596-
```
597-
598-
With this configuration, RabbitMQ expects *custom scopes* in the field `roles` and
599-
the `scope` field is ignored.
558+
auth_oauth2.scope_aliases.1.alias = api://rabbitmq:Read.All
559+
auth_oauth2.scope_aliases.1.scope = rabbitmq.read:*/*
600560

601-
```javascript
602-
{
603-
"sub": "rabbitmq-client-code",
604-
"roles": "api://rabbitmq:Administrator.All",
605-
"aud": [
606-
"rabbitmq"
607-
]
608-
}
609-
```
561+
auth_oauth2.scope_aliases.2.alias = api://rabbitmq:Write.All
562+
auth_oauth2.scope_aliases.2.scope = rabbitmq.write:*/*
610563

611-
#### UAA Configuration
564+
auth_oauth2.scope_aliases.3.alias = api://rabbitmq:Configure.All
565+
auth_oauth2.scope_aliases.3.scope = rabbitmq.configure:*/*
612566

613-
To demonstrate this new capability you have configured UAA with two Oauth 2.0 clients. One
614-
called `producer_with_roles` with the *custom scope* `api://rabbitmq:producer` and `consumer_with_roles` with
615-
`api://rabbitmq:Read:All,api://rabbitmq:Configure:All,api://rabbitmq:Write:All`.
616-
> You are granting configure and write permissions to the consumer because you have configured perf-test to declare
617-
resources regardless whether it is a producer or consumer application.
567+
auth_oauth2.scope_aliases.3.alias = api://rabbitmq:Administrator
568+
auth_oauth2.scope_aliases.3.scope = rabbitmq.tag:administrator
618569

619-
These two uaac commands declare the two OAuth 2.0 clients above. You are adding an extra scope called `rabbitmq.*` so
620-
that UAA populates the JWT claim `aud` with the value `rabbitmq`. RabbitMQ expects `aud` to match the value you
621-
configure RabbitMQ with in the `resource_server_id` field.
570+
auth_oauth2.scope_aliases.4.alias = api://rabbitmq:producer
571+
auth_oauth2.scope_aliases.4.scope = rabbitmq.read:*/* rabbitmq.write:*/* rabbitmq.configure:*/* rabbitmq.tag:management
622572

623-
```bash
624-
uaac client add producer_with_roles --name producer_with_roles \
625-
--authorities "rabbitmq.*,api://rabbitmq:producer,api://rabbitmq:Administrator" \
626-
--authorized_grant_types client_credentials \
627-
--secret producer_with_roles_secret
628-
uaac client add consumer_with_roles --name consumer_with_roles \
629-
--authorities "rabbitmq.* api://rabbitmq:read:All" \
630-
--authorized_grant_types client_credentials \
631-
--secret consumer_with_roles_secret
632573
```
633574

634575

635576
#### RabbitMQ Configuration
636577

637578
In the OAuth 2.0 tutorial repository, there are two RabbitMQ configuration files ready to be used, for UAA:
638579

639-
- [conf/uaa/advanced-scope-aliases.config](https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/conf/uaa/advanced-scope-aliases.config): configures a set of scope aliases.
640-
- [conf/uaa/rabbitmq.conf](https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/conf/uaa/rabbitmq.conf) : configure the rest of oauth2 configuration in addition to configuring `extra_scope` as another claim from where to read scopes from
580+
* [conf/uaa/advanced-scope-aliases.config](https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/conf/uaa/advanced-scope-aliases.config):
581+
configures a set of scope aliases.
582+
* [conf/uaa/rabbitmq.conf](https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/conf/uaa/rabbitmq.conf):
583+
configure the rest of oauth2 configuration in addition to configuring `extra_scope` as another claim from where to read scopes from
641584

642585

643586
#### Demo 1: Launch RabbitMQ with custom scopes in scope field

docs/oauth2.md

Lines changed: 59 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ auth_backends.1 = rabbit_auth_backend_oauth2
7979

8080
Next, let's take a look at the workflows the OAuth 2 plugin supports.
8181

82-
### Prerequisites {#prerequisites}
82+
## Prerequisites {#prerequisites}
8383

8484
To use the OAuth 2 plugin, all RabbitMQ nodes must be
8585

@@ -116,7 +116,7 @@ auth_oauth2.discovery_endpoint_params.appid = some-app-id
116116

117117
More detail is included in the next section about what happens during the authentication and how to configure OAuth 2.0 beyond the basic configuration shown previously.
118118

119-
### Authorization Flow {#authorization-flow}
119+
## Authorization Flow {#authorization-flow}
120120

121121
This plugin does not communicate with any OAuth 2.0 provider in order to authenticate user and grants access. Instead, it decodes an access token provided by the client and authorises a user based on the scopes found in the token.
122122

@@ -138,7 +138,7 @@ In chronological order, here is the sequence of events that occur when a client
138138
5. RabbitMQ validates that the token has the **audience** claim and whose value matches the `resource_server_id` (this operation can be deactivated by setting `auth_oauth2.verify_aud` to `false`).
139139
6. RabbitMQ translates the **scopes** found in the token into RabbitMQ **permissions** (the same permissions used in the RabbitMQ's internal database).
140140

141-
### Variables configurable in rabbitmq.conf {#variables-configurable}
141+
## Variables Configurable in rabbitmq.conf {#variables-configurable}
142142

143143
| Key | Documentation
144144
|--------------------------------------------|-----------
@@ -150,8 +150,6 @@ In chronological order, here is the sequence of events that occur when a client
150150
| `auth_oauth2.default_key` | ID of the default signing key.
151151
| `auth_oauth2.signing_keys` | Paths to the [signing key files](#signing-key-files).
152152
| `auth_oauth2.issuer` | The [issuer URL](#configure-issuer) of the authorization server that is used to either discover endpoints such as `jwks_uri` and/or where to redirect RabbitMQ management users to login and get a token.
153-
| `auth_oauth2.discovery_endpoint_path` | The path used for the [OpenId discovery endpoint](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata). The endpoint URI is built using `auth_oauth2.issuer`, this path or else the default path `.well-known/openid-configuration` followed by query parameters configured in the following variable
154-
| `auth_oauth2.discovery_endpoint_params` | [List of HTTP query parameters](#discovery-endpoint-params) sent to the OpenId discovery endpoint.
155153
| `auth_oauth2.jwks_uri` | The URL of the [JWKS endpoint](#jwks-endpoint). According to the [JWT Specification](https://datatracker.ietf.org/doc/html/rfc7515#section-4.1.2), the endpoint URL must be https. Optional if you set `auth_oauth2.issuer`. If this URL is set, it overrides the `jwks_uri` discovered via the discovery endpoint.
156154
| `auth_oauth2.jwks_url` | This variable is **deprecated** and you should use instead `auth_oauth2.jwks_uri`. In RabbitMQ 4.2.0, this variable will be removed. In the meantime, RabbitMQ supports it until you change your configuration.
157155
| `auth_oauth2.token_endpoint` | The URL of the OAuth 2.0 token endpoint. Optional if you set `auth_oauth2.issuer`. If this URL is set, it overrides the `token_endpoint` discovered via the discovery endpoint.
@@ -168,7 +166,7 @@ In chronological order, here is the sequence of events that occur when a client
168166
| `auth_oauth2.default_oauth_provider` | ID of the OAuth 2.0 provider used for the `auth_oauth2.resource_servers`, that did not specify any (via the variable `oauth_provider_id`) or when `auth_oauth2.jwks_uri` and `auth_oauth2.issuer` are both missing.
169167

170168

171-
#### Resource Server ID {#resource-server-id}
169+
## Resource Server ID {#resource-server-id}
172170

173171
A RabbitMQ cluster must have at least one resource server identifier configured. If it has just one resource, this is configured in the `auth_oauth2.resource_server_id` variable and it is **mandatory**.
174172
If the RabbitMQ cluster has more than one OAuth resource then they are configured under `auth_oauth2.resource_servers.<index>` and in this case `auth_oauth2.resource_server_id` variable is not mandatory.
@@ -177,7 +175,7 @@ RabbitMQ uess the resource server identity for these two purposes:
177175
- To validate the token's audience (`aud`) whose value must contain the resource server identifier. This validation can be disabled though.
178176
- To initiate the OAuth 2.0 Authorization Code flow in the Management UI. This is the flow used to authenticate a user and to get its access token. RabbitMQ must include the resource server identifier in the request's attribute called `resource`.
179177

180-
#### Scope prefix {#scope-prefix}
178+
## Scope Prefix {#scope-prefix}
181179

182180
OAuth 2.0 tokens use scopes to communicate what set of permissions particular client are granted. The scopes are free form strings.
183181

@@ -198,7 +196,56 @@ auth_oauth2.scope_prefix = ''
198196
...
199197
```
200198

201-
#### Signing keys files {#signing-key-files}
199+
## Scope Aliases {#scope-aliases}
200+
201+
:::important
202+
203+
Scope aliases are necessary when scopes in the RabbitMQ format cannot be
204+
configured on the identity provider (IDP) side
205+
206+
:::
207+
208+
A scope alias is a mapping between a custom JWT token scope and a set of RabbitMQ-specific scopes. A custom
209+
scope can also be defined as any scope which is not recogonized by RabbitMQ's OAuth 2 subsystem.
210+
211+
Scope aliases are necessary when scopes in the RabbitMQ format cannot be
212+
configured on the identity provider (IDP) side. Instead, a set of names is configured
213+
on the IDP side, and mapped to a set of scoped that RabbitMQ can parse and use.
214+
215+
For instance, let's consider an identity provider with the following two roles:
216+
217+
* `admin`
218+
* `developer`
219+
220+
These roles should be mapped to the following RabbitMQ scopes:
221+
222+
* `admin` to `rabbitmq.tag:administrator rabbitmq.read:*/`
223+
* `developer` to `rabbitmq.tag:management rabbitmq.read:*/* rabbitmq.write:*/* rabbitmq.configure:*/*`
224+
225+
The following `rabbitmq.conf` example performs the aforementioned mapping using scope aliases. The mapping can be one-to-one or one-to-many:
226+
227+
```ìni
228+
# ...
229+
# the "admin" role above
230+
auth_oauth2.scope_aliases.admin = rabbitmq.tag:administrator rabbitmq.read:*/
231+
# the "developer" role above
232+
auth_oauth2.scope_aliases.developer = rabbitmq.tag:management rabbitmq.read:*/* rabbitmq.write:*/* rabbitmq.configure:*/*
233+
# ...
234+
```
235+
236+
Sometimes an alias may have to use special characters and symbols including the separator character, `.`.
237+
In those cases, configure the scope aliases as follows:
238+
239+
```ìni
240+
# ...
241+
auth_oauth2.scope_aliases.1.alias = api://admin
242+
auth_oauth2.scope_aliases.1.scope = rabbitmq.tag:administrator rabbitmq.read:*/
243+
auth_oauth2.scope_aliases.2.alias = api://developer.All
244+
auth_oauth2.scope_aliases.2.scope = rabbitmq.tag:management rabbitmq.read:*/* rabbitmq.write:*/* rabbitmq.configure:*/*
245+
# ...
246+
```
247+
248+
## Signing Keys Files {#signing-key-files}
202249

203250
The following configuration declares two signing keys and configures the kid of the default signing key. For more information check the section [Configure Signing keys](#configure-signing-keys).
204251

@@ -214,7 +261,7 @@ auth_oauth2.algorithms.1 = HS256
214261
auth_oauth2.algorithms.2 = RS256
215262
```
216263

217-
#### JWKS endpoint {#jwks-endpoint}
264+
## JWKS endpoint {#jwks-endpoint}
218265

219266
The following configuration sets the JWKS endpoint from which RabbitMQ downloads the signing keys using the configured CA certificate and TLS variables.
220267

@@ -231,7 +278,7 @@ auth_oauth2.algorithms.2 = RS256
231278
```
232279

233280

234-
#### Multiple Resource Servers configuration {#multiple-resource-servers-configuration}
281+
## Multiple Resource Servers Сonfiguration {#multiple-resource-servers-configuration}
235282

236283
Each `auth_oauth2.resource_servers.<id/index>.` entry has the following variables shown in the table below. Except for the variables `id` and `oauth_provider_id`, if a resource does not configure a variable, RabbitMQ uses the variable configured at the root level. For instance, if the resource `auth_oauth2.resource_servers.prod` does not configure `preferred_username_claims` variable, RabbitMQ uses the value configured in `auth_oauth2.preferred_username_claims` for the resource `prod`.
237284

@@ -241,6 +288,7 @@ Each `auth_oauth2.resource_servers.<id/index>.` entry has the following variable
241288
| `resource_server_type` | The Resource Server Type required when using [Rich Authorization Request](#rich-authorization-request) token format.
242289
| `additional_scopes_key` | Configure the plugin to look for scopes in other fields (maps to `additional_rabbitmq_scopes` in the old format).
243290
| `scope_prefix` | [Configure the prefix for all scopes](#scope-prefix). The default value is `auth_oauth2.resource_server_id` followed by the dot `.` character.
291+
| `scope_aliases` | [Configure scope aliases](#scope-aliases)
244292
| `preferred_username_claims` | [List of the JWT claims](#preferred-username-claims) to look for the username associated with the token separated by commas.
245293
| `oauth_provider_id` | The identifier of the OAuth Provider associated to this resource. RabbitMQ uses the signing keys issued by this OAuth Provider to validate tokens whose audience matches this resource's id.
246294

@@ -259,7 +307,7 @@ auth_oauth2.resource_servers.2.id = dev
259307

260308
See the advanced usage section called [Multiple Resource Servers](#multiple-resource-servers) for more information on how to configure them.
261309

262-
#### Multiple OAuth Providers configuration {#multiple-oauth-providers-configuration}
310+
## Multiple OAuth Providers Сonfiguration {#multiple-oauth-providers-configuration}
263311

264312
Each `auth_oauth2.oauth_providers.{id/index}` entry has the following sub-keys.
265313

versioned_docs/version-3.13/oauth2-examples-okta.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,15 @@ Once you've added the user to the appropriate groups and apps, they should have
150150

151151
## Configure RabbitMQ to use Okta as OAuth 2.0 Authentication Backend
152152

153-
The configuration on Okta side is done. You now have to configure RabbitMQ to use the resources you just created.
153+
The configuration on the Okta side is now done. The next step is to configure RabbitMQ
154+
to use the resources created earlier.
154155

155156
[rabbitmq.conf](https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/tree/main/conf/okta/rabbitmq.conf) is a RabbitMQ configuration to **enable okta as OAuth 2.0 authentication backend** for the RabbitMQ OAuth2 and Management plugins. And [advanced.config](https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/tree/main/conf/okta/advanced.config) is the RabbitMQ advanced configuration that maps RabbitMQ scopes to the permissions previously configured in Okta.
156157

157-
Update it with the following values (you should have noted these in the previous steps):
158+
Update it with the following values from the earlier steps:
158159

159-
- **okta-domain-name** associated to your okta domain name.
160-
- **okta_client_app_ID** associated to the okta app that you registered in okta for rabbitMQ.
160+
* **okta-domain-name**: the Okta domain name
161+
* **okta_client_app_ID**: the Okta app registered above to be used with RabbitMQ
161162

162163

163164
## Start RabbitMQ

0 commit comments

Comments
 (0)