chore(authz): test Mria authz

This commit is contained in:
Ilya Averyanov 2021-12-21 14:08:13 +03:00
parent d75e0104cc
commit 2bada0bab8
7 changed files with 139 additions and 80 deletions

View File

@ -114,18 +114,19 @@ authorize(#{username := Username,
%% Management API %% Management API
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-spec(init_tables() -> ok).
init_tables() -> init_tables() ->
ok = mria_rlog:wait_for_shards([?ACL_SHARDED], infinity). ok = mria_rlog:wait_for_shards([?ACL_SHARDED], infinity).
-spec(store_rules(who(), rules()) -> ok). -spec(store_rules(who(), rules()) -> ok).
store_rules({username, Username}, Rules) -> store_rules({username, Username}, Rules) ->
Record = #emqx_acl{who = {?ACL_TABLE_USERNAME, Username}, rules = Rules}, Record = #emqx_acl{who = {?ACL_TABLE_USERNAME, Username}, rules = normalize_rules(Rules)},
mria:dirty_write(Record); mria:dirty_write(Record);
store_rules({clientid, Clientid}, Rules) -> store_rules({clientid, Clientid}, Rules) ->
Record = #emqx_acl{who = {?ACL_TABLE_CLIENTID, Clientid}, rules = Rules}, Record = #emqx_acl{who = {?ACL_TABLE_CLIENTID, Clientid}, rules = normalize_rules(Rules)},
mria:dirty_write(Record); mria:dirty_write(Record);
store_rules(all, Rules) -> store_rules(all, Rules) ->
Record = #emqx_acl{who = ?ACL_TABLE_ALL, rules = Rules}, Record = #emqx_acl{who = ?ACL_TABLE_ALL, rules = normalize_rules(Rules)},
mria:dirty_write(Record). mria:dirty_write(Record).
-spec(purge_rules() -> ok). -spec(purge_rules() -> ok).
@ -176,6 +177,29 @@ record_count() ->
%% Internal functions %% Internal functions
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
normalize_rules(Rules) ->
lists:map(fun normalize_rule/1, Rules).
normalize_rule({Permission, Action, Topic}) ->
{normalize_permission(Permission),
normalize_action(Action),
normalize_topic(Topic)};
normalize_rule(Rule) ->
error({invalid_rule, Rule}).
normalize_topic(Topic) when is_list(Topic) -> list_to_binary(Topic);
normalize_topic(Topic) when is_binary(Topic) -> Topic;
normalize_topic(Topic) -> error({invalid_rule_topic, Topic}).
normalize_action(publish) -> publish;
normalize_action(subscribe) -> subscribe;
normalize_action(all) -> all;
normalize_action(Action) -> error({invalid_rule_action, Action}).
normalize_permission(allow) -> allow;
normalize_permission(deny) -> deny;
normalize_permission(Permission) -> error({invalid_rule_permission, Permission}).
do_get_rules(Key) -> do_get_rules(Key) ->
case mnesia:dirty_read(?ACL_TABLE, Key) of case mnesia:dirty_read(?ACL_TABLE, Key) of
[#emqx_acl{rules = Rules}] -> {ok, Rules}; [#emqx_acl{rules = Rules}] -> {ok, Rules};
@ -184,9 +208,8 @@ do_get_rules(Key) ->
do_authorize(_Client, _PubSub, _Topic, []) -> nomatch; do_authorize(_Client, _PubSub, _Topic, []) -> nomatch;
do_authorize(Client, PubSub, Topic, [ {Permission, Action, TopicFilter} | Tail]) -> do_authorize(Client, PubSub, Topic, [ {Permission, Action, TopicFilter} | Tail]) ->
case emqx_authz_rule:match(Client, PubSub, Topic, Rule = emqx_authz_rule:compile({Permission, all, Action, [TopicFilter]}),
emqx_authz_rule:compile({Permission, all, Action, [TopicFilter]}) case emqx_authz_rule:match(Client, PubSub, Topic, Rule) of
) of
{matched, Permission} -> {matched, Permission}; {matched, Permission} -> {matched, Permission};
nomatch -> do_authorize(Client, PubSub, Topic, Tail) nomatch -> do_authorize(Client, PubSub, Topic, Tail)
end. end.

View File

@ -38,7 +38,7 @@ end_per_suite(_Config) ->
ok = emqx_authz_test_lib:restore_authorizers(), ok = emqx_authz_test_lib:restore_authorizers(),
ok = emqx_common_test_helpers:stop_apps([emqx_authz]). ok = emqx_common_test_helpers:stop_apps([emqx_authz]).
init_per_testcase(Config) -> init_per_testcase(_TestCase, Config) ->
ok = emqx_authz_test_lib:reset_authorizers(), ok = emqx_authz_test_lib:reset_authorizers(),
Config. Config.

View File

@ -18,10 +18,8 @@
-compile(nowarn_export_all). -compile(nowarn_export_all).
-compile(export_all). -compile(export_all).
-include("emqx_authz.hrl").
-include_lib("eunit/include/eunit.hrl"). -include_lib("eunit/include/eunit.hrl").
-include_lib("common_test/include/ct.hrl"). -include_lib("common_test/include/ct.hrl").
-include_lib("emqx/include/emqx_placeholder.hrl").
all() -> all() ->
emqx_common_test_helpers:all(?MODULE). emqx_common_test_helpers:all(?MODULE).
@ -31,86 +29,123 @@ groups() ->
init_per_suite(Config) -> init_per_suite(Config) ->
ok = emqx_common_test_helpers:start_apps( ok = emqx_common_test_helpers:start_apps(
[emqx_connector, emqx_conf, emqx_authz], [emqx_conf, emqx_authz],
fun set_special_configs/1 fun set_special_configs/1),
),
Config. Config.
end_per_suite(_Config) -> end_per_suite(_Config) ->
{ok, _} = emqx:update_config( ok = emqx_authz_test_lib:restore_authorizers(),
[authorization], ok = emqx_common_test_helpers:stop_apps([emqx_authz]).
#{<<"no_match">> => <<"allow">>,
<<"cache">> => #{<<"enable">> => <<"true">>}, init_per_testcase(_TestCase, Config) ->
<<"sources">> => []}), ok = emqx_authz_test_lib:reset_authorizers(),
emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]), ok = setup_config(),
ok. Config.
end_per_testcase(_TestCase, _Config) ->
ok = emqx_authz_mnesia:purge_rules().
set_special_configs(emqx_authz) -> set_special_configs(emqx_authz) ->
{ok, _} = emqx:update_config([authorization, cache, enable], false), ok = emqx_authz_test_lib:reset_authorizers();
{ok, _} = emqx:update_config([authorization, no_match], deny),
{ok, _} = emqx:update_config([authorization, sources], set_special_configs(_) ->
[#{<<"type">> => <<"built-in-database">>}]),
ok;
set_special_configs(_App) ->
ok. ok.
init_per_testcase(t_authz, Config) ->
emqx_authz_mnesia:store_rules(
{username, <<"test_username">>},
[{allow, publish, <<"test/", ?PH_S_USERNAME>>},
{allow, subscribe, <<"eq #">>}]),
emqx_authz_mnesia:store_rules(
{clientid, <<"test_clientid">>},
[{allow, publish, <<"test/", ?PH_S_CLIENTID>>},
{deny, subscribe, <<"eq #">>}]),
emqx_authz_mnesia:store_rules(
all,
[{deny, all, <<"#">>}]),
Config;
init_per_testcase(_, Config) -> Config.
end_per_testcase(t_authz, Config) ->
ok = emqx_authz_mnesia:purge_rules(),
Config;
end_per_testcase(_, Config) -> Config.
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
%% Testcases %% Testcases
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
t_username_topic_rules(_Config) ->
ok = test_topic_rules(username).
t_authz(_) -> t_clientid_topic_rules(_Config) ->
ClientInfo1 = #{clientid => <<"test">>, ok = test_topic_rules(clientid).
username => <<"test">>,
peerhost => {127,0,0,1},
listener => {tcp, default}
},
ClientInfo2 = #{clientid => <<"fake_clientid">>,
username => <<"test_username">>,
peerhost => {127,0,0,1},
listener => {tcp, default}
},
ClientInfo3 = #{clientid => <<"test_clientid">>,
username => <<"fake_username">>,
peerhost => {127,0,0,1},
listener => {tcp, default}
},
?assertEqual(deny, emqx_access_control:authorize( t_all_topic_rules(_Config) ->
ClientInfo1, subscribe, <<"#">>)), ok = test_topic_rules(all).
?assertEqual(deny, emqx_access_control:authorize(
ClientInfo1, publish, <<"#">>)),
?assertEqual(allow, emqx_access_control:authorize( test_topic_rules(Key) ->
ClientInfo2, publish, <<"test/test_username">>)), ClientInfo = #{clientid => <<"clientid">>,
?assertEqual(allow, emqx_access_control:authorize( username => <<"username">>,
ClientInfo2, subscribe, <<"#">>)), peerhost => {127,0,0,1},
zone => default,
listener => {tcp, default}
},
?assertEqual(allow, emqx_access_control:authorize( SetupSamples = fun(CInfo, Samples) ->
ClientInfo3, publish, <<"test/test_clientid">>)), setup_client_samples(CInfo, Samples, Key)
?assertEqual(deny, emqx_access_control:authorize( end,
ClientInfo3, subscribe, <<"#">>)),
ok. ok = emqx_authz_test_lib:test_no_topic_rules(ClientInfo, SetupSamples),
ok = emqx_authz_test_lib:test_allow_topic_rules(ClientInfo, SetupSamples),
ok = emqx_authz_test_lib:test_deny_topic_rules(ClientInfo, SetupSamples).
t_normalize_rules(_Config) ->
ClientInfo = #{clientid => <<"clientid">>,
username => <<"username">>,
peerhost => {127,0,0,1},
zone => default,
listener => {tcp, default}
},
ok = emqx_authz_mnesia:store_rules(
{username, <<"username">>},
[{allow, publish, "t"}]),
?assertEqual(
allow,
emqx_access_control:authorize(ClientInfo, publish, <<"t">>)),
?assertException(
error,
{invalid_rule, _},
emqx_authz_mnesia:store_rules(
{username, <<"username">>},
[[allow, publish, <<"t">>]])),
?assertException(
error,
{invalid_rule_action, _},
emqx_authz_mnesia:store_rules(
{username, <<"username">>},
[{allow, pub, <<"t">>}])),
?assertException(
error,
{invalid_rule_permission, _},
emqx_authz_mnesia:store_rules(
{username, <<"username">>},
[{accept, publish, <<"t">>}])).
%%------------------------------------------------------------------------------
%% Helpers
%%------------------------------------------------------------------------------
raw_mnesia_authz_config() ->
#{
<<"enable">> => <<"true">>,
<<"type">> => <<"built-in-database">>
}.
setup_client_samples(ClientInfo, Samples, Key) ->
ok = emqx_authz_mnesia:purge_rules(),
Rules = lists:flatmap(
fun(#{topics := Topics, permission := Permission, action := Action}) ->
lists:map(
fun(Topic) ->
{binary_to_atom(Permission), binary_to_atom(Action), Topic}
end,
Topics)
end,
Samples),
#{username := Username, clientid := ClientId} = ClientInfo,
Who = case Key of
username -> {username, Username};
clientid -> {clientid, ClientId};
all -> all
end,
ok = emqx_authz_mnesia:store_rules(Who, Rules).
setup_config() ->
emqx_authz_test_lib:setup_config(raw_mnesia_authz_config(), #{}).

View File

@ -56,7 +56,7 @@ end_per_suite(_Config) ->
ok = stop_apps([emqx_resource, emqx_connector]), ok = stop_apps([emqx_resource, emqx_connector]),
ok = emqx_common_test_helpers:stop_apps([emqx_authz]). ok = emqx_common_test_helpers:stop_apps([emqx_authz]).
init_per_testcase(Config) -> init_per_testcase(_TestCase, Config) ->
ok = emqx_authz_test_lib:reset_authorizers(), ok = emqx_authz_test_lib:reset_authorizers(),
Config. Config.

View File

@ -56,7 +56,7 @@ end_per_suite(_Config) ->
ok = stop_apps([emqx_resource, emqx_connector]), ok = stop_apps([emqx_resource, emqx_connector]),
ok = emqx_common_test_helpers:stop_apps([emqx_authz]). ok = emqx_common_test_helpers:stop_apps([emqx_authz]).
init_per_testcase(Config) -> init_per_testcase(_TestCase, Config) ->
ok = emqx_authz_test_lib:reset_authorizers(), ok = emqx_authz_test_lib:reset_authorizers(),
Config. Config.

View File

@ -57,7 +57,7 @@ end_per_suite(_Config) ->
ok = stop_apps([emqx_resource, emqx_connector]), ok = stop_apps([emqx_resource, emqx_connector]),
ok = emqx_common_test_helpers:stop_apps([emqx_authz]). ok = emqx_common_test_helpers:stop_apps([emqx_authz]).
init_per_testcase(Config) -> init_per_testcase(_TestCase, Config) ->
ok = emqx_authz_test_lib:reset_authorizers(), ok = emqx_authz_test_lib:reset_authorizers(),
Config. Config.

View File

@ -70,6 +70,7 @@ test_samples(ClientInfo, Samples) ->
test_no_topic_rules(ClientInfo, SetupSamples) -> test_no_topic_rules(ClientInfo, SetupSamples) ->
%% No rules %% No rules
ok = reset_authorizers(deny, false),
ok = SetupSamples(ClientInfo, []), ok = SetupSamples(ClientInfo, []),
ok = test_samples( ok = test_samples(