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