Skip to content

Commit 3139268

Browse files
Merge pull request #14008 from rabbitmq/mergify/bp/v4.1.x/pr-13941
Oauth2: Support variable expansion when checking resource access (backport #13941)
2 parents d02881f + c22af2a commit 3139268

File tree

7 files changed

+88
-24
lines changed

7 files changed

+88
-24
lines changed

.github/workflows/test-authnz.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ jobs:
7272
docker build -t mocha-test --target test .
7373
7474
- name: Run Suites
75-
id: run-suites
75+
id: tests
7676
run: |
7777
IMAGE_TAG=$(find PACKAGES/rabbitmq-server-generic-unix-*.tar.xz | awk -F 'PACKAGES/rabbitmq-server-generic-unix-|.tar.xz' '{print $2}')
7878
CONF_DIR_PREFIX="$(mktemp -d)" RABBITMQ_DOCKER_IMAGE=pivotalrabbitmq/rabbitmq:$IMAGE_TAG \
@@ -83,7 +83,7 @@ jobs:
8383
if: always()
8484
uses: actions/[email protected]
8585
env:
86-
SELENIUM_ARTIFACTS: ${{ steps.run-suites.outputs.SELENIUM_ARTIFACTS }}
86+
SELENIUM_ARTIFACTS: ${{ steps.tests.outputs.SELENIUM_ARTIFACTS }}
8787
with:
8888
name: test-artifacts-${{ matrix.browser }}-${{ matrix.erlang_version }}
8989
path: |

.github/workflows/test-management-ui-for-pr.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ jobs:
5757
docker build -t mocha-test --target test .
5858
5959
- name: Run short UI suites on a standalone rabbitmq server
60+
id: tests
6061
run: |
6162
IMAGE_TAG=$(find PACKAGES/rabbitmq-server-generic-unix-*.tar.xz | awk -F 'PACKAGES/rabbitmq-server-generic-unix-|.tar.xz' '{print $2}')
6263
CONF_DIR_PREFIX="$(mktemp -d)" RABBITMQ_DOCKER_IMAGE=pivotalrabbitmq/rabbitmq:$IMAGE_TAG \
@@ -67,7 +68,7 @@ jobs:
6768
if: ${{ failure() && steps.tests.outcome == 'failed' }}
6869
uses: actions/upload-artifact@v4
6970
env:
70-
SELENIUM_ARTIFACTS: ${{ steps.run-suites.outputs.SELENIUM_ARTIFACTS }}
71+
SELENIUM_ARTIFACTS: ${{ steps.tests.outputs.SELENIUM_ARTIFACTS }}
7172
with:
7273
name: test-artifacts-${{ matrix.browser }}-${{ matrix.erlang_version }}
7374
path: |

deps/rabbitmq_auth_backend_oauth2/src/rabbit_auth_backend_oauth2.erl

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,19 +87,16 @@ user_login_authorization(Username, AuthProps) ->
8787
check_vhost_access(#auth_user{impl = DecodedTokenFun},
8888
VHost, _AuthzData) ->
8989
with_decoded_token(DecodedTokenFun(),
90-
fun(_Token) ->
91-
DecodedToken = DecodedTokenFun(),
92-
Scopes = get_scope(DecodedToken),
93-
ScopeString = rabbit_oauth2_scope:concat_scopes(Scopes, ","),
94-
rabbit_log:debug("Matching virtual host '~ts' against the following scopes: ~ts", [VHost, ScopeString]),
90+
fun(Token) ->
91+
Scopes = get_expanded_scopes(Token, #resource{virtual_host = VHost}),
9592
rabbit_oauth2_scope:vhost_access(VHost, Scopes)
9693
end).
9794

9895
check_resource_access(#auth_user{impl = DecodedTokenFun},
9996
Resource, Permission, _AuthzContext) ->
10097
with_decoded_token(DecodedTokenFun(),
10198
fun(Token) ->
102-
Scopes = get_scope(Token),
99+
Scopes = get_expanded_scopes(Token, Resource),
103100
rabbit_oauth2_scope:resource_access(Resource, Permission, Scopes)
104101
end).
105102

deps/rabbitmq_auth_backend_oauth2/src/rabbit_oauth2_scope.erl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ resource_access(#resource{virtual_host = VHost, name = Name},
4141
end,
4242
get_scope_permissions(Scopes)).
4343

44+
-spec topic_access(rabbit_types:r(atom()), permission(), map(), [binary()]) -> boolean().
4445
topic_access(#resource{virtual_host = VHost, name = ExchangeName},
4546
Permission,
4647
#{routing_key := RoutingKey},

deps/rabbitmq_auth_backend_oauth2/test/rabbit_auth_backend_oauth2_test_util.erl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ fixture_token() ->
117117

118118
token_with_sub(TokenFixture, Sub) ->
119119
maps:put(<<"sub">>, Sub, TokenFixture).
120+
token_with_claim(TokenFixture, Name, Value) ->
121+
maps:put(Name, Value, TokenFixture).
120122
token_with_scopes(TokenFixture, Scopes) ->
121123
maps:put(<<"scope">>, Scopes, TokenFixture).
122124

deps/rabbitmq_auth_backend_oauth2/test/system_SUITE.erl

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@ groups() ->
3535
test_successful_connection_with_a_full_permission_token_and_all_defaults,
3636
test_successful_connection_with_a_full_permission_token_and_explicitly_configured_vhost,
3737
test_successful_connection_with_simple_strings_for_aud_and_scope,
38+
test_successful_connection_with_variable_expansion_on_queue_access,
3839
test_successful_token_refresh,
3940
test_successful_connection_without_verify_aud,
4041
mqtt
4142
]},
4243
{basic_unhappy_path, [], [
4344
test_failed_connection_with_expired_token,
4445
test_failed_connection_with_a_non_token,
46+
test_failed_connection_with_a_token_with_variable_expansion,
4547
test_failed_connection_with_a_token_with_insufficient_vhost_permission,
4648
test_failed_connection_with_a_token_with_insufficient_resource_permission,
4749
more_than_one_resource_server_id_not_allowed_in_one_token,
@@ -134,7 +136,8 @@ end_per_group(_Group, Config) ->
134136
%%
135137

136138
init_per_testcase(Testcase, Config) when Testcase =:= test_successful_connection_with_a_full_permission_token_and_explicitly_configured_vhost orelse
137-
Testcase =:= test_successful_token_refresh ->
139+
Testcase =:= test_successful_token_refresh orelse
140+
Testcase =:= test_successful_connection_with_variable_expansion_on_queue_access ->
138141
rabbit_ct_broker_helpers:add_vhost(Config, <<"vhost1">>),
139142
rabbit_ct_helpers:testcase_started(Config, Testcase),
140143
Config;
@@ -420,6 +423,19 @@ test_successful_connection_with_simple_strings_for_aud_and_scope(Config) ->
420423
amqp_channel:call(Ch, #'queue.declare'{exclusive = true}),
421424
close_connection_and_channel(Conn, Ch).
422425

426+
test_successful_connection_with_variable_expansion_on_queue_access(Config) ->
427+
{_Algo, Token} = generate_valid_token(
428+
Config,
429+
<<"rabbitmq.configure:*/{vhost}-{sub}-* rabbitmq.write:*/* rabbitmq.read:*/*">>,
430+
[<<"hare">>, <<"rabbitmq">>],
431+
<<"Bob">>
432+
),
433+
Conn = open_unmanaged_connection(Config, 0, <<"vhost1">>, <<"Bob">>, Token),
434+
{ok, Ch} = amqp_connection:open_channel(Conn),
435+
#'queue.declare_ok'{} =
436+
amqp_channel:call(Ch, #'queue.declare'{queue = <<"vhost1-Bob-1">>, exclusive = true}),
437+
close_connection_and_channel(Conn, Ch).
438+
423439
test_successful_connection_without_verify_aud(Config) ->
424440
{_Algo, Token} = generate_valid_token(
425441
Config,
@@ -895,6 +911,18 @@ test_failed_connection_with_a_token_with_insufficient_vhost_permission(Config) -
895911
?assertEqual({error, not_allowed},
896912
open_unmanaged_connection(Config, 0, <<"off-limits-vhost">>, <<"username">>, Token)).
897913

914+
test_failed_connection_with_a_token_with_variable_expansion(Config) ->
915+
{_Algo, Token} = generate_valid_token(
916+
Config,
917+
<<"rabbitmq.configure:*/{vhost}-{sub}-* rabbitmq.write:*/* rabbitmq.read:*/*">>,
918+
[<<"hare">>, <<"rabbitmq">>]
919+
),
920+
Conn = open_unmanaged_connection(Config, 0, <<"vhost2">>, <<"username">>, Token),
921+
{ok, Ch} = amqp_connection:open_channel(Conn),
922+
?assertExit({{shutdown, {server_initiated_close, 403, _}}, _},
923+
amqp_channel:call(Ch, #'queue.declare'{queue = <<"vhost1-username-3">>, exclusive = true})),
924+
close_connection(Conn).
925+
898926
test_failed_connection_with_a_token_with_insufficient_resource_permission(Config) ->
899927
{_Algo, Token} = generate_valid_token(Config, [<<"rabbitmq.configure:vhost2/jwt*">>,
900928
<<"rabbitmq.write:vhost2/jwt*">>,

deps/rabbitmq_auth_backend_oauth2/test/unit_SUITE.erl

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ all() ->
4949
test_unsuccessful_access_with_a_token_that_uses_missing_scope_alias_in_scope_field,
5050
test_unsuccessful_access_with_a_token_that_uses_missing_scope_alias_in_extra_scope_source_field,
5151
test_username_from,
52-
{group, with_rabbitmq_node}
52+
{group, with_rabbitmq_node},
53+
{group, with_resource_server_id}
5354

5455
].
5556
groups() ->
@@ -62,11 +63,11 @@ groups() ->
6263
},
6364
{with_resource_server_id, [], [
6465
test_successful_access_with_a_token,
65-
test_validate_payload_resource_server_id_mismatch,
6666
test_successful_access_with_a_token_that_uses_single_scope_alias_in_scope_field,
6767
test_successful_access_with_a_token_that_uses_multiple_scope_aliases_in_scope_field,
6868
test_successful_authorization_without_scopes,
6969
test_successful_authentication_without_scopes,
70+
test_successful_access_with_a_token_that_uses_single_scope_alias_with_var_expansion,
7071
test_successful_access_with_a_token_that_uses_single_scope_alias_in_extra_scope_source_field,
7172
test_successful_access_with_a_token_that_uses_multiple_scope_aliases_in_extra_scope_source_field,
7273
normalize_token_scope_with_additional_scopes_complex_claims,
@@ -634,7 +635,7 @@ normalize_token_scope_with_additional_scopes_complex_claims(_) ->
634635
<<"rabbitmq3">> =>
635636
[<<"rabbitmq-resource.write:*/*">>,
636637
<<"rabbitmq-resource-write">>]},
637-
[<<"read:*/*">>, <<"rabbitmq.rabbitmq-resource-read">>]
638+
[<<"read:*/*">>]
638639
},
639640
{
640641
"claims are map with list content - empty result",
@@ -647,7 +648,7 @@ normalize_token_scope_with_additional_scopes_complex_claims(_) ->
647648
"claims are map with binary content",
648649
#{ <<"rabbitmq">> => <<"rabbitmq-resource.read:*/* rabbitmq-resource-read">>,
649650
<<"rabbitmq3">> => <<"rabbitmq-resource.write:*/* rabbitmq-resource-write">>},
650-
[<<"rabbitmq.rabbitmq-resource.read:*/*">>, <<"rabbitmq.rabbitmq-resource-read">>]
651+
[<<"read:*/*">>]
651652
},
652653
{
653654
"claims are map with binary content - empty result",
@@ -777,6 +778,45 @@ test_successful_access_with_a_token_that_has_tag_scopes(_) ->
777778
{ok, #auth_user{username = Username, tags = [management, policymaker]}} =
778779
user_login_authentication(Username, [{password, Token}]).
779780

781+
test_successful_access_with_a_token_that_uses_single_scope_alias_with_var_expansion(_) ->
782+
Jwk = ?UTIL_MOD:fixture_jwk(),
783+
UaaEnv = [{signing_keys, #{<<"token-key">> => {map, Jwk}}}],
784+
set_env(key_config, UaaEnv),
785+
Alias = <<"client-alias-1">>,
786+
set_env(scope_aliases, #{
787+
Alias => [
788+
<<"rabbitmq.configure:{vhost}/q-{sub}/rk-{client_id}**">>
789+
]
790+
}),
791+
792+
VHost = <<"vhost">>,
793+
Username = <<"bob">>,
794+
ClientId = <<"rmq">>,
795+
Token = ?UTIL_MOD:sign_token_hs(?UTIL_MOD:token_with_sub(
796+
?UTIL_MOD:token_with_claim(
797+
?UTIL_MOD:token_with_scope_alias_in_scope_field(Alias), <<"client_id">>, ClientId),
798+
Username), Jwk),
799+
800+
{ok, #auth_user{username = Username} = AuthUser} =
801+
user_login_authentication(Username, [{password, Token}]),
802+
803+
%% vhost access
804+
assert_vhost_access_granted(AuthUser, ClientId),
805+
806+
%% resource access
807+
assert_resource_access_denied(AuthUser, VHost, <<"none">>, read),
808+
assert_resource_access_granted(AuthUser, VHost, <<"q-bob">>, configure),
809+
810+
%% topic access
811+
assert_topic_access_refused(AuthUser, VHost, <<"q-bob">>, configure,
812+
#{routing_key => <<"rk-r2mq/#">>}),
813+
assert_topic_access_granted(AuthUser, VHost, <<"q-bob">>, configure,
814+
#{routing_key => <<"rk-rmq/#">>}),
815+
816+
817+
application:unset_env(rabbitmq_auth_backend_oauth2, scope_aliases),
818+
application:unset_env(rabbitmq_auth_backend_oauth2, key_config).
819+
780820
test_successful_access_with_a_token_that_uses_single_scope_alias_in_scope_field(_) ->
781821
Jwk = ?UTIL_MOD:fixture_jwk(),
782822
UaaEnv = [{signing_keys, #{<<"token-key">> => {map, Jwk}}}],
@@ -813,8 +853,7 @@ test_successful_access_with_a_token_that_uses_single_scope_alias_in_scope_field(
813853
assert_resource_access_denied(AuthUser, VHost, <<"three">>, write),
814854

815855
application:unset_env(rabbitmq_auth_backend_oauth2, scope_aliases),
816-
application:unset_env(rabbitmq_auth_backend_oauth2, key_config),
817-
application:unset_env(rabbitmq_auth_backend_oauth2, resource_server_id).
856+
application:unset_env(rabbitmq_auth_backend_oauth2, key_config).
818857

819858

820859
test_successful_access_with_a_token_that_uses_single_scope_alias_in_scope_field_and_custom_scope_prefix(_) ->
@@ -855,8 +894,7 @@ test_successful_access_with_a_token_that_uses_single_scope_alias_in_scope_field_
855894

856895
application:unset_env(rabbitmq_auth_backend_oauth2, scope_aliases),
857896
application:unset_env(rabbitmq_auth_backend_oauth2, key_config),
858-
application:unset_env(rabbitmq_auth_backend_oauth2, scope_prefix),
859-
application:unset_env(rabbitmq_auth_backend_oauth2, resource_server_id).
897+
application:unset_env(rabbitmq_auth_backend_oauth2, scope_prefix).
860898

861899
test_successful_access_with_a_token_that_uses_multiple_scope_aliases_in_scope_field(_) ->
862900
Jwk = ?UTIL_MOD:fixture_jwk(),
@@ -901,8 +939,7 @@ test_successful_access_with_a_token_that_uses_multiple_scope_aliases_in_scope_fi
901939
assert_resource_access_denied(AuthUser, VHost, <<"three">>, write),
902940

903941
application:unset_env(rabbitmq_auth_backend_oauth2, scope_aliases),
904-
application:unset_env(rabbitmq_auth_backend_oauth2, key_config),
905-
application:unset_env(rabbitmq_auth_backend_oauth2, resource_server_id).
942+
application:unset_env(rabbitmq_auth_backend_oauth2, key_config).
906943

907944
test_unsuccessful_access_with_a_token_that_uses_missing_scope_alias_in_scope_field(_) ->
908945
Jwk = ?UTIL_MOD:fixture_jwk(),
@@ -976,8 +1013,7 @@ test_successful_access_with_a_token_that_uses_single_scope_alias_in_extra_scope_
9761013
assert_resource_access_denied(AuthUser, VHost, <<"three">>, write),
9771014

9781015
application:unset_env(rabbitmq_auth_backend_oauth2, scope_aliases),
979-
application:unset_env(rabbitmq_auth_backend_oauth2, key_config),
980-
application:unset_env(rabbitmq_auth_backend_oauth2, resource_server_id).
1016+
application:unset_env(rabbitmq_auth_backend_oauth2, key_config).
9811017

9821018
test_successful_access_with_a_token_that_uses_multiple_scope_aliases_in_extra_scope_source_field(_) ->
9831019
Jwk = ?UTIL_MOD:fixture_jwk(),
@@ -1021,8 +1057,7 @@ test_successful_access_with_a_token_that_uses_multiple_scope_aliases_in_extra_sc
10211057
assert_resource_access_denied(AuthUser, VHost, <<"three">>, write),
10221058

10231059
application:unset_env(rabbitmq_auth_backend_oauth2, scope_aliases),
1024-
application:unset_env(rabbitmq_auth_backend_oauth2, key_config),
1025-
application:unset_env(rabbitmq_auth_backend_oauth2, resource_server_id).
1060+
application:unset_env(rabbitmq_auth_backend_oauth2, key_config).
10261061

10271062
test_unsuccessful_access_with_a_token_that_uses_missing_scope_alias_in_extra_scope_source_field(_) ->
10281063
Jwk = ?UTIL_MOD:fixture_jwk(),

0 commit comments

Comments
 (0)