215 lines
8.7 KiB
Erlang
215 lines
8.7 KiB
Erlang
%%--------------------------------------------------------------------
|
|
%% Copyright (c) 2020-2021 EMQ Technologies Co., Ltd. All Rights Reserved.
|
|
%%
|
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
|
%% you may not use this file except in compliance with the License.
|
|
%% You may obtain a copy of the License at
|
|
%%
|
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
|
%%
|
|
%% Unless required by applicable law or agreed to in writing, software
|
|
%% distributed under the License is distributed on an "AS IS" BASIS,
|
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
%% See the License for the specific language governing permissions and
|
|
%% limitations under the License.
|
|
%%--------------------------------------------------------------------
|
|
-module(emqx_mgmt_auth_api_SUITE).
|
|
|
|
-compile(export_all).
|
|
-compile(nowarn_export_all).
|
|
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
|
|
all() -> [{group, parallel}, {group, sequence}].
|
|
suite() -> [{timetrap, {minutes, 1}}].
|
|
groups() -> [
|
|
{parallel, [parallel], [t_create, t_update, t_delete, t_authorize, t_create_unexpired_app]},
|
|
{sequence, [], [t_create_failed]}
|
|
].
|
|
|
|
init_per_suite(Config) ->
|
|
emqx_mgmt_api_test_util:init_suite(),
|
|
Config.
|
|
|
|
end_per_suite(_) ->
|
|
emqx_mgmt_api_test_util:end_suite().
|
|
|
|
t_create(_Config) ->
|
|
Name = <<"EMQX-API-KEY-1">>,
|
|
{ok, Create} = create_app(Name),
|
|
?assertMatch(#{<<"api_key">> := _,
|
|
<<"api_secret">> := _,
|
|
<<"created_at">> := _,
|
|
<<"desc">> := _,
|
|
<<"enable">> := true,
|
|
<<"expired_at">> := _,
|
|
<<"name">> := Name}, Create),
|
|
{ok, List} = list_app(),
|
|
[App] = lists:filter(fun(#{<<"name">> := NameA}) -> NameA =:= Name end, List),
|
|
?assertEqual(false, maps:is_key(<<"api_secret">>, App)),
|
|
{ok, App1} = read_app(Name),
|
|
?assertEqual(Name, maps:get(<<"name">>, App1)),
|
|
?assertEqual(true, maps:get(<<"enable">>, App1)),
|
|
?assertEqual(false, maps:is_key(<<"api_secret">>, App1)),
|
|
?assertEqual({error, {"HTTP/1.1", 404, "Not Found"}}, read_app(<<"EMQX-API-KEY-NO-EXIST">>)),
|
|
ok.
|
|
|
|
t_create_failed(_Config) ->
|
|
BadRequest = {error, {"HTTP/1.1", 400, "Bad Request"}},
|
|
|
|
?assertEqual(BadRequest, create_app(<<" error format name">>)),
|
|
LongName = iolist_to_binary(lists:duplicate(257, "A")),
|
|
?assertEqual(BadRequest, create_app(<<" error format name">>)),
|
|
?assertEqual(BadRequest, create_app(LongName)),
|
|
|
|
{ok, List} = list_app(),
|
|
CreateNum = 30 - erlang:length(List),
|
|
Names = lists:map(fun(Seq) ->
|
|
<<"EMQX-API-FAILED-KEY-", (integer_to_binary(Seq))/binary>>
|
|
end, lists:seq(1, CreateNum)),
|
|
lists:foreach(fun(N) -> {ok, _} = create_app(N) end, Names),
|
|
?assertEqual(BadRequest, create_app(<<"EMQX-API-KEY-MAXIMUM">>)),
|
|
|
|
lists:foreach(fun(N) -> {ok, _} = delete_app(N) end, Names),
|
|
Name = <<"EMQX-API-FAILED-KEY-1">>,
|
|
?assertMatch({ok, _}, create_app(Name)),
|
|
?assertEqual(BadRequest, create_app(Name)),
|
|
{ok, _} = delete_app(Name),
|
|
?assertMatch({ok, #{<<"name">> := Name}}, create_app(Name)),
|
|
{ok, _} = delete_app(Name),
|
|
ok.
|
|
|
|
t_update(_Config) ->
|
|
Name = <<"EMQX-API-UPDATE-KEY">>,
|
|
{ok, _} = create_app(Name),
|
|
|
|
ExpiredAt = to_rfc3339(erlang:system_time(second) + 10000),
|
|
Change = #{
|
|
expired_at => ExpiredAt,
|
|
desc => <<"NoteVersion1"/utf8>>,
|
|
enable => false
|
|
},
|
|
{ok, Update1} = update_app(Name, Change),
|
|
?assertEqual(Name, maps:get(<<"name">>, Update1)),
|
|
?assertEqual(false, maps:get(<<"enable">>, Update1)),
|
|
?assertEqual(<<"NoteVersion1"/utf8>>, maps:get(<<"desc">>, Update1)),
|
|
?assertEqual(calendar:rfc3339_to_system_time(binary_to_list(ExpiredAt)),
|
|
calendar:rfc3339_to_system_time(binary_to_list(maps:get(<<"expired_at">>, Update1)))
|
|
),
|
|
Unexpired1 = maps:without([expired_at], Change),
|
|
{ok, Update2} = update_app(Name, Unexpired1),
|
|
?assertEqual(<<"undefined">>, maps:get(<<"expired_at">>, Update2)),
|
|
Unexpired2 = Change#{expired_at => <<"undefined">>},
|
|
{ok, Update3} = update_app(Name, Unexpired2),
|
|
?assertEqual(<<"undefined">>, maps:get(<<"expired_at">>, Update3)),
|
|
|
|
?assertEqual({error, {"HTTP/1.1", 404, "Not Found"}}, update_app(<<"Not-Exist">>, Change)),
|
|
ok.
|
|
|
|
t_delete(_Config) ->
|
|
Name = <<"EMQX-API-DELETE-KEY">>,
|
|
{ok, _Create} = create_app(Name),
|
|
{ok, Delete} = delete_app(Name),
|
|
?assertEqual([], Delete),
|
|
?assertEqual({error, {"HTTP/1.1", 404, "Not Found"}}, delete_app(Name)),
|
|
ok.
|
|
|
|
t_authorize(_Config) ->
|
|
Name = <<"EMQX-API-AUTHORIZE-KEY">>,
|
|
{ok, #{<<"api_key">> := ApiKey, <<"api_secret">> := ApiSecret}} = create_app(Name),
|
|
BasicHeader = emqx_common_test_http:auth_header(binary_to_list(ApiKey),
|
|
binary_to_list(ApiSecret)),
|
|
SecretError = emqx_common_test_http:auth_header(binary_to_list(ApiKey),
|
|
binary_to_list(ApiKey)),
|
|
KeyError = emqx_common_test_http:auth_header("not_found_key", binary_to_list(ApiSecret)),
|
|
Unauthorized = {error, {"HTTP/1.1", 401, "Unauthorized"}},
|
|
|
|
BanPath = emqx_mgmt_api_test_util:api_path(["banned"]),
|
|
ApiKeyPath = emqx_mgmt_api_test_util:api_path(["api_key"]),
|
|
UserPath = emqx_mgmt_api_test_util:api_path(["users"]),
|
|
|
|
{ok, _Status} = emqx_mgmt_api_test_util:request_api(get, BanPath, BasicHeader),
|
|
?assertEqual(Unauthorized, emqx_mgmt_api_test_util:request_api(get, BanPath, KeyError)),
|
|
?assertEqual(Unauthorized, emqx_mgmt_api_test_util:request_api(get, BanPath, SecretError)),
|
|
?assertEqual(Unauthorized, emqx_mgmt_api_test_util:request_api(get, ApiKeyPath, BasicHeader)),
|
|
?assertEqual(Unauthorized, emqx_mgmt_api_test_util:request_api(get, UserPath, BasicHeader)),
|
|
|
|
?assertMatch({ok, #{<<"api_key">> := _, <<"enable">> := false}},
|
|
update_app(Name, #{enable => false})),
|
|
?assertEqual(Unauthorized, emqx_mgmt_api_test_util:request_api(get, BanPath, BasicHeader)),
|
|
|
|
Expired = #{
|
|
expired_at => to_rfc3339(erlang:system_time(second) - 1),
|
|
enable => true
|
|
},
|
|
?assertMatch({ok, #{<<"api_key">> := _, <<"enable">> := true}}, update_app(Name, Expired)),
|
|
?assertEqual(Unauthorized, emqx_mgmt_api_test_util:request_api(get, BanPath, BasicHeader)),
|
|
UnExpired = #{expired_at => undefined},
|
|
?assertMatch({ok, #{<<"api_key">> := _, <<"expired_at">> := <<"undefined">>}},
|
|
update_app(Name, UnExpired)),
|
|
{ok, _Status1} = emqx_mgmt_api_test_util:request_api(get, BanPath, BasicHeader),
|
|
ok.
|
|
|
|
t_create_unexpired_app(_Config) ->
|
|
Name1 = <<"EMQX-UNEXPIRED-API-KEY-1">>,
|
|
Name2 = <<"EMQX-UNEXPIRED-API-KEY-2">>,
|
|
{ok, Create1} = create_unexpired_app(Name1, #{}),
|
|
?assertMatch(#{<<"expired_at">> := <<"undefined">>}, Create1),
|
|
{ok, Create2} = create_unexpired_app(Name2, #{expired_at => <<"undefined">>}),
|
|
?assertMatch(#{<<"expired_at">> := <<"undefined">>}, Create2),
|
|
ok.
|
|
|
|
|
|
list_app() ->
|
|
Path = emqx_mgmt_api_test_util:api_path(["api_key"]),
|
|
case emqx_mgmt_api_test_util:request_api(get, Path) of
|
|
{ok, Apps} -> {ok, emqx_json:decode(Apps, [return_maps])};
|
|
Error -> Error
|
|
end.
|
|
|
|
read_app(Name) ->
|
|
Path = emqx_mgmt_api_test_util:api_path(["api_key", Name]),
|
|
case emqx_mgmt_api_test_util:request_api(get, Path) of
|
|
{ok, Res} -> {ok, emqx_json:decode(Res, [return_maps])};
|
|
Error -> Error
|
|
end.
|
|
|
|
create_app(Name) ->
|
|
AuthHeader = emqx_mgmt_api_test_util:auth_header_(),
|
|
Path = emqx_mgmt_api_test_util:api_path(["api_key"]),
|
|
ExpiredAt = to_rfc3339(erlang:system_time(second) + 1000),
|
|
App = #{
|
|
name => Name,
|
|
expired_at => ExpiredAt,
|
|
desc => <<"Note"/utf8>>,
|
|
enable => true
|
|
},
|
|
case emqx_mgmt_api_test_util:request_api(post, Path, "", AuthHeader, App) of
|
|
{ok, Res} -> {ok, emqx_json:decode(Res, [return_maps])};
|
|
Error -> Error
|
|
end.
|
|
|
|
create_unexpired_app(Name, Params) ->
|
|
AuthHeader = emqx_mgmt_api_test_util:auth_header_(),
|
|
Path = emqx_mgmt_api_test_util:api_path(["api_key"]),
|
|
App = maps:merge(#{name => Name, desc => <<"Note"/utf8>>, enable => true}, Params),
|
|
case emqx_mgmt_api_test_util:request_api(post, Path, "", AuthHeader, App) of
|
|
{ok, Res} -> {ok, emqx_json:decode(Res, [return_maps])};
|
|
Error -> Error
|
|
end.
|
|
|
|
delete_app(Name) ->
|
|
DeletePath = emqx_mgmt_api_test_util:api_path(["api_key", Name]),
|
|
emqx_mgmt_api_test_util:request_api(delete, DeletePath).
|
|
|
|
update_app(Name, Change) ->
|
|
AuthHeader = emqx_mgmt_api_test_util:auth_header_(),
|
|
UpdatePath = emqx_mgmt_api_test_util:api_path(["api_key", Name]),
|
|
case emqx_mgmt_api_test_util:request_api(put, UpdatePath, "", AuthHeader, Change) of
|
|
{ok, Update} -> {ok, emqx_json:decode(Update, [return_maps])};
|
|
Error -> Error
|
|
end.
|
|
|
|
to_rfc3339(Sec) ->
|
|
list_to_binary(calendar:system_time_to_rfc3339(Sec)).
|