refactor: refactor emqx_authz

Signed-off-by: zhanghongtong <rory-z@outlook.com>
This commit is contained in:
zhanghongtong 2021-08-30 17:42:56 +08:00 committed by Rory Z
parent caef8cb381
commit 6b313a60d4
5 changed files with 415 additions and 380 deletions

View File

@ -51,33 +51,41 @@ init() ->
lookup() -> lookup() ->
{_M, _F, [A]}= find_action_in_hooks(), {_M, _F, [A]}= find_action_in_hooks(),
A. A.
lookup(Id) -> lookup(Type) ->
try find_source_by_id(Id, lookup()) of try find_source_by_type(atom(Type), lookup()) of
{_, Source} -> Source {_, Source} -> Source
catch catch
error:Reason -> {error, Reason} error:Reason -> {error, Reason}
end. end.
move(Id, Position) -> move(Type, #{<<"before">> := Before}) ->
emqx:update_config(?CONF_KEY_PATH, {move, Id, Position}). 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) -> update(Cmd, Sources) ->
emqx:update_config(?CONF_KEY_PATH, {Cmd, Sources}). emqx:update_config(?CONF_KEY_PATH, {Cmd, Sources}).
pre_config_update({move, Id, <<"top">>}, Conf) when is_list(Conf) -> pre_config_update({move, Type, <<"top">>}, Conf) when is_list(Conf) ->
{Index, _} = find_source_by_id(Id), {Index, _} = find_source_by_type(Type),
{List1, List2} = lists:split(Index, Conf), {List1, List2} = lists:split(Index, Conf),
{ok, [lists:nth(Index, Conf)] ++ lists:droplast(List1) ++ List2}; {ok, [lists:nth(Index, Conf)] ++ lists:droplast(List1) ++ List2};
pre_config_update({move, Id, <<"bottom">>}, Conf) when is_list(Conf) -> pre_config_update({move, Type, <<"bottom">>}, Conf) when is_list(Conf) ->
{Index, _} = find_source_by_id(Id), {Index, _} = find_source_by_type(Type),
{List1, List2} = lists:split(Index, Conf), {List1, List2} = lists:split(Index, Conf),
{ok, lists:droplast(List1) ++ List2 ++ [lists:nth(Index, Conf)]}; {ok, lists:droplast(List1) ++ List2 ++ [lists:nth(Index, Conf)]};
pre_config_update({move, Id, #{<<"before">> := BeforeId}}, Conf) when is_list(Conf) -> pre_config_update({move, Type, #{<<"before">> := Before}}, Conf) when is_list(Conf) ->
{Index1, _} = find_source_by_id(Id), {Index1, _} = find_source_by_type(Type),
Conf1 = lists:nth(Index1, Conf), Conf1 = lists:nth(Index1, Conf),
{Index2, _} = find_source_by_id(BeforeId), {Index2, _} = find_source_by_type(Before),
Conf2 = lists:nth(Index2, Conf), Conf2 = lists:nth(Index2, Conf),
{List1, List2} = lists:split(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] ++ [Conf1] ++ [Conf2]
++ lists:delete(Conf1, List2)}; ++ lists:delete(Conf1, List2)};
pre_config_update({move, Id, #{<<"after">> := AfterId}}, Conf) when is_list(Conf) -> pre_config_update({move, Type, #{<<"after">> := After}}, Conf) when is_list(Conf) ->
{Index1, _} = find_source_by_id(Id), {Index1, _} = find_source_by_type(Type),
Conf1 = lists:nth(Index1, Conf), Conf1 = lists:nth(Index1, Conf),
{Index2, _} = find_source_by_id(AfterId), {Index2, _} = find_source_by_type(After),
{List1, List2} = lists:split(Index2, Conf), {List1, List2} = lists:split(Index2, Conf),
{ok, lists:delete(Conf1, List1) {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}; {ok, Sources ++ Conf};
pre_config_update({tail, Sources}, Conf) when is_list(Sources), is_list(Conf) -> pre_config_update({tail, Sources}, Conf) when is_list(Sources), is_list(Conf) ->
{ok, Conf ++ Sources}; {ok, Conf ++ Sources};
pre_config_update({{replace_once, Id}, Source}, Conf) when is_map(Source), is_list(Conf) -> pre_config_update({{replace_once, Type}, Source}, Conf) when is_map(Source), is_list(Conf) ->
{Index, _} = find_source_by_id(Id), {Index, _} = find_source_by_type(Type),
{List1, List2} = lists:split(Index, Conf), {List1, List2} = lists:split(Index, Conf),
{ok, lists:droplast(List1) ++ [Source] ++ List2}; {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)-> pre_config_update({_, Sources}, _Conf) when is_list(Sources)->
%% overwrite the entire config! %% overwrite the entire config!
{ok, Sources}. {ok, Sources}.
post_config_update(_, undefined, _Conf, _AppEnvs) -> post_config_update(_, undefined, _Conf, _AppEnvs) ->
ok; ok;
post_config_update({move, Id, <<"top">>}, _NewSources, _OldSources, _AppEnvs) -> post_config_update({move, Type, <<"top">>}, _NewSources, _OldSources, _AppEnvs) ->
InitedSources = lookup(), InitedSources = lookup(),
{Index, Source} = find_source_by_id(Id, InitedSources), {Index, Source} = find_source_by_type(Type, InitedSources),
{Sources1, Sources2 } = lists:split(Index, InitedSources), {Sources1, Sources2 } = lists:split(Index, InitedSources),
Sources3 = [Source] ++ lists:droplast(Sources1) ++ Sources2, Sources3 = [Source] ++ lists:droplast(Sources1) ++ Sources2,
ok = emqx_hooks:put('client.authorize', {?MODULE, authorize, [Sources3]}, -1), ok = emqx_hooks:put('client.authorize', {?MODULE, authorize, [Sources3]}, -1),
ok = emqx_authz_cache:drain_cache(); 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(), InitedSources = lookup(),
{Index, Source} = find_source_by_id(Id, InitedSources), {Index, Source} = find_source_by_type(Type, InitedSources),
{Sources1, Sources2 } = lists:split(Index, InitedSources), {Sources1, Sources2 } = lists:split(Index, InitedSources),
Sources3 = lists:droplast(Sources1) ++ Sources2 ++ [Source], Sources3 = lists:droplast(Sources1) ++ Sources2 ++ [Source],
ok = emqx_hooks:put('client.authorize', {?MODULE, authorize, [Sources3]}, -1), ok = emqx_hooks:put('client.authorize', {?MODULE, authorize, [Sources3]}, -1),
ok = emqx_authz_cache:drain_cache(); 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(), InitedSources = lookup(),
{_, Source0} = find_source_by_id(Id, InitedSources), {_, Source0} = find_source_by_type(Type, InitedSources),
{Index, Source1} = find_source_by_id(BeforeId, InitedSources), {Index, Source1} = find_source_by_type(Before, InitedSources),
{Sources1, Sources2} = lists:split(Index, InitedSources), {Sources1, Sources2} = lists:split(Index, InitedSources),
Sources3 = lists:delete(Source0, lists:droplast(Sources1)) Sources3 = lists:delete(Source0, lists:droplast(Sources1))
++ [Source0] ++ [Source1] ++ [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_hooks:put('client.authorize', {?MODULE, authorize, [Sources3]}, -1),
ok = emqx_authz_cache:drain_cache(); 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(), InitedSources = lookup(),
{_, Source} = find_source_by_id(Id, InitedSources), {_, Source} = find_source_by_type(Type, InitedSources),
{Index, _} = find_source_by_id(AfterId, InitedSources), {Index, _} = find_source_by_type(After, InitedSources),
{Sources1, Sources2} = lists:split(Index, InitedSources), {Sources1, Sources2} = lists:split(Index, InitedSources),
Sources3 = lists:delete(Source, Sources1) Sources3 = lists:delete(Source, Sources1)
++ [Source] ++ [Source]
@ -155,9 +166,9 @@ post_config_update({tail, Sources}, _NewSources, _OldConf, _AppEnvs) ->
emqx_hooks:put('client.authorize', {?MODULE, authorize, [lookup() ++ InitedSources]}, -1), emqx_hooks:put('client.authorize', {?MODULE, authorize, [lookup() ++ InitedSources]}, -1),
ok = emqx_authz_cache:drain_cache(); 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(), 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 case maps:get(type, OldSource, undefined) of
undefined -> ok; undefined -> ok;
_ -> _ ->
@ -165,10 +176,19 @@ post_config_update({{replace_once, Id}, Source}, _NewSources, _OldConf, _AppEnvs
ok = emqx_resource:remove(Id) ok = emqx_resource:remove(Id)
end, end,
{OldSources1, OldSources2 } = lists:split(Index, OldInitedSources), {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_hooks:put('client.authorize', {?MODULE, authorize, [lists:droplast(OldSources1) ++ InitedSources ++ OldSources2]}, -1),
ok = emqx_authz_cache:drain_cache(); 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) -> post_config_update(_, NewSources, _OldConf, _AppEnvs) ->
%% overwrite the entire config! %% overwrite the entire config!
OldInitedSources = lookup(), OldInitedSources = lookup(),
@ -181,48 +201,9 @@ post_config_update(_, NewSources, _OldConf, _AppEnvs) ->
ok = emqx_authz_cache:drain_cache(). 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, init_source(#{enable := true,
type := file, type := file,
path := Path path := Path
@ -240,10 +221,7 @@ init_source(#{enable := true,
?LOG(alert, "Failed to read ~s: ~p", [Path, Reason]), ?LOG(alert, "Failed to read ~s: ~p", [Path, Reason]),
error(Reason) error(Reason)
end, end,
Source#{annotations => Source#{annotations => #{rules => Rules}};
#{id => gen_id(file),
rules => Rules
}};
init_source(#{enable := true, init_source(#{enable := true,
type := http, type := http,
config := #{url := Url} = Config config := #{url := Url} = Config
@ -251,9 +229,7 @@ init_source(#{enable := true,
NConfig = maps:merge(Config, #{base_url => maps:remove(query, Url)}), NConfig = maps:merge(Config, #{base_url => maps:remove(query, Url)}),
case create_resource(Source#{config := NConfig}) of case create_resource(Source#{config := NConfig}) of
{error, Reason} -> error({load_config_error, Reason}); {error, Reason} -> error({load_config_error, Reason});
Id -> Source#{annotations => Id -> Source#{annotations => #{id => Id}}
#{id => Id}
}
end; end;
init_source(#{enable := true, init_source(#{enable := true,
type := DB type := DB
@ -261,9 +237,7 @@ init_source(#{enable := true,
DB =:= mongo -> DB =:= mongo ->
case create_resource(Source) of case create_resource(Source) of
{error, Reason} -> error({load_config_error, Reason}); {error, Reason} -> error({load_config_error, Reason});
Id -> Source#{annotations => Id -> Source#{annotations => #{id => Id}}
#{id => Id}
}
end; end;
init_source(#{enable := true, init_source(#{enable := true,
type := DB, type := DB,
@ -323,8 +297,58 @@ do_authorize(Client, PubSub, Topic,
Matched -> Matched Matched -> Matched
end. 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) -> authz_module(Type) ->
list_to_existing_atom("emqx_authz_" ++ atom_to_list(Type)). list_to_existing_atom("emqx_authz_" ++ atom_to_list(Type)).
connector_module(Type) -> connector_module(Type) ->
list_to_existing_atom("emqx_connector_" ++ atom_to_list(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.

View File

@ -30,7 +30,7 @@
-define(EXAMPLE_RETURNED_RULES, -define(EXAMPLE_RETURNED_RULES,
#{rules => [?EXAMPLE_RETURNED_RULE1 #{sources => [?EXAMPLE_RETURNED_RULE1
] ]
}). }).
@ -40,23 +40,23 @@
topics => [<<"#">>]}). topics => [<<"#">>]}).
-export([ api_spec/0 -export([ api_spec/0
, rules/2 , sources/2
, rule/2 , source/2
, move_rule/2 , move_source/2
]). ]).
api_spec() -> api_spec() ->
{[ rules_api() {[ sources_api()
, rule_api() , source_api()
, move_rule_api() , move_source_api()
], definitions()}. ], definitions()}.
definitions() -> emqx_authz_api_schema:definitions(). definitions() -> emqx_authz_api_schema:definitions().
rules_api() -> sources_api() ->
Metadata = #{ Metadata = #{
get => #{ get => #{
description => "List authorization rules", description => "List authorization sources",
parameters => [ parameters => [
#{ #{
name => page, name => page,
@ -82,16 +82,16 @@ rules_api() ->
'application/json' => #{ 'application/json' => #{
schema => #{ schema => #{
type => object, type => object,
required => [rules], required => [sources],
properties => #{rules => #{ properties => #{sources => #{
type => array, type => array,
items => minirest:ref(<<"returned_rules">>) items => minirest:ref(<<"returned_sources">>)
} }
} }
}, },
examples => #{ examples => #{
rules => #{ sources => #{
summary => <<"Rules">>, summary => <<"Sources">>,
value => jsx:encode(?EXAMPLE_RETURNED_RULES) value => jsx:encode(?EXAMPLE_RETURNED_RULES)
} }
} }
@ -101,14 +101,14 @@ rules_api() ->
} }
}, },
post => #{ post => #{
description => "Add new rule", description => "Add new source",
requestBody => #{ requestBody => #{
content => #{ content => #{
'application/json' => #{ 'application/json' => #{
schema => minirest:ref(<<"rules">>), schema => minirest:ref(<<"sources">>),
examples => #{ examples => #{
simple_rule => #{ simple_source => #{
summary => <<"Rules">>, summary => <<"Sources">>,
value => jsx:encode(?EXAMPLE_RULE1) value => jsx:encode(?EXAMPLE_RULE1)
} }
} }
@ -138,17 +138,17 @@ rules_api() ->
}, },
put => #{ put => #{
description => "Update all rules", description => "Update all sources",
requestBody => #{ requestBody => #{
content => #{ content => #{
'application/json' => #{ 'application/json' => #{
schema => #{ schema => #{
type => array, type => array,
items => minirest:ref(<<"returned_rules">>) items => minirest:ref(<<"returned_sources">>)
}, },
examples => #{ examples => #{
rules => #{ sources => #{
summary => <<"Rules">>, summary => <<"Sources">>,
value => jsx:encode([?EXAMPLE_RULE1]) value => jsx:encode([?EXAMPLE_RULE1])
} }
} }
@ -177,15 +177,15 @@ rules_api() ->
} }
} }
}, },
{"/authorization", Metadata, rules}. {"/authorization", Metadata, sources}.
rule_api() -> source_api() ->
Metadata = #{ Metadata = #{
get => #{ get => #{
description => "List authorization rules", description => "List authorization sources",
parameters => [ parameters => [
#{ #{
name => id, name => type,
in => path, in => path,
schema => #{ schema => #{
type => string type => string
@ -198,10 +198,10 @@ rule_api() ->
description => <<"OK">>, description => <<"OK">>,
content => #{ content => #{
'application/json' => #{ 'application/json' => #{
schema => minirest:ref(<<"returned_rules">>), schema => minirest:ref(<<"returned_sources">>),
examples => #{ examples => #{
rules => #{ sources => #{
summary => <<"Rules">>, summary => <<"Sources">>,
value => jsx:encode(?EXAMPLE_RETURNED_RULE1) value => jsx:encode(?EXAMPLE_RETURNED_RULE1)
} }
} }
@ -218,7 +218,7 @@ rule_api() ->
summary => <<"Not Found">>, summary => <<"Not Found">>,
value => #{ value => #{
code => <<"NOT_FOUND">>, code => <<"NOT_FOUND">>,
message => <<"rule xxx not found">> message => <<"source xxx not found">>
} }
} }
} }
@ -228,10 +228,10 @@ rule_api() ->
} }
}, },
put => #{ put => #{
description => "Update rule", description => "Update source",
parameters => [ parameters => [
#{ #{
name => id, name => type,
in => path, in => path,
schema => #{ schema => #{
type => string type => string
@ -242,10 +242,10 @@ rule_api() ->
requestBody => #{ requestBody => #{
content => #{ content => #{
'application/json' => #{ 'application/json' => #{
schema => minirest:ref(<<"rules">>), schema => minirest:ref(<<"sources">>),
examples => #{ examples => #{
simple_rule => #{ simple_source => #{
summary => <<"Rules">>, summary => <<"Sources">>,
value => jsx:encode(?EXAMPLE_RULE1) value => jsx:encode(?EXAMPLE_RULE1)
} }
} }
@ -264,7 +264,7 @@ rule_api() ->
summary => <<"Not Found">>, summary => <<"Not Found">>,
value => #{ value => #{
code => <<"NOT_FOUND">>, code => <<"NOT_FOUND">>,
message => <<"rule xxx not found">> message => <<"source xxx not found">>
} }
} }
} }
@ -291,7 +291,7 @@ rule_api() ->
} }
}, },
delete => #{ delete => #{
description => "Delete rule", description => "Delete source",
parameters => [ parameters => [
#{ #{
name => id, name => id,
@ -324,15 +324,15 @@ rule_api() ->
} }
} }
}, },
{"/authorization/:id", Metadata, rule}. {"/authorization/:type", Metadata, source}.
move_rule_api() -> move_source_api() ->
Metadata = #{ Metadata = #{
post => #{ post => #{
description => "Change the order of rules", description => "Change the order of sources",
parameters => [ parameters => [
#{ #{
name => id, name => type,
in => path, in => path,
schema => #{ schema => #{
type => string type => string
@ -381,15 +381,13 @@ move_rule_api() ->
}, },
<<"404">> => #{ <<"404">> => #{
description => <<"Bad Request">>, description => <<"Bad Request">>,
content => #{ content => #{ 'application/json' => #{ schema => minirest:ref(<<"error">>),
'application/json' => #{
schema => minirest:ref(<<"error">>),
examples => #{ examples => #{
example1 => #{ example1 => #{
summary => <<"Not Found">>, summary => <<"Not Found">>,
value => #{ value => #{
code => <<"NOT_FOUND">>, 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}) -> sources(get, #{query_string := Query}) ->
Rules = lists:foldl(fun (#{type := _Type, enable := true, config := #{server := Server} = Config, annotations := #{id := Id}} = Rule, AccIn) -> Sources = lists:foldl(fun (#{type := _Type, enable := true, config := #{server := Server} = Config, annotations := #{id := Id}} = Source, AccIn) ->
NRule = case emqx_resource:health_check(Id) of NSource = case emqx_resource:health_check(Id) of
ok -> ok ->
Rule#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, Source#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)},
annotations => #{id => Id, annotations => #{id => Id,
status => healthy}}; status => healthy}};
_ -> _ ->
Rule#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, Source#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)},
annotations => #{id => Id, annotations => #{id => Id,
status => unhealthy}} status => unhealthy}}
end, end,
lists:append(AccIn, [NRule]); lists:append(AccIn, [NSource]);
(#{type := _Type, enable := true, annotations := #{id := Id}} = Rule, AccIn) -> (#{type := _Type, enable := true, annotations := #{id := Id}} = Source, AccIn) ->
NRule = case emqx_resource:health_check(Id) of NSource = case emqx_resource:health_check(Id) of
ok -> ok ->
Rule#{annotations => #{id => Id, Source#{annotations => #{status => healthy}};
status => healthy}};
_ -> _ ->
Rule#{annotations => #{id => Id, Source#{annotations => #{status => unhealthy}}
status => unhealthy}}
end, end,
lists:append(AccIn, [NRule]); lists:append(AccIn, [NSource]);
(Rule, AccIn) -> (Source, AccIn) ->
lists:append(AccIn, [Rule]) lists:append(AccIn, [Source])
end, [], emqx_authz:lookup()), end, [], emqx_authz:lookup()),
case maps:is_key(<<"page">>, Query) andalso maps:is_key(<<"limit">>, Query) of case maps:is_key(<<"page">>, Query) andalso maps:is_key(<<"limit">>, Query) of
true -> true ->
Page = maps:get(<<"page">>, Query), Page = maps:get(<<"page">>, Query),
Limit = maps:get(<<"limit">>, Query), Limit = maps:get(<<"limit">>, Query),
Index = (binary_to_integer(Page) - 1) * binary_to_integer(Limit), Index = (binary_to_integer(Page) - 1) * binary_to_integer(Limit),
{_, Rules1} = lists:split(Index, Rules), {_, Sources1} = lists:split(Index, Sources),
case binary_to_integer(Limit) < length(Rules1) of case binary_to_integer(Limit) < length(Sources1) of
true -> true ->
{Rules2, _} = lists:split(binary_to_integer(Limit), Rules1), {Sources2, _} = lists:split(binary_to_integer(Limit), Sources1),
{200, #{rules => Rules2}}; {200, #{sources => Sources2}};
false -> {200, #{rules => Rules1}} false -> {200, #{sources => Sources1}}
end; end;
false -> {200, #{rules => Rules}} false -> {200, #{sources => Sources}}
end; end;
rules(post, #{body := RawConfig}) -> sources(post, #{body := RawConfig}) ->
case emqx_authz:update(head, [RawConfig]) of case emqx_authz:update(head, [RawConfig]) of
{ok, _} -> {204}; {ok, _} -> {204};
{error, Reason} -> {error, Reason} ->
{400, #{code => <<"BAD_REQUEST">>, {400, #{code => <<"BAD_REQUEST">>,
messgae => atom_to_binary(Reason)}} messgae => atom_to_binary(Reason)}}
end; end;
rules(put, #{body := RawConfig}) -> sources(put, #{body := RawConfig}) ->
case emqx_authz:update(replace, RawConfig) of case emqx_authz:update(replace, RawConfig) of
{ok, _} -> {204}; {ok, _} -> {204};
{error, Reason} -> {error, Reason} ->
@ -473,56 +469,57 @@ rules(put, #{body := RawConfig}) ->
messgae => atom_to_binary(Reason)}} messgae => atom_to_binary(Reason)}}
end. end.
rule(get, #{bindings := #{id := Id}}) -> source(get, #{bindings := #{type := Type}}) ->
case emqx_authz:lookup(Id) of case emqx_authz:lookup(Type) of
{error, Reason} -> {404, #{messgae => atom_to_binary(Reason)}}; {error, Reason} -> {404, #{messgae => atom_to_binary(Reason)}};
#{type := file} = Rule -> {200, Rule}; #{enable := false} = Source -> {200, Source};
#{config := #{server := Server} = Config} = Rule -> #{type := file} = Source -> {200, Source};
#{config := #{server := Server,
annotations := #{id := Id}
} = Config} = Source ->
case emqx_resource:health_check(Id) of case emqx_resource:health_check(Id) of
ok -> ok ->
{200, Rule#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, {200, Source#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)},
annotations => #{id => Id, annotations => #{status => healthy}}};
status => healthy}}};
_ -> _ ->
{200, Rule#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)}, {200, Source#{config => Config#{server => emqx_connector_schema_lib:ip_port_to_string(Server)},
annotations => #{id => Id, annotations => #{status => unhealthy}}}
status => unhealthy}}}
end; end;
Rule -> #{config := #{annotations := #{id := Id}}} = Source ->
case emqx_resource:health_check(Id) of case emqx_resource:health_check(Id) of
ok -> ok ->
{200, Rule#{annotations => #{id => Id, {200, Source#{annotations => #{status => healthy}}};
status => healthy}}};
_ -> _ ->
{200, Rule#{annotations => #{id => Id, {200, Source#{annotations => #{status => unhealthy}}}
status => unhealthy}}}
end end
end; end;
rule(put, #{bindings := #{id := RuleId}, body := RawConfig}) -> source(put, #{bindings := #{type := Type}, body := RawConfig}) ->
case emqx_authz:update({replace_once, RuleId}, RawConfig) of case emqx_authz:update({replace_once, Type}, RawConfig) of
{ok, _} -> {204}; {ok, _} -> {204};
{error, not_found_rule} -> {error, not_found_source} ->
{404, #{code => <<"NOT_FOUND">>, {404, #{code => <<"NOT_FOUND">>,
messgae => <<"rule ", RuleId/binary, " not found">>}}; messgae => <<"source ", Type/binary, " not found">>}};
{error, Reason} -> {error, Reason} ->
{400, #{code => <<"BAD_REQUEST">>, {400, #{code => <<"BAD_REQUEST">>,
messgae => atom_to_binary(Reason)}} messgae => atom_to_binary(Reason)}}
end; end;
rule(delete, #{bindings := #{id := RuleId}}) -> source(delete, #{bindings := #{type := Type}}) ->
case emqx_authz:update({replace_once, RuleId}, #{}) of case emqx_authz:update({delete_once, Type}, #{}) of
{ok, _} -> {204}; {ok, _} -> {204};
{error, Reason} -> {error, Reason} ->
{400, #{code => <<"BAD_REQUEST">>, {400, #{code => <<"BAD_REQUEST">>,
messgae => atom_to_binary(Reason)}} messgae => atom_to_binary(Reason)}}
end. end.
move_rule(post, #{bindings := #{id := RuleId}, body := Body}) -> move_source(post, #{bindings := #{type := Type}, body := #{<<"position">> := Position}}) ->
#{<<"position">> := Position} = Body, case emqx_authz:move(Type, Position) of
case emqx_authz:move(RuleId, Position) of
{ok, _} -> {204}; {ok, _} -> {204};
{error, not_found_rule} -> {error, not_found_source} ->
{404, #{code => <<"NOT_FOUND">>, {404, #{code => <<"NOT_FOUND">>,
messgae => <<"rule ", RuleId/binary, " not found">>}}; messgae => <<"source ", Type/binary, " not found">>}};
{error, Reason} -> {error, Reason} ->
{400, #{code => <<"BAD_REQUEST">>, {400, #{code => <<"BAD_REQUEST">>,
messgae => atom_to_binary(Reason)}} messgae => atom_to_binary(Reason)}}
end. end.

