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

View File

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