diff --git a/apps/emqx_management/src/emqx_management.app.src b/apps/emqx_management/src/emqx_management.app.src index 3eb690bdb..fe927c097 100644 --- a/apps/emqx_management/src/emqx_management.app.src +++ b/apps/emqx_management/src/emqx_management.app.src @@ -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]}, diff --git a/apps/emqx_management/src/emqx_mgmt_auth.erl b/apps/emqx_management/src/emqx_mgmt_auth.erl index 37e3a4f90..a30ddb250 100644 --- a/apps/emqx_management/src/emqx_mgmt_auth.erl +++ b/apps/emqx_management/src/emqx_mgmt_auth.erl @@ -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}) diff --git a/apps/emqx_management/test/emqx_auth_mnesia_data_export_import_SUITE.erl b/apps/emqx_management/test/emqx_auth_mnesia_data_export_import_SUITE.erl index cce4ca85f..ac95d848b 100644 --- a/apps/emqx_management/test/emqx_auth_mnesia_data_export_import_SUITE.erl +++ b/apps/emqx_management/test/emqx_auth_mnesia_data_export_import_SUITE.erl @@ -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). diff --git a/apps/emqx_management/test/emqx_mgmt_bootstrap_app_SUITE.erl b/apps/emqx_management/test/emqx_mgmt_bootstrap_app_SUITE.erl index 9509a0948..af7c5cd57 100644 --- a/apps/emqx_management/test/emqx_mgmt_bootstrap_app_SUITE.erl +++ b/apps/emqx_management/test/emqx_mgmt_bootstrap_app_SUITE.erl @@ -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())). diff --git a/changes/v4.4.14-en.md b/changes/v4.4.14-en.md index be84952b4..838cc1c54 100644 --- a/changes/v4.4.14-en.md +++ b/changes/v4.4.14-en.md @@ -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). diff --git a/changes/v4.4.14-zh.md b/changes/v4.4.14-zh.md index 38c5ca30f..d0e28290a 100644 --- a/changes/v4.4.14-zh.md +++ b/changes/v4.4.14-zh.md @@ -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)。 diff --git a/include/emqx_release.hrl b/include/emqx_release.hrl index 68728047d..bba0303d1 100644 --- a/include/emqx_release.hrl +++ b/include/emqx_release.hrl @@ -29,7 +29,7 @@ -ifndef(EMQX_ENTERPRISE). --define(EMQX_RELEASE, {opensource, "4.4.14-alpha.1"}). +-define(EMQX_RELEASE, {opensource, "4.4.14"}). -else. diff --git a/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl b/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl index fe92796ab..9554a7731 100644 --- a/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl +++ b/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl @@ -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. diff --git a/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl b/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl index 9723a51f9..e10cdfc0b 100644 --- a/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl +++ b/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl @@ -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">>, <>, _}] = emqx_dashboard_admin:lookup_user(<<"username">>), - ?assertEqual(Hash, erlang:md5(<>/binary>>)), - emqx_dashboard_cli:admins(["passwd", "username", "newpassword"]), + ?assertEqual(Hash, erlang:md5(<>/binary>>)), + emqx_dashboard_cli:admins(["passwd", "username", "newpassword1"]), [{mqtt_admin, <<"username">>, <>, _}] = emqx_dashboard_admin:lookup_user(<<"username">>), - ?assertEqual(Hash1, erlang:md5(<>/binary>>)), + ?assertEqual(Hash1, erlang:md5(<>/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)). diff --git a/scripts/get-dashboard.sh b/scripts/get-dashboard.sh index 07bb60382..b4d08c216 100755 --- a/scripts/get-dashboard.sh +++ b/scripts/get-dashboard.sh @@ -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' ;; *) diff --git a/src/emqx.appup.src b/src/emqx.appup.src index 7d766cf05..e782a181b 100644 --- a/src/emqx.appup.src +++ b/src/emqx.appup.src @@ -2,14 +2,11 @@ %% 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,[]}, + [{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_cm,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.11", @@ -413,14 +410,11 @@ [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,[]}, + [{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_cm,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.11",