emqx/apps/emqx_auth_mnesia/src/emqx_acl_mnesia.erl

88 lines
3.2 KiB
Erlang

%%--------------------------------------------------------------------
%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%--------------------------------------------------------------------
-module(emqx_acl_mnesia).
-include("emqx_auth_mnesia.hrl").
%% ACL Callbacks
-export([ init/0
, check_acl/5
, description/0
]).
init() ->
ok = emqx_acl_mnesia_db:create_table(),
ok = emqx_acl_mnesia_db:create_table2().
check_acl(ClientInfo = #{ clientid := Clientid }, PubSub, Topic, _NoMatchAction, _Params) ->
Username = maps:get(username, ClientInfo, undefined),
Acls = case Username of
undefined ->
emqx_acl_mnesia_db:lookup_acl({clientid, Clientid}) ++
emqx_acl_mnesia_db:lookup_acl(all);
_ ->
emqx_acl_mnesia_db:lookup_acl({clientid, Clientid}) ++
emqx_acl_mnesia_db:lookup_acl({username, Username}) ++
emqx_acl_mnesia_db:lookup_acl(all)
end,
case match(ClientInfo, PubSub, Topic, Acls) of
allow ->
{stop, allow};
deny ->
{stop, deny};
_ ->
ok
end.
description() -> "Acl with Mnesia".
%%--------------------------------------------------------------------
%% Internal functions
%%-------------------------------------------------------------------
match(_ClientInfo, _PubSub, _Topic, []) ->
nomatch;
match(ClientInfo, PubSub, Topic, [ {_, ACLTopic, Action, Access, _} | Acls]) ->
case match_actions(PubSub, Action) andalso match_topic(ClientInfo, Topic, ACLTopic) of
true -> Access;
false -> match(ClientInfo, PubSub, Topic, Acls)
end.
match_topic(ClientInfo, Topic, ACLTopic) when is_binary(Topic) ->
emqx_topic:match(Topic, feed_var(ClientInfo, ACLTopic)).
match_actions(subscribe, sub) -> true;
match_actions(publish, pub) -> true;
match_actions(_, _) -> false.
feed_var(ClientInfo, Pattern) ->
feed_var(ClientInfo, emqx_topic:words(Pattern), []).
feed_var(_ClientInfo, [], Acc) ->
emqx_topic:join(lists:reverse(Acc));
feed_var(ClientInfo = #{clientid := undefined}, [<<"%c">>|Words], Acc) ->
feed_var(ClientInfo, Words, [<<"%c">>|Acc]);
feed_var(ClientInfo = #{clientid := ClientId}, [<<"%c">>|Words], Acc) ->
feed_var(ClientInfo, Words, [ClientId |Acc]);
feed_var(ClientInfo = #{username := undefined}, [<<"%u">>|Words], Acc) ->
feed_var(ClientInfo, Words, [<<"%u">>|Acc]);
feed_var(ClientInfo = #{username := Username}, [<<"%u">>|Words], Acc) ->
feed_var(ClientInfo, Words, [Username|Acc]);
feed_var(ClientInfo, [W|Words], Acc) ->
feed_var(ClientInfo, Words, [W|Acc]).