|
|
@@ -25,11 +25,9 @@
|
|
|
|
|
|
-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()]}).
|
|
|
|
|
|
%%------------------------------------------------------------------------------
|
|
|
@@ -37,46 +35,22 @@
|
|
|
%%------------------------------------------------------------------------------
|
|
|
|
|
|
load(_Env) ->
|
|
|
- Rules = load_rules_from_file(acl_file()),
|
|
|
- emqx_hooks:add('client.check_acl', ?FUNC(?MODULE, check_acl, [Rules]), -1).
|
|
|
+ Rules = rules_from_file(acl_file()),
|
|
|
+ emqx_hooks:add('client.check_acl', ?MFA(?MODULE, check_acl, [Rules]), -1).
|
|
|
|
|
|
unload(_Env) ->
|
|
|
- Rules = load_rules_from_file(acl_file()),
|
|
|
- emqx_hooks:del('client.check_acl', ?FUNC(?MODULE, check_acl, [Rules])).
|
|
|
+ Rules = rules_from_file(acl_file()),
|
|
|
+ emqx_hooks:del('client.check_acl', ?MFA(?MODULE, check_acl, [Rules])).
|
|
|
|
|
|
%% @doc Read all rules
|
|
|
-spec(all_rules() -> list(emqx_access_rule:rule())).
|
|
|
all_rules() ->
|
|
|
- load_rules_from_file(acl_file()).
|
|
|
+ rules_from_file(acl_file()).
|
|
|
|
|
|
%%------------------------------------------------------------------------------
|
|
|
%% ACL callbacks
|
|
|
%%------------------------------------------------------------------------------
|
|
|
|
|
|
-load_rules_from_file(AclFile) ->
|
|
|
- case file:consult(AclFile) of
|
|
|
- {ok, Terms} ->
|
|
|
- Rules = [emqx_access_rule:compile(Term) || Term <- Terms],
|
|
|
- #{publish => lists:filter(fun(Rule) -> filter(publish, Rule) end, Rules),
|
|
|
- subscribe => lists:filter(fun(Rule) -> filter(subscribe, Rule) end, Rules)};
|
|
|
- {error, Reason} ->
|
|
|
- ?LOG(error, "[ACL_INTERNAL] Failed to read ~s: ~p", [AclFile, Reason]),
|
|
|
- #{}
|
|
|
- end.
|
|
|
-
|
|
|
-filter(_PubSub, {allow, all}) ->
|
|
|
- true;
|
|
|
-filter(_PubSub, {deny, all}) ->
|
|
|
- true;
|
|
|
-filter(publish, {_AllowDeny, _Who, publish, _Topics}) ->
|
|
|
- true;
|
|
|
-filter(_PubSub, {_AllowDeny, _Who, pubsub, _Topics}) ->
|
|
|
- true;
|
|
|
-filter(subscribe, {_AllowDeny, _Who, subscribe, _Topics}) ->
|
|
|
- true;
|
|
|
-filter(_PubSub, {_AllowDeny, _Who, _, _Topics}) ->
|
|
|
- false.
|
|
|
-
|
|
|
%% @doc Check ACL
|
|
|
-spec(check_acl(emqx_types:credentials(), emqx_types:pubsub(), emqx_topic:topic(),
|
|
|
emqx_access_rule:acl_result(), acl_rules())
|
|
|
@@ -88,6 +62,17 @@ check_acl(Credentials, PubSub, Topic, _AclResult, Rules) ->
|
|
|
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, []).
|
|
|
|
|
|
@@ -101,19 +86,28 @@ match(Credentials, Topic, [Rule|Rules]) ->
|
|
|
{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}
|
|
|
+-spec(rules_from_file(file:filename()) -> map()).
|
|
|
+rules_from_file(AclFile) ->
|
|
|
+ case file:consult(AclFile) of
|
|
|
+ {ok, Terms} ->
|
|
|
+ Rules = [emqx_access_rule:compile(Term) || Term <- Terms],
|
|
|
+ #{publish => [Rule || Rule <- Rules, filter(publish, Rule)],
|
|
|
+ subscribe => [Rule || Rule <- Rules, filter(subscribe, Rule)]};
|
|
|
+ {error, Reason} ->
|
|
|
+ ?LOG(error, "[ACL_INTERNAL] Failed to read ~s: ~p", [AclFile, Reason]),
|
|
|
+ #{}
|
|
|
end.
|
|
|
|
|
|
-acl_file() ->
|
|
|
- emqx_config:get_env(acl_file).
|
|
|
+filter(_PubSub, {allow, all}) ->
|
|
|
+ true;
|
|
|
+filter(_PubSub, {deny, all}) ->
|
|
|
+ true;
|
|
|
+filter(publish, {_AllowDeny, _Who, publish, _Topics}) ->
|
|
|
+ true;
|
|
|
+filter(_PubSub, {_AllowDeny, _Who, pubsub, _Topics}) ->
|
|
|
+ true;
|
|
|
+filter(subscribe, {_AllowDeny, _Who, subscribe, _Topics}) ->
|
|
|
+ true;
|
|
|
+filter(_PubSub, {_AllowDeny, _Who, _, _Topics}) ->
|
|
|
+ false.
|
|
|
+
|