fix: use minirest filter

This commit is contained in:
Stefan Strigler 2023-10-24 09:57:08 +02:00
parent 4e0e755b28
commit ea9228108b
2 changed files with 154 additions and 177 deletions

View File

@ -18,6 +18,7 @@
-behaviour(minirest_api). -behaviour(minirest_api).
-include("emqx_auth_mnesia.hrl").
-include_lib("emqx_auth/include/emqx_authz.hrl"). -include_lib("emqx_auth/include/emqx_authz.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("hocon/include/hoconsc.hrl"). -include_lib("hocon/include/hoconsc.hrl").
@ -55,6 +56,9 @@
format_result/1 format_result/1
]). ]).
%% minirest filter callback
-export([is_configured_authz_source/2]).
-define(BAD_REQUEST, 'BAD_REQUEST'). -define(BAD_REQUEST, 'BAD_REQUEST').
-define(NOT_FOUND, 'NOT_FOUND'). -define(NOT_FOUND, 'NOT_FOUND').
-define(ALREADY_EXISTS, 'ALREADY_EXISTS'). -define(ALREADY_EXISTS, 'ALREADY_EXISTS').
@ -85,6 +89,7 @@ paths() ->
schema("/authorization/sources/built_in_database/rules/users") -> schema("/authorization/sources/built_in_database/rules/users") ->
#{ #{
'operationId' => users, 'operationId' => users,
filter => fun ?MODULE:is_configured_authz_source/2,
get => get =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
@ -131,6 +136,7 @@ schema("/authorization/sources/built_in_database/rules/users") ->
schema("/authorization/sources/built_in_database/rules/clients") -> schema("/authorization/sources/built_in_database/rules/clients") ->
#{ #{
'operationId' => clients, 'operationId' => clients,
filter => fun ?MODULE:is_configured_authz_source/2,
get => get =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
@ -177,6 +183,7 @@ schema("/authorization/sources/built_in_database/rules/clients") ->
schema("/authorization/sources/built_in_database/rules/users/:username") -> schema("/authorization/sources/built_in_database/rules/users/:username") ->
#{ #{
'operationId' => user, 'operationId' => user,
filter => fun ?MODULE:is_configured_authz_source/2,
get => get =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
@ -230,6 +237,7 @@ schema("/authorization/sources/built_in_database/rules/users/:username") ->
schema("/authorization/sources/built_in_database/rules/clients/:clientid") -> schema("/authorization/sources/built_in_database/rules/clients/:clientid") ->
#{ #{
'operationId' => client, 'operationId' => client,
filter => fun ?MODULE:is_configured_authz_source/2,
get => get =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
@ -283,6 +291,7 @@ schema("/authorization/sources/built_in_database/rules/clients/:clientid") ->
schema("/authorization/sources/built_in_database/rules/all") -> schema("/authorization/sources/built_in_database/rules/all") ->
#{ #{
'operationId' => all, 'operationId' => all,
filter => fun ?MODULE:is_configured_authz_source/2,
get => get =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
@ -317,6 +326,7 @@ schema("/authorization/sources/built_in_database/rules/all") ->
schema("/authorization/sources/built_in_database/rules") -> schema("/authorization/sources/built_in_database/rules") ->
#{ #{
'operationId' => rules, 'operationId' => rules,
filter => fun ?MODULE:is_configured_authz_source/2,
delete => delete =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
@ -426,210 +436,173 @@ fields(rules) ->
%% HTTP API %% HTTP API
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
-define(IF_CONFIGURED_AUTHZ_SOURCE(EXPR), is_configured_authz_source(Params, _Meta) ->
emqx_authz_api_sources:with_source( emqx_authz_api_sources:with_source(
<<"built_in_database">>, ?AUTHZ_TYPE_BIN,
fun(_Source) -> fun(_Source) ->
EXPR {ok, Params}
end end
) ).
).
users(get, #{query_string := QueryString}) -> users(get, #{query_string := QueryString}) ->
?IF_CONFIGURED_AUTHZ_SOURCE( case
case emqx_mgmt_api:node_query(
emqx_mgmt_api:node_query( node(),
node(), ?ACL_TABLE,
?ACL_TABLE, QueryString,
QueryString, ?ACL_USERNAME_QSCHEMA,
?ACL_USERNAME_QSCHEMA, ?QUERY_USERNAME_FUN,
?QUERY_USERNAME_FUN, fun ?MODULE:format_result/1
fun ?MODULE:format_result/1 )
) of
of {error, page_limit_invalid} ->
{error, page_limit_invalid} -> {400, #{code => <<"INVALID_PARAMETER">>, message => <<"page_limit_invalid">>}};
{400, #{code => <<"INVALID_PARAMETER">>, message => <<"page_limit_invalid">>}}; {error, Node, Error} ->
{error, Node, Error} -> Message = list_to_binary(
Message = list_to_binary( io_lib:format("bad rpc call ~p, Reason ~p", [Node, Error])
io_lib:format("bad rpc call ~p, Reason ~p", [Node, Error]) ),
), {500, #{code => <<"NODE_DOWN">>, message => Message}};
{500, #{code => <<"NODE_DOWN">>, message => Message}}; Result ->
Result -> {200, Result}
{200, Result} end;
end
);
users(post, #{body := Body}) when is_list(Body) -> users(post, #{body := Body}) when is_list(Body) ->
?IF_CONFIGURED_AUTHZ_SOURCE( case ensure_all_not_exists(<<"username">>, username, Body) of
case ensure_all_not_exists(<<"username">>, username, Body) of [] ->
[] -> lists:foreach(
lists:foreach( fun(#{<<"username">> := Username, <<"rules">> := Rules}) ->
fun(#{<<"username">> := Username, <<"rules">> := Rules}) -> emqx_authz_mnesia:store_rules({username, Username}, Rules)
emqx_authz_mnesia:store_rules({username, Username}, Rules) end,
end, Body
Body ),
), {204};
{204}; Exists ->
Exists -> {409, #{
{409, #{ code => <<"ALREADY_EXISTS">>,
code => <<"ALREADY_EXISTS">>, message => binfmt("Users '~ts' already exist", [binjoin(Exists)])
message => binfmt("Users '~ts' already exist", [binjoin(Exists)]) }}
}} end.
end
).
clients(get, #{query_string := QueryString}) -> clients(get, #{query_string := QueryString}) ->
?IF_CONFIGURED_AUTHZ_SOURCE( case
case emqx_mgmt_api:node_query(
emqx_mgmt_api:node_query( node(),
node(), ?ACL_TABLE,
?ACL_TABLE, QueryString,
QueryString, ?ACL_CLIENTID_QSCHEMA,
?ACL_CLIENTID_QSCHEMA, ?QUERY_CLIENTID_FUN,
?QUERY_CLIENTID_FUN, fun ?MODULE:format_result/1
fun ?MODULE:format_result/1 )
) of
of {error, page_limit_invalid} ->
{error, page_limit_invalid} -> {400, #{code => <<"INVALID_PARAMETER">>, message => <<"page_limit_invalid">>}};
{400, #{code => <<"INVALID_PARAMETER">>, message => <<"page_limit_invalid">>}}; {error, Node, Error} ->
{error, Node, Error} -> Message = list_to_binary(
Message = list_to_binary( io_lib:format("bad rpc call ~p, Reason ~p", [Node, Error])
io_lib:format("bad rpc call ~p, Reason ~p", [Node, Error]) ),
), {500, #{code => <<"NODE_DOWN">>, message => Message}};
{500, #{code => <<"NODE_DOWN">>, message => Message}}; Result ->
Result -> {200, Result}
{200, Result} end;
end
);
clients(post, #{body := Body}) when is_list(Body) -> clients(post, #{body := Body}) when is_list(Body) ->
?IF_CONFIGURED_AUTHZ_SOURCE( case ensure_all_not_exists(<<"clientid">>, clientid, Body) of
case ensure_all_not_exists(<<"clientid">>, clientid, Body) of [] ->
[] -> lists:foreach(
lists:foreach( fun(#{<<"clientid">> := ClientID, <<"rules">> := Rules}) ->
fun(#{<<"clientid">> := ClientID, <<"rules">> := Rules}) -> emqx_authz_mnesia:store_rules({clientid, ClientID}, Rules)
emqx_authz_mnesia:store_rules({clientid, ClientID}, Rules) end,
end, Body
Body ),
), {204};
{204}; Exists ->
Exists -> {409, #{
{409, #{ code => <<"ALREADY_EXISTS">>,
code => <<"ALREADY_EXISTS">>, message => binfmt("Clients '~ts' already exist", [binjoin(Exists)])
message => binfmt("Clients '~ts' already exist", [binjoin(Exists)]) }}
}} end.
end
).
user(get, #{bindings := #{username := Username}}) -> user(get, #{bindings := #{username := Username}}) ->
?IF_CONFIGURED_AUTHZ_SOURCE( case emqx_authz_mnesia:get_rules({username, Username}) of
case emqx_authz_mnesia:get_rules({username, Username}) of not_found ->
not_found -> {404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}};
{404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}}; {ok, Rules} ->
{ok, Rules} -> {200, #{
{200, #{ username => Username,
username => Username, rules => format_rules(Rules)
rules => format_rules(Rules) }}
}} end;
end
);
user(put, #{ user(put, #{
bindings := #{username := Username}, bindings := #{username := Username},
body := #{<<"username">> := Username, <<"rules">> := Rules} body := #{<<"username">> := Username, <<"rules">> := Rules}
}) -> }) ->
?IF_CONFIGURED_AUTHZ_SOURCE( emqx_authz_mnesia:store_rules({username, Username}, Rules),
begin {204};
emqx_authz_mnesia:store_rules({username, Username}, Rules),
{204}
end
);
user(delete, #{bindings := #{username := Username}}) -> user(delete, #{bindings := #{username := Username}}) ->
?IF_CONFIGURED_AUTHZ_SOURCE( case emqx_authz_mnesia:get_rules({username, Username}) of
case emqx_authz_mnesia:get_rules({username, Username}) of not_found ->
not_found -> {404, #{code => <<"NOT_FOUND">>, message => <<"Username Not Found">>}};
{404, #{code => <<"NOT_FOUND">>, message => <<"Username Not Found">>}}; {ok, _Rules} ->
{ok, _Rules} -> emqx_authz_mnesia:delete_rules({username, Username}),
emqx_authz_mnesia:delete_rules({username, Username}), {204}
{204} end.
end
).
client(get, #{bindings := #{clientid := ClientID}}) -> client(get, #{bindings := #{clientid := ClientID}}) ->
?IF_CONFIGURED_AUTHZ_SOURCE( case emqx_authz_mnesia:get_rules({clientid, ClientID}) of
case emqx_authz_mnesia:get_rules({clientid, ClientID}) of not_found ->
not_found -> {404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}};
{404, #{code => <<"NOT_FOUND">>, message => <<"Not Found">>}}; {ok, Rules} ->
{ok, Rules} -> {200, #{
{200, #{ clientid => ClientID,
clientid => ClientID, rules => format_rules(Rules)
rules => format_rules(Rules) }}
}} end;
end
);
client(put, #{ client(put, #{
bindings := #{clientid := ClientID}, bindings := #{clientid := ClientID},
body := #{<<"clientid">> := ClientID, <<"rules">> := Rules} body := #{<<"clientid">> := ClientID, <<"rules">> := Rules}
}) -> }) ->
?IF_CONFIGURED_AUTHZ_SOURCE( emqx_authz_mnesia:store_rules({clientid, ClientID}, Rules),
begin {204};
emqx_authz_mnesia:store_rules({clientid, ClientID}, Rules),
{204}
end
);
client(delete, #{bindings := #{clientid := ClientID}}) -> client(delete, #{bindings := #{clientid := ClientID}}) ->
?IF_CONFIGURED_AUTHZ_SOURCE( case emqx_authz_mnesia:get_rules({clientid, ClientID}) of
case emqx_authz_mnesia:get_rules({clientid, ClientID}) of not_found ->
not_found -> {404, #{code => <<"NOT_FOUND">>, message => <<"ClientID Not Found">>}};
{404, #{code => <<"NOT_FOUND">>, message => <<"ClientID Not Found">>}}; {ok, _Rules} ->
{ok, _Rules} -> emqx_authz_mnesia:delete_rules({clientid, ClientID}),
emqx_authz_mnesia:delete_rules({clientid, ClientID}), {204}
{204} end.
end
).
all(get, _) -> all(get, _) ->
?IF_CONFIGURED_AUTHZ_SOURCE( case emqx_authz_mnesia:get_rules(all) of
case emqx_authz_mnesia:get_rules(all) of not_found ->
not_found -> {200, #{rules => []}};
{200, #{rules => []}}; {ok, Rules} ->
{ok, Rules} -> {200, #{
{200, #{ rules => format_rules(Rules)
rules => format_rules(Rules) }}
}} end;
end
);
all(post, #{body := #{<<"rules">> := Rules}}) -> all(post, #{body := #{<<"rules">> := Rules}}) ->
?IF_CONFIGURED_AUTHZ_SOURCE( emqx_authz_mnesia:store_rules(all, Rules),
begin {204};
emqx_authz_mnesia:store_rules(all, Rules),
{204}
end
);
all(delete, _) -> all(delete, _) ->
?IF_CONFIGURED_AUTHZ_SOURCE( emqx_authz_mnesia:store_rules(all, []),
begin {204}.
emqx_authz_mnesia:store_rules(all, []),
{204}
end
).
rules(delete, _) -> rules(delete, _) ->
?IF_CONFIGURED_AUTHZ_SOURCE( case emqx_authz_api_sources:get_raw_source(<<"built_in_database">>) of
case emqx_authz_api_sources:get_raw_source(<<"built_in_database">>) of [#{<<"enable">> := false}] ->
[#{<<"enable">> := false}] -> ok = emqx_authz_mnesia:purge_rules(),
ok = emqx_authz_mnesia:purge_rules(), {204};
{204}; [#{<<"enable">> := true}] ->
[#{<<"enable">> := true}] -> {400, #{
{400, #{ code => <<"BAD_REQUEST">>,
code => <<"BAD_REQUEST">>, message =>
message => <<"'built_in_database' type source must be disabled before purge.">>
<<"'built_in_database' type source must be disabled before purge.">> }};
}}; [] ->
[] -> {404, #{
{404, #{ code => <<"BAD_REQUEST">>,
code => <<"BAD_REQUEST">>, message => <<"'built_in_database' type source is not found.">>
message => <<"'built_in_database' type source is not found.">> }}
}} end.
end
).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% QueryString to MatchSpec %% QueryString to MatchSpec

View File

@ -415,7 +415,9 @@ run_examples(Code, Examples) when is_number(Code) ->
run_examples( run_examples(
fun fun
({ok, ResCode, _}) when Code =:= ResCode -> true; ({ok, ResCode, _}) when Code =:= ResCode -> true;
(_) -> false (_Res) ->
ct:pal("check failed: ~p", [_Res]),
false
end, end,
Examples Examples
). ).
@ -455,7 +457,9 @@ make_examples(ApiMod, Replacements) ->
end, end,
{replace_parts(to_parts(Path), Replacements), Op, Body} {replace_parts(to_parts(Path), Replacements), Op, Body}
end, end,
lists:sort(fun op_sort/2, maps:to_list(maps:remove('operationId', Schema))) lists:sort(
fun op_sort/2, maps:to_list(maps:with([get, put, post, delete], Schema))
)
) )
end, end,
Paths Paths