|
|
@@ -0,0 +1,186 @@
|
|
|
+%%--------------------------------------------------------------------
|
|
|
+%% 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]},
|
|
|
+ {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)))
|
|
|
+ ),
|
|
|
+ ?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)),
|
|
|
+
|
|
|
+ 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.
|
|
|
+
|
|
|
+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)).
|