Fix dashboard APIs return (#6177)
* fix(dashboard_api): delete non-exist user wrongly return 204 * fix(dashboard): dashboard user should use `tags` not `tag` * fix(dashboard): create/update user return 200 with full users list * fix(dashboard): logout status code 204 * fix(dashboard): update pwd status code 204 * test: test suite for dashboard APIs * refactor(dashboard): user info mnesia record name use description * style: make elvis happy * fix(api): dashboard swagger check request should not override env * fix(dashboard): add/modify dashboard returns single record * ci: update emqx-fvt version to new tag 1.0.2-dev1
This commit is contained in:
parent
14da850e06
commit
e361cd5733
|
@ -61,7 +61,7 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: emqx/emqx-fvt
|
||||
ref: v1.5.0
|
||||
ref: 1.0.2-dev1
|
||||
path: .
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
|
|
|
@ -19,14 +19,14 @@
|
|||
-include_lib("common_test/include/ct.hrl").
|
||||
|
||||
-export([ request_api/3
|
||||
, request_api/4
|
||||
, request_api/5
|
||||
, get_http_data/1
|
||||
, create_default_app/0
|
||||
, delete_default_app/0
|
||||
, default_auth_header/0
|
||||
, auth_header/2
|
||||
]).
|
||||
, request_api/4
|
||||
, request_api/5
|
||||
, get_http_data/1
|
||||
, create_default_app/0
|
||||
, delete_default_app/0
|
||||
, default_auth_header/0
|
||||
, auth_header/2
|
||||
]).
|
||||
|
||||
request_api(Method, Url, Auth) ->
|
||||
request_api(Method, Url, [], Auth, []).
|
||||
|
@ -57,15 +57,14 @@ do_request_api(Method, Request, HttpOpts) ->
|
|||
case httpc:request(Method, Request, HttpOpts, [{body_format, binary}]) of
|
||||
{error, socket_closed_remotely} ->
|
||||
{error, socket_closed_remotely};
|
||||
{ok, {{"HTTP/1.1", Code, _}, _Headers, Return} }
|
||||
when Code =:= 200 orelse Code =:= 201 ->
|
||||
{ok, Return};
|
||||
{ok, {{"HTTP/1.1", Code, _}, _Headers, Return} } ->
|
||||
{ok, Code, Return};
|
||||
{ok, {Reason, _, _}} ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
get_http_data(ResponseBody) ->
|
||||
maps:get(<<"data">>, emqx_json:decode(ResponseBody, [return_maps])).
|
||||
emqx_json:decode(ResponseBody, [return_maps]).
|
||||
|
||||
auth_header(User, Pass) ->
|
||||
Encoded = base64:encode_to_string(lists:append([User,":",Pass])),
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
-record(?ADMIN, {
|
||||
username :: binary(),
|
||||
pwdhash :: binary(),
|
||||
tags :: list() | binary(),
|
||||
description :: binary(),
|
||||
role = undefined :: atom(),
|
||||
extra = [] :: term() %% not used so far, for future extension
|
||||
}).
|
||||
|
|
|
@ -40,7 +40,7 @@ start_listeners() ->
|
|||
Authorization = {?MODULE, authorize_appid},
|
||||
GlobalSpec = #{
|
||||
openapi => "3.0.0",
|
||||
info => #{title => "EMQ X Dashboard API", version => "5.0.0"},
|
||||
info => #{title => "EMQ X API", version => "5.0.0"},
|
||||
servers => [#{url => ?BASE_PATH}],
|
||||
components => #{
|
||||
schemas => #{},
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
-module(emqx_dashboard_admin).
|
||||
|
||||
-include("emqx_dashboard.hrl").
|
||||
-include_lib("stdlib/include/ms_transform.hrl").
|
||||
|
||||
-boot_mnesia({mnesia, [boot]}).
|
||||
|
||||
|
@ -63,17 +64,17 @@ mnesia(boot) ->
|
|||
%% API
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
-spec(add_user(binary(), binary(), binary()) -> ok | {error, any()}).
|
||||
add_user(Username, Password, Tags) when is_binary(Username), is_binary(Password) ->
|
||||
Admin = #?ADMIN{username = Username, pwdhash = hash(Password), tags = Tags},
|
||||
return(mria:transaction(?DASHBOARD_SHARD, fun add_user_/1, [Admin])).
|
||||
-spec(add_user(binary(), binary(), binary()) -> {ok, map()} | {error, any()}).
|
||||
add_user(Username, Password, Desc)
|
||||
when is_binary(Username), is_binary(Password) ->
|
||||
return(mria:transaction(?DASHBOARD_SHARD, fun add_user_/3, [Username, Password, Desc])).
|
||||
|
||||
%% black-magic: force overwrite a user
|
||||
force_add_user(Username, Password, Tags) ->
|
||||
force_add_user(Username, Password, Desc) ->
|
||||
AddFun = fun() ->
|
||||
mnesia:write(#?ADMIN{username = Username,
|
||||
pwdhash = hash(Password),
|
||||
tags = Tags})
|
||||
description = Desc})
|
||||
end,
|
||||
case mria:transaction(?DASHBOARD_SHARD, AddFun) of
|
||||
{atomic, ok} -> ok;
|
||||
|
@ -81,33 +82,38 @@ force_add_user(Username, Password, Tags) ->
|
|||
end.
|
||||
|
||||
%% @private
|
||||
add_user_(Admin = #?ADMIN{username = Username}) ->
|
||||
add_user_(Username, Password, Desc) ->
|
||||
case mnesia:wread({?ADMIN, Username}) of
|
||||
[] -> mnesia:write(Admin);
|
||||
[_] -> mnesia:abort(<<"Username Already Exist">>)
|
||||
[] ->
|
||||
Admin = #?ADMIN{username = Username, pwdhash = hash(Password), description = Desc},
|
||||
mnesia:write(Admin),
|
||||
#{username => Username, description => Desc};
|
||||
[_] ->
|
||||
mnesia:abort(<<"Username Already Exist">>)
|
||||
end.
|
||||
|
||||
-spec(remove_user(binary()) -> ok | {error, any()}).
|
||||
-spec(remove_user(binary()) -> {ok, any()} | {error, any()}).
|
||||
remove_user(Username) when is_binary(Username) ->
|
||||
Trans = fun() ->
|
||||
case lookup_user(Username) of
|
||||
[] ->
|
||||
mnesia:abort(<<"Username Not Found">>);
|
||||
_ -> ok
|
||||
end,
|
||||
mnesia:delete({?ADMIN, Username})
|
||||
[] -> mnesia:abort(<<"Username Not Found">>);
|
||||
_ -> mnesia:delete({?ADMIN, Username})
|
||||
end
|
||||
end,
|
||||
return(mria:transaction(?DASHBOARD_SHARD, Trans)).
|
||||
|
||||
-spec(update_user(binary(), binary()) -> ok | {error, term()}).
|
||||
update_user(Username, Tags) when is_binary(Username) ->
|
||||
return(mria:transaction(?DASHBOARD_SHARD, fun update_user_/2, [Username, Tags])).
|
||||
-spec(update_user(binary(), binary()) -> {ok, map()} | {error, term()}).
|
||||
update_user(Username, Desc) when is_binary(Username) ->
|
||||
return(mria:transaction(?DASHBOARD_SHARD, fun update_user_/2, [Username, Desc])).
|
||||
|
||||
%% @private
|
||||
update_user_(Username, Tags) ->
|
||||
update_user_(Username, Desc) ->
|
||||
case mnesia:wread({?ADMIN, Username}) of
|
||||
[] -> mnesia:abort(<<"Username Not Found">>);
|
||||
[Admin] -> mnesia:write(Admin#?ADMIN{tags = Tags})
|
||||
[] ->
|
||||
mnesia:abort(<<"Username Not Found">>);
|
||||
[Admin] ->
|
||||
mnesia:write(Admin#?ADMIN{description = Desc}),
|
||||
#{username => Username, description => Desc}
|
||||
end.
|
||||
|
||||
change_password(Username, OldPasswd, NewPasswd) when is_binary(Username) ->
|
||||
|
@ -146,17 +152,15 @@ lookup_user(Username) when is_binary(Username) ->
|
|||
-spec(all_users() -> [map()]).
|
||||
all_users() ->
|
||||
lists:map(fun(#?ADMIN{username = Username,
|
||||
tags = Tags
|
||||
description = Desc
|
||||
}) ->
|
||||
#{username => Username,
|
||||
%% named tag but not tags, for unknown reason
|
||||
%% TODO: fix this comment
|
||||
tag => Tags
|
||||
description => Desc
|
||||
}
|
||||
end, ets:tab2list(?ADMIN)).
|
||||
|
||||
return({atomic, _}) ->
|
||||
ok;
|
||||
return({atomic, Result}) ->
|
||||
{ok, Result};
|
||||
return({aborted, Reason}) ->
|
||||
{error, Reason}.
|
||||
|
||||
|
@ -219,5 +223,5 @@ add_default_user(Username, Password) when ?EMPTY_KEY(Username) orelse ?EMPTY_KEY
|
|||
add_default_user(Username, Password) ->
|
||||
case lookup_user(Username) of
|
||||
[] -> add_user(Username, Password, <<"administrator">>);
|
||||
_ -> ok
|
||||
_ -> {ok, default_user_exists}
|
||||
end.
|
||||
|
|
|
@ -37,14 +37,21 @@
|
|||
|
||||
-define(EMPTY(V), (V == undefined orelse V == <<>>)).
|
||||
-define(ERROR_USERNAME_OR_PWD, 'ERROR_USERNAME_OR_PWD').
|
||||
-define(USER_NOT_FOUND_BODY, #{ code => <<"USER_NOT_FOUND">>
|
||||
, message => <<"User not found">>}).
|
||||
|
||||
|
||||
namespace() -> "dashboard".
|
||||
|
||||
api_spec() ->
|
||||
emqx_dashboard_swagger:spec(?MODULE, #{check_schema => true, translate_body => true}).
|
||||
|
||||
paths() -> ["/login", "/logout", "/users",
|
||||
"/users/:username", "/users/:username/change_pwd"].
|
||||
paths() ->
|
||||
[ "/login"
|
||||
, "/logout"
|
||||
, "/users"
|
||||
, "/users/:username"
|
||||
, "/users/:username/change_pwd"].
|
||||
|
||||
schema("/login") ->
|
||||
#{
|
||||
|
@ -53,8 +60,7 @@ schema("/login") ->
|
|||
tags => [<<"dashboard">>],
|
||||
description => <<"Dashboard Auth">>,
|
||||
summary => <<"Dashboard Auth">>,
|
||||
'requestBody' =>
|
||||
[
|
||||
'requestBody' => [
|
||||
{username, mk(binary(),
|
||||
#{desc => <<"The User for which to create the token.">>,
|
||||
'maxLength' => 100, example => <<"admin">>})},
|
||||
|
@ -67,10 +73,12 @@ schema("/login") ->
|
|||
{license, [{edition,
|
||||
mk(enum([community, enterprise]), #{desc => <<"license">>,
|
||||
example => "community"})}]},
|
||||
{version, mk(string(), #{desc => <<"version">>, example => <<"5.0.0">>})}],
|
||||
{version, mk(string(), #{desc => <<"version">>, example => <<"5.0.0">>})}
|
||||
],
|
||||
401 => [
|
||||
{code, mk(string(), #{example => 'ERROR_USERNAME_OR_PWD'})},
|
||||
{message, mk(string(), #{example => "Unauthorized"})}]
|
||||
{message, mk(string(), #{example => "Unauthorized"})}
|
||||
]
|
||||
},
|
||||
security => []
|
||||
}};
|
||||
|
@ -86,7 +94,7 @@ schema("/logout") ->
|
|||
'maxLength' => 100, example => <<"admin">>})}
|
||||
],
|
||||
responses => #{
|
||||
200 => <<"Dashboard logout successfully">>
|
||||
204 => <<"Dashboard logout successfully">>
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -95,10 +103,10 @@ schema("/users") ->
|
|||
'operationId' => users,
|
||||
get => #{
|
||||
tags => [<<"dashboard">>],
|
||||
description => <<"Get dashboard users">>,
|
||||
description => <<"Get dashboard users list">>,
|
||||
responses => #{
|
||||
200 => mk(array(ref(?MODULE, user)),
|
||||
#{desc => "User lists"})
|
||||
200 => mk( array(ref(?MODULE, user))
|
||||
, #{desc => "User lists"})
|
||||
}
|
||||
},
|
||||
post => #{
|
||||
|
@ -106,9 +114,12 @@ schema("/users") ->
|
|||
description => <<"Create dashboard users">>,
|
||||
'requestBody' => fields(user_password),
|
||||
responses => #{
|
||||
200 => <<"Create user successfully">>,
|
||||
200 => mk( ref(?MODULE, user)
|
||||
, #{desc => <<"Create User successfully">>}),
|
||||
400 => [{code, mk(string(), #{example => 'CREATE_FAIL'})},
|
||||
{message, mk(string(), #{example => "Create user failed"})}]}
|
||||
{message, mk(string(), #{example => "Create user failed"})}
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -120,11 +131,20 @@ schema("/users/:username") ->
|
|||
description => <<"Update dashboard users">>,
|
||||
parameters => [{username, mk(binary(),
|
||||
#{in => path, example => <<"admin">>})}],
|
||||
'requestBody' => [{tag, mk(binary(), #{desc => <<"Tag">>})}],
|
||||
'requestBody' => [
|
||||
{ description
|
||||
, mk(binary(), #{desc => <<"User description">>, example => <<"administrator">>})}
|
||||
],
|
||||
responses => #{
|
||||
200 => <<"Update User successfully">>,
|
||||
400 => [{code, mk(string(), #{example => 'UPDATE_FAIL'})},
|
||||
{message, mk(string(), #{example => "Update Failed unknown"})}]}},
|
||||
200 => mk( ref(?MODULE, user)
|
||||
, #{desc => <<"Update User successfully">>}),
|
||||
400 => [
|
||||
{code, mk(string(), #{example => 'UPDATE_FAIL'})},
|
||||
{message, mk(string(), #{example => "Update Failed unknown"})}
|
||||
],
|
||||
404 => emqx_dashboard_swagger:error_codes(['USER_NOT_FOUND'], <<"User Not Found">>)
|
||||
}
|
||||
},
|
||||
delete => #{
|
||||
tags => [<<"dashboard">>],
|
||||
description => <<"Delete dashboard users">>,
|
||||
|
@ -134,7 +154,11 @@ schema("/users/:username") ->
|
|||
204 => <<"Delete User successfully">>,
|
||||
400 => [
|
||||
{code, mk(string(), #{example => 'CANNOT_DELETE_ADMIN'})},
|
||||
{message, mk(string(), #{example => "CANNOT DELETE ADMIN"})}]}}
|
||||
{message, mk(string(), #{example => "CANNOT DELETE ADMIN"})}
|
||||
],
|
||||
404 => emqx_dashboard_swagger:error_codes(['USER_NOT_FOUND'], <<"User Not Found">>)
|
||||
}
|
||||
}
|
||||
};
|
||||
schema("/users/:username/change_pwd") ->
|
||||
#{
|
||||
|
@ -149,23 +173,26 @@ schema("/users/:username/change_pwd") ->
|
|||
{new_pwd, mk(binary(), #{required => true})}
|
||||
],
|
||||
responses => #{
|
||||
200 => <<"Update user password successfully">>,
|
||||
204 => <<"Update user password successfully">>,
|
||||
400 => [
|
||||
{code, mk(string(), #{example => 'UPDATE_FAIL'})},
|
||||
{message, mk(string(), #{example => "Failed Reason"})}]}}
|
||||
{message, mk(string(), #{example => "Failed Reason"})}
|
||||
]
|
||||
}
|
||||
}
|
||||
}.
|
||||
|
||||
fields(user) ->
|
||||
[
|
||||
{tag,
|
||||
{description,
|
||||
mk(binary(),
|
||||
#{desc => <<"tag">>, example => "administrator"})},
|
||||
#{desc => <<"User description">>, example => "administrator"})},
|
||||
{username,
|
||||
mk(binary(),
|
||||
#{desc => <<"username">>, example => "emqx"})}
|
||||
];
|
||||
fields(user_password) ->
|
||||
fields(user) ++ [{password, mk(binary(), #{desc => "Password"})}].
|
||||
fields(user) ++ [{password, mk(binary(), #{desc => "Password", example => <<"public">>})}].
|
||||
|
||||
login(post, #{body := Params}) ->
|
||||
Username = maps:get(<<"username">>, Params),
|
||||
|
@ -182,7 +209,7 @@ logout(_, #{body := #{<<"username">> := Username},
|
|||
headers := #{<<"authorization">> := <<"Bearer ", Token/binary>>}}) ->
|
||||
case emqx_dashboard_admin:destroy_token_by_username(Username, Token) of
|
||||
ok ->
|
||||
200;
|
||||
204;
|
||||
_R ->
|
||||
{401, 'BAD_TOKEN_OR_USERNAME', <<"Ensure your token & username">>}
|
||||
end.
|
||||
|
@ -191,7 +218,7 @@ users(get, _Request) ->
|
|||
{200, emqx_dashboard_admin:all_users()};
|
||||
|
||||
users(post, #{body := Params}) ->
|
||||
Tag = maps:get(<<"tag">>, Params),
|
||||
Desc = maps:get(<<"description">>, Params),
|
||||
Username = maps:get(<<"username">>, Params),
|
||||
Password = maps:get(<<"password">>, Params),
|
||||
case ?EMPTY(Username) orelse ?EMPTY(Password) of
|
||||
|
@ -199,35 +226,43 @@ users(post, #{body := Params}) ->
|
|||
{400, #{code => <<"CREATE_USER_FAIL">>,
|
||||
message => <<"Username or password undefined">>}};
|
||||
false ->
|
||||
case emqx_dashboard_admin:add_user(Username, Password, Tag) of
|
||||
ok -> {200};
|
||||
case emqx_dashboard_admin:add_user(Username, Password, Desc) of
|
||||
{ok, Result} ->
|
||||
{200, Result};
|
||||
{error, Reason} ->
|
||||
{400, #{code => <<"CREATE_USER_FAIL">>, message => Reason}}
|
||||
end
|
||||
end.
|
||||
|
||||
user(put, #{bindings := #{username := Username}, body := Params}) ->
|
||||
Tag = maps:get(<<"tag">>, Params),
|
||||
case emqx_dashboard_admin:update_user(Username, Tag) of
|
||||
ok -> {200};
|
||||
{error, Reason} ->
|
||||
{400, #{code => <<"UPDATE_FAIL">>, message => Reason}}
|
||||
Desc = maps:get(<<"description">>, Params),
|
||||
case emqx_dashboard_admin:update_user(Username, Desc) of
|
||||
{ok, Result} ->
|
||||
{200, Result};
|
||||
{error, _Reason} ->
|
||||
{404, ?USER_NOT_FOUND_BODY}
|
||||
end;
|
||||
|
||||
user(delete, #{bindings := #{username := Username}}) ->
|
||||
case Username == <<"admin">> of
|
||||
true -> {400, #{code => <<"CANNOT_DELETE_ADMIN">>,
|
||||
message => <<"Cannot delete admin">>}};
|
||||
true ->
|
||||
{400, #{code => <<"ACTION_NOT_ALLOWED">>,
|
||||
message => <<"Cannot delete admin">>}};
|
||||
false ->
|
||||
_ = emqx_dashboard_admin:remove_user(Username),
|
||||
{204}
|
||||
case emqx_dashboard_admin:remove_user(Username) of
|
||||
{error, _Reason} ->
|
||||
{404, ?USER_NOT_FOUND_BODY};
|
||||
{ok, _} ->
|
||||
{204}
|
||||
end
|
||||
end.
|
||||
|
||||
change_pwd(put, #{bindings := #{username := Username}, body := Params}) ->
|
||||
OldPwd = maps:get(<<"old_pwd">>, Params),
|
||||
NewPwd = maps:get(<<"new_pwd">>, Params),
|
||||
case emqx_dashboard_admin:change_password(Username, OldPwd, NewPwd) of
|
||||
ok -> {200};
|
||||
{ok, _} ->
|
||||
{204};
|
||||
{error, Reason} ->
|
||||
{400, #{code => <<"CHANGE_PWD_FAIL">>, message => Reason}}
|
||||
end.
|
||||
|
|
|
@ -29,7 +29,7 @@ start(_StartType, _StartArgs) ->
|
|||
ok = mria_rlog:wait_for_shards([?DASHBOARD_SHARD], infinity),
|
||||
_ = emqx_dashboard:start_listeners(),
|
||||
emqx_dashboard_cli:load(),
|
||||
ok = emqx_dashboard_admin:add_default_user(),
|
||||
{ok, _Result} = emqx_dashboard_admin:add_default_user(),
|
||||
{ok, Sup}.
|
||||
|
||||
stop(_State) ->
|
||||
|
|
|
@ -27,9 +27,9 @@ load() ->
|
|||
admins(["add", Username, Password]) ->
|
||||
admins(["add", Username, Password, ""]);
|
||||
|
||||
admins(["add", Username, Password, Tag]) ->
|
||||
case emqx_dashboard_admin:add_user(bin(Username), bin(Password), bin(Tag)) of
|
||||
ok ->
|
||||
admins(["add", Username, Password, Desc]) ->
|
||||
case emqx_dashboard_admin:add_user(bin(Username), bin(Password), bin(Desc)) of
|
||||
{ok, _} ->
|
||||
emqx_ctl:print("ok~n");
|
||||
{error, already_existed} ->
|
||||
emqx_ctl:print("Error: already existed~n");
|
||||
|
@ -46,9 +46,10 @@ admins(["del", Username]) ->
|
|||
emqx_ctl:print("~p~n", [Status]);
|
||||
|
||||
admins(_) ->
|
||||
emqx_ctl:usage([{"admins add <Username> <Password> <Tags>", "Add dashboard user"},
|
||||
{"admins passwd <Username> <Password>", "Reset dashboard user password"},
|
||||
{"admins del <Username>", "Delete dashboard user" }]).
|
||||
emqx_ctl:usage(
|
||||
[{"admins add <Username> <Password> <Description>", "Add dashboard user"},
|
||||
{"admins passwd <Username> <Password>", "Reset dashboard user password"},
|
||||
{"admins del <Username>", "Delete dashboard user" }]).
|
||||
|
||||
unload() ->
|
||||
emqx_ctl:unregister_command(admins).
|
||||
|
|
|
@ -213,7 +213,7 @@ check_request_body(#{body := Body}, Schema, Module, CheckFun, true) ->
|
|||
check_request_body(#{body := Body}, Spec, _Module, CheckFun, false) ->
|
||||
lists:foldl(fun({Name, Type}, Acc) ->
|
||||
Schema = ?INIT_SCHEMA#{roots => [{Name, Type}]},
|
||||
maps:merge(Acc, CheckFun(Schema, Body, #{}))
|
||||
maps:merge(Acc, CheckFun(Schema, Body, #{override_env => false}))
|
||||
end, #{}, Spec).
|
||||
|
||||
%% tags, description, summary, security, deprecated
|
||||
|
|
|
@ -31,11 +31,14 @@
|
|||
|
||||
-define(CONTENT_TYPE, "application/x-www-form-urlencoded").
|
||||
|
||||
-define(HOST, "http://127.0.0.1:18083/").
|
||||
-define(HOST, "http://127.0.0.1:18083").
|
||||
|
||||
-define(API_VERSION, "v4").
|
||||
%% -define(API_VERSION, "v5").
|
||||
|
||||
-define(BASE_PATH, "api").
|
||||
-define(BASE_PATH, "/api/v5").
|
||||
|
||||
-define(APP_DASHBOARD, emqx_dashboard).
|
||||
-define(APP_MANAGEMENT, emqx_management).
|
||||
|
||||
-define(OVERVIEWS, ['alarms/activated',
|
||||
'alarms/deactivated',
|
||||
|
@ -51,9 +54,24 @@
|
|||
]).
|
||||
|
||||
all() ->
|
||||
%% TODO: V5 API
|
||||
% emqx_common_test_helpers:all(?MODULE).
|
||||
[t_cli, t_lookup_by_username_jwt, t_clean_expired_jwt].
|
||||
%% TODO: V5 API
|
||||
%% emqx_common_test_helpers:all(?MODULE).
|
||||
[t_cli, t_lookup_by_username_jwt, t_clean_expired_jwt, t_rest_api].
|
||||
|
||||
init_suite() ->
|
||||
init_suite([]).
|
||||
|
||||
init_suite(Apps) ->
|
||||
mria:start(),
|
||||
application:load(emqx_management),
|
||||
emqx_common_test_helpers:start_apps(Apps ++ [emqx_dashboard], fun set_special_configs/1).
|
||||
|
||||
end_suite() ->
|
||||
end_suite([]).
|
||||
|
||||
end_suite(Apps) ->
|
||||
application:unload(emqx_management),
|
||||
emqx_common_test_helpers:stop_apps(Apps ++ [emqx_dashboard]).
|
||||
|
||||
init_per_suite(Config) ->
|
||||
emqx_common_test_helpers:start_apps([emqx_management, emqx_dashboard],
|
||||
|
@ -66,23 +84,32 @@ end_per_suite(_Config) ->
|
|||
|
||||
set_special_configs(emqx_management) ->
|
||||
Listeners = [#{protocol => http, port => 8081}],
|
||||
emqx_config:put([emqx_management], #{listeners => Listeners,
|
||||
applications =>[#{id => "admin", secret => "public"}]}),
|
||||
Config = #{listeners => Listeners,
|
||||
applications => [#{id => "admin", secret => "public"}]},
|
||||
emqx_config:put([emqx_management], Config),
|
||||
ok;
|
||||
set_special_configs(emqx_dashboard) ->
|
||||
Listeners = [#{protocol => http, port => 18083}],
|
||||
Config = #{listeners => Listeners,
|
||||
default_username => <<"admin">>,
|
||||
default_password => <<"public">>
|
||||
},
|
||||
emqx_config:put([emqx_dashboard], Config),
|
||||
ok;
|
||||
set_special_configs(_) ->
|
||||
ok.
|
||||
|
||||
t_overview(_) ->
|
||||
mnesia:clear_table(?ADMIN),
|
||||
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, <<"tag">>),
|
||||
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, <<"simple_description">>),
|
||||
[?assert(request_dashboard(get, api_path(erlang:atom_to_list(Overview)),
|
||||
auth_header_()))|| Overview <- ?OVERVIEWS].
|
||||
auth_header_())) || Overview <- ?OVERVIEWS].
|
||||
|
||||
t_admins_add_delete(_) ->
|
||||
mnesia:clear_table(?ADMIN),
|
||||
Tag = <<"tag">>,
|
||||
ok = emqx_dashboard_admin:add_user(<<"username">>, <<"password">>, Tag),
|
||||
ok = emqx_dashboard_admin:add_user(<<"username1">>, <<"password1">>, Tag),
|
||||
Desc = <<"simple description">>,
|
||||
ok = emqx_dashboard_admin:add_user(<<"username">>, <<"password">>, Desc),
|
||||
ok = emqx_dashboard_admin:add_user(<<"username1">>, <<"password1">>, Desc),
|
||||
Admins = emqx_dashboard_admin:all_users(),
|
||||
?assertEqual(2, length(Admins)),
|
||||
ok = emqx_dashboard_admin:remove_user(<<"username1">>),
|
||||
|
@ -92,7 +119,7 @@ t_admins_add_delete(_) ->
|
|||
<<"password">>,
|
||||
<<"pwd">>),
|
||||
timer:sleep(10),
|
||||
Header = auth_header_("username", "pwd"),
|
||||
Header = auth_header_(<<"username">>, <<"pwd">>),
|
||||
?assert(request_dashboard(get, api_path("brokers"), Header)),
|
||||
|
||||
ok = emqx_dashboard_admin:remove_user(<<"username">>),
|
||||
|
@ -100,28 +127,22 @@ t_admins_add_delete(_) ->
|
|||
|
||||
t_rest_api(_Config) ->
|
||||
mnesia:clear_table(?ADMIN),
|
||||
Tag = <<"administrator">>,
|
||||
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, Tag),
|
||||
{ok, Res0} = http_get("users"),
|
||||
|
||||
Desc = <<"administrator">>,
|
||||
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, Desc),
|
||||
{ok, 200, Res0} = http_get(["users"]),
|
||||
?assertEqual([#{<<"username">> => <<"admin">>,
|
||||
<<"tags">> => <<"administrator">>}], get_http_data(Res0)),
|
||||
|
||||
AssertSuccess = fun({ok, Res}) ->
|
||||
?assertEqual(#{<<"code">> => 0}, json(Res))
|
||||
end,
|
||||
[AssertSuccess(R)
|
||||
|| R <- [ http_put("users/admin", #{<<"tags">> => <<"a_new_tag">>})
|
||||
, http_post("users", #{<<"username">> => <<"usera">>,
|
||||
<<"password">> => <<"passwd">>})
|
||||
, http_post("auth", #{<<"username">> => <<"usera">>,
|
||||
<<"password">> => <<"passwd">>})
|
||||
, http_delete("users/usera")
|
||||
, http_put("users/admin/change_pwd", #{<<"old_pwd">> => <<"public">>,
|
||||
<<"new_pwd">> => <<"newpwd">>})
|
||||
, http_post("auth", #{<<"username">> => <<"admin">>,
|
||||
<<"password">> => <<"newpwd">>})
|
||||
]],
|
||||
<<"description">> => <<"administrator">>}], get_http_data(Res0)),
|
||||
{ok, 200, _} = http_put(["users", "admin"], #{<<"description">> => <<"a_new_description">>}),
|
||||
{ok, 200, _} = http_post(["users"], #{<<"username">> => <<"usera">>,
|
||||
<<"password">> => <<"passwd">>,
|
||||
<<"description">> => Desc}),
|
||||
{ok, 204, _} = http_delete(["users", "usera"]),
|
||||
{ok, 404, _} = http_delete(["users", "usera"]),
|
||||
{ok, 204, _} = http_put( ["users", "admin", "change_pwd"]
|
||||
, #{<<"old_pwd">> => <<"public">>,
|
||||
<<"new_pwd">> => <<"newpwd">>}),
|
||||
mnesia:clear_table(?ADMIN),
|
||||
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, <<"administrator">>),
|
||||
ok.
|
||||
|
||||
t_cli(_Config) ->
|
||||
|
@ -175,17 +196,17 @@ bin(X) -> iolist_to_binary(X).
|
|||
random_num() ->
|
||||
erlang:system_time(nanosecond).
|
||||
|
||||
http_get(Path) ->
|
||||
request_api(get, api_path(Path), auth_header_()).
|
||||
http_get(Parts) ->
|
||||
request_api(get, api_path(Parts), auth_header_()).
|
||||
|
||||
http_delete(Path) ->
|
||||
request_api(delete, api_path(Path), auth_header_()).
|
||||
http_delete(Parts) ->
|
||||
request_api(delete, api_path(Parts), auth_header_()).
|
||||
|
||||
http_post(Path, Body) ->
|
||||
request_api(post, api_path(Path), [], auth_header_(), Body).
|
||||
http_post(Parts, Body) ->
|
||||
request_api(post, api_path(Parts), [], auth_header_(), Body).
|
||||
|
||||
http_put(Path, Body) ->
|
||||
request_api(put, api_path(Path), [], auth_header_(), Body).
|
||||
http_put(Parts, Body) ->
|
||||
request_api(put, api_path(Parts), [], auth_header_(), Body).
|
||||
|
||||
request_dashboard(Method, Url, Auth) ->
|
||||
Request = {Url, [Auth]},
|
||||
|
@ -198,21 +219,22 @@ do_request_dashboard(Method, Request)->
|
|||
case httpc:request(Method, Request, [], []) of
|
||||
{error, socket_closed_remotely} ->
|
||||
{error, socket_closed_remotely};
|
||||
{ok, {{"HTTP/1.1", 200, _}, _, _Return} } ->
|
||||
true;
|
||||
{ok, {{"HTTP/1.1", Code, _}, _Headers, Return} }
|
||||
when Code >= 200 andalso Code =< 299 ->
|
||||
{ok, Return};
|
||||
{ok, {Reason, _, _}} ->
|
||||
{error, Reason}
|
||||
end.
|
||||
|
||||
auth_header_() ->
|
||||
auth_header_("admin", "public").
|
||||
auth_header_(<<"admin">>, <<"public">>).
|
||||
|
||||
auth_header_(User, Pass) ->
|
||||
Encoded = base64:encode_to_string(lists:append([User,":",Pass])),
|
||||
{"Authorization","Basic " ++ Encoded}.
|
||||
auth_header_(Username, Password) ->
|
||||
{ok, Token} = emqx_dashboard_admin:sign_token(Username, Password),
|
||||
{"Authorization","Bearer " ++ binary_to_list(Token)}.
|
||||
|
||||
api_path(Path) ->
|
||||
?HOST ++ filename:join([?BASE_PATH, ?API_VERSION, Path]).
|
||||
api_path(Parts) ->
|
||||
?HOST ++ filename:join([?BASE_PATH | Parts]).
|
||||
|
||||
json(Data) ->
|
||||
{ok, Jsx} = emqx_json:safe_decode(Data, [return_maps]), Jsx.
|
||||
|
|
Loading…
Reference in New Issue