1"use strict";(self.webpackChunkrabbitmq_website=self.webpackChunkrabbitmq_website||[]).push([["1957"],{1716(e,n,i){i.r(n),i.d(n,{metadata:()=>t,default:()=>d,frontMatter:()=>r,contentTitle:()=>o,toc:()=>l,assets:()=>c});var t=JSON.parse('{"id":"oauth2-examples/index","title":"OAuth 2.0 Authentication Examples","description":"\x3c!--","source":"@site/versioned_docs/version-4.3/oauth2-examples/index.md","sourceDirName":"oauth2-examples","slug":"/oauth2-examples/","permalink":"/docs/oauth2-examples/","draft":false,"unlisted":false,"editUrl":"https://github.com/rabbitmq/rabbitmq-website/tree/main/versioned_docs/version-4.3/oauth2-examples/index.md","tags":[],"version":"4.3","frontMatter":{"title":"OAuth 2.0 Authentication Examples","displayed_sidebar":"docsSidebar"},"sidebar":"docsSidebar","previous":{"title":"OAuth 2.0 Authentication Backend","permalink":"/docs/oauth2"},"next":{"title":"Auth0","permalink":"/docs/oauth2-examples-auth0"}}'),s=i(74848),a=i(28453);let r={title:"OAuth 2.0 Authentication Examples",displayed_sidebar:"docsSidebar"},o="OAuth 2.0 Authentication Examples",c={},l=[{value:"Overview",id:"overview",level:2},{value:"Table of Contents",id:"toc",level:2},{value:"Basics",id:"basics",level:3},{value:"Management UI Access",id:"management-ui-access",level:3},{value:"Using JWT tokens in several protocols to access RabbitMQ",id:"using-jwt-tokens-in-several-protocols-to-access-rabbitmq",level:3},{value:"Signing Keys, Scope Aliases, Rich Authorization Requests",id:"signing-keys-scope-aliases-rich-authorization-requests",level:3},{value:"Examples for Specific OAuth 2.0 Identity Providers",id:"examples-for-specific-oauth-20-identity-providers",level:3},{value:"Examples for Tanzu RabbitMQ (commercial-only feature)",id:"examples-for-tanzu-rabbitmq-commercial-only-feature",level:3},{value:"Prerequisites Used by the Examples in This Guide",id:"prerequisites",level:2},{value:"Getting started with UAA and RabbitMQ",id:"getting-started-with-uaa-and-rabbitmq",level:2},{value:"Access management UI using OAuth 2.0 tokens",id:"access-management-ui",level:2},{value:"Service-Provider initiated logon",id:"service-provider-initiated-logon",level:3},{value:"Identity-Provider initiated logon",id:"identity-provider-initiated-logon",level:3},{value:"Idp-initiated Logon using the Login Endpoint",id:"idp-initiated-logon-using-the-login-endpoint",level:4},{value:"Using JWT tokens in several protocols to access RabbitMQ",id:"access-other-protocols",level:2},{value:"Management REST api",id:"management-rest-api",level:3},{value:"AMQP protocol",id:"amqp-protocol",level:3},{value:"JMS protocol",id:"jms-clients",level:3},{value:"MQTT protocol",id:"mqtt-protocol",level:3},{value:"AMQP 1.0 protocol",id:"amqp10-protocol",level:3},{value:"Using Topic Exchanges",id:"using-topic-exchanges",level:2},{value:"Advanced OAuth 2.0 Configuration Topics",id:"advanced-configuration",level:2},{value:"Using a Custom Scope Field",id:"using-custom-scope-field",level:3},{value:"Using Multiple Asymmetrical Signing Keys",id:"using-multiple-asymmetrical-signing-keys",level:3},{value:"Using Scope Aliases",id:"using-scope-aliases",level:3},{value:"How to Configure Scope Aliases",id:"how-to-configure-scope-aliases",level:4},{value:"RabbitMQ Configuration",id:"rabbitmq-configuration",level:4},{value:"Demo 1: Launch RabbitMQ with custom scopes in scope field",id:"demo-1-launch-rabbitmq-with-custom-scopes-in-scope-field",level:4},{value:"Demo 2: Launch RabbitMQ with custom scopes in extra scope field",id:"demo-2-launch-rabbitmq-with-custom-scopes-in-extra-scope-field",level:4},{value:"Using variable expansion in scopes",id:"using-var-expansion",level:3},{value:"Preferred username claims",id:"preferred-username-claims",level:3},{value:"Use Rich Authorization Request Tokens",id:"use-rar-tokens",level:3}];function h(e){let n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.header,{children:(0,s.jsx)(n.h1,{id:"oauth-20-authentication-examples",children:"OAuth 2.0 Authentication
1Examples"})}),"\n",(0,s.jsx)(n.h2,{id:"overview",children:"Overview"}),"\n",(0,s.jsx)(n.p,{children:"This tutorial-style guide has two primary goals:"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["Explore how applications and end users can ",(0,s.jsx)(n.a,{href:"./access-control",children:"authenticate"})," with RabbitMQ server using OAuth 2.0 rather than the traditional username/password pairs or x.509 certificates."]}),"\n",(0,s.jsx)(n.li,{children:"Explore what it takes to set up RabbitMQ Server with OAuth 2.0 authentication mechanism across several authorization servers."}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["The guide is accompanied by ",(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/tree/next",children:"a public GitHub repository"})," which hosts all the scripts required to deploy the examples demonstrated on the guide."]}),"\n",(0,s.jsx)(n.h2,{id:"toc",children:"Table of Contents"}),"\n",(0,s.jsx)(n.h3,{id:"basics",children:"Basics"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#prerequisites",children:"Prerequisites to follow this guide"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#getting-started-with-uaa-and-rabbitmq",children:"Getting started with UAA and RabbitMQ"})}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"management-ui-access",children:"Management UI Access"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#access-management-ui",children:"Access management UI using OAuth 2.0 tokens"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#service-provider-initiated-logon",children:"Service-Provider initiated logon"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#identity-provider-initiated-logon",children:"Identity-Provider initiated logon"})}),"\n"]}),"\n",(0,s.jsxs)(n.h3,{id:"using-jwt-tokens-in-several-protocols-to-access-rabbitmq",children:["Using ",(0,s.jsx)(n.a,{href:"#access-other-protocols",children:"JWT tokens in several protocols"})," to access RabbitMQ"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#management-rest-api",children:"Management REST API"})}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#amqp-protocol",children:"AMQP 0-9-1"})," (and ",(0,s.jsx)(n.a,{href:"#using-topic-exchanges",children:"scopes for topic exchanges"})," in a separate section)"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#amqp10-protocol",children:"AMQP 1.0"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#jms-clients",children:"JMS"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#mqtt-protocol",children:"MQTT"})}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"signing-keys-scope-aliases-rich-authorization-requests",children:"Signing Keys, Scope Aliases, Rich Authorization Requests"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#advanced-configuration",children:"How to Use Advanced OAuth 2.0 Configuration"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#using-custom-scope-field",children:"Using a custom scope field"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#using-multiple-asymmetrical-signing-keys",children:"Using multiple asymmetrical signing keys"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#using-scope-aliases",children:"Using scope aliases"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#using-var-expansion",children:"Using variable expansion in scopes"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#preferred-username-claims",children:"Preferred username claims"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"#use-rar-tokens",children:"Using Rich Authorization Requests tokens"})}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"examples-for-specific-oauth-20-identity-providers",children:"Examples for Specific OAuth 2.0 Identity Providers"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"./oauth2-examples-keycloak",children:"Keycloak"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"./oauth2-examples-auth0",children:"Auth0"})}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"./oauth2-examples-entra-id",children:"Microsoft Entra ID"})," (formerly known as Azure Active Directory)"]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"./oauth2-examples-proxy",children:"OAuth2 Proxy"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"./oauth2-examples-okta",children:"Okta"})}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"./oauth2-examples-google",children:"Google"})," ",(0,s.jsx)(n.strong,{children:"NOT SUPPORTED"})]}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"./oauth2-examples-multiresource",children:"Multiple OAuth 2.0 servers and/or audiences"})}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"examples-for-tanzu-rabbitmq-commercial-only-feature",children:"Examples for Tanzu RabbitMQ (commercial-only feature)"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.a,{href:"./oauth2-examples-forward-proxy",children:"Forward proxy"})}),"\n"]}),"\n",(0,s.jsx)(n.h2,{id:"prerequisites",children:"Prerequisites Used by the Examples in This Guide"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"Docker must be installed"}),"\n",(0,s.jsx)(n.li,{children:"Ruby must be installed"}),"\n",(0,s.jsx)(n.li,{children:"make"}),"\n",(0,s.jsxs)(n.li,{children:["A local clone of a ",(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/tree/next",children:"GitHub repository"})," for branch ",(0,s.jsx)(n.code,{children:"next"}
1)," that contains all the configuration files and scripts used on this example."]}),"\n",(0,s.jsxs)(n.li,{children:["The following entries must be in your ",(0,s.jsx)(n.code,{children:"/etc/hosts"})," file:"]}),"\n"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{children:"127.0.0.1 localhost uaa rabbitmq\n"})}),"\n",(0,s.jsx)(n.h2,{id:"getting-started-with-uaa-and-rabbitmq",children:"Getting started with UAA and RabbitMQ"}),"\n",(0,s.jsxs)(n.p,{children:["To demonstrate OAuth 2.0 you need, at least, an OAuth 2.0 authorization server and RabbitMQ appropriately configured for the chosen authorization server. This guide uses ",(0,s.jsx)(n.a,{href:"https://docs.cloudfoundry.org/concepts/architecture/uaa.html",children:"UAA"})," as authorization server to demonstrate basic and advanced configuration to access to the Management UI and various messaging protocols."]}),"\n",(0,s.jsxs)(n.p,{children:["This guide also demonstrates how to configure RabbitMQ to use other authorization servers besides ",(0,s.jsx)(n.a,{href:"https://docs.cloudfoundry.org/concepts/architecture/uaa.html",children:"UAA"})," such as ",(0,s.jsx)(n.a,{href:"./oauth2-examples-keycloak",children:"Keycloak"}),". The table of content of this guide has the full list of authorization servers."]}),"\n",(0,s.jsx)(n.p,{children:"Run the following two commands to start UAA and RabbitMQ configured for UAA:"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"make start-uaa"})," to get UAA server running"]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"make start-rabbitmq"})," to start RabbitMQ server"]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["The last command starts a RabbitMQ with a specific configuration file, ",(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/conf/uaa/rabbitmq.conf",children:"rabbitmq.conf"}),"."]}),"\n",(0,s.jsxs)(n.h2,{id:"access-management-ui",children:["Access ",(0,s.jsx)(n.a,{href:"./management/",children:"management UI"})," using OAuth 2.0 tokens"]}),"\n",(0,s.jsx)(n.p,{children:"The RabbitMQ Management UI can be configured with one of these two login modes:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#service-provider-initiated-logon",children:"Service-Provider initiated logon"}),": this is the default and traditional OAuth 2.0 logon mode.\nWhen the user visits the RabbitMQ Management UI, it shows a button with the label ",(0,s.jsx)(n.code,{children:"Click here to logon"}),". When the user clicks it,\nthe logon process starts by redirecting to the configured ",(0,s.jsx)(n.strong,{children:"authorization server"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"#identity-provider-initiated-logon",children:"Identity-Provider initiated logon"}),": this mode is opposite to the previous mode.\nThe user must first access the RabbitMQ Management's ",(0,s.jsx)(n.code,{children:"/login"})," endpoint with a token. If the token is valid, the user is allowed to access the RabbitMQ Management UI.\nThis mode is very useful for Web sites which allow users to access the RabbitMQ Management UI with a single click.\nThe original Web site get a token on user's behalf and redirects the user to the RabbitMQ Management's ",(0,s.jsx)(n.code,{children:"/login"})," endpoint."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"service-provider-initiated-logon",children:"Service-Provider initiated logon"}),"\n",(0,s.jsx)(n.p,{children:"The first time an end user arrives to the management UI, they are redirected to the configured OAuth 2.0 provider to authenticate.\nOnce they successfully authenticate, the user is redirected back to RabbitMQ\nwith a valid access token. RabbitMQ validates it and identify the user and its permissions from the token."}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-plain",children:" [ UAA ] <----2. auth---- [ RabbitMQ ]\n ----3. redirect--\x3e [ http ]\n /|\\\n |\n 1. rabbit_admin from a browser\n"})}),"\n",(0,s.jsx)(n.p,{children:"At step 2, if this is the first time the user is accessing RabbitMQ resource, UAA will prompt the user to\nauthorize RabbitMQ application as shown on the screenshot below."}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.img,{alt:"authorize application",src:i(43202).A+"",width:"319",height:"563"})}),"\n",(0,s.jsx)(n.p,{children:"UAA has previously been configured with two users:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.code,{children:"rabbit_admin:rabbit_admin"})}),"\n",(0,s.jsxs)(n.li,{children:["and ",(0,s.jsx)(n.code,{children:"rabbit_monitor:rabbit_monitor"})]}),"\n"]}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["First visit ",(0,s.jsx)(n.a,{href:"https://uaa:8443",children:"https://uaa:8443"})," so that your browser can trust the self-signed\ncertificate ",(0,s.jsx)(n.code,{children:"uua"})," has. Otherwise, the management UI will fail to connect to\n",(0,s.jsx)(n.code,{children:"uaa"}),"."]})}),"\n",(0,s.jsxs)(n.p,{children:["Now navigating to the ",(0,s.jsx)(n.a,{href:"http://localhost:15672",children:"local node's management UI"})," and login using any of those two users."]}),"\n",(0,s.jsxs)(n.p,{children:["This is a token issued by UAA for the ",(0,s.jsx)(n.code,{children:"rabbit_admin"})," user thru the redirect flow you just saw above.\nIt was signed with the symmetric key."]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.img,{alt:"JWT token",src:i(1855).A+"",width:"457",height:"741"})}),"\n",(0,s.jsxs)(n.p,{children:["To configure the RabbitMQ Management UI with OAuth 2.0, the following configuration entries are required\nin ",(0,s.jsx)(n.code,{children:"rabbitmq.conf"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ini",children:"# ...\nmanagement.oauth_enabled = true\nmanagement.oauth_client_id = rabbit_client_code\nauth_oauth2.issuer = https://uaa:8443\n# ...\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You only need to set ",(0,s.jsx)(n.code,{children:"management.oauth_provider_url"})," when you have not configured\n",(0,s.jsx)(n.code,{children:"auth_oauth2.issuer"})," and/or they have different URLs."]})}),"\n",(0,s.jsx)(n.h3,{id:"identity-provider-initiated-logon",children:"Identity-Provider initiated logon"}),"\n",(0,s.jsx)(n.p,{children:"Like Service-Provider initiated logon, with Idp-initiated logon users get to the RabbitMQ Management UI with a valid token.\nThe following scenarios are examples of Idp-initiated logon:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"RabbitMQ is behind a web portal which conveniently allow users to navigate directly to RabbitMQ fully authenticated."}),"\n",(0,s.jsxs)(n.li,{children:["There is an OAuth2 proxy in between users and RabbitMQ which intercepts their requests and forwards them to RabbitMQ inserting the token into the HTTP ",(0,s.jsx)(n.code,{children:"Authorization"})," header."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["The latter scenario is demonstrated ",(0,s.jsx)(n.a,{href:"./oauth2-examples-proxy",children:"here"}),". The former scenario is covered in the following section."]}),"\n",(0,s.jsx)(n.h4,{id:"idp-initiated-logon-using-the-login-endpoint",children:"Idp-initiated Logon using the Login Endpoint"}),"\n",(0,s.jsxs)(n.p,{children:["A Web portal offers their authenticated users the option to navigate to RabbitMQ\nby submitting a form with their OAuth token in the ",(0,s.jsx)(n.code,{children:"access_token"})," form field as provided below:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-plain",children:" [ Idp | WebPortal ] ----\x3e 2. /login [access_token: TOKEN]---- [ RabbitMQ Cluster ]\n /|\\ |\n | |\n 1. rabbit_admin from a browser <-----3. 302 redirect to RabbitMQ w/cookie--+\n\n"})}),"\n",(0,s.jsxs)(n.p,{children:["If the access token is valid, RabbitMQ redirects the user to the ",(0,s.jsx)(n.strong,{children:"Overview"})," page with a cookie\nthat carries the validated token. When RabbitMQ delivers the ",(0,s.jsx)(n.strong,{children:"Overview"})," page, it clears the\ncookie."]}),"\n",(0,s.jsxs)(n.p,{children:["By default, the RabbitMQ Management UI is configured with ",(0,s.jsx)(n.strong,{children:"service-provider initiated logon"}),", to configure ",(0,s.jsx)(n.strong,{children:"Identity-Provider initiated logon"}),", the following configuration entries are required in ",(0,s.jsx)(n.code,{children:"rabbitmq.conf"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ini",children:"# ...\nmanagement.oauth_enabled = true\nmanagement.oauth_initiated_logon_type = idp_initiated\nmanagement.oauth_provider_url = http://localhost:8080\n# ...\n"})}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["You only need to set ",(0,s.jsx)(n.code,{children:"management.oauth_provider_url"})," when you have not configured\n",(0,s.jsx)(n.code,{children:"auth_oauth2.issuer"})," and/or they have different URLs."]})}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"Important"}),": when the user logs out, or its RabbitMQ session expires, or the token expires, the user is directed to the\nRabbitMQ Management landing page which has a ",(0,s.jsx)(n.strong,{children:"Click here to login"})," button.\nThe user is never automatically redirected back to the url configured in the ",(0,s.jsx)(n.code,{children:"auth_oauth2.issuer"}),".\nIt is only when the user clicks ",(0,s.jsx)(n.strong,{children:"Click here to login"})," , the user is redirected to the configured url in ",(0,s.jsx)(n.code,{children:"auth_oauth2.issuer"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["This scenario is demonstrated ",(0,s.jsx)(n.a,{href:"./oauth2-examples-idp-initiated",children:"here"}),"."]}),"\n",(0,s.jsx)(n.h2,{id:"access-other-protocols",children:"Using JWT tokens in several protocols to access RabbitMQ"}),"\n",(0,s.jsx)(n.p,{children:"The following subsections demonstrate how to use access tokens with any messaging protocol and also to access the management HTTP API."}),"\n",(0,s.jsx)(n.h3,{id:"management-rest-api",children:"Management REST api"}),"\n",(0,s.jsxs)(n.p,{children:["In this scenario a monitoring agent uses RabbitMQ HTTP API to collect monitoring information.\nBecause it is not an end user, or human, you refer to it as a ",(0,s.jsx)(n.em,{children:"service account"}),".\nThis ",(0,s.jsx)(n.em,{children:"service account"})," could be our ",(0,s.jsx)(n.code,{children:"mgt_api_client"})," client you created in UAA with the ",(0,s.jsx)(n.code,{children:"monitoring"})," ",(0,s.jsx)(n.em,{children:"user tag"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["This ",(0,s.jsx)(n.em,{children:"monitoring agent"})," would use the ",(0,s.jsx)(n.em,{children:"client credentials"})," or ",(0,s.jsx)(n.em,{children:"password"})," grant flow to authenticate (1) with\nUAA and get back a JWT token (2). Once it gets the token, it sends (3) a HTTP request\nto the RabbitMQ management endpoint passing the JWT token within the ",(0,s.jsx)(n.code,{children:"Authorization"})," header as a ",(0,s.jsx)(n.em,{children:"Bearer token"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-plain",children:"[ UAA ] [ RabbitMQ ]\n /|\\ [ http ]\n | /|\\\n | 3.http://broker:15672/api/overview passing JWT token\n | |\n +-----1.auth--------- monitoring agent\n --------2.JWT--------\x3e\n"})}),"\n",(0,s.jsxs)(n.p,{children:["The following command launches the browser with ",(0,s.jsx)(n.code,{children:"mgt_api_client"})," client with a JWT token previously obtained from UAA:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make curl-uaa url=http://localhost:15672/api/overview client_id=mgt_api_client secret=mgt_api_client\n"})}),"\n",(0,s.jsx)(n.h3,{id:"amqp-protocol",children:"AMQP protocol"}),"\n",(0,s.jsxs)(n.p,{children:["An application connects to RabbitMQ using AMQP protocol and presents a JWT Token as a credential.\nThe application you are going to use is ",(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-perf-test",children:"PerfTest"})," which is not an OAuth 2.0 aware application.\nOAuth 2.0-aware application is covered in scenario four."]}),"\n",(0,s.jsx)(n.p,{children:"Instead you are launching the application with a token that you have previously obtained from UAA. This is just to probe AMQP access with a JWT Token. Needless to say that the application should instead obtain the JWT Token prior to connecting to RabbitMQ and it should also be able to refresh it before reconnecting. RabbitMQ validates the token before accepting it. If the token has expired, RabbitMQ will reject the connection."}),"\n",(0,s.jsxs)(n.p,{children:["First of all, an application which wants to connect to RabbitMQ using Oauth 2.0 must present a\nvalid JWT token. To obtain the token, the application must first authenticate (",(0,s.jsx)(n.code,{children:"1."}),") with UAA. In case of a successful\nauthentication, it gets back a JWT token (",(0,s.jsx)(n.code,{children:"2."}),") which uses it to connect (",(0,s.jsx)(n.code,{children:"3."}),") to RabbitMQ."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-plain",children:"[ UAA ] [ RabbitMQ ]\n /|\\ [ amqp ]\n | /|\\\n | 3.connect passing JWT\n | |\n +-----1.auth--------- amqp application\n --------2.JWT--------\x3e\n"})}),"\n",(0,s.jsx)(n.p,{children:"You have previously configured UAA with these 2 OAuth 2.0 clients:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.code,{children:"consumer"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.code,{children:"producer"})}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["In order to get a JWT token, an OAuth 2.0 client must be used.\nApplications use the ",(0,s.jsx)(n.code,{children:"Oauth client grant flow"})," to obtain a JWT token."]}),"\n",(0,s.jsxs)(n.p,{children:["This the token issued by UAA for the ",(0,s.jsx)(n.code,{children:"consumer"})," OAuth 2.0 client."]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.img,{alt:"JWT token",src:i(88963).A+"",width:"460",height:"723"})}),"\n",(0,s.jsx)(n.p,{children:"To launch the consumer application invoke the following command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-perftest-consumer\n"})}),"\n",(0,s.jsx)(n.p,{children:"To see consumer logs:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"docker logs consumer -f\n"})}),"\n",(0,s.jsx)(n.p,{children:"To launch the producer application invoke the following command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-perftest-producer\n"})}),"\n",(0,s.jsx)(n.p,{children:"To inspect producer logs:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"docker logs producer -f\n"})}),"\n",(0,s.jsx)(n.p,{children:"To stop all the applications call the following command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make stop-all-apps\n"})}),"\n",(0,s.jsx)(n.h3,{id:"jms-clients",children:"JMS protocol"}),"\n",(0,s.jsxs)(n.p,{children:["In this use case you are demonstrating a basic JMS application which reads, via an environment variable (",(0,s.jsx)(n.code,{children:"TOKEN"}),"),\nthe JWT token that will use as password when authenticating with RabbitMQ."]}),"\n",(0,s.jsxs)(n.p,{children:["It is ",(0,s.jsx)(n.strong,{children:"critically important"})," to grant the required permission to the ",(0,s.jsx)(n.em,{children:"exchange"})," ",(0,s.jsx)(n.code,{children:"jms.durable.queues"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"Applications which send JMS messages require of these permissions:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n
1.code,{children:"rabbitmq.configure:*/jms.durable.queues"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.code,{children:"rabbitmq.write:*/jms.durable.queues"})}),"\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.code,{children:"rabbitmq.read:*/jms.durable.queues"})}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Those permissions grant access on all virtual hosts."}),"\n",(0,s.jsx)(n.p,{children:"Before testing a publisher and a subscriber application you need to build a local image for the\nbasic jms application by invoking this command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make build-jms-client\n"})}),"\n",(0,s.jsx)(n.p,{children:"To test a JMS application sending a message and authenticating via OAuth 2.0 run this command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-jms-publisher\n"})}),"\n",(0,s.jsxs)(n.p,{children:["It sends a message to a queue called ",(0,s.jsx)(n.code,{children:"q-test-queue"})]}),"\n",(0,s.jsx)(n.p,{children:"Applications which subscribe to a JMS queue require of these permissions:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:(0,s.jsx)(n.code,{children:"rabbitmq.write:*/jms.durable.queues"})}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"Those permissions grant access to all virtual hosts."}),"\n",(0,s.jsx)(n.p,{children:"To test a JMS application subscribing to a queue and authenticating via OAuth 2.0 run this command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-jms-subscriber\n"})}),"\n",(0,s.jsxs)(n.p,{children:["It subscribes to a queue called ",(0,s.jsx)(n.code,{children:"q-test-queue"})]}),"\n",(0,s.jsx)(n.h3,{id:"mqtt-protocol",children:"MQTT protocol"}),"\n",(0,s.jsx)(n.p,{children:"This scenario explores the use case where you authenticate with a JWT token to RabbitMQ MQTT port."}),"\n",(0,s.jsxs)(n.p,{children:["Note: in this example, RabbitMQ is already configured with the ",(0,s.jsxs)(n.a,{href:"./mqtt",children:[(0,s.jsx)(n.code,{children:"rabbitmq_mqtt"})," plugin"]}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["This is no different than using AMQP or JMS protocols, all that matters is to pass an empty username and a JWT token as password.\nHowever, ",(0,s.jsx)(n.strong,{children:"what it is really different"})," is how you encode the permissions. In this use case you are going to proceed as you did it in the previous use case where you handcrafted the JWT token rather than requesting it to UAA. Here is the the scopes required to publish\na message to a mqtt topic (",(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/jwts/scopes-for-mqtt.json",children:"scopes-for-mqtt.json"}),")"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-javascript",children:'{\n "scope": [\n "rabbitmq.write:*/*/*",\n "rabbitmq.configure:*/*/*",\n "rabbitmq.read:*/*/*"\n\n ],\n "extra_scope": "rabbitmq.tag:management",\n "aud": [\n "rabbitmq"\n ]\n}\n'})}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"rabbitmq.write:*/*/*"}),' means allow write operation on a any vhost, on any exchange and any topic. In fact,\nit is any "routing-key" because that is translated to a topic/queue.']}),"\n",(0,s.jsxs)(n.p,{children:["You are going to publish a mqtt message by running the following command. If you have not run any of the\nprevious use cases, you need to launch rabbitmq first like this ",(0,s.jsx)(n.code,{children:"make start-rabbitmq"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-mqtt-publish TOKEN=$(bin/jwt_token scopes-for-mqtt.json legacy-token-key private.pem public.pem)\n"})}),"\n",(0,s.jsxs)(n.blockquote,{children:["\n",(0,s.jsxs)(n.p,{children:["IMPORTANT: If you try to access the Management UI and authenticate with UAA using rabbit_admin you\nwont be able to do bind a queue with routing_key ",(0,s.jsx)(n.code,{children:"test"})," to the ",(0,s.jsx)(n.code,{children:"amq.topic"})," exchange because that user\nin UAA does not have the required permissions. In our handcrafted token, you have granted ourselves the right permissions/scopes."]}),"\n"]}),"\n",(0,s.jsx)(n.h3,{id:"amqp10-protocol",children:"AMQP 1.0 protocol"}),"\n",(0,s.jsxs)(n.p,{children:["In this use case you are demonstrating a basic AMQP 1.0 application which reads a JWT token from the ",(0,s.jsx)(n.code,{children:"PASSWORD"})," environment variable.\nThe application then uses the token as a password when authenticating with RabbitMQ."]}),"\n",(0,s.jsx)(n.p,{children:"Before testing a publisher and a subscriber application you need to build a local image for the\nbasic AMQP 1.0 application by invoking this command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make build-amqp1_0-client\n"})}),"\n",(0,s.jsx)(n.p,{children:"Launch RabbitMQ with the following command. It will start RabbitMQ configured with UAA as its authorization server:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-rabbitmq\n"})}),"\n",(0,s.jsx)(n.p,{children:"Launch UAA:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-uaa\n"})}),"\n",(0,s.jsxs)(n.p,{children:["And send a message. It uses the ",(0,s.jsx)(n.em,{children:"client_id"})," ",(0,s.jsx)(n.code,{children:"jms_producer"}),", declared in UAA, to obtain a token:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-amqp1_0-publisher\n"})}),"\n",(0,s.jsx)(n.h2,{id:"using-topic-exchanges",children:"Using Topic
1Exchanges"}),"\n",(0,s.jsx)(n.p,{children:"This section explains what scopes will be necessary for applications that use topic exchanges."}),"\n",(0,s.jsx)(n.admonition,{type:"important",children:(0,s.jsxs)(n.p,{children:["None of the users and/or clients declared in any of authorization servers provided by this tutorial have the\nappropriate scopes for topic exchanges. In the ",(0,s.jsx)(n.a,{href:"#mqtt-protocol",children:"MQTT"})," section, the application used a hand-crafted token\nwith appropriate the scopes because that protocol's routing is entirely topics-based."]})}),"\n",(0,s.jsx)(n.p,{children:"To bind and/or unbind a queue to/from a topic exchange, you need to have the following scopes:"}),"\n",(0,s.jsxs)("table",{children:[(0,s.jsx)("caption",{children:"For consumers"}),(0,s.jsx)("thead",{children:(0,s.jsxs)("tr",{children:[(0,s.jsx)("td",{children:"Permission"}),(0,s.jsx)("td",{children:"Example"})]})}),(0,s.jsxs)("tbody",{children:[(0,s.jsxs)("tr",{children:[(0,s.jsxs)("td",{children:[(0,s.jsx)(n.strong,{children:"write"})," permission on the queue and routing key -> ",(0,s.jsx)(n.code,{children:"rabbitmq.write:<vhost>/<queue>/<routingkey>"})]}),(0,s.jsx)("td",{children:(0,s.jsx)(n.code,{children:"rabbitmq.write:*/*/*"})})]}),(0,s.jsxs)("tr",{children:[(0,s.jsxs)("td",{children:[(0,s.jsx)(n.strong,{children:"read"})," permission on the exchange and routing key -> ",(0,s.jsx)(n.code,{children:"rabbitmq.write:<vhost>/<exchange>/<routingkey>"})]}),(0,s.jsx)("td",{children:(0,s.jsx)(n.code,{children:"rabbitmq.read:*/*/*"})})]})]})]}),"\n",(0,s.jsxs)("table",{children:[(0,s.jsx)("caption",{children:"For publishers"}),(0,s.jsx)("thead",{children:(0,s.jsxs)("tr",{children:[(0,s.jsx)("td",{children:"Permission"}),(0,s.jsx)("td",{children:"Example"})]})}),(0,s.jsx)("tbody",{children:(0,s.jsxs)("tr",{children:[(0,s.jsxs)("td",{children:[(0,s.jsx)(n.strong,{children:"write"})," permission on the exchange and routing key -> ",(0,s.jsx)(n.code,{children:"rabbitmq.write:<vhost>/<exchange>/<routingkey>"})]}),(0,s.jsx)("td",{children:(0,s.jsx)(n.code,{children:"rabbitmq.write:*/*/*"})})]})})]}),"\n",(0,s.jsxs)(n.p,{children:["OAuth 2.0 authorisation backend supports variable expansion when checking permission on topics.\nIt supports any JWT claim whose value is a plain string and the ",(0,s.jsx)(n.code,{children:"vhost"})," variable."]}),"\n",(0,s.jsxs)(n.p,{children:["For example, if a user has connected with the token below against the vhost ",(0,s.jsx)(n.code,{children:"prod"}),",\nthey should have write permission to send to any exchange starting with ",(0,s.jsx)(n.code,{children:"x-prod-"}),"\nand any routing key starting with ",(0,s.jsx)(n.code,{children:"u-bob-"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-json",children:'{\n "sub" : "bob",\n "scope" : [ "rabbitmq.write:*/q-{vhost}-*/u-{sub}-*" ]\n}\n'})}),"\n",(0,s.jsx)(n.h2,{id:"advanced-configuration",children:"Advanced OAuth 2.0 Configuration Topics"}),"\n",(0,s.jsx)(n.h3,{id:"using-custom-scope-field",children:"Using a Custom Scope Field"}),"\n",(0,s.jsxs)(n.p,{children:["There are some authorization servers which cannot include RabbitMQ scopes into the standard\nJWT ",(0,s.jsx)(n.code,{children:"scope"})," field. Instead, they can include RabbitMQ scopes in a custom JWT scope of their choice."]}),"\n",(0,s.jsx)(n.p,{children:"It is possible to configure RabbitMQ with a different field to look for scopes as shown below:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ini",children:"...\nauth_oauth2.additional_scopes_key = extra_scope\n...\n"})}),"\n",(0,s.jsxs)(n.p,{children:["To test this feature you are going to build a token, sign it and use it to hit one of the RabbitMQ management endpoints.\nThe command below allows us to hit any management endpoint, in this case it is the ",(0,s.jsx)(n.code,{children:"overview"}),", with a token."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make curl-with-token URL=http://localhost:15672/api/overview TOKEN=$(bin/jwt_token scope-and-extra-scope.json legacy-token-key private.pem public.pem)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["You use the python script ",(0,s.jsx)(n.code,{children:"bin/jwt_token.py"})," to build the minimal JWT token possible that RabbitMQ is able to\nvalidate which is:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-javascript",children:'{\n "scope": [\n\n ],\n "extra_scope": [\n "rabbitmq.tag:management"\n ],\n "aud": [\n "rabbitmq"\n ]\n}\n'})}),"\n",(0,s.jsx)(n.h3,{id:"using-multiple-asymmetrical-signing-keys",children:"Using Multiple Asymmetrical Signing Keys"}),"\n",(0,s.jsx)(n.p,{children:"This scenario explores the use case where JWT tokens may be signed by different asymmetrical signing keys."}),"\n",(0,s.jsx)(n.p,{children:"There are two ways to configure RabbitMQ with multiple signing keys:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Statically"})," configure them via ",(0,s.jsx)(n.code,{children:"rabbitmq.conf"})," as shown in the ",(0,s.jsx)(n.a,{href:"./oauth2#configure-signing-keys",children:"plugin documentation page"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.strong,{children:"Dynamically"})," add the keys to a running RabbitMQ node without having to restart it."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["First you add a second signing key called ",(0,s.jsx)(n.code,{children:"legacy-token-2-key"})," whose public key is ",(0,s.jsx)(n.code,{children:"conf/public-2.pem"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'docker exec -it rabbitmq rabbitmqctl add_signing_key legacy-token-2-key --pem-file=/conf/public-2.pem\nAdding OAuth signing key "legacy-token-2-key" filename: "/conf/public-2.pem"\n'})}),"\n",(0,s.jsxs)(n.p,{children:["And then you issue a token using the corresponding private key and use it to access the management endpoint ",(0,s.jsx)(n.code,{children:"/api/overview"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make curl-with-token URL=http://localhost:15672/api/overview TOKEN=$(bin/jwt_token scope-and-extra-scope.json legacy-token-2-key private-2.pem public-2.pem)\n"})}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"bin/jwt_token"})," searches for private and public key files under the ",(0,s.jsx)(n.code,{children:"conf"})," directory and jwt files under ",(0,s.jsx)(n.code,{children:"jwts"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"using-scope-aliases",children:"Using Scope Aliases"}),"\n",(0,s.jsx)(n.p,{children:"This example demonstrates how to use custom scopes with RabbitMQ."}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"UAA"})," identity provider has been configured with two clients (",(0,s.jsx)(n.code,{children:"producer_with_roles"}),"\nand ",(0,s.jsx)(n.code,{children:"consumer_with_roles"}),") with the following custom scopes:"]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"producer_with_roles"})," with"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"api://rabbitmq:producer"}),"."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.code,{children:"consumer_with_roles"})," with"]}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"api://rabbitmq:Read.All"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"api://rabbitmq:Write.All"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"api://rabbitmq:Configure.All"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"api://rabbitmq:Administrator"}),"."]}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["For more information about scope aliases, check out\nthe ",(0,s.jsx)(n.a,{href:"./oauth2#scope-aliases",children:"section"})," that explains it in more detail."]}),"\n",(0,s.jsx)(n.h4,{id:"how-to-configure-scope-aliases",children:"How to Configure Scope Aliases"}),"\n",(0,s.jsx)(n.p,{children:"This is the configuration required to map those custom scopes to RabbitMQ scopes."}),"\n",(0,s.jsx)(n.admonition,{type:"tip",children:(0,s.jsxs)(n.p,{children:["Since RabbitMQ 4.1, it is possible to configure ",(0,s.jsx)(n.strong,{children:"scope aliases"})," using the ",(0,s.jsx)(n.a,{href:"./configure#config-file",children:"ini-like"})," configuration style. Earlier versions only supported\nthe legacy Erlang-style."]})}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ini",children:"auth_oauth2.scope_aliases.1.alias = api://rabbitmq:Read.All\nauth_oauth2.scope_aliases.1.scope = rabbitmq.read:*/*\n\nauth_oauth2.scope_aliases.2.alias = api://rabbitmq:Write.All\nauth_oauth2.scope_aliases.2.scope = rabbitmq.write:*/*\n\nauth_oauth2.scope_aliases.3.alias = api://rabbitmq:Configure.All\nauth_oauth2.scope_aliases.3.scope = rabbitmq.configure:*/*\n\nauth_oauth2.scope_aliases.3.alias = api://rabbitmq:Administrator\nauth_oauth2.scope_aliases.3.scope = rabbitmq.tag:administrator\n\nauth_oauth2.scope_aliases.4.alias = api://rabbitmq:producer\nauth_oauth2.scope_aliases.4.scope = rabbitmq.read:*/* rabbitmq.write:*/* rabbitmq.configure:*/* rabbitmq.tag:management\n\n"})}),"\n",(0,s.jsx)(n.h4,{id:"rabbitmq-configuration",children:"RabbitMQ Configuration"}),"\n",(0,s.jsx)(n.p,{children:"In the OAuth 2.0 tutorial repository, there are two RabbitMQ configuration files ready to be used, for UAA:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/conf/uaa/advanced-scope-aliases.config",children:"conf/uaa/advanced-scope-aliases.config"}),":\nconfigures a set of scope aliases."]}),"\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/conf/uaa/rabbitmq.conf",children:"conf/uaa/rabbitmq.conf"}),":\nconfigure the rest of oauth2 configuration in addition to configuring ",(0,s.jsx)(n.code,{children:"extra_scope"})," as another claim from where to read scopes from"]}),"\n"]}),"\n",(0,s.jsx)(n.h4,{id:"demo-1-launch-rabbitmq-with-custom-scopes-in-scope-field",children:"Demo 1: Launch RabbitMQ with custom scopes in scope field"}),"\n",(0,s.jsxs)(n.p,{children:["To launch RabbitMq with scope mappings and with ",(0,s.jsx)(n.em,{children:"custom scopes"})," in the ",(0,s.jsx)(n.code,{children:"scope"})," field you run the following command:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"ADVANCED=advanced-scope-aliases.config make start-rabbitmq\n"})}),"\n",(0,s.jsx)(n.p,{children:"This command will stop RabbitMQ if it is already running."}),"\n",(0,s.jsxs)(n.p,{children:["Launch a producer application with the client ",(0,s.jsx)(n.code,{children:"producer_with_roles"})]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-perftest-producer PRODUCER=producer_with_roles\n"})}),"\n",(0,s.jsx)(n.p,{children:"To inspect the logs:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"docker logs producer_with_roles -f\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Launch a consumer application with the client ",(0,s.jsx)(n.code,{children:"consumer_with_roles"})]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-perftest-consumer CONSUMER=consumer_with_roles\n"})}),"\n",(0,s.jsx)(n.p,{children:"To check the logs : docker logs consumer_with_roles -f"}),"\n",(0,s.jsxs)(n.p,{children:["Access management api with the client ",(0,s.jsx)(n.code,{children:"producer_with_roles"})]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make curl url=http://localhost:15672/api/overview client_id=producer_with_roles secret=producer_with_roles_secret\n"})}),"\n",(0,s.jsx)(n.p,{children:"To stop the perf-test applications run :"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make stop-perftest-producer PRODUCER=producer_with_roles\nmake stop-perftest-consumer CONSUMER=consumer_with_roles\n"})}),"\n",(0,s.jsx)(n.h4,{id:"demo-2-launch-rabbitmq-with-custom-scopes-in-extra-scope-field",children:"Demo 2: Launc
1h RabbitMQ with custom scopes in extra scope field"}),"\n",(0,s.jsxs)(n.p,{children:["To launch RabbitMq with scope mappings and with ",(0,s.jsx)(n.em,{children:"custom scopes"})," in the ",(0,s.jsx)(n.code,{children:"extra_scope"})," you run the following command:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-rabbitmq\n"})}),"\n",(0,s.jsx)(n.p,{children:"This command will stop RabbitMQ if it is already running"}),"\n",(0,s.jsxs)(n.p,{children:["You cannot use UAA to issue the tokens because you cannot configure UAA to use a custom field for scopes.\nInstead you are going to issue the token ourselves with the command ",(0,s.jsx)(n.code,{children:"bin/jwt_token"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Launch a producer application with the token ",(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/jwts/producer-roles-in-extra-scope.json",children:"producer-role-in-scope.json"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-perftest-producer-with-token PRODUCER=producer_with_roles TOKEN=$(bin/jwt_token producer-role-in-extra-scope.json legacy-token-key private.pem public.pem)\n"})}),"\n",(0,s.jsx)(n.p,{children:"To inspect the logs:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"docker logs producer_with_roles -f\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Launch a consumer application with the token ",(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/jwts/consumer-roles-in-extra-scope.json",children:"consumer-roles-in-extra-scope.json"}),":"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-perftest-consumer-with-token CONSUMER=consumer_with_roles TOKEN=$(bin/jwt_token consumer-roles-in-extra-scope.json legacy-token-key private.pem public.pem)\n"})}),"\n",(0,s.jsxs)(n.p,{children:["Access management api with the token ",(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/jwts/producer-roles-in-extra-scope.json",children:"producer-roles-in-extra-scope.json"})]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:'make curl-with-token URL="http://localhost:15672/api/overview" TOKEN=$(bin/jwt_token producer-roles-in-extra-scope.json legacy-token-key private.pem public.pem)\n'})}),"\n",(0,s.jsxs)(n.p,{children:["To stop the ",(0,s.jsx)(n.code,{children:"perf-test"})," applications, run:"]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make stop-perftest-producer PRODUCER=producer_with_roles\nmake stop-perftest-consumer CONSUMER=consumer_with_roles\n"})}),"\n",(0,s.jsx)(n.h3,{id:"using-var-expansion",children:"Using variable expansion in scopes"}),"\n",(0,s.jsx)(n.p,{children:"There are times when it is convenient to define a scope that uses a variable in either:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"The vhost part of the scope"}),"\n",(0,s.jsx)(n.li,{children:"The resource and/or in the routing key part"}),"\n"]}),"\n",(0,s.jsxs)(n.p,{children:["The variable name can be ",(0,s.jsx)(n.code,{children:"vhost"}),", whose value matches the vhost you are accessing, or any single\nvalue claim in the token, such as ",(0,s.jsx)(n.code,{children:"user_name"}),"."]}),"\n",(0,s.jsx)(n.p,{children:"To demonstrate this feature:"}),"\n",(0,s.jsxs)(n.ol,{children:["\n",(0,s.jsxs)(n.li,{children:["Start Keycloak Oauth provider and RabbitMQ by following the steps in\n",(0,s.jsx)(n.a,{href:"./oauth2-examples-keycloak",children:"Keycloak"}),". Keycloak is already configured to issue tokens with the\nscope ",(0,s.jsx)(n.code,{children:"rabbitmq.configure:*/q-{user_name}"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["Log in to the management UI at ",(0,s.jsx)(n.code,{children:"http://localhost:15672"})," with the user name ",(0,s.jsx)(n.code,{children:"rabbit_admin"}),"."]}),"\n",(0,s.jsxs)(n.li,{children:["Try to create a queue with the name ",(0,s.jsx)(n.code,{children:"test"}),". Expect the effort to fail with an authorization error."]}),"\n",(0,s.jsxs)(n.li,{children:["Create a queue with the name ",(0,s.jsx)(n.code,{children:"q-rabbit_admin"}),". Expect to be allowed to do this."]}),"\n"]}),"\n",(0,s.jsx)(n.p,{children:"There is no configuration required in RabbitMQ, but the version must be RabbitMQ 4.1.1 or later."}),"\n",(0,s.jsx)(n.h3,{id:"preferred-username-claims",children:"Preferred username claims"}),"\n",(0,s.jsxs)(n.p,{children:["RabbitMQ needs to figure out the username associated to the token so that it can display it in the Management UI.\nBy default, RabbitMQ will first look for the ",(0,s.jsx)(n.code,{children:"sub"})," claim and if it is not found it uses the ",(0,s.jsx)(n.code,{children:"client_id"}),"."]}),"\n",(0,s.jsxs)(n.p,{children:["Most authorization servers return the user's GUID in the ",(0,s.jsx)(n.code,{children:"sub"})," claim rather than the actual user's username or email address, anything the user can relate to. When the ",(0,s.jsx)(n.code,{children:"sub"})," claim does not carry a ",(0,s.jsx)(n.em,{children:"user-friendly username"}),", you can configure one or several claims to extract the username from the token."]}),"\n",(0,s.jsx)(n.p,{children:"Given this configuration:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-ini",children:"...\nauth_oauth2.resource_server_id = rabbitmq\nauth_oauth2.preferred_username_claims.1 = user_name\nauth_oauth2.preferred_username_claims.2 = email\n...\n"})}),"\n",(0,s.jsxs)(n.p,{children:["RabbitMQ would first look for the ",(0,s.jsx)(n.code,{children:"user_name"})," claim and if it is not found it looks for ",(0,s.jsx)(n.code,{children:"email"}),". Else it uses its default lookup mechanism which first looks for ",(0,s.jsx)(n.code,{children:"sub"})," and then ",(0,s.jsx)(n.code,{children:"client_id"}),"."]}),"\n",(0,s.jsx)(n.h3,{id:"use-rar-tokens",children:"Use Rich Authorization Request Tokens"}),"\n",(0,s.jsxs)(n.p,{children:["The ",(0,s.jsx)(n.a,{href:"https://oauth.net/2/rich-authorization-requests/",children:"Rich Authorization Request"})," extension provides a way for\nOAuth 2.0 clients to request fine-grained permissions during an authorization request.\nIt moves away from the concept of scopes that are text labels and instead\ndefines a more sophisticated permission model."]}),"\n",(0,s.jsx)(n.p,{children:"RabbitMQ supports JWT tokens compliant with the extension. Below is a sample example section of JWT token:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-javascript",children:'{\n "authorization_details": [\n { "type" : "rabbitmq",\n "locations": ["cluster:finance/vhost:primary-*"],\n "actions": [ "read", "write", "configure" ]\n },\n { "type" : "rabbitmq",\n "locations": ["cluster:finance", "cluster:inventory", ],\n "actions": ["tag:administrator" ]\n }\n ]\n}\n'})}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.em,{children:"Get the environment ready"})}),"\n",(0,s.jsxs)(n.p,{children:["To demonstrate this new capability you have to deploy RabbitMQ with the appropriate configuration file\nunder ",(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/conf/uaa/rabbitmq-for-rar-tokens.config",children:"conf/uaa/rabbitmq-for-rar-tokens.config"}),"."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"export CONFIG=rabbitmq-for-rar-tokens.config\nmake start-rabbitmq\n"})}),"\n",(0,s.jsxs)(n.p,{children:[(0,s.jsx)(n.strong,{children:"NOTE"}),": You do not need to run any OAuth 2.0 server like UAA. This is because you are creating a token and signing it using the same\nprivate-public key pair RabbitMQ is configured with."]}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.em,{children:"Use a Rich Authorization Token to access the management HTTP API"})}),"\n",(0,s.jsxs)(n.p,{children:["You are going use this token ",(0,s.jsx)(n.a,{href:"https://github.com/rabbitmq/rabbitmq-oauth2-tutorial/blob/next/jwts/rar-token.json",children:"jwts/rar-token.json"})," to access an endpoint of the Management HTTP API."]}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make curl-with-token URL=http://localhost:15672/api/overview TOKEN=$(bin/jwt_token rar-token.json legacy-token-key private.pem public.pem)\n"})}),"\n",(0,s.jsx)(n.p,{children:"Note: You are using curl to go to the URL using a TOKEN which you have built using the command bin/jwt_token which takes the JWT payload, the name of the signing key and the private and public certificates to sign the token"}),"\n",(0,s.jsx)(n.p,{children:(0,s.jsx)(n.em,{children:"Use a Rich Authorization Token to Application authentication and authorization"})}),"\n",(0,s.jsx)(n.p,{children:"This time, You are going to use the same token you used in the previous section to access the AMQP protocol via the PerfTest tool which acts as a AMQP producer application:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"make start-perftest-producer-with-token PRODUCER=producer_with_roles TOKEN=$(bin/jwt_token rar-token.json legacy-token-key private.pem public.pem)\n"})}),"\n",(0,s.jsx)(n.p,{children:"The command above launches the application in the background, you can check the logs by running this command:"}),"\n",(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-bash",children:"docker logs producer_with_roles -f\n"})}),"\n",(0,s.jsxs)(n.p,{children:["For more information on this new capability check out the ",(0,s.jsx)(n.a,{href:"./oauth2#rich-authorization-request",children:"OAuth 2 guide"}),"."]})]})}function d(e={}){let{wrapper:n}={...(0,a.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(h,{...e})}):h(e)}},1855(e,n,i){i.d(n,{A:()=>t});let t=i.p+"assets/images/admin-token-signed-sym-key-50c4225c3dd7029b75f860e998c038d6.png"},43202(e,n,i){i.d(n,{A:()=>t});let t=i.p+"assets/images/authorize-app-455399ab65dc3b2c5b6811c45eab2159.png"},88963(e,n,i){i.d(n,{A:()=>t});let t=i.p+"assets/images/consumer-token-signed-with-sym-key-8639295f97da47812e09b99280fc26e8.png"},28453(e,n,i){i.d(n,{R:()=>r,x:()=>o});var t=i(96540);let s={},a=t.createContext(s);function r(e){let n=t.useContext(a);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:r(e.components),t.createElement(a.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.