Replace credentials with client

This commit is contained in:
Feng Lee 2019-07-27 23:22:02 +08:00
parent 32b2a01d68
commit d99c9daf76
2 changed files with 74 additions and 73 deletions

View File

@ -28,52 +28,57 @@
%% APIs
%%--------------------------------------------------------------------
-spec(authenticate(emqx_types:credentials())
-> {ok, emqx_types:credentials()} | {error, term()}).
authenticate(Credentials) ->
case emqx_hooks:run_fold('client.authenticate', [], init_auth_result(Credentials)) of
#{auth_result := success, anonymous := true} = NewCredentials ->
-spec(authenticate(emqx_types:client())
-> {ok, #{auth_result := emqx_types:auth_result(),
anonymous := boolean}} | {error, term()}).
authenticate(Client = #{zone := Zone}) ->
case emqx_hooks:run_fold('client.authenticate',
[Client], default_auth_result(Zone)) of
Result = #{auth_result := success, anonymous := true} ->
emqx_metrics:inc('auth.mqtt.anonymous'),
{ok, NewCredentials};
#{auth_result := success} = NewCredentials ->
{ok, NewCredentials};
NewCredentials ->
{error, maps:get(auth_result, NewCredentials, unknown_error)}
end.
%% @doc Check ACL
-spec(check_acl(emqx_types:credentials(), emqx_types:pubsub(), emqx_types:topic())
-> allow | deny).
check_acl(Credentials, PubSub, Topic) ->
case emqx_acl_cache:is_enabled() of
false ->
do_check_acl(Credentials, PubSub, Topic);
true ->
case emqx_acl_cache:get_acl_cache(PubSub, Topic) of
not_found ->
AclResult = do_check_acl(Credentials, PubSub, Topic),
emqx_acl_cache:put_acl_cache(PubSub, Topic, AclResult),
AclResult;
AclResult -> AclResult
end
{ok, Result};
Result = #{auth_result := success} ->
{ok, Result};
Result ->
{error, maps:get(auth_result, Result, unknown_error)}
end.
do_check_acl(#{zone := Zone} = Credentials, PubSub, Topic) ->
case emqx_hooks:run_fold('client.check_acl', [Credentials, PubSub, Topic],
emqx_zone:get_env(Zone, acl_nomatch, deny)) of
allow -> allow;
_ -> deny
%% @doc Check ACL
-spec(check_acl(emqx_types:cient(), emqx_types:pubsub(), emqx_types:topic())
-> allow | deny).
check_acl(Client, PubSub, Topic) ->
case emqx_acl_cache:is_enabled() of
true ->
check_acl_cache(Client, PubSub, Topic);
false ->
do_check_acl(Client, PubSub, Topic)
end.
check_acl_cache(Client, PubSub, Topic) ->
case emqx_acl_cache:get_acl_cache(PubSub, Topic) of
not_found ->
AclResult = do_check_acl(Client, PubSub, Topic),
emqx_acl_cache:put_acl_cache(PubSub, Topic, AclResult),
AclResult;
AclResult -> AclResult
end.
do_check_acl(#{zone := Zone} = Client, PubSub, Topic) ->
Default = emqx_zone:get_env(Zone, acl_nomatch, deny),
case emqx_hooks:run_fold('client.check_acl', [Client, PubSub, Topic], Default) of
allow -> allow;
_Other -> deny
end.
-spec(reload_acl() -> ok | {error, term()}).
reload_acl() ->
emqx_acl_cache:is_enabled() andalso
emqx_acl_cache:empty_acl_cache(),
emqx_acl_cache:is_enabled()
andalso emqx_acl_cache:empty_acl_cache(),
emqx_mod_acl_internal:reload_acl().
init_auth_result(Credentials) ->
case emqx_zone:get_env(maps:get(zone, Credentials, undefined), allow_anonymous, false) of
true -> Credentials#{auth_result => success, anonymous => true};
false -> Credentials#{auth_result => not_authorized, anonymous => false}
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.

View File

@ -40,10 +40,6 @@
-define(ALLOW_DENY(A), ((A =:= allow) orelse (A =:= deny))).
-define(PUBSUB(A), ((A =:= subscribe) orelse (A =:= publish) orelse (A =:= pubsub))).
%%--------------------------------------------------------------------
%% APIs
%%--------------------------------------------------------------------
%% @doc Compile Access Rule.
compile({A, all}) when ?ALLOW_DENY(A) ->
{A, all};
@ -92,21 +88,21 @@ bin(B) when is_binary(B) ->
%% @doc Match access rule
-spec(match(emqx_types:credentials(), emqx_types:topic(), rule())
-> {matched, allow} | {matched, deny} | nomatch).
match(_Credentials, _Topic, {AllowDeny, all}) when ?ALLOW_DENY(AllowDeny) ->
match(_Client, _Topic, {AllowDeny, all}) when ?ALLOW_DENY(AllowDeny) ->
{matched, AllowDeny};
match(Credentials, Topic, {AllowDeny, Who, _PubSub, TopicFilters})
match(Client, Topic, {AllowDeny, Who, _PubSub, TopicFilters})
when ?ALLOW_DENY(AllowDeny) ->
case match_who(Credentials, Who)
andalso match_topics(Credentials, Topic, TopicFilters) of
case match_who(Client, Who)
andalso match_topics(Client, Topic, TopicFilters) of
true -> {matched, AllowDeny};
false -> nomatch
end.
match_who(_Credentials, all) ->
match_who(_Client, all) ->
true;
match_who(_Credentials, {user, all}) ->
match_who(_Client, {user, all}) ->
true;
match_who(_Credentials, {client, all}) ->
match_who(_Client, {client, all}) ->
true;
match_who(#{client_id := ClientId}, {client, ClientId}) ->
true;
@ -116,44 +112,44 @@ match_who(#{peername := undefined}, {ipaddr, _Tup}) ->
false;
match_who(#{peername := {IP, _}}, {ipaddr, CIDR}) ->
esockd_cidr:match(IP, CIDR);
match_who(Credentials, {'and', Conds}) when is_list(Conds) ->
match_who(Client, {'and', Conds}) when is_list(Conds) ->
lists:foldl(fun(Who, Allow) ->
match_who(Credentials, Who) andalso Allow
match_who(Client, Who) andalso Allow
end, true, Conds);
match_who(Credentials, {'or', Conds}) when is_list(Conds) ->
match_who(Client, {'or', Conds}) when is_list(Conds) ->
lists:foldl(fun(Who, Allow) ->
match_who(Credentials, Who) orelse Allow
match_who(Client, Who) orelse Allow
end, false, Conds);
match_who(_Credentials, _Who) ->
match_who(_Client, _Who) ->
false.
match_topics(_Credentials, _Topic, []) ->
match_topics(_Client, _Topic, []) ->
false;
match_topics(Credentials, Topic, [{pattern, PatternFilter}|Filters]) ->
TopicFilter = feed_var(Credentials, PatternFilter),
match_topics(Client, Topic, [{pattern, PatternFilter}|Filters]) ->
TopicFilter = feed_var(Client, PatternFilter),
match_topic(emqx_topic:words(Topic), TopicFilter)
orelse match_topics(Credentials, Topic, Filters);
match_topics(Credentials, Topic, [TopicFilter|Filters]) ->
orelse match_topics(Client, Topic, Filters);
match_topics(Client, Topic, [TopicFilter|Filters]) ->
match_topic(emqx_topic:words(Topic), TopicFilter)
orelse match_topics(Credentials, Topic, Filters).
orelse match_topics(Client, Topic, Filters).
match_topic(Topic, {eq, TopicFilter}) ->
Topic == TopicFilter;
match_topic(Topic, TopicFilter) ->
emqx_topic:match(Topic, TopicFilter).
feed_var(Credentials, Pattern) ->
feed_var(Credentials, Pattern, []).
feed_var(_Credentials, [], Acc) ->
feed_var(Client, Pattern) ->
feed_var(Client, Pattern, []).
feed_var(_Client, [], Acc) ->
lists:reverse(Acc);
feed_var(Credentials = #{client_id := undefined}, [<<"%c">>|Words], Acc) ->
feed_var(Credentials, Words, [<<"%c">>|Acc]);
feed_var(Credentials = #{client_id := ClientId}, [<<"%c">>|Words], Acc) ->
feed_var(Credentials, Words, [ClientId |Acc]);
feed_var(Credentials = #{username := undefined}, [<<"%u">>|Words], Acc) ->
feed_var(Credentials, Words, [<<"%u">>|Acc]);
feed_var(Credentials = #{username := Username}, [<<"%u">>|Words], Acc) ->
feed_var(Credentials, Words, [Username|Acc]);
feed_var(Credentials, [W|Words], Acc) ->
feed_var(Credentials, Words, [W|Acc]).
feed_var(Client = #{client_id := undefined}, [<<"%c">>|Words], Acc) ->
feed_var(Client, Words, [<<"%c">>|Acc]);
feed_var(Client = #{client_id := ClientId}, [<<"%c">>|Words], Acc) ->
feed_var(Client, Words, [ClientId |Acc]);
feed_var(Client = #{username := undefined}, [<<"%u">>|Words], Acc) ->
feed_var(Client, Words, [<<"%u">>|Acc]);
feed_var(Client = #{username := Username}, [<<"%u">>|Words], Acc) ->
feed_var(Client, Words, [Username|Acc]);
feed_var(Client, [W|Words], Acc) ->
feed_var(Client, Words, [W|Acc]).