feat(authz): allow the placeholder to be anywhere in the topic for authz rules
This commit is contained in:
parent
e288424924
commit
c034cbf6de
|
@ -100,15 +100,17 @@ compile_topic(<<"eq ", Topic/binary>>) ->
|
||||||
compile_topic({eq, Topic}) ->
|
compile_topic({eq, Topic}) ->
|
||||||
{eq, emqx_topic:words(bin(Topic))};
|
{eq, emqx_topic:words(bin(Topic))};
|
||||||
compile_topic(Topic) ->
|
compile_topic(Topic) ->
|
||||||
Words = emqx_topic:words(bin(Topic)),
|
TopicBin = bin(Topic),
|
||||||
case pattern(Words) of
|
case
|
||||||
true -> {pattern, Words};
|
emqx_placeholder:preproc_tmpl(
|
||||||
false -> Words
|
TopicBin,
|
||||||
|
#{placeholders => [?PH_USERNAME, ?PH_CLIENTID]}
|
||||||
|
)
|
||||||
|
of
|
||||||
|
[{str, _}] -> emqx_topic:words(TopicBin);
|
||||||
|
Tokens -> {pattern, Tokens}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
pattern(Words) ->
|
|
||||||
lists:member(?PH_USERNAME, Words) orelse lists:member(?PH_CLIENTID, Words).
|
|
||||||
|
|
||||||
atom(B) when is_binary(B) ->
|
atom(B) when is_binary(B) ->
|
||||||
try
|
try
|
||||||
binary_to_existing_atom(B, utf8)
|
binary_to_existing_atom(B, utf8)
|
||||||
|
@ -202,8 +204,8 @@ match_who(_, _) ->
|
||||||
match_topics(_ClientInfo, _Topic, []) ->
|
match_topics(_ClientInfo, _Topic, []) ->
|
||||||
false;
|
false;
|
||||||
match_topics(ClientInfo, Topic, [{pattern, PatternFilter} | Filters]) ->
|
match_topics(ClientInfo, Topic, [{pattern, PatternFilter} | Filters]) ->
|
||||||
TopicFilter = feed_var(ClientInfo, PatternFilter),
|
TopicFilter = emqx_placeholder:proc_tmpl(PatternFilter, ClientInfo),
|
||||||
match_topic(emqx_topic:words(Topic), TopicFilter) orelse
|
match_topic(emqx_topic:words(Topic), emqx_topic:words(TopicFilter)) orelse
|
||||||
match_topics(ClientInfo, Topic, Filters);
|
match_topics(ClientInfo, Topic, Filters);
|
||||||
match_topics(ClientInfo, Topic, [TopicFilter | Filters]) ->
|
match_topics(ClientInfo, Topic, [TopicFilter | Filters]) ->
|
||||||
match_topic(emqx_topic:words(Topic), TopicFilter) orelse
|
match_topic(emqx_topic:words(Topic), TopicFilter) orelse
|
||||||
|
@ -213,18 +215,3 @@ 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(ClientInfo, Pattern) ->
|
|
||||||
feed_var(ClientInfo, Pattern, []).
|
|
||||||
feed_var(_ClientInfo, [], Acc) ->
|
|
||||||
lists:reverse(Acc);
|
|
||||||
feed_var(ClientInfo = #{clientid := undefined}, [?PH_CLIENTID | Words], Acc) ->
|
|
||||||
feed_var(ClientInfo, Words, [?PH_CLIENTID | Acc]);
|
|
||||||
feed_var(ClientInfo = #{clientid := ClientId}, [?PH_CLIENTID | Words], Acc) ->
|
|
||||||
feed_var(ClientInfo, Words, [ClientId | Acc]);
|
|
||||||
feed_var(ClientInfo = #{username := undefined}, [?PH_USERNAME | Words], Acc) ->
|
|
||||||
feed_var(ClientInfo, Words, [?PH_USERNAME | Acc]);
|
|
||||||
feed_var(ClientInfo = #{username := Username}, [?PH_USERNAME | Words], Acc) ->
|
|
||||||
feed_var(ClientInfo, Words, [Username | Acc]);
|
|
||||||
feed_var(ClientInfo, [W | Words], Acc) ->
|
|
||||||
feed_var(ClientInfo, Words, [W | Acc]).
|
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
]},
|
]},
|
||||||
publish, [?PH_S_USERNAME, ?PH_S_CLIENTID]}
|
publish, [?PH_S_USERNAME, ?PH_S_CLIENTID]}
|
||||||
).
|
).
|
||||||
|
-define(SOURCE6, {allow, {username, "test"}, publish, ["t/foo${username}boo"]}).
|
||||||
|
|
||||||
all() ->
|
all() ->
|
||||||
emqx_common_test_helpers:all(?MODULE).
|
emqx_common_test_helpers:all(?MODULE).
|
||||||
|
@ -80,7 +81,7 @@ t_compile(_) ->
|
||||||
{{127, 0, 0, 1}, {127, 0, 0, 1}, 32},
|
{{127, 0, 0, 1}, {127, 0, 0, 1}, 32},
|
||||||
{{192, 168, 1, 0}, {192, 168, 1, 255}, 24}
|
{{192, 168, 1, 0}, {192, 168, 1, 255}, 24}
|
||||||
]},
|
]},
|
||||||
subscribe, [{pattern, [?PH_CLIENTID]}]},
|
subscribe, [{pattern, [{var, {var, <<"clientid">>}}]}]},
|
||||||
emqx_authz_rule:compile(?SOURCE3)
|
emqx_authz_rule:compile(?SOURCE3)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -97,9 +98,18 @@ t_compile(_) ->
|
||||||
{username, {re_pattern, _, _, _, _}},
|
{username, {re_pattern, _, _, _, _}},
|
||||||
{clientid, {re_pattern, _, _, _, _}}
|
{clientid, {re_pattern, _, _, _, _}}
|
||||||
]},
|
]},
|
||||||
publish, [{pattern, [?PH_USERNAME]}, {pattern, [?PH_CLIENTID]}]},
|
publish, [
|
||||||
|
{pattern, [{var, {var, <<"username">>}}]}, {pattern, [{var, {var, <<"clientid">>}}]}
|
||||||
|
]},
|
||||||
emqx_authz_rule:compile(?SOURCE5)
|
emqx_authz_rule:compile(?SOURCE5)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
?assertEqual(
|
||||||
|
{allow, {username, {eq, <<"test">>}}, publish, [
|
||||||
|
{pattern, [{str, <<"t/foo">>}, {var, {var, <<"username">>}}, {str, <<"boo">>}]}
|
||||||
|
]},
|
||||||
|
emqx_authz_rule:compile(?SOURCE6)
|
||||||
|
),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
t_match(_) ->
|
t_match(_) ->
|
||||||
|
@ -307,4 +317,24 @@ t_match(_) ->
|
||||||
emqx_authz_rule:compile(?SOURCE5)
|
emqx_authz_rule:compile(?SOURCE5)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
?assertEqual(
|
||||||
|
nomatch,
|
||||||
|
emqx_authz_rule:match(
|
||||||
|
ClientInfo1,
|
||||||
|
publish,
|
||||||
|
<<"t/foo${username}boo">>,
|
||||||
|
emqx_authz_rule:compile(?SOURCE6)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
?assertEqual(
|
||||||
|
{matched, allow},
|
||||||
|
emqx_authz_rule:match(
|
||||||
|
ClientInfo4,
|
||||||
|
publish,
|
||||||
|
<<"t/footestboo">>,
|
||||||
|
emqx_authz_rule:compile(?SOURCE6)
|
||||||
|
)
|
||||||
|
),
|
||||||
ok.
|
ok.
|
||||||
|
|
Loading…
Reference in New Issue