diff --git a/site/management.md b/site/management.md index 16dae15f84..7f8c7994fe 100644 --- a/site/management.md +++ b/site/management.md @@ -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:
 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
 
-> 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 @@ -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 @@ -348,12 +354,6 @@ curl -i --header "authorization: Bearer <token>" 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. @@ -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. + ### Configure OpenID Connect Discovery endpoint By default, RabbitMQ assumes the OpenID Connect Discovery endpoint is at `/.well-known/openid-configuration`. If your endpoint differs, you can set yours via the `management.oauth_metadata_url` setting. @@ -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 +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: + +
+management.oauth_enabled = true
+management.oauth_initiated_logon_type = idp_initiated
+management.oauth_provider_url = https://my-web-portal
+
+ ## HTTP API diff --git a/site/oauth2-examples-azure.md b/site/oauth2-examples-azure.md index c1d98a04b1..8b3d6c273d 100644 --- a/site/oauth2-examples-azure.md +++ b/site/oauth2-examples-azure.md @@ -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**. - - ⚠️ **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 @@ -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`
@@ -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, [
diff --git a/site/oauth2-examples-keycloak.md b/site/oauth2-examples-keycloak.md
index 7382c72bd5..f3b19fe283 100644
--- a/site/oauth2-examples-keycloak.md
+++ b/site/oauth2-examples-keycloak.md
@@ -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`
-* In tab `Credentials` you have the client id secret
+* In the `Credentials` tab, you have the `client id`
 
 
 ### Configure Client scopes
diff --git a/site/oauth2-examples-oauth0.md b/site/oauth2-examples-oauth0.md
index 2debe26ad2..6750e93e4a 100644
--- a/site/oauth2-examples-oauth0.md
+++ b/site/oauth2-examples-oauth0.md
@@ -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`.
 
diff --git a/site/oauth2-examples.md b/site/oauth2-examples.md
index 46c5b56cbe..30aad8b551 100644
--- a/site/oauth2-examples.md
+++ b/site/oauth2-examples.md
@@ -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)
@@ -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.
 
+## Access Management UI using OAuth 2.0 tokens
 
-## Use access tokens
+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.
 
-### Management user accessing the Management UI
+### Service-Provider initiated logon
 
 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
@@ -117,15 +125,64 @@ 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)
 
-### Monitoring agent accessing management REST api
+To configure the RabbitMQ Management UI with OAuth 2.0, the following configuration entries are required
+in `advanced.config`:
+
+
+ ...
+ {rabbitmq_management, [
+    {oauth_enabled, true},
+    {oauth_client_id, "rabbit_client_code"},
+    {oauth_provider_url, "http://localhost:8080"},      
+    ...
+  ]},
+
+ +### Identity-Provider initiated logon + +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. + +
+    [ Idp | WebPortal ] ----> 2. /login [access_token: TOKEN]----   [ RabbitMQ Cluster ]            
+              /|\                                                        |       /|\
+               |                                                         +--------+
+      1. rabbit_admin from a browser                                   3. validate token        
+
+ +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: + +
+ ...
+ {rabbitmq_management, [
+    {oauth_enabled, true},
+    {oauth_client_id, "rabbit_client_code"},
+    {oauth_provider_url, "http://localhost:8080"},      
+    {oauth_initiated_logon_type, idp_initiated},
+    ...
+  ]},
+
+ +**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`. + +## Access other protocols using OAuth 2.0 tokens + +The following subsections demonstrate how to use access tokens with any messaging protocol and also to access the management rest api. + +### Management REST api 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*. @@ -133,7 +190,7 @@ This *service account* could be our `mgt_api_client` client you created in UAA w 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*.
 [ UAA ]                  [ RabbitMQ ]
@@ -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:
 
 
-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
 
@@ -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`.
 make start-mqtt-publish TOKEN=$(bin/jwt_token scopes-for-mqtt.json legacy-token-key private.pem public.pem)
@@ -688,12 +745,14 @@ The following configuration snippets demonstrate these steps:
 
 [
   {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"}
   ]},
 ].
 
diff --git a/site/oauth2.md b/site/oauth2.md index ed6641b188..9d999941f8 100644 --- a/site/oauth2.md +++ b/site/oauth2.md @@ -33,6 +33,7 @@ This guide covers * [Using Tokens with Clients](#use-tokens-with-clients) * [Scope and Tags](#scope-and-tags) * [Token Expiration and Refresh](#token-expiration) + * [Preferred username claims](#preferred-username-claims) * [Rich Authorization Request](#rich-authorization-request) * [Examples](#examples) @@ -164,6 +165,7 @@ NOTE: `jwks_url` takes precedence over `signing_keys` if both are provided. | Key | Documentation |------------------------------------------|----------- | `auth_oauth2.resource_server_id` | [The Resource Server ID](#resource-server-id-and-scope-prefixes) +| `auth_oauth2.resource_server_type` | [The Resource Server Type](#rich-authorization-request) | `auth_oauth2.additional_scopes_key` | Configure the plugin to also look in other fields (maps to `additional_rabbitmq_scopes` in the old format). | `auth_oauth2.default_key` | ID of the default signing key. | `auth_oauth2.signing_keys` | Paths to signing key files. @@ -314,6 +316,24 @@ In the OAuth context, tags can be added as part of the scope, using a format lik example, if `resource_server_id` is "my_rabbit", a scope to grant access to the management plugin with the `monitoring` tag will be `my_rabbit.tag:monitoring`. +### Preferred username claims + +The username associated with the token must be available to RabbitMQ so that this username is displayed in the RabbitMQ Management UI. +By default, RabbitMQ searches for the `sub` claim first, and if it is not found, RabbitMQ uses the `client_id`. + +Most authorization servers return the user's GUID in the `sub` claim instead of the user's username or email address, anything the user can relate to. When the `sub` claim does not carry a *user-friendly username*, you can configure one or several claims to extract the username from the token. + +Example `advanced.config` configuration: + +
+  ...
+  {rabbitmq_auth_backend_oauth2, [
+    {resource_server_id, <<"rabbitmq">>},
+    {preferred_username_claims, [<<"user_name">>,<<"email">>]},
+  ...
+
+In the example configuration, RabbitMQ searches for the `user_name` claim first and if it is not found, RabbitMQ searches for the `email`. If these are not found, RabbitMQ uses its default lookup mechanism which first looks for `sub` and then `client_id`. + ### Token Expiration and Refresh On an existing connection the token can be refreshed by the [update-secret](https://rabbitmq.com/amqp-0-9-1-reference.html#connection.update-secret) AMQP 0.9.1 method. Please check your client whether it supports this method. (Eg. see documentation of the [Java client](https://rabbitmq.com/api-guide.html#oauth2-refreshing-token).) Otherwise the client has to disconnect and reconnect to use a new token.