Fix reload ACL failed (#2344)
The original `reload_acl` function only parse the ACL file, not compile and rehook to 'client.check_acl'
This commit is contained in:
parent
416bc75d5d
commit
513d2bcaaa
|
@ -57,12 +57,14 @@ do_check_acl(#{zone := Zone} = Credentials, PubSub, Topic) ->
|
||||||
_ -> deny
|
_ -> deny
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec(reload_acl() -> list(ok | {error, term()})).
|
-spec(reload_acl() -> ok | {error, term()}).
|
||||||
reload_acl() ->
|
reload_acl() ->
|
||||||
|
emqx_acl_cache:is_enabled() andalso
|
||||||
|
emqx_acl_cache:empty_acl_cache(),
|
||||||
emqx_mod_acl_internal:reload_acl().
|
emqx_mod_acl_internal:reload_acl().
|
||||||
|
|
||||||
init_auth_result(Credentials) ->
|
init_auth_result(Credentials) ->
|
||||||
case emqx_zone:get_env(maps:get(zone, Credentials, undefined), allow_anonymous, false) of
|
case emqx_zone:get_env(maps:get(zone, Credentials, undefined), allow_anonymous, false) of
|
||||||
true -> success;
|
true -> success;
|
||||||
false -> not_authorized
|
false -> not_authorized
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -16,19 +16,19 @@
|
||||||
|
|
||||||
-include("emqx.hrl").
|
-include("emqx.hrl").
|
||||||
|
|
||||||
-export([ get_acl_cache/2
|
-export([ get_acl_cache/2
|
||||||
, put_acl_cache/3
|
, put_acl_cache/3
|
||||||
, cleanup_acl_cache/0
|
, cleanup_acl_cache/0
|
||||||
, empty_acl_cache/0
|
, empty_acl_cache/0
|
||||||
, dump_acl_cache/0
|
, dump_acl_cache/0
|
||||||
, get_cache_size/0
|
, get_cache_size/0
|
||||||
, get_cache_max_size/0
|
, get_cache_max_size/0
|
||||||
, get_newest_key/0
|
, get_newest_key/0
|
||||||
, get_oldest_key/0
|
, get_oldest_key/0
|
||||||
, cache_k/2
|
, cache_k/2
|
||||||
, cache_v/1
|
, cache_v/1
|
||||||
, is_enabled/0
|
, is_enabled/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-type(acl_result() :: allow | deny).
|
-type(acl_result() :: allow | deny).
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,9 @@
|
||||||
|
|
||||||
-export([check_acl/5, reload_acl/0]).
|
-export([check_acl/5, reload_acl/0]).
|
||||||
|
|
||||||
-define(ACL_RULE_TAB, emqx_acl_rule).
|
-define(MFA(M, F, A), {M, F, A}).
|
||||||
|
|
||||||
-define(FUNC(M, F, A), {M, F, A}).
|
-type(acl_rules() :: #{publish => [emqx_access_rule:rule()],
|
||||||
|
|
||||||
-type(acl_rules() :: #{publish => [emqx_access_rule:rule()],
|
|
||||||
subscribe => [emqx_access_rule:rule()]}).
|
subscribe => [emqx_access_rule:rule()]}).
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
@ -37,28 +35,64 @@
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
load(_Env) ->
|
load(_Env) ->
|
||||||
Rules = load_rules_from_file(acl_file()),
|
Rules = rules_from_file(acl_file()),
|
||||||
emqx_hooks:add('client.check_acl', ?FUNC(?MODULE, check_acl, [Rules]), -1).
|
emqx_hooks:add('client.check_acl', ?MFA(?MODULE, check_acl, [Rules]), -1).
|
||||||
|
|
||||||
unload(_Env) ->
|
unload(_Env) ->
|
||||||
Rules = load_rules_from_file(acl_file()),
|
Rules = rules_from_file(acl_file()),
|
||||||
emqx_hooks:del('client.check_acl', ?FUNC(?MODULE, check_acl, [Rules])).
|
emqx_hooks:del('client.check_acl', ?MFA(?MODULE, check_acl, [Rules])).
|
||||||
|
|
||||||
%% @doc Read all rules
|
%% @doc Read all rules
|
||||||
-spec(all_rules() -> list(emqx_access_rule:rule())).
|
-spec(all_rules() -> list(emqx_access_rule:rule())).
|
||||||
all_rules() ->
|
all_rules() ->
|
||||||
load_rules_from_file(acl_file()).
|
rules_from_file(acl_file()).
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% ACL callbacks
|
%% ACL callbacks
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
load_rules_from_file(AclFile) ->
|
%% @doc Check ACL
|
||||||
|
-spec(check_acl(emqx_types:credentials(), emqx_types:pubsub(), emqx_topic:topic(),
|
||||||
|
emqx_access_rule:acl_result(), acl_rules())
|
||||||
|
-> {ok, allow} | {ok, deny} | ok).
|
||||||
|
check_acl(Credentials, PubSub, Topic, _AclResult, Rules) ->
|
||||||
|
case match(Credentials, Topic, lookup(PubSub, Rules)) of
|
||||||
|
{matched, allow} -> {ok, allow};
|
||||||
|
{matched, deny} -> {ok, deny};
|
||||||
|
nomatch -> ok
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec(reload_acl() -> ok | {error, term()}).
|
||||||
|
reload_acl() ->
|
||||||
|
unload([]), load([]).
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% Internal Functions
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
acl_file() ->
|
||||||
|
emqx_config:get_env(acl_file).
|
||||||
|
|
||||||
|
lookup(PubSub, Rules) ->
|
||||||
|
maps:get(PubSub, Rules, []).
|
||||||
|
|
||||||
|
match(_Credentials, _Topic, []) ->
|
||||||
|
nomatch;
|
||||||
|
match(Credentials, Topic, [Rule|Rules]) ->
|
||||||
|
case emqx_access_rule:match(Credentials, Topic, Rule) of
|
||||||
|
nomatch ->
|
||||||
|
match(Credentials, Topic, Rules);
|
||||||
|
{matched, AllowDeny} ->
|
||||||
|
{matched, AllowDeny}
|
||||||
|
end.
|
||||||
|
|
||||||
|
-spec(rules_from_file(file:filename()) -> map()).
|
||||||
|
rules_from_file(AclFile) ->
|
||||||
case file:consult(AclFile) of
|
case file:consult(AclFile) of
|
||||||
{ok, Terms} ->
|
{ok, Terms} ->
|
||||||
Rules = [emqx_access_rule:compile(Term) || Term <- Terms],
|
Rules = [emqx_access_rule:compile(Term) || Term <- Terms],
|
||||||
#{publish => lists:filter(fun(Rule) -> filter(publish, Rule) end, Rules),
|
#{publish => [Rule || Rule <- Rules, filter(publish, Rule)],
|
||||||
subscribe => lists:filter(fun(Rule) -> filter(subscribe, Rule) end, Rules)};
|
subscribe => [Rule || Rule <- Rules, filter(subscribe, Rule)]};
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
?LOG(error, "[ACL_INTERNAL] Failed to read ~s: ~p", [AclFile, Reason]),
|
?LOG(error, "[ACL_INTERNAL] Failed to read ~s: ~p", [AclFile, Reason]),
|
||||||
#{}
|
#{}
|
||||||
|
@ -77,43 +111,3 @@ filter(subscribe, {_AllowDeny, _Who, subscribe, _Topics}) ->
|
||||||
filter(_PubSub, {_AllowDeny, _Who, _, _Topics}) ->
|
filter(_PubSub, {_AllowDeny, _Who, _, _Topics}) ->
|
||||||
false.
|
false.
|
||||||
|
|
||||||
%% @doc Check ACL
|
|
||||||
-spec(check_acl(emqx_types:credentials(), emqx_types:pubsub(), emqx_topic:topic(),
|
|
||||||
emqx_access_rule:acl_result(), acl_rules())
|
|
||||||
-> {ok, allow} | {ok, deny} | ok).
|
|
||||||
check_acl(Credentials, PubSub, Topic, _AclResult, Rules) ->
|
|
||||||
case match(Credentials, Topic, lookup(PubSub, Rules)) of
|
|
||||||
{matched, allow} -> {ok, allow};
|
|
||||||
{matched, deny} -> {ok, deny};
|
|
||||||
nomatch -> ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
lookup(PubSub, Rules) ->
|
|
||||||
maps:get(PubSub, Rules, []).
|
|
||||||
|
|
||||||
match(_Credentials, _Topic, []) ->
|
|
||||||
nomatch;
|
|
||||||
match(Credentials, Topic, [Rule|Rules]) ->
|
|
||||||
case emqx_access_rule:match(Credentials, Topic, Rule) of
|
|
||||||
nomatch ->
|
|
||||||
match(Credentials, Topic, Rules);
|
|
||||||
{matched, AllowDeny} ->
|
|
||||||
{matched, AllowDeny}
|
|
||||||
end.
|
|
||||||
|
|
||||||
-spec(reload_acl() -> ok | {error, term()}).
|
|
||||||
reload_acl() ->
|
|
||||||
try load_rules_from_file(acl_file()) of
|
|
||||||
_ ->
|
|
||||||
emqx_logger:info("Reload acl_file ~s successfully", [acl_file()]),
|
|
||||||
ok;
|
|
||||||
{error, Error} ->
|
|
||||||
{error, Error}
|
|
||||||
catch
|
|
||||||
error:Reason:StackTrace ->
|
|
||||||
?LOG(error, "Reload acl failed. StackTrace: ~p", [StackTrace]),
|
|
||||||
{error, Reason}
|
|
||||||
end.
|
|
||||||
|
|
||||||
acl_file() ->
|
|
||||||
emqx_config:get_env(acl_file).
|
|
||||||
|
|
Loading…
Reference in New Issue