From 6b313a60d4d9920494ceeed908905725e9945b56 Mon Sep 17 00:00:00 2001 From: zhanghongtong Date: Mon, 30 Aug 2021 17:42:56 +0800 Subject: [PATCH] refactor: refactor emqx_authz Signed-off-by: zhanghongtong --- apps/emqx_authz/src/emqx_authz.erl | 206 ++++++++++-------- apps/emqx_authz/src/emqx_authz_api.erl | 195 ++++++++--------- apps/emqx_authz/src/emqx_authz_api_schema.erl | 10 +- apps/emqx_authz/test/emqx_authz_SUITE.erl | 192 ++++++++-------- apps/emqx_authz/test/emqx_authz_api_SUITE.erl | 192 ++++++++-------- 5 files changed, 415 insertions(+), 380 deletions(-) diff --git a/apps/emqx_authz/src/emqx_authz.erl b/apps/emqx_authz/src/emqx_authz.erl index 3a39a2984..4a6d7033e 100644 --- a/apps/emqx_authz/src/emqx_authz.erl +++ b/apps/emqx_authz/src/emqx_authz.erl @@ -51,33 +51,41 @@ init() -> lookup() -> {_M, _F, [A]}= find_action_in_hooks(), A. -lookup(Id) -> - try find_source_by_id(Id, lookup()) of +lookup(Type) -> + try find_source_by_type(atom(Type), lookup()) of {_, Source} -> Source catch error:Reason -> {error, Reason} end. -move(Id, Position) -> - emqx:update_config(?CONF_KEY_PATH, {move, Id, Position}). +move(Type, #{<<"before">> := Before}) -> + emqx:update_config(?CONF_KEY_PATH, {move, atom(Type), #{<<"before">> => atom(Before)}}); +move(Type, #{<<"after">> := After}) -> + emqx:update_config(?CONF_KEY_PATH, {move, atom(Type), #{<<"after">> => atom(After)}}); +move(Type, Position) -> + emqx:update_config(?CONF_KEY_PATH, {move, atom(Type), Position}). +update({replace_once, Type}, Sources) -> + emqx:update_config(?CONF_KEY_PATH, {{replace_once, atom(Type)}, Sources}); +update({delete_once, Type}, Sources) -> + emqx:update_config(?CONF_KEY_PATH, {{delete_once, atom(Type)}, Sources}); update(Cmd, Sources) -> emqx:update_config(?CONF_KEY_PATH, {Cmd, Sources}). -pre_config_update({move, Id, <<"top">>}, Conf) when is_list(Conf) -> - {Index, _} = find_source_by_id(Id), +pre_config_update({move, Type, <<"top">>}, Conf) when is_list(Conf) -> + {Index, _} = find_source_by_type(Type), {List1, List2} = lists:split(Index, Conf), {ok, [lists:nth(Index, Conf)] ++ lists:droplast(List1) ++ List2}; -pre_config_update({move, Id, <<"bottom">>}, Conf) when is_list(Conf) -> - {Index, _} = find_source_by_id(Id), +pre_config_update({move, Type, <<"bottom">>}, Conf) when is_list(Conf) -> + {Index, _} = find_source_by_type(Type), {List1, List2} = lists:split(Index, Conf), {ok, lists:droplast(List1) ++ List2 ++ [lists:nth(Index, Conf)]}; -pre_config_update({move, Id, #{<<"before">> := BeforeId}}, Conf) when is_list(Conf) -> - {Index1, _} = find_source_by_id(Id), +pre_config_update({move, Type, #{<<"before">> := Before}}, Conf) when is_list(Conf) -> + {Index1, _} = find_source_by_type(Type), Conf1 = lists:nth(Index1, Conf), - {Index2, _} = find_source_by_id(BeforeId), + {Index2, _} = find_source_by_type(Before), Conf2 = lists:nth(Index2, Conf), {List1, List2} = lists:split(Index2, Conf), @@ -85,10 +93,10 @@ pre_config_update({move, Id, #{<<"before">> := BeforeId}}, Conf) when is_list(Co ++ [Conf1] ++ [Conf2] ++ lists:delete(Conf1, List2)}; -pre_config_update({move, Id, #{<<"after">> := AfterId}}, Conf) when is_list(Conf) -> - {Index1, _} = find_source_by_id(Id), +pre_config_update({move, Type, #{<<"after">> := After}}, Conf) when is_list(Conf) -> + {Index1, _} = find_source_by_type(Type), Conf1 = lists:nth(Index1, Conf), - {Index2, _} = find_source_by_id(AfterId), + {Index2, _} = find_source_by_type(After), {List1, List2} = lists:split(Index2, Conf), {ok, lists:delete(Conf1, List1) @@ -99,34 +107,37 @@ pre_config_update({head, Sources}, Conf) when is_list(Sources), is_list(Conf) -> {ok, Sources ++ Conf}; pre_config_update({tail, Sources}, Conf) when is_list(Sources), is_list(Conf) -> {ok, Conf ++ Sources}; -pre_config_update({{replace_once, Id}, Source}, Conf) when is_map(Source), is_list(Conf) -> - {Index, _} = find_source_by_id(Id), +pre_config_update({{replace_once, Type}, Source}, Conf) when is_map(Source), is_list(Conf) -> + {Index, _} = find_source_by_type(Type), {List1, List2} = lists:split(Index, Conf), {ok, lists:droplast(List1) ++ [Source] ++ List2}; +pre_config_update({{delete_once, Type}, _Source}, Conf) when is_list(Conf) -> + {_, Source} = find_source_by_type(Type), + {ok, lists:delete(Source, Conf)}; pre_config_update({_, Sources}, _Conf) when is_list(Sources)-> %% overwrite the entire config! {ok, Sources}. post_config_update(_, undefined, _Conf, _AppEnvs) -> ok; -post_config_update({move, Id, <<"top">>}, _NewSources, _OldSources, _AppEnvs) -> +post_config_update({move, Type, <<"top">>}, _NewSources, _OldSources, _AppEnvs) -> InitedSources = lookup(), - {Index, Source} = find_source_by_id(Id, InitedSources), + {Index, Source} = find_source_by_type(Type, InitedSources), {Sources1, Sources2 } = lists:split(Index, InitedSources), Sources3 = [Source] ++ lists:droplast(Sources1) ++ Sources2, ok = emqx_hooks:put('client.authorize', {?MODULE, authorize, [Sources3]}, -1), ok = emqx_authz_cache:drain_cache(); -post_config_update({move, Id, <<"bottom">>}, _NewSources, _OldSources, _AppEnvs) -> +post_config_update({move, Type, <<"bottom">>}, _NewSources, _OldSources, _AppEnvs) -> InitedSources = lookup(), - {Index, Source} = find_source_by_id(Id, InitedSources), + {Index, Source} = find_source_by_type(Type, InitedSources), {Sources1, Sources2 } = lists:split(Index, InitedSources), Sources3 = lists:droplast(Sources1) ++ Sources2 ++ [Source], ok = emqx_hooks:put('client.authorize', {?MODULE, authorize, [Sources3]}, -1), ok = emqx_authz_cache:drain_cache(); -post_config_update({move, Id, #{<<"before">> := BeforeId}}, _NewSources, _OldSources, _AppEnvs) -> +post_config_update({move, Type, #{<<"before">> := Before}}, _NewSources, _OldSources, _AppEnvs) -> InitedSources = lookup(), - {_, Source0} = find_source_by_id(Id, InitedSources), - {Index, Source1} = find_source_by_id(BeforeId, InitedSources), + {_, Source0} = find_source_by_type(Type, InitedSources), + {Index, Source1} = find_source_by_type(Before, InitedSources), {Sources1, Sources2} = lists:split(Index, InitedSources), Sources3 = lists:delete(Source0, lists:droplast(Sources1)) ++ [Source0] ++ [Source1] @@ -134,10 +145,10 @@ post_config_update({move, Id, #{<<"before">> := BeforeId}}, _NewSources, _OldSou ok = emqx_hooks:put('client.authorize', {?MODULE, authorize, [Sources3]}, -1), ok = emqx_authz_cache:drain_cache(); -post_config_update({move, Id, #{<<"after">> := AfterId}}, _NewSources, _OldSources, _AppEnvs) -> +post_config_update({move, Type, #{<<"after">> := After}}, _NewSources, _OldSources, _AppEnvs) -> InitedSources = lookup(), - {_, Source} = find_source_by_id(Id, InitedSources), - {Index, _} = find_source_by_id(AfterId, InitedSources), + {_, Source} = find_source_by_type(Type, InitedSources), + {Index, _} = find_source_by_type(After, InitedSources), {Sources1, Sources2} = lists:split(Index, InitedSources), Sources3 = lists:delete(Source, Sources1) ++ [Source] @@ -155,9 +166,9 @@ post_config_update({tail, Sources}, _NewSources, _OldConf, _AppEnvs) -> emqx_hooks:put('client.authorize', {?MODULE, authorize, [lookup() ++ InitedSources]}, -1), ok = emqx_authz_cache:drain_cache(); -post_config_update({{replace_once, Id}, Source}, _NewSources, _OldConf, _AppEnvs) when is_map(Source) -> +post_config_update({{replace_once, Type}, #{type := Type} = Source}, _NewSources, _OldConf, _AppEnvs) when is_map(Source) -> OldInitedSources = lookup(), - {Index, OldSource} = find_source_by_id(Id, OldInitedSources), + {Index, OldSource} = find_source_by_type(Type, OldInitedSources), case maps:get(type, OldSource, undefined) of undefined -> ok; _ -> @@ -165,10 +176,19 @@ post_config_update({{replace_once, Id}, Source}, _NewSources, _OldConf, _AppEnvs ok = emqx_resource:remove(Id) end, {OldSources1, OldSources2 } = lists:split(Index, OldInitedSources), - InitedSources = [init_source(R#{annotations => #{id => Id}}) || R <- check_sources([Source])], + InitedSources = [init_source(R) || R <- check_sources([Source])], ok = emqx_hooks:put('client.authorize', {?MODULE, authorize, [lists:droplast(OldSources1) ++ InitedSources ++ OldSources2]}, -1), ok = emqx_authz_cache:drain_cache(); - +post_config_update({{delete_once, Type}, _Source}, _NewSources, _OldConf, _AppEnvs) -> + OldInitedSources = lookup(), + {_, OldSource} = find_source_by_type(Type, OldInitedSources), + case OldSource of + #{annotations := #{id := Id}} -> + ok = emqx_resource:remove(Id); + _ -> ok + end, + ok = emqx_hooks:put('client.authorize', {?MODULE, authorize, [lists:delete(OldSource, OldInitedSources)]}, -1), + ok = emqx_authz_cache:drain_cache(); post_config_update(_, NewSources, _OldConf, _AppEnvs) -> %% overwrite the entire config! OldInitedSources = lookup(), @@ -181,52 +201,13 @@ post_config_update(_, NewSources, _OldConf, _AppEnvs) -> ok = emqx_authz_cache:drain_cache(). %%-------------------------------------------------------------------- -%% Internal functions +%% Initialize source %%-------------------------------------------------------------------- -check_sources(RawSources) -> - {ok, Conf} = hocon:binary(jsx:encode(#{<<"authorization">> => #{<<"sources">> => RawSources}}), #{format => richmap}), - CheckConf = hocon_schema:check(emqx_authz_schema, Conf, #{atom_key => true}), - #{authorization:= #{sources := Sources}} = hocon_schema:richmap_to_map(CheckConf), - Sources. - -find_source_by_id(Id) -> find_source_by_id(Id, lookup()). -find_source_by_id(Id, Sources) -> find_source_by_id(Id, Sources, 1). -find_source_by_id(_SourceId, [], _N) -> error(not_found_rule); -find_source_by_id(SourceId, [ Source = #{annotations := #{id := Id}} | Tail], N) -> - case SourceId =:= Id of - true -> {N, Source}; - false -> find_source_by_id(SourceId, Tail, N + 1) - end. - -find_action_in_hooks() -> - Callbacks = emqx_hooks:lookup('client.authorize'), - [Action] = [Action || {callback,{?MODULE, authorize, _} = Action, _, _} <- Callbacks ], - Action. - -gen_id(Type) -> - iolist_to_binary([io_lib:format("~s_~s",[?APP, Type]), "_", integer_to_list(erlang:system_time())]). - -create_resource(#{type := DB, - config := Config, - annotations := #{id := ResourceID}}) -> - case emqx_resource:update(ResourceID, connector_module(DB), Config, []) of - {ok, _} -> ResourceID; - {error, Reason} -> {error, Reason} - end; -create_resource(#{type := DB, - config := Config}) -> - ResourceID = gen_id(DB), - case emqx_resource:create(ResourceID, connector_module(DB), Config) of - {ok, already_created} -> ResourceID; - {ok, _} -> ResourceID; - {error, Reason} -> {error, Reason} - end. - init_source(#{enable := true, - type := file, - path := Path - } = Source) -> + type := file, + path := Path + } = Source) -> Rules = case file:consult(Path) of {ok, Terms} -> [emqx_authz_rule:compile(Term) || Term <- Terms]; @@ -240,35 +221,28 @@ init_source(#{enable := true, ?LOG(alert, "Failed to read ~s: ~p", [Path, Reason]), error(Reason) end, - Source#{annotations => - #{id => gen_id(file), - rules => Rules - }}; + Source#{annotations => #{rules => Rules}}; init_source(#{enable := true, - type := http, - config := #{url := Url} = Config - } = Source) -> + type := http, + config := #{url := Url} = Config + } = Source) -> NConfig = maps:merge(Config, #{base_url => maps:remove(query, Url)}), case create_resource(Source#{config := NConfig}) of {error, Reason} -> error({load_config_error, Reason}); - Id -> Source#{annotations => - #{id => Id} - } + Id -> Source#{annotations => #{id => Id}} end; init_source(#{enable := true, - type := DB - } = Source) when DB =:= redis; + type := DB + } = Source) when DB =:= redis; DB =:= mongo -> case create_resource(Source) of {error, Reason} -> error({load_config_error, Reason}); - Id -> Source#{annotations => - #{id => Id} - } + Id -> Source#{annotations => #{id => Id}} end; init_source(#{enable := true, - type := DB, - sql := SQL - } = Source) when DB =:= mysql; + type := DB, + sql := SQL + } = Source) when DB =:= mysql; DB =:= pgsql -> Mod = authz_module(DB), case create_resource(Source) of @@ -323,8 +297,58 @@ do_authorize(Client, PubSub, Topic, Matched -> Matched end. +%%-------------------------------------------------------------------- +%% Internal function +%%-------------------------------------------------------------------- + +check_sources(RawSources) -> + {ok, Conf} = hocon:binary(jsx:encode(#{<<"authorization">> => #{<<"sources">> => RawSources}}), #{format => richmap}), + CheckConf = hocon_schema:check(emqx_authz_schema, Conf, #{atom_key => true}), + #{authorization:= #{sources := Sources}} = hocon_schema:richmap_to_map(CheckConf), + Sources. + +find_source_by_type(Type) -> find_source_by_type(Type, lookup()). +find_source_by_type(Type, Sources) -> find_source_by_type(Type, Sources, 1). +find_source_by_type(_, [], _N) -> error(not_found_rule); +find_source_by_type(Type, [ Source = #{type := T} | Tail], N) -> + case Type =:= T of + true -> {N, Source}; + false -> find_source_by_type(Type, Tail, N + 1) + end. + +find_action_in_hooks() -> + Callbacks = emqx_hooks:lookup('client.authorize'), + [Action] = [Action || {callback,{?MODULE, authorize, _} = Action, _, _} <- Callbacks ], + Action. + +gen_id(Type) -> + iolist_to_binary([io_lib:format("~s_~s",[?APP, Type])]). + +create_resource(#{type := DB, + config := Config, + annotations := #{id := ResourceID}}) -> + case emqx_resource:update(ResourceID, connector_module(DB), Config, []) of + {ok, _} -> ResourceID; + {error, Reason} -> {error, Reason} + end; +create_resource(#{type := DB, + config := Config}) -> + ResourceID = gen_id(DB), + case emqx_resource:create(ResourceID, connector_module(DB), Config) of + {ok, already_created} -> ResourceID; + {ok, _} -> ResourceID; + {error, Reason} -> {error, Reason} + end. + authz_module(Type) -> list_to_existing_atom("emqx_authz_" ++ atom_to_list(Type)). connector_module(Type) -> list_to_existing_atom("emqx_connector_" ++ atom_to_list(Type)). + +atom(B) when is_binary(B) -> + try binary_to_existing_atom(B, utf8) + catch + _ -> binary_to_atom(B) + end; +atom(A) when is_atom(A) -> A. diff --git a/apps/emqx_authz/src/emqx_authz_api.erl b/apps/emqx_authz/src/emqx_authz_api.erl index 1646a9af2..ff5217426 100644 --- a/apps/emqx_authz/src/emqx_authz_api.erl +++ b/apps/emqx_authz/src/emqx_authz_api.erl @@ -30,7 +30,7 @@ -define(EXAMPLE_RETURNED_RULES, - #{rules => [?EXAMPLE_RETURNED_RULE1 + #{sources => [?EXAMPLE_RETURNED_RULE1 ] }). @@ -40,23 +40,23 @@ topics => [<<"#">>]}). -export([ api_spec/0 - , rules/2 - , rule/2 - , move_rule/2 + , sources/2 + , source/2 + , move_source/2 ]). api_spec() -> - {[ rules_api() - , rule_api() - , move_rule_api() + {[ sources_api() + , source_api() + , move_source_api() ], definitions()}. definitions() -> emqx_authz_api_schema:definitions(). -rules_api() -> +sources_api() -> Metadata = #{ get => #{ - description => "List authorization rules", + description => "List authorization sources", parameters => [ #{ name => page, @@ -82,16 +82,16 @@ rules_api() -> 'application/json' => #{ schema => #{ type => object, - required => [rules], - properties => #{rules => #{ + required => [sources], + properties => #{sources => #{ type => array, - items => minirest:ref(<<"returned_rules">>) + items => minirest:ref(<<"returned_sources">>) } } }, examples => #{ - rules => #{ - summary => <<"Rules">>, + sources => #{ + summary => <<"Sources">>, value => jsx:encode(?EXAMPLE_RETURNED_RULES) } } @@ -101,14 +101,14 @@ rules_api() -> } }, post => #{ - description => "Add new rule", + description => "Add new source", requestBody => #{ content => #{ 'application/json' => #{ - schema => minirest:ref(<<"rules">>), + schema => minirest:ref(<<"sources">>), examples => #{ - simple_rule => #{ - summary => <<"Rules">>, + simple_source => #{ + summary => <<"Sources">>, value => jsx:encode(?EXAMPLE_RULE1) } } @@ -138,17 +138,17 @@ rules_api() -> }, put => #{ - description => "Update all rules", + description => "Update all sources", requestBody => #{ content => #{ 'application/json' => #{ schema => #{ type => array, - items => minirest:ref(<<"returned_rules">>) + items => minirest:ref(<<"returned_sources">>) }, examples => #{ - rules => #{ - summary => <<"Rules">>, + sources => #{ + summary => <<"Sources">>, value => jsx:encode([?EXAMPLE_RULE1]) } } @@ -177,15 +177,15 @@ rules_api() -> } } }, - {"/authorization", Metadata, rules}. + {"/authorization", Metadata, sources}. -rule_api() -> +source_api() -> Metadata = #{ get => #{ - description => "List authorization rules", + description => "List authorization sources", parameters => [ #{ - name => id, + name => type, in => path, schema => #{ type => string @@ -198,10 +198,10 @@ rule_api() -> description => <<"OK">>, content => #{ 'application/json' => #{ - schema => minirest:ref(<<"returned_rules">>), + schema => minirest:ref(<<"returned_sources">>), examples => #{ - rules => #{ - summary => <<"Rules">>, + sources => #{ + summary => <<"Sources">>, value => jsx:encode(?EXAMPLE_RETURNED_RULE1) } } @@ -218,7 +218,7 @@ rule_api() -> summary => <<"Not Found">>, value => #{ code => <<"NOT_FOUND">>, - message => <<"rule xxx not found">> + message => <<"source xxx not found">> } } } @@ -228,10 +228,10 @@ rule_api() -> } }, put => #{ - description => "Update rule", + description => "Update source", parameters => [ #{ - name => id, + name => type, in => path, schema => #{ type => string @@ -242,10 +242,10 @@ rule_api() -> requestBody => #{ content => #{ 'application/json' => #{ - schema => minirest:ref(<<"rules">>), + schema => minirest:ref(<<"sources">>), examples => #{ - simple_rule => #{ - summary => <<"Rules">>, + simple_source => #{ + summary => <<"Sources">>, value => jsx:encode(?EXAMPLE_RULE1) } } @@ -264,7 +264,7 @@ rule_api() -> summary => <<"Not Found">>, value => #{ code => <<"NOT_FOUND">>, - message => <<"rule xxx not found">> + message => <<"source xxx not found">> } } } @@ -291,7 +291,7 @@ rule_api() -> } }, delete => #{ - description => "Delete rule", + description => "Delete source", parameters => [ #{ name => id, @@ -324,15 +324,15 @@ rule_api() -> } } }, - {"/authorization/:id", Metadata, rule}. + {"/authorization/:type", Metadata, source}. -move_rule_api() -> +move_source_api() -> Metadata = #{ post => #{ - description => "Change the order of rules", + description => "Change the order of sources", parameters => [ #{ - name => id, + name => type, in => path, schema => #{ type => string @@ -381,15 +381,13 @@ move_rule_api() -> }, <<"404">> => #{ description => <<"Bad Request">>, - content => #{ - 'application/json' => #{ - schema => minirest:ref(<<"error">>), + content => #{ 'application/json' => #{ schema => minirest:ref(<<"error">>), examples => #{ example1 => #{ summary => <<"Not Found">>, value => #{ code => <<"NOT_FOUND">>, - message => <<"rule xxx not found">> + message => <<"source xxx not found">> } } } @@ -416,56 +414,54 @@ move_rule_api() -> } } }, - {"/authorization/:id/move", Metadata, move_rule}. + {"/authorization/:type/move", Metadata, move_source}. -rules(get, #{query_string := Query}) -> - Rules = lists:foldl(fun (#{type := _Type, enable := true, config := #{server := Server} = Config, annotations := #{id := Id}} = Rule, AccIn) -> - NRule = case emqx_resource:health_check(Id) of +sources(get, #{query_string := Query}) -> + Sources = lists:foldl(fun (#{type := _Type, enable := true, config := #{server := Server} = Config, annotations := #{id := Id}} = Source, AccIn) -> + NSource = case emqx_resource:health_check(Id) of ok -> - Rule#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, - annotations => #{id => Id, - status => healthy}}; + Source#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, + annotations => #{id => Id, + status => healthy}}; _ -> - Rule#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, - annotations => #{id => Id, - status => unhealthy}} + Source#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, + annotations => #{id => Id, + status => unhealthy}} end, - lists:append(AccIn, [NRule]); - (#{type := _Type, enable := true, annotations := #{id := Id}} = Rule, AccIn) -> - NRule = case emqx_resource:health_check(Id) of + lists:append(AccIn, [NSource]); + (#{type := _Type, enable := true, annotations := #{id := Id}} = Source, AccIn) -> + NSource = case emqx_resource:health_check(Id) of ok -> - Rule#{annotations => #{id => Id, - status => healthy}}; + Source#{annotations => #{status => healthy}}; _ -> - Rule#{annotations => #{id => Id, - status => unhealthy}} + Source#{annotations => #{status => unhealthy}} end, - lists:append(AccIn, [NRule]); - (Rule, AccIn) -> - lists:append(AccIn, [Rule]) + lists:append(AccIn, [NSource]); + (Source, AccIn) -> + lists:append(AccIn, [Source]) end, [], emqx_authz:lookup()), case maps:is_key(<<"page">>, Query) andalso maps:is_key(<<"limit">>, Query) of true -> Page = maps:get(<<"page">>, Query), Limit = maps:get(<<"limit">>, Query), Index = (binary_to_integer(Page) - 1) * binary_to_integer(Limit), - {_, Rules1} = lists:split(Index, Rules), - case binary_to_integer(Limit) < length(Rules1) of + {_, Sources1} = lists:split(Index, Sources), + case binary_to_integer(Limit) < length(Sources1) of true -> - {Rules2, _} = lists:split(binary_to_integer(Limit), Rules1), - {200, #{rules => Rules2}}; - false -> {200, #{rules => Rules1}} + {Sources2, _} = lists:split(binary_to_integer(Limit), Sources1), + {200, #{sources => Sources2}}; + false -> {200, #{sources => Sources1}} end; - false -> {200, #{rules => Rules}} + false -> {200, #{sources => Sources}} end; -rules(post, #{body := RawConfig}) -> +sources(post, #{body := RawConfig}) -> case emqx_authz:update(head, [RawConfig]) of {ok, _} -> {204}; {error, Reason} -> {400, #{code => <<"BAD_REQUEST">>, messgae => atom_to_binary(Reason)}} end; -rules(put, #{body := RawConfig}) -> +sources(put, #{body := RawConfig}) -> case emqx_authz:update(replace, RawConfig) of {ok, _} -> {204}; {error, Reason} -> @@ -473,56 +469,57 @@ rules(put, #{body := RawConfig}) -> messgae => atom_to_binary(Reason)}} end. -rule(get, #{bindings := #{id := Id}}) -> - case emqx_authz:lookup(Id) of +source(get, #{bindings := #{type := Type}}) -> + case emqx_authz:lookup(Type) of {error, Reason} -> {404, #{messgae => atom_to_binary(Reason)}}; - #{type := file} = Rule -> {200, Rule}; - #{config := #{server := Server} = Config} = Rule -> + #{enable := false} = Source -> {200, Source}; + #{type := file} = Source -> {200, Source}; + #{config := #{server := Server, + annotations := #{id := Id} + } = Config} = Source -> case emqx_resource:health_check(Id) of ok -> - {200, Rule#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, - annotations => #{id => Id, - status => healthy}}}; + {200, Source#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, + annotations => #{status => healthy}}}; _ -> - {200, Rule#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, - annotations => #{id => Id, - status => unhealthy}}} + {200, Source#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, + annotations => #{status => unhealthy}}} end; - Rule -> + #{config := #{annotations := #{id := Id}}} = Source -> case emqx_resource:health_check(Id) of ok -> - {200, Rule#{annotations => #{id => Id, - status => healthy}}}; + {200, Source#{annotations => #{status => healthy}}}; _ -> - {200, Rule#{annotations => #{id => Id, - status => unhealthy}}} + {200, Source#{annotations => #{status => unhealthy}}} end end; -rule(put, #{bindings := #{id := RuleId}, body := RawConfig}) -> - case emqx_authz:update({replace_once, RuleId}, RawConfig) of +source(put, #{bindings := #{type := Type}, body := RawConfig}) -> + case emqx_authz:update({replace_once, Type}, RawConfig) of {ok, _} -> {204}; - {error, not_found_rule} -> + {error, not_found_source} -> {404, #{code => <<"NOT_FOUND">>, - messgae => <<"rule ", RuleId/binary, " not found">>}}; + messgae => <<"source ", Type/binary, " not found">>}}; {error, Reason} -> {400, #{code => <<"BAD_REQUEST">>, messgae => atom_to_binary(Reason)}} end; -rule(delete, #{bindings := #{id := RuleId}}) -> - case emqx_authz:update({replace_once, RuleId}, #{}) of +source(delete, #{bindings := #{type := Type}}) -> + case emqx_authz:update({delete_once, Type}, #{}) of {ok, _} -> {204}; {error, Reason} -> {400, #{code => <<"BAD_REQUEST">>, messgae => atom_to_binary(Reason)}} end. -move_rule(post, #{bindings := #{id := RuleId}, body := Body}) -> - #{<<"position">> := Position} = Body, - case emqx_authz:move(RuleId, Position) of +move_source(post, #{bindings := #{type := Type}, body := #{<<"position">> := Position}}) -> + case emqx_authz:move(Type, Position) of {ok, _} -> {204}; - {error, not_found_rule} -> + {error, not_found_source} -> {404, #{code => <<"NOT_FOUND">>, - messgae => <<"rule ", RuleId/binary, " not found">>}}; + messgae => <<"source ", Type/binary, " not found">>}}; {error, Reason} -> {400, #{code => <<"BAD_REQUEST">>, messgae => atom_to_binary(Reason)}} end. + + + diff --git a/apps/emqx_authz/src/emqx_authz_api_schema.erl b/apps/emqx_authz/src/emqx_authz_api_schema.erl index 64ecc58eb..1bc316986 100644 --- a/apps/emqx_authz/src/emqx_authz_api_schema.erl +++ b/apps/emqx_authz/src/emqx_authz_api_schema.erl @@ -34,11 +34,11 @@ definitions() -> } } } - , minirest:ref(<<"rules">>) + , minirest:ref(<<"sources">>) ] }, Rules = #{ - oneOf => [ minirest:ref(<<"simple_rule">>) + oneOf => [ minirest:ref(<<"simple_source">>) % , minirest:ref(<<"connector_redis">>) ] }, @@ -144,9 +144,9 @@ definitions() -> } } }, - [ #{<<"returned_rules">> => RetruenedRules} - , #{<<"rules">> => Rules} - , #{<<"simple_rule">> => SimpleRule} + [ #{<<"returned_sources">> => RetruenedRules} + , #{<<"sources">> => Rules} + , #{<<"simple_source">> => SimpleRule} , #{<<"principal">> => Principal} , #{<<"principal_username">> => PrincipalUsername} , #{<<"principal_clientid">> => PrincipalClientid} diff --git a/apps/emqx_authz/test/emqx_authz_SUITE.erl b/apps/emqx_authz/test/emqx_authz_SUITE.erl index ef7644a65..cee83cd30 100644 --- a/apps/emqx_authz/test/emqx_authz_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_SUITE.erl @@ -61,120 +61,132 @@ init_per_testcase(_, Config) -> Config. -define(SOURCE1, #{<<"type">> => <<"http">>, - <<"config">> => #{ - <<"url">> => <<"https://fake.com:443/">>, - <<"headers">> => #{}, - <<"method">> => <<"get">>, - <<"request_timeout">> => 5000} - }). + <<"enable">> => true, + <<"config">> => #{ + <<"url">> => <<"https://fake.com:443/">>, + <<"headers">> => #{}, + <<"method">> => <<"get">>, + <<"request_timeout">> => 5000} + }). -define(SOURCE2, #{<<"type">> => <<"mongo">>, - <<"config">> => #{ - <<"mongo_type">> => <<"single">>, - <<"server">> => <<"127.0.0.1:27017">>, - <<"pool_size">> => 1, - <<"database">> => <<"mqtt">>, - <<"ssl">> => #{<<"enable">> => false}}, - <<"collection">> => <<"fake">>, - <<"find">> => #{<<"a">> => <<"b">>} - }). + <<"enable">> => true, + <<"config">> => #{ + <<"mongo_type">> => <<"single">>, + <<"server">> => <<"127.0.0.1:27017">>, + <<"pool_size">> => 1, + <<"database">> => <<"mqtt">>, + <<"ssl">> => #{<<"enable">> => false}}, + <<"collection">> => <<"fake">>, + <<"find">> => #{<<"a">> => <<"b">>} + }). -define(SOURCE3, #{<<"type">> => <<"mysql">>, - <<"config">> => #{ - <<"server">> => <<"127.0.0.1:27017">>, - <<"pool_size">> => 1, - <<"database">> => <<"mqtt">>, - <<"username">> => <<"xx">>, - <<"password">> => <<"ee">>, - <<"auto_reconnect">> => true, - <<"ssl">> => #{<<"enable">> => false}}, - <<"sql">> => <<"abcb">> - }). + <<"enable">> => true, + <<"config">> => #{ + <<"server">> => <<"127.0.0.1:27017">>, + <<"pool_size">> => 1, + <<"database">> => <<"mqtt">>, + <<"username">> => <<"xx">>, + <<"password">> => <<"ee">>, + <<"auto_reconnect">> => true, + <<"ssl">> => #{<<"enable">> => false}}, + <<"sql">> => <<"abcb">> + }). -define(SOURCE4, #{<<"type">> => <<"pgsql">>, - <<"config">> => #{ - <<"server">> => <<"127.0.0.1:27017">>, - <<"pool_size">> => 1, - <<"database">> => <<"mqtt">>, - <<"username">> => <<"xx">>, - <<"password">> => <<"ee">>, - <<"auto_reconnect">> => true, - <<"ssl">> => #{<<"enable">> => false}}, - <<"sql">> => <<"abcb">> - }). + <<"enable">> => true, + <<"config">> => #{ + <<"server">> => <<"127.0.0.1:27017">>, + <<"pool_size">> => 1, + <<"database">> => <<"mqtt">>, + <<"username">> => <<"xx">>, + <<"password">> => <<"ee">>, + <<"auto_reconnect">> => true, + <<"ssl">> => #{<<"enable">> => false}}, + <<"sql">> => <<"abcb">> + }). -define(SOURCE5, #{<<"type">> => <<"redis">>, - <<"config">> => #{ - <<"server">> => <<"127.0.0.1:27017">>, - <<"pool_size">> => 1, - <<"database">> => 0, - <<"password">> => <<"ee">>, - <<"auto_reconnect">> => true, - <<"ssl">> => #{<<"enable">> => false}}, - <<"cmd">> => <<"HGETALL mqtt_authz:%u">> - }). + <<"enable">> => true, + <<"config">> => #{ + <<"server">> => <<"127.0.0.1:27017">>, + <<"pool_size">> => 1, + <<"database">> => 0, + <<"password">> => <<"ee">>, + <<"auto_reconnect">> => true, + <<"ssl">> => #{<<"enable">> => false}}, + <<"cmd">> => <<"HGETALL mqtt_authz:%u">> + }). %%------------------------------------------------------------------------------ %% Testcases %%------------------------------------------------------------------------------ t_update_source(_) -> - {ok, _} = emqx_authz:update(replace, [?SOURCE2]), + {ok, _} = emqx_authz:update(replace, [?SOURCE3]), + {ok, _} = emqx_authz:update(head, [?SOURCE2]), {ok, _} = emqx_authz:update(head, [?SOURCE1]), - {ok, _} = emqx_authz:update(tail, [?SOURCE3]), + {ok, _} = emqx_authz:update(tail, [?SOURCE4]), + {ok, _} = emqx_authz:update(tail, [?SOURCE5]), - ?assertMatch([#{type := http}, #{type := mongo}, #{type := mysql}], emqx:get_config([authorization, sources], [])), + ?assertMatch([ #{type := http, enable := true} + , #{type := mongo, enable := true} + , #{type := mysql, enable := true} + , #{type := pgsql, enable := true} + , #{type := redis, enable := true} + ], emqx:get_config([authorization, sources], [])), - [#{annotations := #{id := Id1}, type := http}, - #{annotations := #{id := Id2}, type := mongo}, - #{annotations := #{id := Id3}, type := mysql} - ] = emqx_authz:lookup(), + {ok, _} = emqx_authz:update({replace_once, http}, ?SOURCE1#{<<"enable">> := false}), + {ok, _} = emqx_authz:update({replace_once, mongo}, ?SOURCE2#{<<"enable">> := false}), + {ok, _} = emqx_authz:update({replace_once, mysql}, ?SOURCE3#{<<"enable">> := false}), + {ok, _} = emqx_authz:update({replace_once, pgsql}, ?SOURCE4#{<<"enable">> := false}), + {ok, _} = emqx_authz:update({replace_once, redis}, ?SOURCE5#{<<"enable">> := false}), - {ok, _} = emqx_authz:update({replace_once, Id1}, ?SOURCE5), - {ok, _} = emqx_authz:update({replace_once, Id3}, ?SOURCE4), - ?assertMatch([#{type := redis}, #{type := mongo}, #{type := pgsql}], emqx:get_config([authorization, sources], [])), - - [#{annotations := #{id := Id1}, type := redis}, - #{annotations := #{id := Id2}, type := mongo}, - #{annotations := #{id := Id3}, type := pgsql} - ] = emqx_authz:lookup(), + ?assertMatch([ #{type := http, enable := false} + , #{type := mongo, enable := false} + , #{type := mysql, enable := false} + , #{type := pgsql, enable := false} + , #{type := redis, enable := false} + ], emqx:get_config([authorization, sources], [])), {ok, _} = emqx_authz:update(replace, []). t_move_source(_) -> {ok, _} = emqx_authz:update(replace, [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5]), - [#{annotations := #{id := Id1}}, - #{annotations := #{id := Id2}}, - #{annotations := #{id := Id3}}, - #{annotations := #{id := Id4}}, - #{annotations := #{id := Id5}} - ] = emqx_authz:lookup(), - - {ok, _} = emqx_authz:move(Id4, <<"top">>), - ?assertMatch([#{annotations := #{id := Id4}}, - #{annotations := #{id := Id1}}, - #{annotations := #{id := Id2}}, - #{annotations := #{id := Id3}}, - #{annotations := #{id := Id5}} + ?assertMatch([ #{type := http} + , #{type := mongo} + , #{type := mysql} + , #{type := pgsql} + , #{type := redis} ], emqx_authz:lookup()), - {ok, _} = emqx_authz:move(Id1, <<"bottom">>), - ?assertMatch([#{annotations := #{id := Id4}}, - #{annotations := #{id := Id2}}, - #{annotations := #{id := Id3}}, - #{annotations := #{id := Id5}}, - #{annotations := #{id := Id1}} + {ok, _} = emqx_authz:move(pgsql, <<"top">>), + ?assertMatch([ #{type := pgsql} + , #{type := http} + , #{type := mongo} + , #{type := mysql} + , #{type := redis} ], emqx_authz:lookup()), - {ok, _} = emqx_authz:move(Id3, #{<<"before">> => Id4}), - ?assertMatch([#{annotations := #{id := Id3}}, - #{annotations := #{id := Id4}}, - #{annotations := #{id := Id2}}, - #{annotations := #{id := Id5}}, - #{annotations := #{id := Id1}} + {ok, _} = emqx_authz:move(http, <<"bottom">>), + ?assertMatch([ #{type := pgsql} + , #{type := mongo} + , #{type := mysql} + , #{type := redis} + , #{type := http} ], emqx_authz:lookup()), - {ok, _} = emqx_authz:move(Id2, #{<<"after">> => Id1}), - ?assertMatch([#{annotations := #{id := Id3}}, - #{annotations := #{id := Id4}}, - #{annotations := #{id := Id5}}, - #{annotations := #{id := Id1}}, - #{annotations := #{id := Id2}} + {ok, _} = emqx_authz:move(mysql, #{<<"before">> => pgsql}), + ?assertMatch([ #{type := mysql} + , #{type := pgsql} + , #{type := mongo} + , #{type := redis} + , #{type := http} ], emqx_authz:lookup()), + + {ok, _} = emqx_authz:move(mongo, #{<<"after">> => http}), + ?assertMatch([ #{type := mysql} + , #{type := pgsql} + , #{type := redis} + , #{type := http} + , #{type := mongo} + ], emqx_authz:lookup()), + ok. diff --git a/apps/emqx_authz/test/emqx_authz_api_SUITE.erl b/apps/emqx_authz/test/emqx_authz_api_SUITE.erl index 8d92413b3..c8901af77 100644 --- a/apps/emqx_authz/test/emqx_authz_api_SUITE.erl +++ b/apps/emqx_authz/test/emqx_authz_api_SUITE.erl @@ -38,54 +38,59 @@ -define(BASE_PATH, "api"). -define(SOURCE1, #{<<"type">> => <<"http">>, - <<"config">> => #{ - <<"url">> => <<"https://fake.com:443/">>, - <<"headers">> => #{}, - <<"method">> => <<"get">>, - <<"request_timeout">> => 5000} - }). + <<"enable">> => true, + <<"config">> => #{ + <<"url">> => <<"https://fake.com:443/">>, + <<"headers">> => #{}, + <<"method">> => <<"get">>, + <<"request_timeout">> => 5000} + }). -define(SOURCE2, #{<<"type">> => <<"mongo">>, - <<"config">> => #{ - <<"mongo_type">> => <<"single">>, - <<"server">> => <<"127.0.0.1:27017">>, - <<"pool_size">> => 1, - <<"database">> => <<"mqtt">>, - <<"ssl">> => #{<<"enable">> => false}}, - <<"collection">> => <<"fake">>, - <<"find">> => #{<<"a">> => <<"b">>} - }). + <<"enable">> => true, + <<"config">> => #{ + <<"mongo_type">> => <<"single">>, + <<"server">> => <<"127.0.0.1:27017">>, + <<"pool_size">> => 1, + <<"database">> => <<"mqtt">>, + <<"ssl">> => #{<<"enable">> => false}}, + <<"collection">> => <<"fake">>, + <<"find">> => #{<<"a">> => <<"b">>} + }). -define(SOURCE3, #{<<"type">> => <<"mysql">>, - <<"config">> => #{ - <<"server">> => <<"127.0.0.1:27017">>, - <<"pool_size">> => 1, - <<"database">> => <<"mqtt">>, - <<"username">> => <<"xx">>, - <<"password">> => <<"ee">>, - <<"auto_reconnect">> => true, - <<"ssl">> => #{<<"enable">> => false}}, - <<"sql">> => <<"abcb">> - }). + <<"enable">> => true, + <<"config">> => #{ + <<"server">> => <<"127.0.0.1:27017">>, + <<"pool_size">> => 1, + <<"database">> => <<"mqtt">>, + <<"username">> => <<"xx">>, + <<"password">> => <<"ee">>, + <<"auto_reconnect">> => true, + <<"ssl">> => #{<<"enable">> => false}}, + <<"sql">> => <<"abcb">> + }). -define(SOURCE4, #{<<"type">> => <<"pgsql">>, - <<"config">> => #{ - <<"server">> => <<"127.0.0.1:27017">>, - <<"pool_size">> => 1, - <<"database">> => <<"mqtt">>, - <<"username">> => <<"xx">>, - <<"password">> => <<"ee">>, - <<"auto_reconnect">> => true, - <<"ssl">> => #{<<"enable">> => false}}, - <<"sql">> => <<"abcb">> - }). + <<"enable">> => true, + <<"config">> => #{ + <<"server">> => <<"127.0.0.1:27017">>, + <<"pool_size">> => 1, + <<"database">> => <<"mqtt">>, + <<"username">> => <<"xx">>, + <<"password">> => <<"ee">>, + <<"auto_reconnect">> => true, + <<"ssl">> => #{<<"enable">> => false}}, + <<"sql">> => <<"abcb">> + }). -define(SOURCE5, #{<<"type">> => <<"redis">>, - <<"config">> => #{ - <<"server">> => <<"127.0.0.1:27017">>, - <<"pool_size">> => 1, - <<"database">> => 0, - <<"password">> => <<"ee">>, - <<"auto_reconnect">> => true, - <<"ssl">> => #{<<"enable">> => false}}, - <<"cmd">> => <<"HGETALL mqtt_authz:%u">> - }). + <<"enable">> => true, + <<"config">> => #{ + <<"server">> => <<"127.0.0.1:27017">>, + <<"pool_size">> => 1, + <<"database">> => 0, + <<"password">> => <<"ee">>, + <<"auto_reconnect">> => true, + <<"ssl">> => #{<<"enable">> => false}}, + <<"cmd">> => <<"HGETALL mqtt_authz:%u">> + }). all() -> emqx_ct:all(?MODULE). @@ -134,7 +139,7 @@ set_special_configs(emqx_dashboard) -> emqx_config:put([emqx_dashboard], Config), ok; set_special_configs(emqx_authz) -> - emqx_config:put([authorization], #{rules => []}), + emqx_config:put([authorization], #{sources => []}), ok; set_special_configs(_App) -> ok. @@ -145,89 +150,86 @@ set_special_configs(_App) -> t_api(_) -> {ok, 200, Result1} = request(get, uri(["authorization"]), []), - ?assertEqual([], get_rules(Result1)), + ?assertEqual([], get_sources(Result1)), lists:foreach(fun(_) -> {ok, 204, _} = request(post, uri(["authorization"]), ?SOURCE1) end, lists:seq(1, 20)), {ok, 200, Result2} = request(get, uri(["authorization"]), []), - ?assertEqual(20, length(get_rules(Result2))), + ?assertEqual(20, length(get_sources(Result2))), lists:foreach(fun(Page) -> Query = "?page=" ++ integer_to_list(Page) ++ "&&limit=10", Url = uri(["authorization" ++ Query]), {ok, 200, Result} = request(get, Url, []), - ?assertEqual(10, length(get_rules(Result))) + ?assertEqual(10, length(get_sources(Result))) end, lists:seq(1, 2)), {ok, 204, _} = request(put, uri(["authorization"]), [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4]), {ok, 200, Result3} = request(get, uri(["authorization"]), []), - Rules = get_rules(Result3), - ?assertEqual(4, length(Rules)), + Sources = get_sources(Result3), ?assertMatch([ #{<<"type">> := <<"http">>} , #{<<"type">> := <<"mongo">>} , #{<<"type">> := <<"mysql">>} , #{<<"type">> := <<"pgsql">>} - ], Rules), + ], Sources), - #{<<"annotations">> := #{<<"id">> := Id}} = lists:nth(2, Rules), + {ok, 204, _} = request(put, uri(["authorization", "http"]), ?SOURCE1#{<<"enable">> := false}), - {ok, 204, _} = request(put, uri(["authorization", binary_to_list(Id)]), ?SOURCE5), + {ok, 200, Result4} = request(get, uri(["authorization", "http"]), []), + ?assertMatch(#{<<"type">> := <<"http">>, <<"enable">> := false}, jsx:decode(Result4)), - {ok, 200, Result4} = request(get, uri(["authorization", binary_to_list(Id)]), []), - ?assertMatch(#{<<"type">> := <<"redis">>}, jsx:decode(Result4)), - - lists:foreach(fun(#{<<"annotations">> := #{<<"id">> := Id0}}) -> - {ok, 204, _} = request(delete, uri(["authorization", binary_to_list(Id0)]), []) - end, Rules), + lists:foreach(fun(#{<<"type">> := Type}) -> + {ok, 204, _} = request(delete, uri(["authorization", binary_to_list(Type)]), []) + end, Sources), {ok, 200, Result5} = request(get, uri(["authorization"]), []), - ?assertEqual([], get_rules(Result5)), + ?assertEqual([], get_sources(Result5)), ok. -t_move_rule(_) -> +t_move_source(_) -> {ok, _} = emqx_authz:update(replace, [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5]), - [#{annotations := #{id := Id1}}, - #{annotations := #{id := Id2}}, - #{annotations := #{id := Id3}}, - #{annotations := #{id := Id4}}, - #{annotations := #{id := Id5}} - ] = emqx_authz:lookup(), + ?assertMatch([ #{type := http} + , #{type := mongo} + , #{type := mysql} + , #{type := pgsql} + , #{type := redis} + ], emqx_authz:lookup()), - {ok, 204, _} = request(post, uri(["authorization", Id4, "move"]), + {ok, 204, _} = request(post, uri(["authorization", "pgsql", "move"]), #{<<"position">> => <<"top">>}), - ?assertMatch([#{annotations := #{id := Id4}}, - #{annotations := #{id := Id1}}, - #{annotations := #{id := Id2}}, - #{annotations := #{id := Id3}}, - #{annotations := #{id := Id5}} + ?assertMatch([ #{type := pgsql} + , #{type := http} + , #{type := mongo} + , #{type := mysql} + , #{type := redis} ], emqx_authz:lookup()), - {ok, 204, _} = request(post, uri(["authorization", Id1, "move"]), + {ok, 204, _} = request(post, uri(["authorization", "http", "move"]), #{<<"position">> => <<"bottom">>}), - ?assertMatch([#{annotations := #{id := Id4}}, - #{annotations := #{id := Id2}}, - #{annotations := #{id := Id3}}, - #{annotations := #{id := Id5}}, - #{annotations := #{id := Id1}} + ?assertMatch([ #{type := pgsql} + , #{type := mongo} + , #{type := mysql} + , #{type := redis} + , #{type := http} ], emqx_authz:lookup()), - {ok, 204, _} = request(post, uri(["authorization", Id3, "move"]), - #{<<"position">> => #{<<"before">> => Id4}}), - ?assertMatch([#{annotations := #{id := Id3}}, - #{annotations := #{id := Id4}}, - #{annotations := #{id := Id2}}, - #{annotations := #{id := Id5}}, - #{annotations := #{id := Id1}} + {ok, 204, _} = request(post, uri(["authorization", "mysql", "move"]), + #{<<"position">> => #{<<"before">> => <<"pgsql">>}}), + ?assertMatch([ #{type := mysql} + , #{type := pgsql} + , #{type := mongo} + , #{type := redis} + , #{type := http} ], emqx_authz:lookup()), - {ok, 204, _} = request(post, uri(["authorization", Id2, "move"]), - #{<<"position">> => #{<<"after">> => Id1}}), - ?assertMatch([#{annotations := #{id := Id3}}, - #{annotations := #{id := Id4}}, - #{annotations := #{id := Id5}}, - #{annotations := #{id := Id1}}, - #{annotations := #{id := Id2}} + {ok, 204, _} = request(post, uri(["authorization", "mongo", "move"]), + #{<<"position">> => #{<<"after">> => <<"http">>}}), + ?assertMatch([ #{type := mysql} + , #{type := pgsql} + , #{type := redis} + , #{type := http} + , #{type := mongo} ], emqx_authz:lookup()), ok. @@ -256,8 +258,8 @@ uri(Parts) when is_list(Parts) -> NParts = [E || E <- Parts], ?HOST ++ filename:join([?BASE_PATH, ?API_VERSION | NParts]). -get_rules(Result) -> - maps:get(<<"rules">>, jsx:decode(Result), []). +get_sources(Result) -> + maps:get(<<"sources">>, jsx:decode(Result), []). auth_header_() -> Username = <<"admin">>,