View File

@ -34,11 +34,11 @@ definitions() ->
} }
} }
} }
, minirest:ref(<<"rules">>) , minirest:ref(<<"sources">>)
] ]
}, },
Rules = #{ Rules = #{
oneOf => [ minirest:ref(<<"simple_rule">>) oneOf => [ minirest:ref(<<"simple_source">>)
% , minirest:ref(<<"connector_redis">>) % , minirest:ref(<<"connector_redis">>)
] ]
}, },
@ -144,9 +144,9 @@ definitions() ->
} }
} }
}, },
[ #{<<"returned_rules">> => RetruenedRules} [ #{<<"returned_sources">> => RetruenedRules}
, #{<<"rules">> => Rules} , #{<<"sources">> => Rules}
, #{<<"simple_rule">> => SimpleRule} , #{<<"simple_source">> => SimpleRule}
, #{<<"principal">> => Principal} , #{<<"principal">> => Principal}
, #{<<"principal_username">> => PrincipalUsername} , #{<<"principal_username">> => PrincipalUsername}
, #{<<"principal_clientid">> => PrincipalClientid} , #{<<"principal_clientid">> => PrincipalClientid}

View File

@ -61,6 +61,7 @@ init_per_testcase(_, Config) ->
Config. Config.
-define(SOURCE1, #{<<"type">> => <<"http">>, -define(SOURCE1, #{<<"type">> => <<"http">>,
<<"enable">> => true,
<<"config">> => #{ <<"config">> => #{
<<"url">> => <<"https://fake.com:443/">>, <<"url">> => <<"https://fake.com:443/">>,
<<"headers">> => #{}, <<"headers">> => #{},
@ -68,6 +69,7 @@ init_per_testcase(_, Config) ->
<<"request_timeout">> => 5000} <<"request_timeout">> => 5000}
}). }).
-define(SOURCE2, #{<<"type">> => <<"mongo">>, -define(SOURCE2, #{<<"type">> => <<"mongo">>,
<<"enable">> => true,
<<"config">> => #{ <<"config">> => #{
<<"mongo_type">> => <<"single">>, <<"mongo_type">> => <<"single">>,
<<"server">> => <<"127.0.0.1:27017">>, <<"server">> => <<"127.0.0.1:27017">>,
@ -78,6 +80,7 @@ init_per_testcase(_, Config) ->
<<"find">> => #{<<"a">> => <<"b">>} <<"find">> => #{<<"a">> => <<"b">>}
}). }).
-define(SOURCE3, #{<<"type">> => <<"mysql">>, -define(SOURCE3, #{<<"type">> => <<"mysql">>,
<<"enable">> => true,
<<"config">> => #{ <<"config">> => #{
<<"server">> => <<"127.0.0.1:27017">>, <<"server">> => <<"127.0.0.1:27017">>,
<<"pool_size">> => 1, <<"pool_size">> => 1,
@ -89,6 +92,7 @@ init_per_testcase(_, Config) ->
<<"sql">> => <<"abcb">> <<"sql">> => <<"abcb">>
}). }).
-define(SOURCE4, #{<<"type">> => <<"pgsql">>, -define(SOURCE4, #{<<"type">> => <<"pgsql">>,
<<"enable">> => true,
<<"config">> => #{ <<"config">> => #{
<<"server">> => <<"127.0.0.1:27017">>, <<"server">> => <<"127.0.0.1:27017">>,
<<"pool_size">> => 1, <<"pool_size">> => 1,
@ -100,6 +104,7 @@ init_per_testcase(_, Config) ->
<<"sql">> => <<"abcb">> <<"sql">> => <<"abcb">>
}). }).
-define(SOURCE5, #{<<"type">> => <<"redis">>, -define(SOURCE5, #{<<"type">> => <<"redis">>,
<<"enable">> => true,
<<"config">> => #{ <<"config">> => #{
<<"server">> => <<"127.0.0.1:27017">>, <<"server">> => <<"127.0.0.1:27017">>,
<<"pool_size">> => 1, <<"pool_size">> => 1,
@ -115,66 +120,73 @@ init_per_testcase(_, Config) ->
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
t_update_source(_) -> 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(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}, {ok, _} = emqx_authz:update({replace_once, http}, ?SOURCE1#{<<"enable">> := false}),
#{annotations := #{id := Id2}, type := mongo}, {ok, _} = emqx_authz:update({replace_once, mongo}, ?SOURCE2#{<<"enable">> := false}),
#{annotations := #{id := Id3}, type := mysql} {ok, _} = emqx_authz:update({replace_once, mysql}, ?SOURCE3#{<<"enable">> := false}),
] = emqx_authz:lookup(), {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), ?assertMatch([ #{type := http, enable := false}
{ok, _} = emqx_authz:update({replace_once, Id3}, ?SOURCE4), , #{type := mongo, enable := false}
?assertMatch([#{type := redis}, #{type := mongo}, #{type := pgsql}], emqx:get_config([authorization, sources], [])), , #{type := mysql, enable := false}
, #{type := pgsql, enable := false}
[#{annotations := #{id := Id1}, type := redis}, , #{type := redis, enable := false}
#{annotations := #{id := Id2}, type := mongo}, ], emqx:get_config([authorization, sources], [])),
#{annotations := #{id := Id3}, type := pgsql}
] = emqx_authz:lookup(),
{ok, _} = emqx_authz:update(replace, []). {ok, _} = emqx_authz:update(replace, []).
t_move_source(_) -> t_move_source(_) ->
{ok, _} = emqx_authz:update(replace, [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5]), {ok, _} = emqx_authz:update(replace, [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5]),
[#{annotations := #{id := Id1}}, ?assertMatch([ #{type := http}
#{annotations := #{id := Id2}}, , #{type := mongo}
#{annotations := #{id := Id3}}, , #{type := mysql}
#{annotations := #{id := Id4}}, , #{type := pgsql}
#{annotations := #{id := Id5}} , #{type := redis}
] = 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}}
], emqx_authz:lookup()), ], emqx_authz:lookup()),
{ok, _} = emqx_authz:move(Id1, <<"bottom">>), {ok, _} = emqx_authz:move(pgsql, <<"top">>),
?assertMatch([#{annotations := #{id := Id4}}, ?assertMatch([ #{type := pgsql}
#{annotations := #{id := Id2}}, , #{type := http}
#{annotations := #{id := Id3}}, , #{type := mongo}
#{annotations := #{id := Id5}}, , #{type := mysql}
#{annotations := #{id := Id1}} , #{type := redis}
], emqx_authz:lookup()), ], emqx_authz:lookup()),
{ok, _} = emqx_authz:move(Id3, #{<<"before">> => Id4}), {ok, _} = emqx_authz:move(http, <<"bottom">>),
?assertMatch([#{annotations := #{id := Id3}}, ?assertMatch([ #{type := pgsql}
#{annotations := #{id := Id4}}, , #{type := mongo}
#{annotations := #{id := Id2}}, , #{type := mysql}
#{annotations := #{id := Id5}}, , #{type := redis}
#{annotations := #{id := Id1}} , #{type := http}
], emqx_authz:lookup()), ], emqx_authz:lookup()),
{ok, _} = emqx_authz:move(Id2, #{<<"after">> => Id1}), {ok, _} = emqx_authz:move(mysql, #{<<"before">> => pgsql}),
?assertMatch([#{annotations := #{id := Id3}}, ?assertMatch([ #{type := mysql}
#{annotations := #{id := Id4}}, , #{type := pgsql}
#{annotations := #{id := Id5}}, , #{type := mongo}
#{annotations := #{id := Id1}}, , #{type := redis}
#{annotations := #{id := Id2}} , #{type := http}
], emqx_authz:lookup()), ], 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. ok.

