Merge pull request #13481 from zhongwencool/match_rule_error

chore: add authz tag to match_rule_error log
This commit is contained in:
zhongwencool 2024-07-22 16:46:49 +08:00 committed by GitHub
commit 57b67ebb37
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 90 additions and 83 deletions

View File

@ -163,7 +163,7 @@ qos_from_opts(Opts) ->
) )
end end
catch catch
{bad_qos, QoS} -> throw:{bad_qos, QoS} ->
throw(#{ throw(#{
reason => invalid_authorization_qos, reason => invalid_authorization_qos,
qos => QoS qos => QoS

View File

@ -16,6 +16,8 @@
-module(emqx_authz_utils). -module(emqx_authz_utils).
-feature(maybe_expr, enable).
-include_lib("emqx/include/emqx_placeholder.hrl"). -include_lib("emqx/include/emqx_placeholder.hrl").
-include_lib("emqx_authz.hrl"). -include_lib("emqx_authz.hrl").
-include_lib("snabbkaffe/include/trace.hrl"). -include_lib("snabbkaffe/include/trace.hrl").
@ -37,7 +39,7 @@
render_sql_params/2, render_sql_params/2,
client_vars/1, client_vars/1,
vars_for_rule_query/2, vars_for_rule_query/2,
parse_rule_from_row/2 do_authorize/6
]). ]).
-export([ -export([
@ -221,14 +223,18 @@ content_type(Headers) when is_list(Headers) ->
-define(RAW_RULE_KEYS, [<<"permission">>, <<"action">>, <<"topic">>, <<"qos">>, <<"retain">>]). -define(RAW_RULE_KEYS, [<<"permission">>, <<"action">>, <<"topic">>, <<"qos">>, <<"retain">>]).
parse_rule_from_row(ColumnNames, Row) -> -spec parse_rule_from_row([binary()], [binary()] | map()) ->
RuleRaw = maps:with(?RAW_RULE_KEYS, maps:from_list(lists:zip(ColumnNames, to_list(Row)))), {ok, emqx_authz_rule:rule()} | {error, term()}.
case emqx_authz_rule_raw:parse_rule(RuleRaw) of parse_rule_from_row(_ColumnNames, RuleMap = #{}) ->
case emqx_authz_rule_raw:parse_rule(RuleMap) of
{ok, {Permission, Action, Topics}} -> {ok, {Permission, Action, Topics}} ->
emqx_authz_rule:compile({Permission, all, Action, Topics}); {ok, emqx_authz_rule:compile({Permission, all, Action, Topics})};
{error, Reason} -> {error, Reason} ->
error(Reason) {error, Reason}
end. end;
parse_rule_from_row(ColumnNames, Row) ->
RuleMap = maps:with(?RAW_RULE_KEYS, maps:from_list(lists:zip(ColumnNames, to_list(Row)))),
parse_rule_from_row(ColumnNames, RuleMap).
vars_for_rule_query(Client, ?authz_action(PubSub, Qos) = Action) -> vars_for_rule_query(Client, ?authz_action(PubSub, Qos) = Action) ->
Client#{ Client#{
@ -281,3 +287,39 @@ to_list(Tuple) when is_tuple(Tuple) ->
tuple_to_list(Tuple); tuple_to_list(Tuple);
to_list(List) when is_list(List) -> to_list(List) when is_list(List) ->
List. List.
do_authorize(Type, Client, Action, Topic, ColumnNames, Row) ->
try
maybe
{ok, Rule} ?= parse_rule_from_row(ColumnNames, Row),
{matched, Permission} ?= emqx_authz_rule:match(Client, Action, Topic, Rule),
{matched, Permission}
else
nomatch ->
nomatch;
{error, Reason0} ->
log_match_rule_error(Type, Row, Reason0),
nomatch
end
catch
throw:Reason1 ->
log_match_rule_error(Type, Row, Reason1),
nomatch
end.
log_match_rule_error(Type, Row, Reason0) ->
Msg0 = #{
msg => "match_rule_error",
rule => Row,
type => Type
},
Msg1 =
case is_map(Reason0) of
true -> maps:merge(Msg0, Reason0);
false -> Msg0#{reason => Reason0}
end,
?SLOG(
error,
Msg1,
#{tag => "AUTHZ"}
).

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*- %% -*- mode: erlang -*-
{application, emqx_auth_mysql, [ {application, emqx_auth_mysql, [
{description, "EMQX MySQL Authentication and Authorization"}, {description, "EMQX MySQL Authentication and Authorization"},
{vsn, "0.2.0"}, {vsn, "0.2.1"},
{registered, []}, {registered, []},
{mod, {emqx_auth_mysql_app, []}}, {mod, {emqx_auth_mysql_app, []}},
{applications, [ {applications, [

View File

@ -101,19 +101,9 @@ authorize(
do_authorize(_Client, _Action, _Topic, _ColumnNames, []) -> do_authorize(_Client, _Action, _Topic, _ColumnNames, []) ->
nomatch; nomatch;
do_authorize(Client, Action, Topic, ColumnNames, [Row | Tail]) -> do_authorize(Client, Action, Topic, ColumnNames, [Row | Tail]) ->
try case emqx_authz_utils:do_authorize(mysql, Client, Action, Topic, ColumnNames, Row) of
emqx_authz_rule:match( nomatch ->
Client, Action, Topic, emqx_authz_utils:parse_rule_from_row(ColumnNames, Row) do_authorize(Client, Action, Topic, ColumnNames, Tail);
) {matched, Permission} ->
of {matched, Permission}
{matched, Permission} -> {matched, Permission};
nomatch -> do_authorize(Client, Action, Topic, ColumnNames, Tail)
catch
error:Reason ->
?SLOG(error, #{
msg => "match_rule_error",
reason => Reason,
rule => Row
}),
do_authorize(Client, Action, Topic, ColumnNames, Tail)
end. end.

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*- %% -*- mode: erlang -*-
{application, emqx_auth_postgresql, [ {application, emqx_auth_postgresql, [
{description, "EMQX PostgreSQL Authentication and Authorization"}, {description, "EMQX PostgreSQL Authentication and Authorization"},
{vsn, "0.2.0"}, {vsn, "0.2.1"},
{registered, []}, {registered, []},
{mod, {emqx_auth_postgresql_app, []}}, {mod, {emqx_auth_postgresql_app, []}},
{applications, [ {applications, [

View File

@ -107,22 +107,11 @@ authorize(
do_authorize(_Client, _Action, _Topic, _ColumnNames, []) -> do_authorize(_Client, _Action, _Topic, _ColumnNames, []) ->
nomatch; nomatch;
do_authorize(Client, Action, Topic, ColumnNames, [Row | Tail]) -> do_authorize(Client, Action, Topic, ColumnNames, [Row | Tail]) ->
try case emqx_authz_utils:do_authorize(postgresql, Client, Action, Topic, ColumnNames, Row) of
emqx_authz_rule:match( nomatch ->
Client, Action, Topic, emqx_authz_utils:parse_rule_from_row(ColumnNames, Row) do_authorize(Client, Action, Topic, ColumnNames, Tail);
) {matched, Permission} ->
of {matched, Permission}
{matched, Permission} -> {matched, Permission};
nomatch -> do_authorize(Client, Action, Topic, ColumnNames, Tail)
catch
error:Reason:Stack ->
?SLOG(error, #{
msg => "match_rule_error",
reason => Reason,
rule => Row,
stack => Stack
}),
do_authorize(Client, Action, Topic, ColumnNames, Tail)
end. end.
column_names(Columns) -> column_names(Columns) ->

View File

@ -1,7 +1,7 @@
%% -*- mode: erlang -*- %% -*- mode: erlang -*-
{application, emqx_auth_redis, [ {application, emqx_auth_redis, [
{description, "EMQX Redis Authentication and Authorization"}, {description, "EMQX Redis Authentication and Authorization"},
{vsn, "0.2.0"}, {vsn, "0.2.1"},
{registered, []}, {registered, []},
{mod, {emqx_auth_redis_app, []}}, {mod, {emqx_auth_redis_app, []}},
{applications, [ {applications, [

View File

@ -92,44 +92,30 @@ authorize(
do_authorize(_Client, _Action, _Topic, []) -> do_authorize(_Client, _Action, _Topic, []) ->
nomatch; nomatch;
do_authorize(Client, Action, Topic, [TopicFilterRaw, RuleEncoded | Tail]) -> do_authorize(Client, Action, Topic, [TopicFilterRaw, RuleEncoded | Tail]) ->
try case parse_rule(RuleEncoded) of
emqx_authz_rule:match( {ok, RuleMap0} ->
Client, RuleMap =
Action, maps:merge(
Topic, #{
compile_rule(RuleEncoded, TopicFilterRaw) <<"permission">> => <<"allow">>,
) <<"topic">> => TopicFilterRaw
of },
{matched, Permission} -> {matched, Permission}; RuleMap0
nomatch -> do_authorize(Client, Action, Topic, Tail) ),
catch case emqx_authz_utils:do_authorize(redis, Client, Action, Topic, undefined, RuleMap) of
error:Reason:Stack -> nomatch ->
?SLOG(error, #{ do_authorize(Client, Action, Topic, Tail);
msg => "match_rule_error", {matched, Permission} ->
reason => Reason, {matched, Permission}
rule_encoded => RuleEncoded, end;
topic_filter_raw => TopicFilterRaw, {error, Reason} ->
stacktrace => Stack ?SLOG(error, Reason#{
msg => "parse_rule_error",
rule => RuleEncoded
}), }),
do_authorize(Client, Action, Topic, Tail) do_authorize(Client, Action, Topic, Tail)
end. end.
compile_rule(RuleBin, TopicFilterRaw) ->
RuleRaw =
maps:merge(
#{
<<"permission">> => <<"allow">>,
<<"topic">> => TopicFilterRaw
},
parse_rule(RuleBin)
),
case emqx_authz_rule_raw:parse_rule(RuleRaw) of
{ok, {Permission, Action, Topics}} ->
emqx_authz_rule:compile({Permission, all, Action, Topics});
{error, Reason} ->
error(Reason)
end.
parse_cmd(Query) -> parse_cmd(Query) ->
case emqx_redis_command:split(Query) of case emqx_redis_command:split(Query) of
{ok, Cmd} -> {ok, Cmd} ->
@ -154,17 +140,17 @@ validate_cmd(Cmd) ->
end. end.
parse_rule(<<"publish">>) -> parse_rule(<<"publish">>) ->
#{<<"action">> => <<"publish">>}; {ok, #{<<"action">> => <<"publish">>}};
parse_rule(<<"subscribe">>) -> parse_rule(<<"subscribe">>) ->
#{<<"action">> => <<"subscribe">>}; {ok, #{<<"action">> => <<"subscribe">>}};
parse_rule(<<"all">>) -> parse_rule(<<"all">>) ->
#{<<"action">> => <<"all">>}; {ok, #{<<"action">> => <<"all">>}};
parse_rule(Bin) when is_binary(Bin) -> parse_rule(Bin) when is_binary(Bin) ->
case emqx_utils_json:safe_decode(Bin, [return_maps]) of case emqx_utils_json:safe_decode(Bin, [return_maps]) of
{ok, Map} when is_map(Map) -> {ok, Map} when is_map(Map) ->
maps:with([<<"qos">>, <<"action">>, <<"retain">>], Map); {ok, maps:with([<<"qos">>, <<"action">>, <<"retain">>], Map)};
{ok, _} -> {ok, _} ->
error({invalid_topic_rule, Bin, notamap}); {error, #{reason => invalid_topic_rule_not_map, value => Bin}};
{error, Error} -> {error, _Error} ->
error({invalid_topic_rule, Bin, Error}) {error, #{reason => invalid_topic_rule_not_json, value => Bin}}
end. end.