refactor: refactor emqx_authz
Signed-off-by: zhanghongtong <rory-z@outlook.com>
This commit is contained in:
parent
caef8cb381
commit
6b313a60d4
|
@ -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,52 +201,13 @@ 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
|
||||||
} = Source) ->
|
} = Source) ->
|
||||||
Rules = case file:consult(Path) of
|
Rules = case file:consult(Path) of
|
||||||
{ok, Terms} ->
|
{ok, Terms} ->
|
||||||
[emqx_authz_rule:compile(Term) || Term <- 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]),
|
?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
|
||||||
} = Source) ->
|
} = Source) ->
|
||||||
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
|
||||||
} = Source) when DB =:= redis;
|
} = Source) when DB =:= redis;
|
||||||
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,
|
||||||
sql := SQL
|
sql := SQL
|
||||||
} = Source) when DB =:= mysql;
|
} = Source) when DB =:= mysql;
|
||||||
DB =:= pgsql ->
|
DB =:= pgsql ->
|
||||||
Mod = authz_module(DB),
|
Mod = authz_module(DB),
|
||||||
case create_resource(Source) of
|
case create_resource(Source) of
|
||||||
|
@ -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.
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -61,120 +61,132 @@ init_per_testcase(_, Config) ->
|
||||||
Config.
|
Config.
|
||||||
|
|
||||||
-define(SOURCE1, #{<<"type">> => <<"http">>,
|
-define(SOURCE1, #{<<"type">> => <<"http">>,
|
||||||
<<"config">> => #{
|
<<"enable">> => true,
|
||||||
<<"url">> => <<"https://fake.com:443/">>,
|
<<"config">> => #{
|
||||||
<<"headers">> => #{},
|
<<"url">> => <<"https://fake.com:443/">>,
|
||||||
<<"method">> => <<"get">>,
|
<<"headers">> => #{},
|
||||||
<<"request_timeout">> => 5000}
|
<<"method">> => <<"get">>,
|
||||||
}).
|
<<"request_timeout">> => 5000}
|
||||||
|
}).
|
||||||
-define(SOURCE2, #{<<"type">> => <<"mongo">>,
|
-define(SOURCE2, #{<<"type">> => <<"mongo">>,
|
||||||
<<"config">> => #{
|
<<"enable">> => true,
|
||||||
<<"mongo_type">> => <<"single">>,
|
<<"config">> => #{
|
||||||
<<"server">> => <<"127.0.0.1:27017">>,
|
<<"mongo_type">> => <<"single">>,
|
||||||
<<"pool_size">> => 1,
|
<<"server">> => <<"127.0.0.1:27017">>,
|
||||||
<<"database">> => <<"mqtt">>,
|
<<"pool_size">> => 1,
|
||||||
<<"ssl">> => #{<<"enable">> => false}},
|
<<"database">> => <<"mqtt">>,
|
||||||
<<"collection">> => <<"fake">>,
|
<<"ssl">> => #{<<"enable">> => false}},
|
||||||
<<"find">> => #{<<"a">> => <<"b">>}
|
<<"collection">> => <<"fake">>,
|
||||||
}).
|
<<"find">> => #{<<"a">> => <<"b">>}
|
||||||
|
}).
|
||||||
-define(SOURCE3, #{<<"type">> => <<"mysql">>,
|
-define(SOURCE3, #{<<"type">> => <<"mysql">>,
|
||||||
<<"config">> => #{
|
<<"enable">> => true,
|
||||||
<<"server">> => <<"127.0.0.1:27017">>,
|
<<"config">> => #{
|
||||||
<<"pool_size">> => 1,
|
<<"server">> => <<"127.0.0.1:27017">>,
|
||||||
<<"database">> => <<"mqtt">>,
|
<<"pool_size">> => 1,
|
||||||
<<"username">> => <<"xx">>,
|
<<"database">> => <<"mqtt">>,
|
||||||
<<"password">> => <<"ee">>,
|
<<"username">> => <<"xx">>,
|
||||||
<<"auto_reconnect">> => true,
|
<<"password">> => <<"ee">>,
|
||||||
<<"ssl">> => #{<<"enable">> => false}},
|
<<"auto_reconnect">> => true,
|
||||||
<<"sql">> => <<"abcb">>
|
<<"ssl">> => #{<<"enable">> => false}},
|
||||||
}).
|
<<"sql">> => <<"abcb">>
|
||||||
|
}).
|
||||||
-define(SOURCE4, #{<<"type">> => <<"pgsql">>,
|
-define(SOURCE4, #{<<"type">> => <<"pgsql">>,
|
||||||
<<"config">> => #{
|
<<"enable">> => true,
|
||||||
<<"server">> => <<"127.0.0.1:27017">>,
|
<<"config">> => #{
|
||||||
<<"pool_size">> => 1,
|
<<"server">> => <<"127.0.0.1:27017">>,
|
||||||
<<"database">> => <<"mqtt">>,
|
<<"pool_size">> => 1,
|
||||||
<<"username">> => <<"xx">>,
|
<<"database">> => <<"mqtt">>,
|
||||||
<<"password">> => <<"ee">>,
|
<<"username">> => <<"xx">>,
|
||||||
<<"auto_reconnect">> => true,
|
<<"password">> => <<"ee">>,
|
||||||
<<"ssl">> => #{<<"enable">> => false}},
|
<<"auto_reconnect">> => true,
|
||||||
<<"sql">> => <<"abcb">>
|
<<"ssl">> => #{<<"enable">> => false}},
|
||||||
}).
|
<<"sql">> => <<"abcb">>
|
||||||
|
}).
|
||||||
-define(SOURCE5, #{<<"type">> => <<"redis">>,
|
-define(SOURCE5, #{<<"type">> => <<"redis">>,
|
||||||
<<"config">> => #{
|
<<"enable">> => true,
|
||||||
<<"server">> => <<"127.0.0.1:27017">>,
|
<<"config">> => #{
|
||||||
<<"pool_size">> => 1,
|
<<"server">> => <<"127.0.0.1:27017">>,
|
||||||
<<"database">> => 0,
|
<<"pool_size">> => 1,
|
||||||
<<"password">> => <<"ee">>,
|
<<"database">> => 0,
|
||||||
<<"auto_reconnect">> => true,
|
<<"password">> => <<"ee">>,
|
||||||
<<"ssl">> => #{<<"enable">> => false}},
|
<<"auto_reconnect">> => true,
|
||||||
<<"cmd">> => <<"HGETALL mqtt_authz:%u">>
|
<<"ssl">> => #{<<"enable">> => false}},
|
||||||
}).
|
<<"cmd">> => <<"HGETALL mqtt_authz:%u">>
|
||||||
|
}).
|
||||||
|
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
%% Testcases
|
%% Testcases
|
||||||
%%------------------------------------------------------------------------------
|
%%------------------------------------------------------------------------------
|
||||||
|
|
||||||
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.
|
||||||
|
|
|
@ -38,54 +38,59 @@
|
||||||
-define(BASE_PATH, "api").
|
-define(BASE_PATH, "api").
|
||||||
|
|
||||||
-define(SOURCE1, #{<<"type">> => <<"http">>,
|
-define(SOURCE1, #{<<"type">> => <<"http">>,
|
||||||
<<"config">> => #{
|
<<"enable">> => true,
|
||||||
<<"url">> => <<"https://fake.com:443/">>,
|
<<"config">> => #{
|
||||||
<<"headers">> => #{},
|
<<"url">> => <<"https://fake.com:443/">>,
|
||||||
<<"method">> => <<"get">>,
|
<<"headers">> => #{},
|
||||||
<<"request_timeout">> => 5000}
|
<<"method">> => <<"get">>,
|
||||||
}).
|
<<"request_timeout">> => 5000}
|
||||||
|
}).
|
||||||
-define(SOURCE2, #{<<"type">> => <<"mongo">>,
|
-define(SOURCE2, #{<<"type">> => <<"mongo">>,
|
||||||
<<"config">> => #{
|
<<"enable">> => true,
|
||||||
<<"mongo_type">> => <<"single">>,
|
<<"config">> => #{
|
||||||
<<"server">> => <<"127.0.0.1:27017">>,
|
<<"mongo_type">> => <<"single">>,
|
||||||
<<"pool_size">> => 1,
|
<<"server">> => <<"127.0.0.1:27017">>,
|
||||||
<<"database">> => <<"mqtt">>,
|
<<"pool_size">> => 1,
|
||||||
<<"ssl">> => #{<<"enable">> => false}},
|
<<"database">> => <<"mqtt">>,
|
||||||
<<"collection">> => <<"fake">>,
|
<<"ssl">> => #{<<"enable">> => false}},
|
||||||
<<"find">> => #{<<"a">> => <<"b">>}
|
<<"collection">> => <<"fake">>,
|
||||||
}).
|
<<"find">> => #{<<"a">> => <<"b">>}
|
||||||
|
}).
|
||||||
-define(SOURCE3, #{<<"type">> => <<"mysql">>,
|
-define(SOURCE3, #{<<"type">> => <<"mysql">>,
|
||||||
<<"config">> => #{
|
<<"enable">> => true,
|
||||||
<<"server">> => <<"127.0.0.1:27017">>,
|
<<"config">> => #{
|
||||||
<<"pool_size">> => 1,
|
<<"server">> => <<"127.0.0.1:27017">>,
|
||||||
<<"database">> => <<"mqtt">>,
|
<<"pool_size">> => 1,
|
||||||
<<"username">> => <<"xx">>,
|
<<"database">> => <<"mqtt">>,
|
||||||
<<"password">> => <<"ee">>,
|
<<"username">> => <<"xx">>,
|
||||||
<<"auto_reconnect">> => true,
|
<<"password">> => <<"ee">>,
|
||||||
<<"ssl">> => #{<<"enable">> => false}},
|
<<"auto_reconnect">> => true,
|
||||||
<<"sql">> => <<"abcb">>
|
<<"ssl">> => #{<<"enable">> => false}},
|
||||||
}).
|
<<"sql">> => <<"abcb">>
|
||||||
|
}).
|
||||||
-define(SOURCE4, #{<<"type">> => <<"pgsql">>,
|
-define(SOURCE4, #{<<"type">> => <<"pgsql">>,
|
||||||
<<"config">> => #{
|
<<"enable">> => true,
|
||||||
<<"server">> => <<"127.0.0.1:27017">>,
|
<<"config">> => #{
|
||||||
<<"pool_size">> => 1,
|
<<"server">> => <<"127.0.0.1:27017">>,
|
||||||
<<"database">> => <<"mqtt">>,
|
<<"pool_size">> => 1,
|
||||||
<<"username">> => <<"xx">>,
|
<<"database">> => <<"mqtt">>,
|
||||||
<<"password">> => <<"ee">>,
|
<<"username">> => <<"xx">>,
|
||||||
<<"auto_reconnect">> => true,
|
<<"password">> => <<"ee">>,
|
||||||
<<"ssl">> => #{<<"enable">> => false}},
|
<<"auto_reconnect">> => true,
|
||||||
<<"sql">> => <<"abcb">>
|
<<"ssl">> => #{<<"enable">> => false}},
|
||||||
}).
|
<<"sql">> => <<"abcb">>
|
||||||
|
}).
|
||||||
-define(SOURCE5, #{<<"type">> => <<"redis">>,
|
-define(SOURCE5, #{<<"type">> => <<"redis">>,
|
||||||
<<"config">> => #{
|
<<"enable">> => true,
|
||||||
<<"server">> => <<"127.0.0.1:27017">>,
|
<<"config">> => #{
|
||||||
<<"pool_size">> => 1,
|
<<"server">> => <<"127.0.0.1:27017">>,
|
||||||
<<"database">> => 0,
|
<<"pool_size">> => 1,
|
||||||
<<"password">> => <<"ee">>,
|
<<"database">> => 0,
|
||||||
<<"auto_reconnect">> => true,
|
<<"password">> => <<"ee">>,
|
||||||
<<"ssl">> => #{<<"enable">> => false}},
|
<<"auto_reconnect">> => true,
|
||||||
<<"cmd">> => <<"HGETALL mqtt_authz:%u">>
|
<<"ssl">> => #{<<"enable">> => false}},
|
||||||
}).
|
<<"cmd">> => <<"HGETALL mqtt_authz:%u">>
|
||||||
|
}).
|
||||||
|
|
||||||
all() ->
|
all() ->
|
||||||
emqx_ct:all(?MODULE).
|
emqx_ct:all(?MODULE).
|
||||||
|
@ -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">>,
|
||||||
|
|
Loading…
Reference in New Issue