View File

@ -38,6 +38,7 @@
-define(BASE_PATH, "api"). -define(BASE_PATH, "api").
-define(SOURCE1, #{<<"type">> => <<"http">>, -define(SOURCE1, #{<<"type">> => <<"http">>,
<<"enable">> => true,
<<"config">> => #{ <<"config">> => #{
<<"url">> => <<"https://fake.com:443/">>, <<"url">> => <<"https://fake.com:443/">>,
<<"headers">> => #{}, <<"headers">> => #{},
@ -45,6 +46,7 @@
<<"request_timeout">> => 5000} <<"request_timeout">> => 5000}
}). }).
-define(SOURCE2, #{<<"type">> => <<"mongo">>, -define(SOURCE2, #{<<"type">> => <<"mongo">>,
<<"enable">> => true,
<<"config">> => #{ <<"config">> => #{
<<"mongo_type">> => <<"single">>, <<"mongo_type">> => <<"single">>,
<<"server">> => <<"127.0.0.1:27017">>, <<"server">> => <<"127.0.0.1:27017">>,
@ -55,6 +57,7 @@
<<"find">> => #{<<"a">> => <<"b">>} <<"find">> => #{<<"a">> => <<"b">>}
}). }).
-define(SOURCE3, #{<<"type">> => <<"mysql">>, -define(SOURCE3, #{<<"type">> => <<"mysql">>,
<<"enable">> => true,
<<"config">> => #{ <<"config">> => #{
<<"server">> => <<"127.0.0.1:27017">>, <<"server">> => <<"127.0.0.1:27017">>,
<<"pool_size">> => 1, <<"pool_size">> => 1,
@ -66,6 +69,7 @@
<<"sql">> => <<"abcb">> <<"sql">> => <<"abcb">>
}). }).
-define(SOURCE4, #{<<"type">> => <<"pgsql">>, -define(SOURCE4, #{<<"type">> => <<"pgsql">>,
<<"enable">> => true,
<<"config">> => #{ <<"config">> => #{
<<"server">> => <<"127.0.0.1:27017">>, <<"server">> => <<"127.0.0.1:27017">>,
<<"pool_size">> => 1, <<"pool_size">> => 1,
@ -77,6 +81,7 @@
<<"sql">> => <<"abcb">> <<"sql">> => <<"abcb">>
}). }).
-define(SOURCE5, #{<<"type">> => <<"redis">>, -define(SOURCE5, #{<<"type">> => <<"redis">>,
<<"enable">> => true,
<<"config">> => #{ <<"config">> => #{
<<"server">> => <<"127.0.0.1:27017">>, <<"server">> => <<"127.0.0.1:27017">>,
<<"pool_size">> => 1, <<"pool_size">> => 1,
@ -134,7 +139,7 @@ set_special_configs(emqx_dashboard) ->
emqx_config:put([emqx_dashboard], Config), emqx_config:put([emqx_dashboard], Config),
ok; ok;
set_special_configs(emqx_authz) -> set_special_configs(emqx_authz) ->
emqx_config:put([authorization], #{rules => []}), emqx_config:put([authorization], #{sources => []}),
ok; ok;
set_special_configs(_App) -> set_special_configs(_App) ->
ok. ok.
@ -145,89 +150,86 @@ set_special_configs(_App) ->
t_api(_) -> t_api(_) ->
{ok, 200, Result1} = request(get, uri(["authorization"]), []), {ok, 200, Result1} = request(get, uri(["authorization"]), []),
?assertEqual([], get_rules(Result1)), ?assertEqual([], get_sources(Result1)),
lists:foreach(fun(_) -> lists:foreach(fun(_) ->
{ok, 204, _} = request(post, uri(["authorization"]), ?SOURCE1) {ok, 204, _} = request(post, uri(["authorization"]), ?SOURCE1)
end, lists:seq(1, 20)), end, lists:seq(1, 20)),
{ok, 200, Result2} = request(get, uri(["authorization"]), []), {ok, 200, Result2} = request(get, uri(["authorization"]), []),
?assertEqual(20, length(get_rules(Result2))), ?assertEqual(20, length(get_sources(Result2))),
lists:foreach(fun(Page) -> lists:foreach(fun(Page) ->
Query = "?page=" ++ integer_to_list(Page) ++ "&&limit=10", Query = "?page=" ++ integer_to_list(Page) ++ "&&limit=10",
Url = uri(["authorization" ++ Query]), Url = uri(["authorization" ++ Query]),
{ok, 200, Result} = request(get, Url, []), {ok, 200, Result} = request(get, Url, []),
?assertEqual(10, length(get_rules(Result))) ?assertEqual(10, length(get_sources(Result)))
end, lists:seq(1, 2)), end, lists:seq(1, 2)),
{ok, 204, _} = request(put, uri(["authorization"]), [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4]), {ok, 204, _} = request(put, uri(["authorization"]), [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4]),
{ok, 200, Result3} = request(get, uri(["authorization"]), []), {ok, 200, Result3} = request(get, uri(["authorization"]), []),
Rules = get_rules(Result3), Sources = get_sources(Result3),
?assertEqual(4, length(Rules)),
?assertMatch([ #{<<"type">> := <<"http">>} ?assertMatch([ #{<<"type">> := <<"http">>}
, #{<<"type">> := <<"mongo">>} , #{<<"type">> := <<"mongo">>}
, #{<<"type">> := <<"mysql">>} , #{<<"type">> := <<"mysql">>}
, #{<<"type">> := <<"pgsql">>} , #{<<"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)]), []), lists:foreach(fun(#{<<"type">> := Type}) ->
?assertMatch(#{<<"type">> := <<"redis">>}, jsx:decode(Result4)), {ok, 204, _} = request(delete, uri(["authorization", binary_to_list(Type)]), [])
end, Sources),
lists:foreach(fun(#{<<"annotations">> := #{<<"id">> := Id0}}) ->
{ok, 204, _} = request(delete, uri(["authorization", binary_to_list(Id0)]), [])
end, Rules),
{ok, 200, Result5} = request(get, uri(["authorization"]), []), {ok, 200, Result5} = request(get, uri(["authorization"]), []),
?assertEqual([], get_rules(Result5)), ?assertEqual([], get_sources(Result5)),
ok. ok.
t_move_rule(_) -> t_move_source(_) ->
{ok, _} = emqx_authz:update(replace, [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5]), {ok, _} = emqx_authz:update(replace, [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5]),
[#{annotations := #{id := Id1}}, ?assertMatch([ #{type := http}
#{annotations := #{id := Id2}}, , #{type := mongo}
#{annotations := #{id := Id3}}, , #{type := mysql}
#{annotations := #{id := Id4}}, , #{type := pgsql}
#{annotations := #{id := Id5}} , #{type := redis}
] = emqx_authz:lookup(), ], emqx_authz:lookup()),
{ok, 204, _} = request(post, uri(["authorization", Id4, "move"]), {ok, 204, _} = request(post, uri(["authorization", "pgsql", "move"]),
#{<<"position">> => <<"top">>}), #{<<"position">> => <<"top">>}),
?assertMatch([#{annotations := #{id := Id4}}, ?assertMatch([ #{type := pgsql}
#{annotations := #{id := Id1}}, , #{type := http}
#{annotations := #{id := Id2}}, , #{type := mongo}
#{annotations := #{id := Id3}}, , #{type := mysql}
#{annotations := #{id := Id5}} , #{type := redis}
], emqx_authz:lookup()), ], emqx_authz:lookup()),
{ok, 204, _} = request(post, uri(["authorization", Id1, "move"]), {ok, 204, _} = request(post, uri(["authorization", "http", "move"]),
#{<<"position">> => <<"bottom">>}), #{<<"position">> => <<"bottom">>}),
?assertMatch([#{annotations := #{id := Id4}}, ?assertMatch([ #{type := pgsql}
#{annotations := #{id := Id2}}, , #{type := mongo}
#{annotations := #{id := Id3}}, , #{type := mysql}
#{annotations := #{id := Id5}}, , #{type := redis}
#{annotations := #{id := Id1}} , #{type := http}
], emqx_authz:lookup()), ], emqx_authz:lookup()),
{ok, 204, _} = request(post, uri(["authorization", Id3, "move"]), {ok, 204, _} = request(post, uri(["authorization", "mysql", "move"]),
#{<<"position">> => #{<<"before">> => Id4}}), #{<<"position">> => #{<<"before">> => <<"pgsql">>}}),
?assertMatch([#{annotations := #{id := Id3}}, ?assertMatch([ #{type := mysql}
#{annotations := #{id := Id4}}, , #{type := pgsql}
#{annotations := #{id := Id2}}, , #{type := mongo}
#{annotations := #{id := Id5}}, , #{type := redis}
#{annotations := #{id := Id1}} , #{type := http}
], emqx_authz:lookup()), ], emqx_authz:lookup()),
{ok, 204, _} = request(post, uri(["authorization", Id2, "move"]), {ok, 204, _} = request(post, uri(["authorization", "mongo", "move"]),
#{<<"position">> => #{<<"after">> => Id1}}), #{<<"position">> => #{<<"after">> => <<"http">>}}),
?assertMatch([#{annotations := #{id := Id3}}, ?assertMatch([ #{type := mysql}
#{annotations := #{id := Id4}}, , #{type := pgsql}
#{annotations := #{id := Id5}}, , #{type := redis}
#{annotations := #{id := Id1}}, , #{type := http}
#{annotations := #{id := Id2}} , #{type := mongo}
], emqx_authz:lookup()), ], emqx_authz:lookup()),
ok. ok.
@ -256,8 +258,8 @@ uri(Parts) when is_list(Parts) ->
NParts = [E || E <- Parts], NParts = [E || E <- Parts],
?HOST ++ filename:join([?BASE_PATH, ?API_VERSION | NParts]). ?HOST ++ filename:join([?BASE_PATH, ?API_VERSION | NParts]).
get_rules(Result) -> get_sources(Result) ->
maps:get(<<"rules">>, jsx:decode(Result), []). maps:get(<<"sources">>, jsx:decode(Result), []).
auth_header_() -> auth_header_() ->
Username = <<"admin">>, Username = <<"admin">>,