chore(authz): test Mria authz
This commit is contained in:
parent
d75e0104cc
commit
2bada0bab8
|
@ -114,18 +114,19 @@ authorize(#{username := Username,
|
|||
%% Management API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-spec(init_tables() -> ok).
|
||||
init_tables() ->
|
||||
ok = mria_rlog:wait_for_shards([?ACL_SHARDED], infinity).
|
||||
|
||||
-spec(store_rules(who(), rules()) -> ok).
|
||||
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);
|
||||
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);
|
||||
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).
|
||||
|
||||
-spec(purge_rules() -> ok).
|
||||
|
@ -176,6 +177,29 @@ record_count() ->
|
|||
%% 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) ->
|
||||
case mnesia:dirty_read(?ACL_TABLE, Key) of
|
||||
[#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, [ {Permission, Action, TopicFilter} | Tail]) ->
|
||||
case emqx_authz_rule:match(Client, PubSub, Topic,
|
||||
emqx_authz_rule:compile({Permission, all, Action, [TopicFilter]})
|
||||
) of
|
||||
Rule = emqx_authz_rule:compile({Permission, all, Action, [TopicFilter]}),
|
||||
case emqx_authz_rule:match(Client, PubSub, Topic, Rule) of
|
||||
{matched, Permission} -> {matched, Permission};
|
||||
nomatch -> do_authorize(Client, PubSub, Topic, Tail)
|
||||
end.
|
||||
|
|
|
@ -38,7 +38,7 @@ end_per_suite(_Config) ->
|
|||
ok = emqx_authz_test_lib:restore_authorizers(),
|
||||
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(),
|
||||
Config.
|
||||
|
||||
|
|
|
@ -18,10 +18,8 @@
|
|||
-compile(nowarn_export_all).
|
||||
-compile(export_all).
|
||||
|
||||
-include("emqx_authz.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-include_lib("common_test/include/ct.hrl").
|
||||
-include_lib("emqx/include/emqx_placeholder.hrl").
|
||||
|
||||
all() ->
|
||||
emqx_common_test_helpers:all(?MODULE).
|
||||
|
@ -31,86 +29,123 @@ groups() ->
|
|||
|
||||
init_per_suite(Config) ->
|
||||
ok = emqx_common_test_helpers:start_apps(
|
||||
[emqx_connector, emqx_conf, emqx_authz],
|
||||
fun set_special_configs/1
|
||||
),
|
||||
[emqx_conf, emqx_authz],
|
||||
fun set_special_configs/1),
|
||||
Config.
|
||||
|
||||
end_per_suite(_Config) ->
|
||||
{ok, _} = emqx:update_config(
|
||||
[authorization],
|
||||
#{<<"no_match">> => <<"allow">>,
|
||||
<<"cache">> => #{<<"enable">> => <<"true">>},
|
||||
<<"sources">> => []}),
|
||||
emqx_common_test_helpers:stop_apps([emqx_authz, emqx_conf]),
|
||||
ok.
|
||||
ok = emqx_authz_test_lib:restore_authorizers(),
|
||||
ok = emqx_common_test_helpers:stop_apps([emqx_authz]).
|
||||
|
||||
init_per_testcase(_TestCase, Config) ->
|
||||
ok = emqx_authz_test_lib:reset_authorizers(),
|
||||
ok = setup_config(),
|
||||
Config.
|
||||
|
||||
end_per_testcase(_TestCase, _Config) ->
|
||||
ok = emqx_authz_mnesia:purge_rules().
|
||||
|
||||
set_special_configs(emqx_authz) ->
|
||||
{ok, _} = emqx:update_config([authorization, cache, enable], false),
|
||||
{ok, _} = emqx:update_config([authorization, no_match], deny),
|
||||
{ok, _} = emqx:update_config([authorization, sources],
|
||||
[#{<<"type">> => <<"built-in-database">>}]),
|
||||
ok;
|
||||
set_special_configs(_App) ->
|
||||
ok = emqx_authz_test_lib:reset_authorizers();
|
||||
|
||||
set_special_configs(_) ->
|
||||
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
|
||||
%%------------------------------------------------------------------------------
|
||||
t_username_topic_rules(_Config) ->
|
||||
ok = test_topic_rules(username).
|
||||
|
||||
t_authz(_) ->
|
||||
ClientInfo1 = #{clientid => <<"test">>,
|
||||
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}
|
||||
},
|
||||
t_clientid_topic_rules(_Config) ->
|
||||
ok = test_topic_rules(clientid).
|
||||
|
||||
?assertEqual(deny, emqx_access_control:authorize(
|
||||
ClientInfo1, subscribe, <<"#">>)),
|
||||
?assertEqual(deny, emqx_access_control:authorize(
|
||||
ClientInfo1, publish, <<"#">>)),
|
||||
t_all_topic_rules(_Config) ->
|
||||
ok = test_topic_rules(all).
|
||||
|
||||
?assertEqual(allow, emqx_access_control:authorize(
|
||||
ClientInfo2, publish, <<"test/test_username">>)),
|
||||
?assertEqual(allow, emqx_access_control:authorize(
|
||||
ClientInfo2, subscribe, <<"#">>)),
|
||||
test_topic_rules(Key) ->
|
||||
ClientInfo = #{clientid => <<"clientid">>,
|
||||
username => <<"username">>,
|
||||
peerhost => {127,0,0,1},
|
||||
zone => default,
|
||||
listener => {tcp, default}
|
||||
},
|
||||
|
||||
?assertEqual(allow, emqx_access_control:authorize(
|
||||
ClientInfo3, publish, <<"test/test_clientid">>)),
|
||||
?assertEqual(deny, emqx_access_control:authorize(
|
||||
ClientInfo3, subscribe, <<"#">>)),
|
||||
SetupSamples = fun(CInfo, Samples) ->
|
||||
setup_client_samples(CInfo, Samples, Key)
|
||||
end,
|
||||
|
||||
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(), #{}).
|
||||
|
|
|
@ -56,7 +56,7 @@ end_per_suite(_Config) ->
|
|||
ok = stop_apps([emqx_resource, emqx_connector]),
|
||||
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(),
|
||||
Config.
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ end_per_suite(_Config) ->
|
|||
ok = stop_apps([emqx_resource, emqx_connector]),
|
||||
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(),
|
||||
Config.
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ end_per_suite(_Config) ->
|
|||
ok = stop_apps([emqx_resource, emqx_connector]),
|
||||
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(),
|
||||
Config.
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ test_samples(ClientInfo, Samples) ->
|
|||
test_no_topic_rules(ClientInfo, SetupSamples) ->
|
||||
%% No rules
|
||||
|
||||
ok = reset_authorizers(deny, false),
|
||||
ok = SetupSamples(ClientInfo, []),
|
||||
|
||||
ok = test_samples(
|
||||
|
|
Loading…
Reference in New Issue