fix(acl): Check the real topic in delayed messages

We need to check the true topic of the delayed message correctly
the cheapest way to do this is to extract the true topic from the original topic when doing ACL check
This commit is contained in:
firest 2022-11-03 14:18:28 +08:00
parent 1580f02045
commit bd13ae0ad6
2 changed files with 46 additions and 0 deletions

View File

@ -24,6 +24,11 @@
authorize/3 authorize/3
]). ]).
-ifdef(TEST).
-compile(export_all).
-compile(nowarn_export_all).
-endif.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% APIs %% APIs
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
@ -45,6 +50,19 @@ authenticate(Credential) ->
%% @doc Check Authorization %% @doc Check Authorization
-spec authorize(emqx_types:clientinfo(), emqx_types:pubsub(), emqx_types:topic()) -> -spec authorize(emqx_types:clientinfo(), emqx_types:pubsub(), emqx_types:topic()) ->
allow | deny. allow | deny.
authorize(ClientInfo, PubSub, <<"$delayed/", Data/binary>> = RawTopic) ->
case binary:split(Data, <<"/">>) of
[_, Topic] ->
authorize(ClientInfo, PubSub, Topic);
_ ->
?SLOG(warning, #{
msg => "invalid_dealyed_topic_format",
expected_example => "$delayed/1/t/foo",
got => RawTopic
}),
inc_authz_metrics(deny),
deny
end;
authorize(ClientInfo, PubSub, Topic) -> authorize(ClientInfo, PubSub, Topic) ->
Result = Result =
case emqx_authz_cache:is_enabled() of case emqx_authz_cache:is_enabled() of

View File

@ -32,6 +32,12 @@ init_per_suite(Config) ->
end_per_suite(_Config) -> end_per_suite(_Config) ->
emqx_common_test_helpers:stop_apps([]). emqx_common_test_helpers:stop_apps([]).
end_per_testcase(t_delayed_authorize, Config) ->
meck:unload(emqx_access_control),
Config;
end_per_testcase(_, Config) ->
Config.
t_authenticate(_) -> t_authenticate(_) ->
?assertMatch({ok, _}, emqx_access_control:authenticate(clientinfo())). ?assertMatch({ok, _}, emqx_access_control:authenticate(clientinfo())).
@ -39,6 +45,28 @@ t_authorize(_) ->
Publish = ?PUBLISH_PACKET(?QOS_0, <<"t">>, 1, <<"payload">>), Publish = ?PUBLISH_PACKET(?QOS_0, <<"t">>, 1, <<"payload">>),
?assertEqual(allow, emqx_access_control:authorize(clientinfo(), Publish, <<"t">>)). ?assertEqual(allow, emqx_access_control:authorize(clientinfo(), Publish, <<"t">>)).
t_delayed_authorize(_) ->
RawTopic = "$dealyed/1/foo/2",
InvalidTopic = "$dealyed/1/foo/3",
Topic = "foo/2",
ok = meck:new(emqx_access_control, [passthrough, no_history, no_link]),
ok = meck:expect(
emqx_access_control,
do_authorize,
fun
(_, _, Topic) -> allow;
(_, _, _) -> deny
end
),
Publish1 = ?PUBLISH_PACKET(?QOS_0, RawTopic, 1, <<"payload">>),
?assertEqual(allow, emqx_access_control:authorize(clientinfo(), Publish1, RawTopic)),
Publish2 = ?PUBLISH_PACKET(?QOS_0, InvalidTopic, 1, <<"payload">>),
?assertEqual(allow, emqx_access_control:authorize(clientinfo(), Publish2, InvalidTopic)),
ok.
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Helper functions %% Helper functions
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------