support 'and', 'or'
This commit is contained in:
parent
d09721301e
commit
8491467bbb
|
@ -1,21 +1,21 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%
|
||||
%% [ACL](https://github.com/emqtt/emqttd/wiki/ACL)
|
||||
%%
|
||||
%% -type who() :: all | binary() |
|
||||
%% {ipaddr, esockd_access:cidr()} |
|
||||
%% {client, binary()} |
|
||||
%% {user, binary()}.
|
||||
%%
|
||||
%% -type access() :: subscribe | publish | pubsub.
|
||||
%%
|
||||
%% -type topic() :: binary().
|
||||
%%
|
||||
%% -type rule() :: {allow, all} |
|
||||
%% {allow, who(), access(), list(topic())} |
|
||||
%% {deny, all} |
|
||||
%% {deny, who(), access(), list(topic())}.
|
||||
%%
|
||||
%%%
|
||||
%%% [ACL](https://github.com/emqtt/emqttd/wiki/ACL)
|
||||
%%%
|
||||
%%% -type who() :: all | binary() |
|
||||
%%% {ipaddr, esockd_access:cidr()} |
|
||||
%%% {client, binary()} |
|
||||
%%% {user, binary()}.
|
||||
%%%
|
||||
%%% -type access() :: subscribe | publish | pubsub.
|
||||
%%%
|
||||
%%% -type topic() :: binary().
|
||||
%%%
|
||||
%%% -type rule() :: {allow, all} |
|
||||
%%% {allow, who(), access(), list(topic())} |
|
||||
%%% {deny, all} |
|
||||
%%% {deny, who(), access(), list(topic())}.
|
||||
%%%
|
||||
%%%-----------------------------------------------------------------------------
|
||||
|
||||
{allow, {user, "dashboard"}, subscribe, ["$SYS/#"]}.
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
|
||||
-module(emqttd_access_rule).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
@ -49,14 +48,19 @@
|
|||
|
||||
-export([compile/1, match/3]).
|
||||
|
||||
-define(ALLOW_DENY(A), ((A =:= allow) orelse (A =:= deny))).
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% @doc Compile access rule
|
||||
%% @end
|
||||
%%------------------------------------------------------------------------------
|
||||
compile({A, all}) when (A =:= allow) orelse (A =:= deny) ->
|
||||
compile({A, all}) when ?ALLOW_DENY(A) ->
|
||||
{A, all};
|
||||
|
||||
compile({A, Who, Access, TopicFilters}) when (A =:= allow) orelse (A =:= deny) ->
|
||||
compile({A, Who, Access, Topic}) when ?ALLOW_DENY(A) andalso is_binary(Topic) ->
|
||||
{A, compile(who, Who), Access, [compile(topic, Topic)]};
|
||||
|
||||
compile({A, Who, Access, TopicFilters}) when ?ALLOW_DENY(A) ->
|
||||
{A, compile(who, Who), Access, [compile(topic, Topic) || Topic <- TopicFilters]}.
|
||||
|
||||
compile(who, all) ->
|
||||
|
@ -72,6 +76,10 @@ compile(who, {user, all}) ->
|
|||
{user, all};
|
||||
compile(who, {user, Username}) ->
|
||||
{user, bin(Username)};
|
||||
compile(who, {'and', Conds}) when is_list(Conds) ->
|
||||
{'and', [compile(who, Cond) || Cond <- Conds]};
|
||||
compile(who, {'or', Conds}) when is_list(Conds) ->
|
||||
{'or', [compile(who, Cond) || Cond <- Conds]};
|
||||
|
||||
compile(topic, {eq, Topic}) ->
|
||||
{eq, emqttd_topic:words(bin(Topic))};
|
||||
|
@ -120,6 +128,14 @@ match_who(#mqtt_client{peername = undefined}, {ipaddr, _Tup}) ->
|
|||
match_who(#mqtt_client{peername = {IP, _}}, {ipaddr, {_CDIR, Start, End}}) ->
|
||||
I = esockd_access:atoi(IP),
|
||||
I >= Start andalso I =< End;
|
||||
match_who(Client, {'and', Conds}) when is_list(Conds) ->
|
||||
lists:foldl(fun(Who, Allow) ->
|
||||
match_who(Client, Who) andalso Allow
|
||||
end, true, Conds);
|
||||
match_who(Client, {'or', Conds}) when is_list(Conds) ->
|
||||
lists:foldl(fun(Who, Allow) ->
|
||||
match_who(Client, Who) orelse Allow
|
||||
end, false, Conds);
|
||||
match_who(_Client, _Who) ->
|
||||
false.
|
||||
|
||||
|
|
|
@ -35,6 +35,14 @@
|
|||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
compile_test() ->
|
||||
|
||||
?assertMatch({allow, {'and', [{ipaddr, {"127.0.0.1", _I, _I}},
|
||||
{user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
|
||||
compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]})),
|
||||
?assertMatch({allow, {'or', [{ipaddr, {"127.0.0.1", _I, _I}},
|
||||
{user, <<"user">>}]}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
|
||||
compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"user">>}]}, subscribe, ["$SYS/#", "#"]})),
|
||||
|
||||
?assertMatch({allow, {ipaddr, {"127.0.0.1", _I, _I}}, subscribe, [ [<<"$SYS">>, '#'], ['#'] ]},
|
||||
compile({allow, {ipaddr, "127.0.0.1"}, subscribe, ["$SYS/#", "#"]})),
|
||||
?assertMatch({allow, {user, <<"testuser">>}, subscribe, [ [<<"a">>, <<"b">>, <<"c">>], [<<"d">>, <<"e">>, <<"f">>, '#'] ]},
|
||||
|
@ -70,9 +78,14 @@ match_test() ->
|
|||
compile({allow, all, pubsub, ["clients/$c"]}))),
|
||||
?assertMatch({matched, allow}, match(#mqtt_client{username = <<"user2">>}, <<"users/user2/abc/def">>,
|
||||
compile({allow, all, subscribe, ["users/$u/#"]}))),
|
||||
?assertMatch({matched, deny},
|
||||
match(User, <<"d/e/f">>,
|
||||
compile({deny, all, subscribe, ["$SYS/#", "#"]}))).
|
||||
?assertMatch({matched, deny}, match(User, <<"d/e/f">>,
|
||||
compile({deny, all, subscribe, ["$SYS/#", "#"]}))),
|
||||
Rule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, <<"Topic">>}),
|
||||
?assertMatch(nomatch, match(User, <<"Topic">>, Rule)),
|
||||
AndRule = compile({allow, {'and', [{ipaddr, "127.0.0.1"}, {user, <<"TestUser">>}]}, publish, <<"Topic">>}),
|
||||
?assertMatch({matched, allow}, match(User, <<"Topic">>, AndRule)),
|
||||
OrRule = compile({allow, {'or', [{ipaddr, "127.0.0.1"}, {user, <<"WrongUser">>}]}, publish, ["Topic"]}),
|
||||
?assertMatch({matched, allow}, match(User, <<"Topic">>, OrRule)).
|
||||
|
||||
-endif.
|
||||
|
||||
|
|
Loading…
Reference in New Issue