Merge pull request #9698 from thalesmg/sync-v4414-into-v44
Sync `v4.4.14` into `v44`
This commit is contained in:
commit
80a1c43a19
|
@ -1,6 +1,6 @@
|
|||
{application, emqx_management,
|
||||
[{description, "EMQ X Management API and CLI"},
|
||||
{vsn, "4.4.11"}, % strict semver, bump manually!
|
||||
{vsn, "4.4.12"}, % strict semver, bump manually!
|
||||
{modules, []},
|
||||
{registered, [emqx_management_sup]},
|
||||
{applications, [kernel,stdlib,emqx_plugin_libs,minirest]},
|
||||
|
|
|
@ -36,7 +36,6 @@
|
|||
, del_app/1
|
||||
, list_apps/0
|
||||
, init_bootstrap_apps/0
|
||||
, need_bootstrap/0
|
||||
, clear_bootstrap_apps/0
|
||||
]).
|
||||
|
||||
|
@ -83,21 +82,8 @@ add_default_app() ->
|
|||
end.
|
||||
|
||||
init_bootstrap_apps() ->
|
||||
case need_bootstrap() of
|
||||
true ->
|
||||
Bootstrap = application:get_env(emqx_management, bootstrap_apps_file, undefined),
|
||||
init_bootstrap_apps(Bootstrap);
|
||||
false ->
|
||||
ok
|
||||
end.
|
||||
|
||||
need_bootstrap() ->
|
||||
{atomic, Res} = mnesia:transaction(
|
||||
fun() ->
|
||||
Spec = [{#mqtt_app{id = '$1', desc = ?BOOTSTRAP_TAG, _ = '_'}, [], ['$1']}],
|
||||
mnesia:select(mqtt_app, Spec, 1, read) =:= '$end_of_table'
|
||||
end),
|
||||
Res.
|
||||
Bootstrap = application:get_env(emqx_management, bootstrap_apps_file, undefined),
|
||||
init_bootstrap_apps(Bootstrap).
|
||||
|
||||
clear_bootstrap_apps() ->
|
||||
{atomic, ok} =
|
||||
|
@ -113,13 +99,7 @@ init_bootstrap_apps(File) ->
|
|||
case file:open(File, [read, binary]) of
|
||||
{ok, Dev} ->
|
||||
{ok, MP} = re:compile(<<"(\.+):(\.+$)">>, [ungreedy]),
|
||||
case init_bootstrap_apps(File, Dev, MP) of
|
||||
ok -> ok;
|
||||
Error ->
|
||||
%% if failed add bootstrap users, we should clear all bootstrap apps
|
||||
clear_bootstrap_apps(),
|
||||
Error
|
||||
end;
|
||||
init_bootstrap_apps(File, Dev, MP);
|
||||
{error, Reason} = Error ->
|
||||
?LOG(error,
|
||||
"failed to open the mgmt bootstrap apps file(~s) for ~p",
|
||||
|
@ -145,8 +125,8 @@ add_bootstrap_app(File, Dev, MP, Line) ->
|
|||
case re:run(Bin, MP, [global, {capture, all_but_first, binary}]) of
|
||||
{match, [[AppId, AppSecret]]} ->
|
||||
Name = <<"bootstraped">>,
|
||||
case add_app(AppId, Name, AppSecret, ?BOOTSTRAP_TAG, true, undefined) of
|
||||
{ok, _} ->
|
||||
case force_add_app(AppId, Name, AppSecret, ?BOOTSTRAP_TAG, true, undefined) of
|
||||
ok ->
|
||||
add_bootstrap_app(File, Dev, MP, Line + 1);
|
||||
{error, Reason} ->
|
||||
throw(#{file => File, line => Line, content => Bin, reason => Reason})
|
||||
|
|
|
@ -66,6 +66,70 @@ t_importee430(_) ->
|
|||
{ok, _} = emqx_mgmt_data_backup:export(),
|
||||
remove_all_users_and_acl().
|
||||
|
||||
t_import_test(_) ->
|
||||
SimpleAdmin = <<"simpleAdmin">>,
|
||||
SimplePassword = <<"simplepassword">>,
|
||||
SimplePasswordHash = emqx_dashboard_admin:hash(SimplePassword),
|
||||
|
||||
Admins = [<<"Admin1">>, <<"Admin2">>, <<"Admin3">>, <<"Admin4">>, <<"Admin5">>],
|
||||
Passwords = [<<"password1">>, <<"PAssword2">>,<<"3&*)dkdKlkd">>,<<"&*qwl4kd>">>,<<"PASSWORD5D">>],
|
||||
|
||||
%% add some users
|
||||
add_admins(Admins, Passwords),
|
||||
%% Allow force import simple password.
|
||||
ok = emqx_dashboard_admin:force_add_user(SimpleAdmin, SimplePasswordHash, <<"test">>),
|
||||
|
||||
ct:pal("1111~p~n", [ets:info(mqtt_admin)]),
|
||||
ct:pal("~p~n", [ets:tab2list(mqtt_admin)]),
|
||||
check_admins_ok(Admins, Passwords),
|
||||
|
||||
{ok, #{filename := FileName}} = emqx_mgmt_data_backup:export(),
|
||||
|
||||
remove_admins(Admins),
|
||||
ok = emqx_dashboard_admin:remove_user(SimpleAdmin),
|
||||
ct:pal("0000~n"),
|
||||
check_admins_failed(Admins, Passwords),
|
||||
{error, _} = emqx_dashboard_admin:check(SimpleAdmin, SimplePassword),
|
||||
|
||||
ok = emqx_mgmt_data_backup:import(FileName, <<"{}">>),
|
||||
ct:pal("2222~n"),
|
||||
check_admins_ok(Admins, Passwords),
|
||||
ok = emqx_dashboard_admin:check(SimpleAdmin, SimplePassword),
|
||||
|
||||
remove_admins(Admins),
|
||||
ok = emqx_dashboard_admin:remove_user(SimpleAdmin),
|
||||
|
||||
remove_all_users_and_acl(),
|
||||
ok.
|
||||
|
||||
add_admins(Admins, Passwords) ->
|
||||
lists:foreach(
|
||||
fun({Admin, Password}) ->
|
||||
ok = emqx_dashboard_admin:add_user(Admin, Password, <<"test">>)
|
||||
end, lists:zip(Admins, Passwords)),
|
||||
ok.
|
||||
|
||||
check_admins_ok(Admins, Passwords) ->
|
||||
lists:foreach(
|
||||
fun({Admin, Password}) ->
|
||||
?assertMatch(ok, emqx_dashboard_admin:check(Admin, Password), {Admin, Password})
|
||||
end, lists:zip(Admins, Passwords)),
|
||||
ok.
|
||||
|
||||
check_admins_failed(Admins, Passwords) ->
|
||||
lists:foreach(
|
||||
fun({Admin, Password}) ->
|
||||
?assertMatch({error, _}, emqx_dashboard_admin:check(Admin, Password), {Admin, Password})
|
||||
end, lists:zip(Admins, Passwords)),
|
||||
ok.
|
||||
|
||||
remove_admins(Admins) ->
|
||||
lists:foreach(
|
||||
fun(Admin) ->
|
||||
ok = emqx_dashboard_admin:remove_user(Admin)
|
||||
end, Admins),
|
||||
ok.
|
||||
|
||||
remove_all_users_and_acl() ->
|
||||
mnesia:delete_table(emqx_user),
|
||||
mnesia:delete_table(emqx_acl).
|
||||
|
|
|
@ -68,10 +68,10 @@ t_load_ok(_) ->
|
|||
ok = file:write_file(File, Bin1),
|
||||
application:set_env(emqx_management, bootstrap_apps_file, File),
|
||||
{ok, _} = application:ensure_all_started(emqx_management),
|
||||
?assert(emqx_mgmt_auth:is_authorized(<<"test-1">>, <<"secret-1">>)),
|
||||
?assert(emqx_mgmt_auth:is_authorized(<<"test-2">>, <<"secret-2">>)),
|
||||
?assertNot(emqx_mgmt_auth:is_authorized(<<"test-1">>, <<"new-secret-1">>)),
|
||||
?assertNot(emqx_mgmt_auth:is_authorized(<<"test-2">>, <<"new-secret-2">>)),
|
||||
?assertNot(emqx_mgmt_auth:is_authorized(<<"test-1">>, <<"secret-1">>)),
|
||||
?assertNot(emqx_mgmt_auth:is_authorized(<<"test-2">>, <<"secret-2">>)),
|
||||
?assert(emqx_mgmt_auth:is_authorized(<<"test-1">>, <<"new-secret-1">>)),
|
||||
?assert(emqx_mgmt_auth:is_authorized(<<"test-2">>, <<"new-secret-2">>)),
|
||||
application:stop(emqx_management).
|
||||
|
||||
t_bootstrap_user_file_not_found(_) ->
|
||||
|
@ -84,13 +84,17 @@ t_load_invalid_username_failed(_) ->
|
|||
File = "./bootstrap_apps.txt",
|
||||
ok = file:write_file(File, Bin),
|
||||
check_load_failed(File),
|
||||
?assert(emqx_mgmt_auth:is_authorized(<<"test-1">>, <<"password-1">>)),
|
||||
?assertNot(emqx_mgmt_auth:is_authorized(<<"test&2">>, <<"password-2">>)),
|
||||
ok.
|
||||
|
||||
t_load_invalid_format_failed(_) ->
|
||||
Bin = <<"test-1:password-1\ntest-2password-2">>,
|
||||
Bin = <<"test-1:password-1\ntest-2 password-2">>,
|
||||
File = "./bootstrap_apps.txt",
|
||||
ok = file:write_file(File, Bin),
|
||||
check_load_failed(File),
|
||||
?assert(emqx_mgmt_auth:is_authorized(<<"test-1">>, <<"password-1">>)),
|
||||
?assertNot(emqx_mgmt_auth:is_authorized(<<"test-2">>, <<"password-2">>)),
|
||||
ok.
|
||||
|
||||
check_load_failed(File) ->
|
||||
|
@ -98,5 +102,4 @@ check_load_failed(File) ->
|
|||
application:stop(emqx_management),
|
||||
application:set_env(emqx_management, bootstrap_apps_file, File),
|
||||
?assertMatch({error, _}, application:ensure_all_started(emqx_management)),
|
||||
?assertNot(lists:member(emqx_management, application:which_applications())),
|
||||
?assert(emqx_mgmt_auth:need_bootstrap()).
|
||||
?assertNot(lists:member(emqx_management, application:which_applications())).
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
# v4.4.14
|
||||
|
||||
## Enhancements
|
||||
- Add a password complexity requirement when adding or modifying Dashboard users via the API. Now passwords must contain at least 2 of alphabetic, numeric and special characters, and must be 8 to 64 characters long [#9696](https://github.com/emqx/emqx/pull/9696).
|
||||
|
||||
## Bug fixes
|
||||
|
||||
## Bug Fixes
|
||||
- Fix dashboard password validator is too simple. Now dashboard password must contain at least two different kind of characters from groups of letters, numbers and special characters. [#9696](https://github.com/emqx/emqx/pull/9696).
|
||||
- Fix the problem that adding or importing Dashboard users via the API fails to add complex passwords due to incorrect checksum of the passwords [#9692](https://github.com/emqx/emqx/pull/9692).
|
||||
|
||||
- Fix load bootstrap_app_file's apps is not sync when reboot. [#9692](https://github.com/emqx/emqx/pull/9692).
|
||||
|
|
|
@ -2,5 +2,10 @@
|
|||
|
||||
## 增强
|
||||
|
||||
- 通过 API 添加、修改 Dashboard 用户时,增加对密码复杂度的要求。现在密码必须包含字母、数字以及特殊字符中的至少 2 种,并且长度范围必须是 8~64 个字符 [#9696](https://github.com/emqx/emqx/pull/9696)。
|
||||
|
||||
## 修复
|
||||
|
||||
- 修复通过 API 添加或者导入 Dashboard 用户时,对密码进行了错误的校验,导致复杂密码添加失败的问题 [#9696](https://github.com/emqx/emqx/pull/9696)。
|
||||
|
||||
- 修复 boostrap_apps_file 文件更新后未同步至数据库,导致变更的 apps 无法生效 [#9692](https://github.com/emqx/emqx/pull/9692)。
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
-ifndef(EMQX_ENTERPRISE).
|
||||
|
||||
-define(EMQX_RELEASE, {opensource, "4.4.14-alpha.1"}).
|
||||
-define(EMQX_RELEASE, {opensource, "4.4.14"}).
|
||||
|
||||
-else.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{application, emqx_dashboard,
|
||||
[{description, "EMQX Web Dashboard"},
|
||||
{vsn, "4.4.13"}, % strict semver, bump manually!
|
||||
{vsn, "4.4.14"}, % strict semver, bump manually!
|
||||
{modules, []},
|
||||
{registered, [emqx_dashboard_sup]},
|
||||
{applications, [kernel,stdlib,mnesia,minirest]},
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
-include("emqx_dashboard.hrl").
|
||||
-include_lib("emqx/include/logger.hrl").
|
||||
-define(DEFAULT_PASSWORD, <<"public">>).
|
||||
-define(INVALID_PASSWORD_MSG, <<"The password must contain at least two different kind of characters from groups of letters, numbers, and special characters. For example, if password is composed from letters, it must contain at least one number or a special character.">>).
|
||||
|
||||
-boot_mnesia({mnesia, [boot]}).
|
||||
-copy_mnesia({mnesia, [copy]}).
|
||||
|
@ -41,8 +42,10 @@
|
|||
, lookup_user/1
|
||||
, change_password/2
|
||||
, change_password/3
|
||||
, force_change_password/2
|
||||
, all_users/0
|
||||
, check/2
|
||||
, hash/1
|
||||
]).
|
||||
|
||||
%% gen_server Function Exports
|
||||
|
@ -79,7 +82,7 @@ start_link() ->
|
|||
|
||||
-spec(add_user(binary(), binary(), binary()) -> ok | {error, any()}).
|
||||
add_user(Username, Password, Tags) when is_binary(Username), is_binary(Password) ->
|
||||
case {emqx_misc:is_sane_id(Username), emqx_misc:is_sane_id(Password, 2, 32)} of
|
||||
case {emqx_misc:is_sane_id(Username), is_valid_pwd(Password)} of
|
||||
{ok, ok} ->
|
||||
Admin = #mqtt_admin{username = Username, password = hash(Password), tags = Tags},
|
||||
return(mnesia:transaction(fun add_user_/1, [Admin]));
|
||||
|
@ -88,17 +91,12 @@ add_user(Username, Password, Tags) when is_binary(Username), is_binary(Password)
|
|||
end.
|
||||
|
||||
force_add_user(Username, Password, Tags) ->
|
||||
case {emqx_misc:is_sane_id(Username), emqx_misc:is_sane_id(Password, 2, 32)} of
|
||||
{ok, ok} ->
|
||||
AddFun = fun() ->
|
||||
mnesia:write(#mqtt_admin{username = Username, password = Password, tags = Tags})
|
||||
end,
|
||||
case mnesia:transaction(AddFun) of
|
||||
{atomic, ok} -> ok;
|
||||
{aborted, Reason} -> {error, Reason}
|
||||
end;
|
||||
{{error, Reason}, _} -> {error, Reason};
|
||||
{_, {error, Reason}} -> {error, Reason}
|
||||
AddFun = fun() ->
|
||||
mnesia:write(#mqtt_admin{username = Username, password = Password, tags = Tags})
|
||||
end,
|
||||
case mnesia:transaction(AddFun) of
|
||||
{atomic, ok} -> ok;
|
||||
{aborted, Reason} -> {error, Reason}
|
||||
end.
|
||||
|
||||
%% @private
|
||||
|
@ -138,6 +136,12 @@ change_password(Username, OldPasswd, NewPasswd) when is_binary(Username) ->
|
|||
end.
|
||||
|
||||
change_password(Username, Password) when is_binary(Username), is_binary(Password) ->
|
||||
case is_valid_pwd(Password) of
|
||||
ok -> change_password_hash(Username, hash(Password));
|
||||
{error, Error} -> {error, Error}
|
||||
end.
|
||||
|
||||
force_change_password(Username, Password) when is_binary(Username), is_binary(Password) ->
|
||||
change_password_hash(Username, hash(Password)).
|
||||
|
||||
change_password_hash(Username, PasswordHash) ->
|
||||
|
@ -145,6 +149,37 @@ change_password_hash(Username, PasswordHash) ->
|
|||
User#mqtt_admin{password = PasswordHash}
|
||||
end).
|
||||
|
||||
-define(LOW_LETTER_CHARS, "abcdefghijklmnopqrstuvwxyz").
|
||||
-define(UPPER_LETTER_CHARS, "ABCDEFGHIJKLMNOPQRSTUVWXYZ").
|
||||
-define(LETTER, ?LOW_LETTER_CHARS ++ ?UPPER_LETTER_CHARS).
|
||||
-define(NUMBER, "0123456789").
|
||||
-define(SPECIAL_CHARS, "!@#$%^&*()_+-=[]{}\"|;':,./<>?`~ ").
|
||||
|
||||
is_valid_pwd(Password) when is_binary(Password) ->
|
||||
is_valid_pwd(binary_to_list(Password));
|
||||
is_valid_pwd(Password) ->
|
||||
Len = erlang:length(Password),
|
||||
case Len >= 8 andalso Len =< 64 of
|
||||
true ->
|
||||
Letter = contain(Password, ?LETTER),
|
||||
Number = contain(Password, ?NUMBER),
|
||||
Special = contain(Password, ?SPECIAL_CHARS),
|
||||
OK = lists:filter(fun(C) -> C end, [Letter, Number, Special]),
|
||||
case length(OK) >= 2 of
|
||||
true ->
|
||||
%% regex-any-ascii-character
|
||||
case re:run(Password, "[^\\x00-\\x7F]+", [unicode, {capture, none}]) of
|
||||
match -> {error, <<"only ascii characters are allowed in the password">>};
|
||||
nomatch -> ok
|
||||
end;
|
||||
_ -> {error, ?INVALID_PASSWORD_MSG}
|
||||
end;
|
||||
false ->
|
||||
{error, <<"The password length: 8-64">>}
|
||||
end.
|
||||
|
||||
contain(Xs, Spec) -> lists:any(fun(X) -> lists:member(X, Spec) end, Xs).
|
||||
|
||||
update_pwd(Username, Fun) ->
|
||||
Trans = fun() ->
|
||||
User =
|
||||
|
@ -317,3 +352,36 @@ maybe_warn_default_pwd() ->
|
|||
false ->
|
||||
ok
|
||||
end.
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
password_test() ->
|
||||
?assertEqual({error, <<"The password length: 8-64">>}, is_valid_pwd(<<"123">>)),
|
||||
MaxPassword = iolist_to_binary([lists:duplicate(63, "x"), "1"]),
|
||||
?assertEqual(ok, is_valid_pwd(MaxPassword)),
|
||||
TooLongPassword = lists:duplicate(65, "y"),
|
||||
?assertEqual({error, <<"The password length: 8-64">>}, is_valid_pwd(TooLongPassword)),
|
||||
|
||||
?assertEqual({error, ?INVALID_PASSWORD_MSG}, is_valid_pwd(<<"12345678">>)),
|
||||
?assertEqual({error, ?INVALID_PASSWORD_MSG}, is_valid_pwd(?LETTER)),
|
||||
?assertEqual({error, ?INVALID_PASSWORD_MSG}, is_valid_pwd(?NUMBER)),
|
||||
?assertEqual({error, ?INVALID_PASSWORD_MSG}, is_valid_pwd(?SPECIAL_CHARS)),
|
||||
?assertEqual({error, ?INVALID_PASSWORD_MSG}, is_valid_pwd(<<"映映映映无天在请"/utf8>>)),
|
||||
?assertEqual({error, <<"only ascii characters are allowed in the password">>}, is_valid_pwd(<<"️test_for_non_ascii1中"/utf8>>)),
|
||||
?assertEqual({error, <<"only ascii characters are allowed in the password">>}, is_valid_pwd(<<"云☁️test_for_unicode"/utf8>>)),
|
||||
|
||||
?assertEqual(ok, is_valid_pwd(?LOW_LETTER_CHARS ++ ?NUMBER)),
|
||||
?assertEqual(ok, is_valid_pwd(?UPPER_LETTER_CHARS ++ ?NUMBER)),
|
||||
?assertEqual(ok, is_valid_pwd(?LOW_LETTER_CHARS ++ ?SPECIAL_CHARS)),
|
||||
?assertEqual(ok, is_valid_pwd(?UPPER_LETTER_CHARS ++ ?SPECIAL_CHARS)),
|
||||
?assertEqual(ok, is_valid_pwd(?SPECIAL_CHARS ++ ?NUMBER)),
|
||||
|
||||
?assertEqual(ok, is_valid_pwd(<<"abckldiekflkdf12">>)),
|
||||
?assertEqual(ok, is_valid_pwd(<<"abckldiekflkdf w">>)),
|
||||
?assertEqual(ok, is_valid_pwd(<<"# abckldiekflkdf w">>)),
|
||||
?assertEqual(ok, is_valid_pwd(<<"# 12344858">>)),
|
||||
?assertEqual(ok, is_valid_pwd(<<"# %12344858">>)),
|
||||
ok.
|
||||
|
||||
-endif.
|
||||
|
|
|
@ -71,7 +71,7 @@ init_per_testcase(Case, Config) ->
|
|||
|
||||
end_per_testcase(Case, Config) ->
|
||||
%% revert to default password
|
||||
emqx_dashboard_admin:change_password(<<"admin">>, <<"public">>),
|
||||
emqx_dashboard_admin:force_change_password(<<"admin">>, <<"public">>),
|
||||
?MODULE:Case({'end', Config}).
|
||||
|
||||
t_overview({init, Config}) -> Config;
|
||||
|
@ -85,35 +85,36 @@ t_admins_add_delete(_) ->
|
|||
?assertEqual({error,<<"0 < Length =< 256">>},
|
||||
emqx_dashboard_admin:add_user(<<"">>, <<"password">>, <<"tag1">>)),
|
||||
|
||||
?assertEqual({error,<<"2 < Length =< 32">>},
|
||||
?assertEqual({error,<<"The password length: 8-64">>},
|
||||
emqx_dashboard_admin:add_user(<<"badusername">>, <<"">>, <<"tag1">>)),
|
||||
?assertEqual({error,<<"2 < Length =< 32">>},
|
||||
?assertEqual({error,<<"The password length: 8-64">>},
|
||||
emqx_dashboard_admin:add_user(<<"badusername">>, <<"p">>, <<"tag1">>)),
|
||||
P33 = iolist_to_binary(lists:duplicate(33, <<"p">>)),
|
||||
?assertEqual({error,<<"2 < Length =< 32">>},
|
||||
emqx_dashboard_admin:add_user(<<"badusername">>, P33, <<"tag1">>)),
|
||||
P32 = iolist_to_binary(lists:duplicate(32, <<"p">>)),
|
||||
?assertEqual(ok, emqx_dashboard_admin:add_user(<<"goodusername">>, P32, <<"tag1">>)),
|
||||
P65 = iolist_to_binary(lists:duplicate(65, <<"p">>)),
|
||||
?assertEqual({error,<<"The password length: 8-64">>},
|
||||
emqx_dashboard_admin:add_user(<<"badusername">>, P65, <<"tag1">>)),
|
||||
P64 = iolist_to_binary([<<"1">> | lists:duplicate(63, <<"p">>)]),
|
||||
?assertEqual(ok, emqx_dashboard_admin:add_user(<<"goodusername">>, P64, <<"tag1">>)),
|
||||
ok = emqx_dashboard_admin:remove_user(<<"goodusername">>),
|
||||
|
||||
ok = emqx_dashboard_admin:add_user(<<"username">>, <<"password">>, <<"tag">>),
|
||||
ok = emqx_dashboard_admin:add_user(<<"username1">>, <<"password1">>, <<"tag1">>),
|
||||
ok = emqx_dashboard_admin:add_user(<<"username1">>, <<"password1">>, <<"tag">>),
|
||||
ok = emqx_dashboard_admin:add_user(<<"username2">>, <<"password2">>, <<"tag1">>),
|
||||
ok = emqx_dashboard_admin:add_user(<<"1username1">>, <<"password1">>, <<"tag1">>),
|
||||
{error, _} = emqx_dashboard_admin:add_user(<<"u/sername1">>, <<"password1">>, <<"tag1">>),
|
||||
{error, _} = emqx_dashboard_admin:add_user(<<"/username1">>, <<"password1">>, <<"tag1">>),
|
||||
Admins = emqx_dashboard_admin:all_users(),
|
||||
?assertEqual(4, length(Admins)),
|
||||
ok = emqx_dashboard_admin:remove_user(<<"username1">>),
|
||||
ok = emqx_dashboard_admin:remove_user(<<"username2">>),
|
||||
ok = emqx_dashboard_admin:remove_user(<<"1username1">>),
|
||||
Users = emqx_dashboard_admin:all_users(),
|
||||
?assertEqual(2, length(Users)),
|
||||
ok = emqx_dashboard_admin:change_password(<<"username">>, <<"password">>, <<"pwd">>),
|
||||
{error, _} = emqx_dashboard_admin:change_password(<<"username1">>, <<"password1">>, <<"password">>),
|
||||
ok = emqx_dashboard_admin:change_password(<<"username1">>, <<"password1">>, <<"password+">>),
|
||||
timer:sleep(10),
|
||||
?assert(request_dashboard(get, api_path("brokers"), auth_header_("username", "pwd"))),
|
||||
?assert(request_dashboard(get, api_path("brokers"), auth_header_("username1", "password+"))),
|
||||
|
||||
ok = emqx_dashboard_admin:remove_user(<<"username">>),
|
||||
ok = emqx_dashboard_admin:remove_user(<<"username1">>),
|
||||
?assertNotEqual(true, request_dashboard(get, api_path("brokers"),
|
||||
auth_header_("username", "pwd"))).
|
||||
auth_header_("username1", "password+"))).
|
||||
|
||||
t_admins_persist_default_password({init, Config}) -> Config;
|
||||
t_admins_persist_default_password({'end', _Config}) -> ok;
|
||||
|
@ -212,16 +213,19 @@ t_rest_api(_Config) ->
|
|||
?assert(lists:member(#{<<"username">> => <<"admin">>, <<"tags">> => <<"administrator">>},
|
||||
Users)),
|
||||
|
||||
{ok, ErrorRes} = http_put("change_pwd/admin", [{<<"old_pwd">>, <<"public">>}, {<<"new_pwd">>, <<"simplepwd">>}]),
|
||||
?assertMatch(#{<<"message">> := _}, json(ErrorRes)),
|
||||
|
||||
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("change_pwd/admin", #{<<"old_pwd">> => <<"public">>, <<"new_pwd">> => <<"newpwd">>})
|
||||
, http_post("auth", #{<<"username">> => <<"admin">>, <<"password">> => <<"newpwd">>})
|
||||
, http_post("users", #{<<"username">> => <<"username1">>, <<"password">> => <<"passwd+123">>})
|
||||
, http_post("auth", #{<<"username">> => <<"username1">>, <<"password">> => <<"passwd+123">>})
|
||||
, http_delete("users/username1")
|
||||
, http_put("change_pwd/admin", #{<<"old_pwd">> => <<"public">>, <<"new_pwd">> => <<"newpwd+123">>})
|
||||
, http_post("auth", #{<<"username">> => <<"admin">>, <<"password">> => <<"newpwd+123">>})
|
||||
]],
|
||||
ok.
|
||||
|
||||
|
@ -236,18 +240,18 @@ t_cli({init, Config}) -> Config;
|
|||
t_cli({'end', _Config}) -> ok;
|
||||
t_cli(_Config) ->
|
||||
[mnesia:dirty_delete({mqtt_admin, Admin}) || Admin <- mnesia:dirty_all_keys(mqtt_admin)],
|
||||
emqx_dashboard_cli:admins(["add", "username", "password"]),
|
||||
emqx_dashboard_cli:admins(["add", "username", "password1"]),
|
||||
[{mqtt_admin, <<"username">>, <<Salt:4/binary, Hash/binary>>, _}] =
|
||||
emqx_dashboard_admin:lookup_user(<<"username">>),
|
||||
?assertEqual(Hash, erlang:md5(<<Salt/binary, <<"password">>/binary>>)),
|
||||
emqx_dashboard_cli:admins(["passwd", "username", "newpassword"]),
|
||||
?assertEqual(Hash, erlang:md5(<<Salt/binary, <<"password1">>/binary>>)),
|
||||
emqx_dashboard_cli:admins(["passwd", "username", "newpassword1"]),
|
||||
[{mqtt_admin, <<"username">>, <<Salt1:4/binary, Hash1/binary>>, _}] =
|
||||
emqx_dashboard_admin:lookup_user(<<"username">>),
|
||||
?assertEqual(Hash1, erlang:md5(<<Salt1/binary, <<"newpassword">>/binary>>)),
|
||||
?assertEqual(Hash1, erlang:md5(<<Salt1/binary, <<"newpassword1">>/binary>>)),
|
||||
emqx_dashboard_cli:admins(["del", "username"]),
|
||||
[] = emqx_dashboard_admin:lookup_user(<<"username">>),
|
||||
emqx_dashboard_cli:admins(["add", "admin1", "pass1"]),
|
||||
emqx_dashboard_cli:admins(["add", "admin2", "passw2"]),
|
||||
emqx_dashboard_cli:admins(["add", "admin1", "password+1"]),
|
||||
emqx_dashboard_cli:admins(["add", "admin2", "password+2"]),
|
||||
AdminList = emqx_dashboard_admin:all_users(),
|
||||
?assertEqual(2, length(AdminList)).
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ case "${PKG_VSN}" in
|
|||
;;
|
||||
4.4*)
|
||||
# keep the above 4.3 untouched, otherwise conflicts!
|
||||
EMQX_CE_DASHBOARD_VERSION='v4.4.7'
|
||||
EMQX_CE_DASHBOARD_VERSION='v4.4.8'
|
||||
EMQX_EE_DASHBOARD_VERSION='v4.4.18'
|
||||
;;
|
||||
*)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
%% the emqx `release' version, which in turn is comprised of several
|
||||
%% apps, one of which is this. See `emqx_release.hrl' for more
|
||||
%% info.
|
||||
{vsn, "4.4.14"}, % strict semver, bump manually!
|
||||
{vsn, "4.4.15"}, % strict semver, bump manually!
|
||||
{modules, []},
|
||||
{registered, []},
|
||||
{applications, [ kernel
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
%% -*- mode: erlang -*-
|
||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||
{VSN,
|
||||
[{"4.4.13",
|
||||
[{load_module,emqx_rule_actions_trans,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
[{"4.4.14",
|
||||
[{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_rule_actions_trans,brutal_purge,soft_purge,[]}]},
|
||||
{"4.4.13",
|
||||
[{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_rule_actions_trans,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_relup,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||
{"4.4.12",
|
||||
[{load_module,emqx_rule_actions_trans,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_rule_actions_trans,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_relup,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||
|
@ -412,14 +416,18 @@
|
|||
{apply,{application,set_env,
|
||||
[gen_rpc,insecure_auth_fallback_allowed,true]}}]},
|
||||
{<<".*">>,[]}],
|
||||
[{"4.4.13",
|
||||
[{load_module,emqx_rule_actions_trans,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
[{"4.4.14",
|
||||
[{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_rule_actions_trans,brutal_purge,soft_purge,[]}]},
|
||||
{"4.4.13",
|
||||
[{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_rule_actions_trans,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_relup,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||
{"4.4.12",
|
||||
[{load_module,emqx_rule_actions_trans,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_rule_actions_trans,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_relup,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_app,brutal_purge,soft_purge,[]}]},
|
||||
|
|
Loading…
Reference in New Issue