84 lines
3.0 KiB
Erlang
84 lines
3.0 KiB
Erlang
%%--------------------------------------------------------------------
|
|
%% Copyright (c) 2020 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_access_control).
|
|
|
|
-include("emqx.hrl").
|
|
|
|
-export([authenticate/1]).
|
|
|
|
-export([ check_acl/3
|
|
]).
|
|
|
|
-type(result() :: #{auth_result := emqx_types:auth_result(),
|
|
anonymous := boolean()
|
|
}).
|
|
|
|
%%--------------------------------------------------------------------
|
|
%% APIs
|
|
%%--------------------------------------------------------------------
|
|
|
|
-spec(authenticate(emqx_types:clientinfo()) -> {ok, result()} | {error, term()}).
|
|
authenticate(ClientInfo = #{zone := Zone}) ->
|
|
AuthResult = default_auth_result(Zone),
|
|
case emqx_zone:get_env(Zone, bypass_auth_plugins, false) of
|
|
true ->
|
|
return_auth_result(AuthResult);
|
|
false ->
|
|
return_auth_result(run_hooks('client.authenticate', [ClientInfo], AuthResult))
|
|
end.
|
|
|
|
%% @doc Check ACL
|
|
-spec(check_acl(emqx_types:clientinfo(), emqx_types:pubsub(), emqx_types:topic())
|
|
-> allow | deny).
|
|
check_acl(ClientInfo, PubSub, Topic) ->
|
|
case emqx_acl_cache:is_enabled() of
|
|
true -> check_acl_cache(ClientInfo, PubSub, Topic);
|
|
false -> do_check_acl(ClientInfo, PubSub, Topic)
|
|
end.
|
|
|
|
check_acl_cache(ClientInfo, PubSub, Topic) ->
|
|
case emqx_acl_cache:get_acl_cache(PubSub, Topic) of
|
|
not_found ->
|
|
AclResult = do_check_acl(ClientInfo, PubSub, Topic),
|
|
emqx_acl_cache:put_acl_cache(PubSub, Topic, AclResult),
|
|
AclResult;
|
|
AclResult -> AclResult
|
|
end.
|
|
|
|
do_check_acl(ClientInfo = #{zone := Zone}, PubSub, Topic) ->
|
|
Default = emqx_zone:get_env(Zone, acl_nomatch, deny),
|
|
case run_hooks('client.check_acl', [ClientInfo, PubSub, Topic], Default) of
|
|
allow -> allow;
|
|
_Other -> deny
|
|
end.
|
|
|
|
default_auth_result(Zone) ->
|
|
case emqx_zone:get_env(Zone, allow_anonymous, false) of
|
|
true -> #{auth_result => success, anonymous => true};
|
|
false -> #{auth_result => not_authorized, anonymous => false}
|
|
end.
|
|
|
|
-compile({inline, [run_hooks/3]}).
|
|
run_hooks(Name, Args, Acc) ->
|
|
ok = emqx_metrics:inc(Name), emqx_hooks:run_fold(Name, Args, Acc).
|
|
|
|
-compile({inline, [return_auth_result/1]}).
|
|
return_auth_result(Result = #{auth_result := success}) ->
|
|
{ok, Result};
|
|
return_auth_result(Result) ->
|
|
{error, maps:get(auth_result, Result, unknown_error)}.
|