|
|
@@ -19,9 +19,12 @@
|
|
|
-compile(export_all).
|
|
|
|
|
|
-include("emqx_authz.hrl").
|
|
|
+-include_lib("emqx/include/emqx.hrl").
|
|
|
+-include_lib("emqx/include/emqx_mqtt.hrl").
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
-include_lib("common_test/include/ct.hrl").
|
|
|
-include_lib("emqx/include/emqx_placeholder.hrl").
|
|
|
+-include_lib("snabbkaffe/include/snabbkaffe.hrl").
|
|
|
|
|
|
all() ->
|
|
|
emqx_common_test_helpers:all(?MODULE).
|
|
|
@@ -61,10 +64,26 @@ end_per_suite(_Config) ->
|
|
|
meck:unload(emqx_resource),
|
|
|
ok.
|
|
|
|
|
|
+init_per_testcase(TestCase, Config) when
|
|
|
+ TestCase =:= t_subscribe_deny_disconnect_publishes_last_will_testament;
|
|
|
+ TestCase =:= t_publish_deny_disconnect_publishes_last_will_testament
|
|
|
+->
|
|
|
+ {ok, _} = emqx_authz:update(?CMD_REPLACE, []),
|
|
|
+ {ok, _} = emqx:update_config([authorization, deny_action], disconnect),
|
|
|
+ Config;
|
|
|
init_per_testcase(_, Config) ->
|
|
|
{ok, _} = emqx_authz:update(?CMD_REPLACE, []),
|
|
|
Config.
|
|
|
|
|
|
+end_per_testcase(TestCase, _Config) when
|
|
|
+ TestCase =:= t_subscribe_deny_disconnect_publishes_last_will_testament;
|
|
|
+ TestCase =:= t_publish_deny_disconnect_publishes_last_will_testament
|
|
|
+->
|
|
|
+ {ok, _} = emqx:update_config([authorization, deny_action], ignore),
|
|
|
+ ok;
|
|
|
+end_per_testcase(_TestCase, _Config) ->
|
|
|
+ ok.
|
|
|
+
|
|
|
set_special_configs(emqx_authz) ->
|
|
|
{ok, _} = emqx:update_config([authorization, cache, enable], false),
|
|
|
{ok, _} = emqx:update_config([authorization, no_match], deny),
|
|
|
@@ -139,6 +158,15 @@ set_special_configs(_App) ->
|
|
|
"\n{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}."
|
|
|
>>
|
|
|
}).
|
|
|
+-define(SOURCE7, #{
|
|
|
+ <<"type">> => <<"file">>,
|
|
|
+ <<"enable">> => true,
|
|
|
+ <<"rules">> =>
|
|
|
+ <<
|
|
|
+ "{allow,{username,\"some_client\"},publish,[\"some_client/lwt\"]}.\n"
|
|
|
+ "{deny, all}."
|
|
|
+ >>
|
|
|
+}).
|
|
|
|
|
|
%%------------------------------------------------------------------------------
|
|
|
%% Testcases
|
|
|
@@ -287,5 +315,87 @@ t_get_enabled_authzs_some_enabled(_Config) ->
|
|
|
{ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE4]),
|
|
|
?assertEqual([postgresql], emqx_authz:get_enabled_authzs()).
|
|
|
|
|
|
+t_subscribe_deny_disconnect_publishes_last_will_testament(_Config) ->
|
|
|
+ {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE7]),
|
|
|
+ {ok, C} = emqtt:start_link([
|
|
|
+ {username, <<"some_client">>},
|
|
|
+ {will_topic, <<"some_client/lwt">>},
|
|
|
+ {will_payload, <<"should be published">>}
|
|
|
+ ]),
|
|
|
+ {ok, _} = emqtt:connect(C),
|
|
|
+ ok = emqx:subscribe(<<"some_client/lwt">>),
|
|
|
+ process_flag(trap_exit, true),
|
|
|
+
|
|
|
+ try
|
|
|
+ emqtt:subscribe(C, <<"unauthorized">>),
|
|
|
+ error(should_have_disconnected)
|
|
|
+ catch
|
|
|
+ exit:{{shutdown, tcp_closed}, _} ->
|
|
|
+ ok
|
|
|
+ end,
|
|
|
+
|
|
|
+ receive
|
|
|
+ {deliver, <<"some_client/lwt">>, #message{payload = <<"should be published">>}} ->
|
|
|
+ ok
|
|
|
+ after 2_000 ->
|
|
|
+ error(lwt_not_published)
|
|
|
+ end,
|
|
|
+
|
|
|
+ ok.
|
|
|
+
|
|
|
+t_publish_deny_disconnect_publishes_last_will_testament(_Config) ->
|
|
|
+ {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE7]),
|
|
|
+ {ok, C} = emqtt:start_link([
|
|
|
+ {username, <<"some_client">>},
|
|
|
+ {will_topic, <<"some_client/lwt">>},
|
|
|
+ {will_payload, <<"should be published">>}
|
|
|
+ ]),
|
|
|
+ {ok, _} = emqtt:connect(C),
|
|
|
+ ok = emqx:subscribe(<<"some_client/lwt">>),
|
|
|
+ process_flag(trap_exit, true),
|
|
|
+
|
|
|
+ %% disconnect is async
|
|
|
+ Ref = monitor(process, C),
|
|
|
+ emqtt:publish(C, <<"some/topic">>, <<"unauthorized">>),
|
|
|
+ receive
|
|
|
+ {'DOWN', Ref, process, C, _} ->
|
|
|
+ ok
|
|
|
+ after 1_000 ->
|
|
|
+ error(client_should_have_been_disconnected)
|
|
|
+ end,
|
|
|
+ receive
|
|
|
+ {deliver, <<"some_client/lwt">>, #message{payload = <<"should be published">>}} ->
|
|
|
+ ok
|
|
|
+ after 2_000 ->
|
|
|
+ error(lwt_not_published)
|
|
|
+ end,
|
|
|
+
|
|
|
+ ok.
|
|
|
+
|
|
|
+t_publish_last_will_testament_denied_topic(_Config) ->
|
|
|
+ {ok, C} = emqtt:start_link([
|
|
|
+ {will_topic, <<"$SYS/lwt">>},
|
|
|
+ {will_payload, <<"should not be published">>}
|
|
|
+ ]),
|
|
|
+ {ok, _} = emqtt:connect(C),
|
|
|
+ ok = emqx:subscribe(<<"$SYS/lwt">>),
|
|
|
+ unlink(C),
|
|
|
+ ok = snabbkaffe:start_trace(),
|
|
|
+ {true, {ok, _}} = ?wait_async_action(
|
|
|
+ exit(C, kill),
|
|
|
+ #{?snk_kind := last_will_testament_publish_denied},
|
|
|
+ 1_000
|
|
|
+ ),
|
|
|
+ ok = snabbkaffe:stop(),
|
|
|
+
|
|
|
+ receive
|
|
|
+ {deliver, <<"$SYS/lwt">>, #message{payload = <<"should not be published">>}} ->
|
|
|
+ error(lwt_should_not_be_published_to_forbidden_topic)
|
|
|
+ after 1_000 ->
|
|
|
+ ok
|
|
|
+ end,
|
|
|
+
|
|
|
+ ok.
|
|
|
+
|
|
|
stop_apps(Apps) ->
|
|
|
lists:foreach(fun application:stop/1, Apps).
|