chore(authz mnesia): in the mnesia table, replace atom with int

This commit is contained in:
zhanghongtong 2021-09-23 21:05:11 +08:00
parent 9b3917e0d3
commit 673b12a46d
5 changed files with 38 additions and 29 deletions

View File

@ -55,6 +55,10 @@ authorization {
# collection: mqtt_authz # collection: mqtt_authz
# selector: { "$or": [ { "username": "%u" }, { "clientid": "%c" } ] } # selector: { "$or": [ { "username": "%u" }, { "clientid": "%c" } ] }
# }, # },
{
type: built-in-database
path: "{{ platform_etc_dir }}/acl.conf"
}
{ {
type: file type: file
path: "{{ platform_etc_dir }}/acl.conf" path: "{{ platform_etc_dir }}/acl.conf"

View File

@ -19,15 +19,6 @@
-type(sources() :: [map()]). -type(sources() :: [map()]).
-define(ACL_SHARDED, emqx_acl_sharded).
-define(ACL_TABLE, emqx_acl).
-record(emqx_acl, {
who :: username() | clientid() | all,
rules :: [ {permission(), action(), emqx_topic:topic()} ]
}).
-define(APP, emqx_authz). -define(APP, emqx_authz).
-define(ALLOW_DENY(A), ((A =:= allow) orelse (A =:= <<"allow">>) orelse -define(ALLOW_DENY(A), ((A =:= allow) orelse (A =:= <<"allow">>) orelse
@ -38,6 +29,20 @@
(A =:= all) orelse (A =:= <<"all">>) (A =:= all) orelse (A =:= <<"all">>)
)). )).
-define(ACL_SHARDED, emqx_acl_sharded).
-define(ACL_TABLE, emqx_acl).
%% To save some space, use an integer for label, 0 for 'all', {1, Username} and {2, ClientId}.
-define(ACL_TABLE_ALL, 0).
-define(ACL_TABLE_USERNAME, 1).
-define(ACL_TABLE_CLIENTID, 2).
-record(emqx_acl, {
who :: ?ACL_TABLE_ALL| {?ACL_TABLE_USERNAME, binary()} | {?ACL_TABLE_CLIENTID, binary()},
rules :: [ {permission(), action(), emqx_topic:topic()} ]
}).
-record(authz_metrics, { -record(authz_metrics, {
allow = 'client.authorize.allow', allow = 'client.authorize.allow',
deny = 'client.authorize.deny', deny = 'client.authorize.deny',

View File

@ -409,7 +409,7 @@ records(get, #{bindings := #{type := <<"username">>},
query_string := Qs query_string := Qs
}) -> }) ->
MatchSpec = ets:fun2ms( MatchSpec = ets:fun2ms(
fun({?ACL_TABLE, {username, Username}, Rules}) -> fun({?ACL_TABLE, {?ACL_TABLE_USERNAME, Username}, Rules}) ->
[{username, Username}, {rules, Rules}] [{username, Username}, {rules, Rules}]
end), end),
Format = fun ([{username, Username}, {rules, Rules}]) -> Format = fun ([{username, Username}, {rules, Rules}]) ->
@ -436,7 +436,7 @@ records(get, #{bindings := #{type := <<"clientid">>},
query_string := Qs query_string := Qs
}) -> }) ->
MatchSpec = ets:fun2ms( MatchSpec = ets:fun2ms(
fun({?ACL_TABLE, {clientid, Clientid}, Rules}) -> fun({?ACL_TABLE, {?ACL_TABLE_CLIENTID, Clientid}, Rules}) ->
[{clientid, Clientid}, {rules, Rules}] [{clientid, Clientid}, {rules, Rules}]
end), end),
Format = fun ([{clientid, Clientid}, {rules, Rules}]) -> Format = fun ([{clientid, Clientid}, {rules, Rules}]) ->
@ -460,7 +460,7 @@ records(get, #{bindings := #{type := <<"clientid">>},
end; end;
records(get, #{bindings := #{type := <<"all">>}}) -> records(get, #{bindings := #{type := <<"all">>}}) ->
MatchSpec = ets:fun2ms( MatchSpec = ets:fun2ms(
fun({?ACL_TABLE, all, Rules}) -> fun({?ACL_TABLE, ?ACL_TABLE_ALL, Rules}) ->
[{rules, Rules}] [{rules, Rules}]
end), end),
{200, [ #{rules => [ #{topic => Topic, {200, [ #{rules => [ #{topic => Topic,
@ -472,7 +472,7 @@ records(post, #{bindings := #{type := <<"username">>},
body := Body}) when is_list(Body) -> body := Body}) when is_list(Body) ->
lists:foreach(fun(#{<<"username">> := Username, <<"rules">> := Rules}) -> lists:foreach(fun(#{<<"username">> := Username, <<"rules">> := Rules}) ->
ekka_mnesia:dirty_write(#emqx_acl{ ekka_mnesia:dirty_write(#emqx_acl{
who = {username, Username}, who = {?ACL_TABLE_USERNAME, Username},
rules = format_rules(Rules) rules = format_rules(Rules)
}) })
end, Body), end, Body),
@ -481,7 +481,7 @@ records(post, #{bindings := #{type := <<"clientid">>},
body := Body}) when is_list(Body) -> body := Body}) when is_list(Body) ->
lists:foreach(fun(#{<<"clientid">> := Clientid, <<"rules">> := Rules}) -> lists:foreach(fun(#{<<"clientid">> := Clientid, <<"rules">> := Rules}) ->
ekka_mnesia:dirty_write(#emqx_acl{ ekka_mnesia:dirty_write(#emqx_acl{
who = {clientid, Clientid}, who = {?ACL_TABLE_CLIENTID, Clientid},
rules = format_rules(Rules) rules = format_rules(Rules)
}) })
end, Body), end, Body),
@ -489,15 +489,15 @@ records(post, #{bindings := #{type := <<"clientid">>},
records(put, #{bindings := #{type := <<"all">>}, records(put, #{bindings := #{type := <<"all">>},
body := #{<<"rules">> := Rules}}) -> body := #{<<"rules">> := Rules}}) ->
ekka_mnesia:dirty_write(#emqx_acl{ ekka_mnesia:dirty_write(#emqx_acl{
who = all, who = ?ACL_TABLE_ALL,
rules = format_rules(Rules) rules = format_rules(Rules)
}), }),
{204}. {204}.
record(get, #{bindings := #{type := <<"username">>, key := Key}}) -> record(get, #{bindings := #{type := <<"username">>, key := Key}}) ->
case mnesia:dirty_read(?ACL_TABLE, {username, Key}) of case mnesia:dirty_read(?ACL_TABLE, {?ACL_TABLE_USERNAME, Key}) of
[] -> {404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}}; [] -> {404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}};
[#emqx_acl{who = {username, Username}, rules = Rules}] -> [#emqx_acl{who = {?ACL_TABLE_USERNAME, Username}, rules = Rules}] ->
{200, #{username => Username, {200, #{username => Username,
rules => [ #{topic => Topic, rules => [ #{topic => Topic,
action => Action, action => Action,
@ -506,9 +506,9 @@ record(get, #{bindings := #{type := <<"username">>, key := Key}}) ->
} }
end; end;
record(get, #{bindings := #{type := <<"clientid">>, key := Key}}) -> record(get, #{bindings := #{type := <<"clientid">>, key := Key}}) ->
case mnesia:dirty_read(?ACL_TABLE, {clientid, Key}) of case mnesia:dirty_read(?ACL_TABLE, {?ACL_TABLE_CLIENTID, Key}) of
[] -> {404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}}; [] -> {404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}};
[#emqx_acl{who = {clientid, Clientid}, rules = Rules}] -> [#emqx_acl{who = {?ACL_TABLE_CLIENTID, Clientid}, rules = Rules}] ->
{200, #{clientid => Clientid, {200, #{clientid => Clientid,
rules => [ #{topic => Topic, rules => [ #{topic => Topic,
action => Action, action => Action,
@ -519,22 +519,22 @@ record(get, #{bindings := #{type := <<"clientid">>, key := Key}}) ->
record(put, #{bindings := #{type := <<"username">>, key := Username}, record(put, #{bindings := #{type := <<"username">>, key := Username},
body := #{<<"username">> := Username, <<"rules">> := Rules}}) -> body := #{<<"username">> := Username, <<"rules">> := Rules}}) ->
ekka_mnesia:dirty_write(#emqx_acl{ ekka_mnesia:dirty_write(#emqx_acl{
who = {username, Username}, who = {?ACL_TABLE_USERNAME, Username},
rules = format_rules(Rules) rules = format_rules(Rules)
}), }),
{204}; {204};
record(put, #{bindings := #{type := <<"clientid">>, key := Clientid}, record(put, #{bindings := #{type := <<"clientid">>, key := Clientid},
body := #{<<"clientid">> := Clientid, <<"rules">> := Rules}}) -> body := #{<<"clientid">> := Clientid, <<"rules">> := Rules}}) ->
ekka_mnesia:dirty_write(#emqx_acl{ ekka_mnesia:dirty_write(#emqx_acl{
who = {clientid, Clientid}, who = {?ACL_TABLE_CLIENTID, Clientid},
rules = format_rules(Rules) rules = format_rules(Rules)
}), }),
{204}; {204};
record(delete, #{bindings := #{type := <<"username">>, key := Key}}) -> record(delete, #{bindings := #{type := <<"username">>, key := Key}}) ->
ekka_mnesia:dirty_delete({?ACL_TABLE, {username, Key}}), ekka_mnesia:dirty_delete({?ACL_TABLE, {?ACL_TABLE_USERNAME, Key}}),
{204}; {204};
record(delete, #{bindings := #{type := <<"clientid">>, key := Key}}) -> record(delete, #{bindings := #{type := <<"clientid">>, key := Key}}) ->
ekka_mnesia:dirty_delete({?ACL_TABLE, {clientid, Key}}), ekka_mnesia:dirty_delete({?ACL_TABLE, {?ACL_TABLE_CLIENTID, Key}}),
{204}. {204}.
format_rules(Rules) when is_list(Rules) -> format_rules(Rules) when is_list(Rules) ->

View File

@ -52,15 +52,15 @@ authorize(#{username := Username,
clientid := Clientid clientid := Clientid
} = Client, PubSub, Topic, #{type := 'built-in-database'}) -> } = Client, PubSub, Topic, #{type := 'built-in-database'}) ->
Rules = case mnesia:dirty_read(?ACL_TABLE, {clientid, Clientid}) of Rules = case mnesia:dirty_read(?ACL_TABLE, {?ACL_TABLE_CLIENTID, Clientid}) of
[] -> []; [] -> [];
[#emqx_acl{rules = Rules0}] when is_list(Rules0) -> Rules0 [#emqx_acl{rules = Rules0}] when is_list(Rules0) -> Rules0
end end
++ case mnesia:dirty_read(?ACL_TABLE, {username, Username}) of ++ case mnesia:dirty_read(?ACL_TABLE, {?ACL_TABLE_USERNAME, Username}) of
[] -> []; [] -> [];
[#emqx_acl{rules = Rules1}] when is_list(Rules1) -> Rules1 [#emqx_acl{rules = Rules1}] when is_list(Rules1) -> Rules1
end end
++ case mnesia:dirty_read(?ACL_TABLE, all) of ++ case mnesia:dirty_read(?ACL_TABLE, ?ACL_TABLE_ALL) of
[] -> []; [] -> [];
[#emqx_acl{rules = Rules2}] when is_list(Rules2) -> Rules2 [#emqx_acl{rules = Rules2}] when is_list(Rules2) -> Rules2
end, end,

View File

@ -54,17 +54,17 @@ end_per_suite(_Config) ->
ok. ok.
init_per_testcase(t_authz, Config) -> init_per_testcase(t_authz, Config) ->
mnesia:transaction(fun ekka_mnesia:dirty_write/1, [#emqx_acl{who = {username, <<"test_username">>}, mnesia:transaction(fun ekka_mnesia:dirty_write/1, [#emqx_acl{who = {?ACL_TABLE_USERNAME, <<"test_username">>},
rules = [{allow, publish, <<"test/%u">>}, rules = [{allow, publish, <<"test/%u">>},
{allow, subscribe, <<"eq #">>} {allow, subscribe, <<"eq #">>}
] ]
}]), }]),
mnesia:transaction(fun ekka_mnesia:dirty_write/1, [#emqx_acl{who = {clientid, <<"test_clientid">>}, mnesia:transaction(fun ekka_mnesia:dirty_write/1, [#emqx_acl{who = {?ACL_TABLE_CLIENTID, <<"test_clientid">>},
rules = [{allow, publish, <<"test/%c">>}, rules = [{allow, publish, <<"test/%c">>},
{deny, subscribe, <<"eq #">>} {deny, subscribe, <<"eq #">>}
] ]
}]), }]),
mnesia:transaction(fun ekka_mnesia:dirty_write/1, [#emqx_acl{who = all, mnesia:transaction(fun ekka_mnesia:dirty_write/1, [#emqx_acl{who = ?ACL_TABLE_ALL,
rules = [{deny, all, <<"#">>}] rules = [{deny, all, <<"#">>}]
}]), }]),
Config; Config;