Skip to content

Commit bd2db58

Browse files
Merge pull request #14949 from rabbitmq/mergify/bp/v4.2.x/pr-14931
HTTP API: when virtual host is known, limit permission filtering to just that specific virtual host (backport #14931)
2 parents dec4e24 + 64c15d3 commit bd2db58

File tree

3 files changed

+61
-51
lines changed

3 files changed

+61
-51
lines changed

deps/rabbitmq_management/src/rabbit_mgmt_util.erl

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,6 @@ get_sort_reverse(ReqData) ->
313313
V -> list_to_atom(V)
314314
end.
315315

316-
317316
-spec is_pagination_requested(#pagination{} | undefined) -> boolean().
318317
is_pagination_requested(undefined) ->
319318
false;
@@ -981,9 +980,28 @@ all_or_one_vhost(ReqData, Fun) ->
981980
VHost -> Fun(VHost)
982981
end.
983982

984-
filter_vhost(List, ReqData, Context) ->
985-
User = #user{tags = Tags} = Context#context.user,
986-
Fn = case rabbit_web_dispatch_access_control:is_admin(Tags) of
983+
filter_vhost(List, ReqData, Context = #context{user = #user{tags = Tags}}) ->
984+
IsAdmin = rabbit_web_dispatch_access_control:is_admin(Tags),
985+
filter_vhost({vhost, vhost(ReqData)}, IsAdmin, List, ReqData, Context).
986+
987+
filter_vhost({vhost, not_found}, IsAdmin, List, ReqData, Context) ->
988+
filter_none_or_not_found_vhost(IsAdmin, List, ReqData, Context);
989+
filter_vhost({vhost, none}, IsAdmin, List, ReqData, Context) ->
990+
filter_none_or_not_found_vhost(IsAdmin, List, ReqData, Context);
991+
filter_vhost({vhost, _VHost}, _IsAdmin=true, List, _ReqData, _Context) ->
992+
[I || I <- List, lists:member(pget(vhost, I), rabbit_vhost:list())];
993+
filter_vhost({vhost, VHost}, _IsAdmin=false, List, ReqData, #context{user = User}) ->
994+
AuthzData = get_authz_data(ReqData),
995+
case catch rabbit_access_control:check_vhost_access(User, VHost, AuthzData, #{}) of
996+
ok ->
997+
[I || I <- List, pget(vhost, I) =:= VHost];
998+
NotOK ->
999+
log_access_control_result(NotOK),
1000+
[]
1001+
end.
1002+
1003+
filter_none_or_not_found_vhost(IsAdmin, List, ReqData, #context{user = User}) ->
1004+
Fn = case IsAdmin of
9871005
true -> fun list_visible_vhosts_names/2;
9881006
false -> fun list_login_vhosts_names/2
9891007
end,
@@ -1090,6 +1108,8 @@ list_login_vhosts(User, AuthzData) ->
10901108
end].
10911109

10921110
% rabbitmq/rabbitmq-auth-backend-http#100
1111+
log_access_control_result({'EXIT', #amqp_error{name = Name, explanation = Msg}}) ->
1112+
?LOG_DEBUG("rabbit_access_control:check_vhost_access result: '~tp', ~ts", [Name, Msg]);
10931113
log_access_control_result(NotOK) ->
10941114
?LOG_DEBUG("rabbit_access_control:check_vhost_access result: ~tp", [NotOK]).
10951115

deps/rabbitmq_management/test/rabbit_mgmt_http_SUITE.erl

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,33 +1709,47 @@ permissions_vhost_test(Config) ->
17091709
{tags, <<"administrator">>}], {group, '2xx'}),
17101710
http_put(Config, "/users/myuser", [{password, <<"myuser">>},
17111711
{tags, <<"management">>}], {group, '2xx'}),
1712+
http_put(Config, "/users/mymonitor", [{password, <<"mymonitor">>},
1713+
{tags, [<<"monitor">>, <<"management">>]}], {group, '2xx'}),
17121714
http_put(Config, "/vhosts/myvhost1", none, {group, '2xx'}),
17131715
http_put(Config, "/vhosts/myvhost2", none, {group, '2xx'}),
17141716
http_put(Config, "/permissions/myvhost1/myuser", PermArgs, {group, '2xx'}),
1717+
http_put(Config, "/permissions/myvhost1/mymonitor", PermArgs, {group, '2xx'}),
17151718
http_put(Config, "/permissions/myvhost1/guest", PermArgs, {group, '2xx'}),
17161719
http_put(Config, "/permissions/myvhost2/guest", PermArgs, {group, '2xx'}),
17171720
assert_list([#{name => <<"/">>},
17181721
#{name => <<"myvhost1">>},
17191722
#{name => <<"myvhost2">>}], http_get(Config, "/vhosts", ?OK)),
17201723
assert_list([#{name => <<"myvhost1">>}],
17211724
http_get(Config, "/vhosts", "myuser", "myuser", ?OK)),
1725+
assert_list([#{name => <<"myvhost1">>}],
1726+
http_get(Config, "/vhosts", "mymonitor", "mymonitor", ?OK)),
17221727
http_put(Config, "/queues/myvhost1/myqueue", QArgs, {group, '2xx'}),
17231728
http_put(Config, "/queues/myvhost2/myqueue", QArgs, {group, '2xx'}),
1729+
CheckResult = fun (Path, Result) ->
1730+
case maps:get(vhost, Result) of
1731+
<<"myvhost2">> ->
1732+
throw({got_result_from_vhost2_in, Path, Result});
1733+
_ ->
1734+
ok
1735+
end
1736+
end,
17241737
Test1 =
17251738
fun(Path) ->
1726-
Results = http_get(Config, Path, "myuser", "myuser", ?OK),
1727-
[case maps:get(vhost, Result) of
1728-
<<"myvhost2">> ->
1729-
throw({got_result_from_vhost2_in, Path, Result});
1730-
_ ->
1731-
ok
1732-
end || Result <- Results]
1739+
Results0 = http_get(Config, Path, "myuser", "myuser", ?OK),
1740+
[CheckResult(Path, Result0) || Result0 <- Results0],
1741+
Results1 = http_get(Config, Path, "mymonitor", "mymonitor", ?OK),
1742+
[CheckResult(Path, Result1) || Result1 <- Results1]
17331743
end,
17341744
Test2 =
17351745
fun(Path1, Path2) ->
17361746
http_get(Config, Path1 ++ "/myvhost1/" ++ Path2, "myuser", "myuser",
17371747
?OK),
17381748
http_get(Config, Path1 ++ "/myvhost2/" ++ Path2, "myuser", "myuser",
1749+
?NOT_AUTHORISED),
1750+
http_get(Config, Path1 ++ "/myvhost1/" ++ Path2, "mymonitor", "mymonitor",
1751+
?OK),
1752+
http_get(Config, Path1 ++ "/myvhost2/" ++ Path2, "mymonitor", "mymonitor",
17391753
?NOT_AUTHORISED)
17401754
end,
17411755
Test3 =

deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_access_control.erl

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
is_authorized_vhost_visible_for_monitoring/3,
2121
is_authorized_global_parameters/3]).
2222

23-
-export([list_visible_vhosts/1, list_visible_vhosts_names/1, list_login_vhosts/2]).
2423
-export([id/2]).
2524
-export([not_authorised/3, halt_response/5]).
2625

@@ -255,23 +254,34 @@ user_matches_vhost(ReqData, User) ->
255254
not_found -> true;
256255
none -> true;
257256
V ->
258-
AuthzData = get_authz_data(ReqData),
259-
lists:member(V, list_login_vhosts_names(User, AuthzData))
257+
check_vhost_access(ReqData, User, V)
260258
end.
261259

262-
user_matches_vhost_visible(ReqData, User) ->
260+
user_matches_vhost_visible(ReqData, User = #user{tags = Tags}) ->
263261
case vhost(ReqData) of
264262
not_found -> true;
265263
none -> true;
266264
V ->
267-
AuthzData = get_authz_data(ReqData),
268-
lists:member(V, list_visible_vhosts_names(User, AuthzData))
265+
case is_monitor(Tags) of
266+
true ->
267+
rabbit_vhost:exists(V);
268+
false ->
269+
check_vhost_access(ReqData, User, V)
270+
end
269271
end.
270272

271273
get_authz_data(ReqData) ->
272274
{PeerAddress, _PeerPort} = cowboy_req:peer(ReqData),
273275
{ip, PeerAddress}.
274276

277+
check_vhost_access(ReqData, User, VHost) ->
278+
AuthzData = get_authz_data(ReqData),
279+
case catch rabbit_access_control:check_vhost_access(User, VHost, AuthzData, #{}) of
280+
ok -> true;
281+
NotOK ->
282+
log_access_control_result(NotOK),
283+
false
284+
end.
275285

276286
not_authorised(Reason, ReqData, Context) ->
277287
%% TODO: consider changing to 403 in 4.0
@@ -328,40 +338,6 @@ id0(Key, ReqData) ->
328338
Id -> Id
329339
end.
330340

331-
332-
list_visible_vhosts_names(User) ->
333-
list_visible_vhosts(User, undefined).
334-
335-
list_visible_vhosts_names(User, AuthzData) ->
336-
list_visible_vhosts(User, AuthzData).
337-
338-
list_visible_vhosts(User) ->
339-
list_visible_vhosts(User, undefined).
340-
341-
list_visible_vhosts(User = #user{tags = Tags}, AuthzData) ->
342-
case is_monitor(Tags) of
343-
true -> rabbit_vhost:list_names();
344-
false -> list_login_vhosts_names(User, AuthzData)
345-
end.
346-
347-
list_login_vhosts_names(User, AuthzData) ->
348-
[V || V <- rabbit_vhost:list_names(),
349-
case catch rabbit_access_control:check_vhost_access(User, V, AuthzData, #{}) of
350-
ok -> true;
351-
NotOK ->
352-
log_access_control_result(NotOK),
353-
false
354-
end].
355-
356-
list_login_vhosts(User, AuthzData) ->
357-
[V || V <- rabbit_vhost:all(),
358-
case catch rabbit_access_control:check_vhost_access(User, vhost:get_name(V), AuthzData, #{}) of
359-
ok -> true;
360-
NotOK ->
361-
log_access_control_result(NotOK),
362-
false
363-
end].
364-
365341
% rabbitmq/rabbitmq-auth-backend-http#100
366342
log_access_control_result(NotOK) ->
367343
?LOG_DEBUG("rabbit_access_control:check_vhost_access result: ~tp", [NotOK]).

0 commit comments

Comments
 (0)