Skip to content

Commit dc9ebc5

Browse files
committed
Check topic permissions of CC and BCC headers
1 parent 97512b0 commit dc9ebc5

File tree

2 files changed

+132
-28
lines changed

2 files changed

+132
-28
lines changed

deps/rabbit/src/rabbit_channel.erl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -912,8 +912,13 @@ check_write_permitted(Resource, User, Context) ->
912912
check_read_permitted(Resource, User, Context) ->
913913
check_resource_access(User, Resource, read, Context).
914914

915-
check_write_permitted_on_topic(Resource, User, RoutingKey, AuthzContext) ->
916-
check_topic_authorisation(Resource, User, RoutingKey, AuthzContext, write).
915+
check_write_permitted_on_topics(#exchange{type = topic} = Resource, User, Mc, AuthzContext) ->
916+
lists:foreach(
917+
fun(RoutingKey) ->
918+
check_topic_authorisation(Resource, User, RoutingKey, AuthzContext, write)
919+
end, mc:routing_keys(Mc));
920+
check_write_permitted_on_topics(_, _, _, _) ->
921+
ok.
917922

918923
check_read_permitted_on_topic(Resource, User, RoutingKey, AuthzContext) ->
919924
check_topic_authorisation(Resource, User, RoutingKey, AuthzContext, read).
@@ -1182,7 +1187,6 @@ handle_method(#'basic.publish'{exchange = ExchangeNameBin,
11821187
check_write_permitted(ExchangeName, User, AuthzContext),
11831188
Exchange = rabbit_exchange:lookup_or_die(ExchangeName),
11841189
check_internal_exchange(Exchange),
1185-
check_write_permitted_on_topic(Exchange, User, RoutingKey, AuthzContext),
11861190
%% We decode the content's properties here because we're almost
11871191
%% certain to want to look at delivery-mode and priority.
11881192
DecodedContent = #content {properties = Props} =
@@ -1208,6 +1212,7 @@ handle_method(#'basic.publish'{exchange = ExchangeNameBin,
12081212
{error, Reason} ->
12091213
rabbit_misc:precondition_failed("invalid message: ~tp", [Reason]);
12101214
{ok, Message0} ->
1215+
check_write_permitted_on_topics(Exchange, User, Message0, AuthzContext),
12111216
Message = rabbit_message_interceptor:intercept(Message0),
12121217
check_user_id_header(Message, User),
12131218
QNames = rabbit_exchange:route(Exchange, Message, #{return_binding_keys => true}),

deps/rabbit/test/topic_permission_SUITE.erl

Lines changed: 124 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,52 +7,127 @@
77

88
-module(topic_permission_SUITE).
99

10-
-include_lib("rabbit_common/include/rabbit.hrl").
10+
-include_lib("eunit/include/eunit.hrl").
11+
-include_lib("amqp_client/include/amqp_client.hrl").
1112

12-
-compile(export_all).
13+
-compile([export_all, nowarn_export_all]).
1314

1415
all() ->
1516
[
16-
{group, sequential_tests}
17+
{group, sequential_tests}
1718
].
1819

19-
groups() -> [
20-
{sequential_tests, [], [
21-
topic_permission_database_access,
22-
topic_permission_checks
23-
]}
20+
groups() ->
21+
[
22+
{sequential_tests, [],
23+
[
24+
amqpl_cc_headers,
25+
amqpl_bcc_headers,
26+
topic_permission_database_access,
27+
topic_permission_checks
28+
]}
2429
].
2530

2631
init_per_suite(Config) ->
2732
rabbit_ct_helpers:log_environment(),
28-
Config1 = rabbit_ct_helpers:set_config(Config, [
29-
{rmq_nodename_suffix, ?MODULE}
30-
]),
31-
rabbit_ct_helpers:run_setup_steps(Config1,
32-
rabbit_ct_broker_helpers:setup_steps() ++
33-
rabbit_ct_client_helpers:setup_steps()).
33+
Config1 = rabbit_ct_helpers:set_config(
34+
Config,
35+
[{rmq_nodename_suffix, ?MODULE}]),
36+
rabbit_ct_helpers:run_setup_steps(
37+
Config1,
38+
rabbit_ct_broker_helpers:setup_steps() ++
39+
rabbit_ct_client_helpers:setup_steps()).
3440

3541
end_per_suite(Config) ->
36-
rabbit_ct_helpers:run_teardown_steps(Config,
37-
rabbit_ct_client_helpers:teardown_steps() ++
38-
rabbit_ct_broker_helpers:teardown_steps()).
42+
rabbit_ct_helpers:run_teardown_steps(
43+
Config,
44+
rabbit_ct_client_helpers:teardown_steps() ++
45+
rabbit_ct_broker_helpers:teardown_steps()).
46+
47+
init_per_group(_, Config) ->
48+
Config.
3949

40-
init_per_group(_, Config) -> Config.
41-
end_per_group(_, Config) -> Config.
50+
end_per_group(_, Config) ->
51+
Config.
4252

4353
init_per_testcase(Testcase, Config) ->
44-
ok = rabbit_ct_broker_helpers:rpc(Config, 0,
45-
?MODULE, clear_tables, []),
4654
rabbit_ct_helpers:testcase_started(Config, Testcase).
4755

48-
clear_tables() ->
49-
ok = rabbit_db_vhost:clear(),
50-
ok = rabbit_db_user:clear().
51-
5256
end_per_testcase(Testcase, Config) ->
5357
rabbit_ct_helpers:testcase_finished(Config, Testcase).
5458

59+
amqpl_cc_headers(Config) ->
60+
amqpl_headers(<<"CC">>, Config).
61+
62+
amqpl_bcc_headers(Config) ->
63+
amqpl_headers(<<"BCC">>, Config).
64+
65+
amqpl_headers(Header, Config) ->
66+
QName1 = <<"q1">>,
67+
QName2 = <<"q2">>,
68+
Ch1 = rabbit_ct_client_helpers:open_channel(Config),
69+
70+
ok = set_topic_permissions(Config, "^a", ".*"),
71+
72+
#'queue.declare_ok'{} = amqp_channel:call(Ch1, #'queue.declare'{queue = QName1}),
73+
#'queue.declare_ok'{} = amqp_channel:call(Ch1, #'queue.declare'{queue = QName2}),
74+
#'queue.bind_ok'{} = amqp_channel:call(Ch1, #'queue.bind'{queue = QName1,
75+
exchange = <<"amq.topic">>,
76+
routing_key = <<"a.1">>}),
77+
#'queue.bind_ok'{} = amqp_channel:call(Ch1, #'queue.bind'{queue = QName2,
78+
exchange = <<"amq.topic">>,
79+
routing_key = <<"a.2">>}),
80+
81+
amqp_channel:call(Ch1, #'confirm.select'{}),
82+
amqp_channel:register_confirm_handler(Ch1, self()),
83+
84+
%% We have permissions to send to both topics.
85+
%% Therefore, m1 should be sent to both queues.
86+
amqp_channel:call(
87+
Ch1,
88+
#'basic.publish'{exchange = <<"amq.topic">>,
89+
routing_key = <<"a.1">>},
90+
#amqp_msg{payload = <<"m1">>,
91+
props = #'P_basic'{headers = [{Header, array, [{longstr, <<"a.2">>}]}]}}),
92+
receive #'basic.ack'{} -> ok
93+
after 5000 -> ct:fail({missing_confirm, ?LINE})
94+
end,
95+
96+
monitor(process, Ch1),
97+
amqp_channel:call(
98+
Ch1,
99+
#'basic.publish'{exchange = <<"amq.topic">>,
100+
routing_key = <<"x.1">>},
101+
#amqp_msg{payload = <<"m2">>,
102+
props = #'P_basic'{headers = [{Header, array, [{longstr, <<"a.2">>}]}]}}),
103+
ok = assert_channel_down(
104+
Ch1,
105+
<<"ACCESS_REFUSED - write access to topic 'x.1' in exchange "
106+
"'amq.topic' in vhost '/' refused for user 'guest'">>),
107+
108+
Ch2 = rabbit_ct_client_helpers:open_channel(Config),
109+
monitor(process, Ch2),
110+
amqp_channel:call(
111+
Ch2,
112+
#'basic.publish'{exchange = <<"amq.topic">>,
113+
routing_key = <<"a.1">>},
114+
#amqp_msg{payload = <<"m3">>,
115+
props = #'P_basic'{headers = [{Header, array, [{longstr, <<"x.2">>}]}]}}),
116+
ok = assert_channel_down(
117+
Ch2,
118+
<<"ACCESS_REFUSED - write access to topic 'x.2' in exchange "
119+
"'amq.topic' in vhost '/' refused for user 'guest'">>),
120+
121+
Ch3 = rabbit_ct_client_helpers:open_channel(Config),
122+
?assertEqual(#'queue.delete_ok'{message_count = 1},
123+
amqp_channel:call(Ch3, #'queue.delete'{queue = QName1})),
124+
?assertEqual(#'queue.delete_ok'{message_count = 1},
125+
amqp_channel:call(Ch3, #'queue.delete'{queue = QName2})),
126+
ok = rabbit_ct_client_helpers:close_channel(Ch3),
127+
ok = clear_topic_permissions(Config).
128+
55129
topic_permission_database_access(Config) ->
130+
ok = rabbit_ct_broker_helpers:rpc(Config, ?MODULE, clear_tables, []),
56131
ok = rabbit_ct_broker_helpers:rpc(Config, 0,
57132
?MODULE, topic_permission_database_access1, [Config]).
58133

@@ -134,6 +209,7 @@ topic_permission_database_access1(_Config) ->
134209
ok.
135210

136211
topic_permission_checks(Config) ->
212+
ok = rabbit_ct_broker_helpers:rpc(Config, ?MODULE, clear_tables, []),
137213
ok = rabbit_ct_broker_helpers:rpc(Config, 0,
138214
?MODULE, topic_permission_checks1, [Config]).
139215

@@ -228,3 +304,26 @@ topic_permission_checks1(_Config) ->
228304
) || Perm <- Permissions],
229305

230306
ok.
307+
308+
clear_tables() ->
309+
ok = rabbit_db_vhost:clear(),
310+
ok = rabbit_db_user:clear().
311+
312+
set_topic_permissions(Config, WritePat, ReadPat) ->
313+
ok = rabbit_ct_broker_helpers:rpc(
314+
Config, 0, rabbit_auth_backend_internal, set_topic_permissions,
315+
[<<"guest">>, <<"/">>, <<"amq.topic">>, WritePat, ReadPat, <<"acting-user">>]).
316+
317+
clear_topic_permissions(Config) ->
318+
ok = rabbit_ct_broker_helpers:rpc(
319+
Config, 0, rabbit_auth_backend_internal, clear_topic_permissions,
320+
[<<"guest">>, <<"/">>, <<"acting-user">>]).
321+
322+
assert_channel_down(Ch, Reason) ->
323+
receive {'DOWN', _MonitorRef, process, Ch,
324+
{shutdown,
325+
{server_initiated_close, 403, Reason}}} ->
326+
ok
327+
after 5000 ->
328+
ct:fail({did_not_receive, Reason})
329+
end.

0 commit comments

Comments
 (0)