rabbitmq-server/deps/rabbitmq_auth_backend_oauth2
Michael Klishin e5c84c31fa Pass decoded token so that effective username is computed from it
[#158782152]
[#158782156]
2018-07-06 17:35:34 +03:00
..
demo Fix demo script. Add rabbit_client client to request token. 2018-06-25 15:29:12 +01:00
scripts Add a seed script for development 2018-07-02 22:01:12 +03:00
src Pass decoded token so that effective username is computed from it 2018-07-06 17:35:34 +03:00
test Expect access token in the password field 2018-07-05 19:50:12 +03:00
.gitignore Init. Make request to /check_token 2016-01-15 14:50:21 +00:00
.travis.yml Use erlang 18.3 only in travis 2016-05-17 09:55:50 +01:00
Makefile Sync rabbitmq-components.mk, drop Elixir build system bits 2018-07-03 02:15:43 +03:00
README.md Fix demo script. Add rabbit_client client to request token. 2018-06-25 15:29:12 +01:00
erlang.mk Update erlang.mk 2017-08-30 19:35:00 +01:00
rabbitmq-components.mk Sync rabbitmq-components.mk, drop Elixir build system bits 2018-07-03 02:15:43 +03:00

README.md

RabbitMQ authorisation Backend for Cloud Foundry UAA

This RabbitMQ authentication/authorisation backend plugin lets Cloud Foundry UAA (OAuth 2.0) access tokens to be used by RabbitMQ client connections.

This plugin is experimental and targets RabbitMQ 3.7.0 only.

Supported RabbitMQ Versions

This plugins is developed for RabbitMQ 3.7 (currently in development). This plugin does not target RabbitMQ 3.6.x release series.

To test the plugin it has to be built from source together with RabbitMQ.

How it Works

Authorization Workflow

This plugin does not communicate with an UAA server. It decodes an access token provided by the client and authorises a user based on the data stored in the token.

The token can be any JWT token which contains the scope and aud fields. The way the token was retrieved (such as what grant type was used) is outside of the scope of this plugin.

Prerequisites

To use this plugin

  1. A symmetrically encrypted JWT token containing a set of RabbitMQ permission scopes.
  2. All RabbitMQ nodes must be configured to use the rabbit_auth_backend_uaa backend
  3. All RabbitMQ nodes must be configure with a resource service ID (resource_server_id) that matches the scope prefix (e.g. rabbitmq in rabbitmq.read:*/*).

Authorization Flow

  1. Client authorize with UAA, requesting an access_token (using any grant type desired)
  2. Token scope returned by UAA must include RabbitMQ resource scopes that follow a convention used by this plugin: configure:%2F/foo means "configure permissions for 'foo' in vhost '/'")
  3. Client passes the token as username when connecting to a RabbitMQ node. The password field is ignored.

Usage

The plugin needs a UAA signing key to be configured in order to decrypt and verify client-provided tokens. To get the signing key from a running UAA node, use the token_key endpoint or uaac (the uaac signing key command).

The following fields are required: kty, value, alg, and kid.

Assuming UAA reports the following signing key information:

uaac signing key
  kty: RSA
  e: AQAB
  use: sig
  kid: a-key-ID
  alg: RS256
  value: -----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2dP+vRn+Kj+S/oGd49kq
6+CKNAduCC1raLfTH7B3qjmZYm45yDl+XmgK9CNmHXkho9qvmhdksdzDVsdeDlhK
IdcIWadhqDzdtn1hj/22iUwrhH0bd475hlKcsiZ+oy/sdgGgAzvmmTQmdMqEXqV2
B9q9KFBmo4Ahh/6+d4wM1rH9kxl0RvMAKLe+daoIHIjok8hCO4cKQQEw/ErBe4SF
2cr3wQwCfF1qVu4eAVNVfxfy/uEvG3Q7x005P3TcK+QcYgJxav3lictSi5dyWLgG
QAvkknWitpRK8KVLypEj5WKej6CF8nq30utn15FQg0JkHoqzwiCqqeen8GIPteI7
VwIDAQAB
-----END PUBLIC KEY-----
  n: ANnT_r0Z_io_kv6BnePZKuvgijQHbggta2i30x-wd6o5mWJuOcg5fl5oCvQjZh15IaPar5oXZLHcw1bHXg5YSiHXCFmnYag83bZ9YY_9tolMK4R9G3eO-YZSnLImfqMv7HYBoAM75pk0JnTKhF6ldgfavShQZqOAIYf-vneMDNax_ZMZdEbzACi3vnWqCByI6JPIQju
      HCkEBMPxKwXuEhdnK98EMAnxdalbuHgFTVX8X8v7hLxt0O8dNOT903CvkHGICcWr95YnLUouXcli4BkAL5JJ1oraUSvClS8qRI-Vino-ghfJ6t9LrZ9eRUINCZB6Ks8Igqqnnp_BiD7XiO1c

it will translate into the following configuration (in the advanced RabbitMQ config format):

[
  %% ...
  %% backend configuration
  {rabbitmq_auth_backend_uaa, [{resource_server_id, <<"my_rabbit_server">>}]},
  %% UAA signing key configuration
  {uaa_jwt, [
    {signing_keys, #{
        <<"a-key-ID">> => {map, #{<<"kty">> => <<"RSA">>,
                                          <<"alg">> => <<"RS256">>,
                                          <<"value">> => <<"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2dP+vRn+Kj+S/oGd49kq
6+CKNAduCC1raLfTH7B3qjmZYm45yDl+XmgK9CNmHXkho9qvmhdksdzDVsdeDlhK
IdcIWadhqDzdtn1hj/22iUwrhH0bd475hlKcsiZ+oy/sdgGgAzvmmTQmdMqEXqV2
B9q9KFBmo4Ahh/6+d4wM1rH9kxl0RvMAKLe+daoIHIjok8hCO4cKQQEw/ErBe4SF
2cr3wQwCfF1qVu4eAVNVfxfy/uEvG3Q7x005P3TcK+QcYgJxav3lictSi5dyWLgG
QAvkknWitpRK8KVLypEj5WKej6CF8nq30utn15FQg0JkHoqzwiCqqeen8GIPteI7
VwIDAQAB
-----END PUBLIC KEY-----">>}}
        }}
    ]}
].

If you are using a symmetric key, the configuration will look like this:

[ {rabbitmq_auth_backend_uaa, [{resource_server_id, <<"my_rabbit_server">>}]},
  {uaa_jwt, [
    {signing_keys, #{
        <<"a-key-ID">> => {map, #{<<"kty">> => <<"MAC">>,
                                  <<"alg">> => <<"HS256">>,
                                  <<"value">> => <<"my_signing_key">>}}
        }}
    ]}
].

Key signature verification is implemented by the UAA JWT library.

Resource Server ID and Scope Prefixes

OAuth 2.0 and (thus UAA-provided) tokens use scopes to communicate what set of permissions are particular client has been granted. The scopes are free form strings.

resource_server_id is a prefix used for scopes in UAA to avoid scope collisions (or unintended overlap). It is an empty string by default.

Scope-to-Permission Translation

Scopes are translated into permission grants to RabbitMQ resources for the provided token.

The current scope format is <permission>:<vhost_pattern>/<name_pattern>[/<routing_key_pattern>] where

  • <permission> is an access permission (configure, read, or write)
  • <vhost_pattern> is a wildcard pattern for vhosts, token has access to.
  • <name_pattern> is a wildcard pattern for resource name
  • <routing_key_pattern> is an optional wildcard pattern for routing key in topic authorization

Wildcard patterns are strings with optional wildcard symbols * that match any sequence of characters.

Wildcard patterns match as wollowing:

  • * matches any string
  • foo* matches any string starting with a foo
  • *foo matches any string ending with a foo
  • foo*bar matches any string starting with a foo and ending with a bar

There can be multiple wildcards in a pattern:

  • start*middle*end
  • *before*after*

If you want to use special characters like *, %, or / in a wildacrd pattern, the pattern must be URL-encoded.

These are the typical permissions examples:

  • read:*/*(read:*/*/*) - read permissions to any resource on any vhost
  • write:*/*(write:*/*/*) - write permissions to any resource on any vhost
  • read:vhost1/*(read:vhost1/*/*) - read permissions to any resource on the vhost1 vhost
  • read:vhost1/some* - read permissions to all the resources, starting with some on the vhost1 vhost
  • write:vhsot1/some*/routing* - topic write permissions to publish to an exchange starting with some with a routing key starting with routing

See the [./test/wildcard_match_SUITE.erl](wildcard matching test suite) and [./test/scope_SUITE.erl](scopes test suite) for more examples.

Scopes should be prefixed with resource_server_id. For example, if resource_server_id is "my_rabbit", a scope to enable read from any vhost will be my_rabbit.read:*/*.

Using Tokens with Clients

A client must present a valid access_token acquired from UAA as username in order to authenticate with RabbitMQ.

To learn more about UAA/OAuth 2.0 clients see UAA docs.

Examples

The demo directory contains example configuration files which can be used to set up a development UAA server and issue tokens, which can be used to access RabbitMQ resources.

UAA and RabbitMQ Config Files

To run the demo you need to have a UAA node intalled or built from source.

To make UAA use a particular config file, such as those provided in the demo directory, export the CLOUD_FOUNDRY_CONFIG_PATH environment variable. For example, to use symmetric keys, see the UAA config files under the demo/symmetric_keys directory.

demo/symmetric_keys/rabbit.config contains a RabbitMQ configuration file that sets up a matching signing key on the RbbitMQ end.

Running UAA

To run UAA with a custom config file path, use the following from the UAA git repository:

CLOUD_FOUNDRY_CONFIG_PATH=<path_to_plugin>/demo/symmetric_keys ./gradlew run

Running RabbitMQ

RABBITMQ_CONFIG_FILE=<path_to_plugin>/demo/symmetric_keys/rabbitmq rabbitmq-server
## Or to run from source from the plugin directory
make run-broker RABBITMQ_CONFIG_FILE=demo/symmetric_keys/rabbitmq

The rabbitmq_auth_backend_uaa plugin must be enabled on the RabbitMQ node.

Asymmetric Key Example

To use an RSA (asymmetric) key, you can set CLOUD_FOUNDRY_CONFIG_PATH to demo/rsa_keys. This directory also contains rabbit.config file, as well as a public key (public_key.pem) which will be used for signature verification.

UAA User and Permission Management

UAA sets scopes from client scopes and user groups. The demo uses groups to set up a set of RabbitMQ permissions scopes.

The demo/setup.sh script can be used to configure a demo user and groups. The script will also create RabbitMQ resources associated with permissions. The script uses uaac and bunny (RabbitMQ client) and requires them to be installed.

When running the script, UAA server and RabbitMQ server should be running. You should configure UAA_HOST (localhost:8080/uaa for local machine) and RABBITMQCTL (a path to rabbitmqctl script) environment variables to run this script.

gem install uaac
gem install bunny
RABBITMQCTL=<path_to_rabbitmqctl> demo/setup.sh

Please refer to demo/setup.sh to get more info about configuring UAA permissions.

The script will return an access tokens, which can be used to authorise in RabbitMQ. When authorising, you should use the token as a username.

(c) 2016-2017 Pivotal Software Inc.

Released under the Mozilla Public License 1.1, same as RabbitMQ.