diff --git a/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl b/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl index e19ea48bc..505c468cd 100644 --- a/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl +++ b/lib-ce/emqx_dashboard/src/emqx_dashboard_admin.erl @@ -158,7 +158,8 @@ update_pwd(Username, Fun) -> lookup_user(Username) when is_binary(Username) -> case binenv(default_user_username) of Username -> - [#mqtt_admin{username=Username, password=hashed_default_passwd()}]; + Password = hashed_default_passwd(), + [#mqtt_admin{username=Username, password=Password, tags= <<"administrator">>}]; _ -> mnesia:dirty_read(mqtt_admin, Username) end. @@ -193,6 +194,7 @@ check(Username, Password) -> init([]) -> %% Add default admin user {ok, _} = mnesia:subscribe({table, mqtt_admin, simple}), + add_default_user_hashed(binenv(default_user_username), hashed_default_passwd()), {ok, state}. handle_call(_Req, _From, State) -> @@ -240,13 +242,24 @@ salt() -> binenv(Key) -> iolist_to_binary(application:get_env(emqx_dashboard, Key, <<>>)). +add_default_user_hashed(Username, HashedPassword) -> + case mnesia:dirty_read(mqtt_admin, Username) of + [] -> + Admin = #mqtt_admin{username=Username, password=HashedPassword, tags= <<"administrator">>}, + return(mnesia:transaction(fun add_user_/1, [Admin])); + _ -> ok + end. + hashed_default_passwd() -> case binenv(default_user_passwd_hashed) of Empty0 when ?EMPTY_KEY(Empty0) -> case binenv(default_user_passwd) of Empty when ?EMPTY_KEY(Empty) -> undefined; - Password -> hash(Password) + Password -> + Hashed = hash(Password), + application:set_env(emqx_dashboard, default_user_passwd_hashed, Hashed), + Hashed end; HashedPassword -> HashedPassword end. diff --git a/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl b/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl index 013e5707f..28d80ae7d 100644 --- a/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl +++ b/lib-ce/emqx_dashboard/test/emqx_dashboard_SUITE.erl @@ -52,8 +52,8 @@ all() -> groups() -> [ {overview, [sequence], [t_overview]}, - {admins, [sequence], [t_default_password_persists_after_leaving_cluster]}, - {rest, [sequence], [t_rest_api, t_auth_exhaustive_attack]}, + {admins, [sequence], [t_admins_add_delete, t_admins_persist_default_password, t_default_password_persists_after_leaving_cluster]}, + {rest, [sequence], [t_rest_api]}, {cli, [sequence], [t_cli]} ]. @@ -90,10 +90,14 @@ t_admins_add_delete(_) -> t_admins_persist_default_password(_) -> emqx_dashboard_admin:change_password(<<"admin">>, <<"new_password">>), - [#mqtt_admin{password=Password}] = emqx_dashboard_admin:lookup_user(<<"admin">>), + ct:sleep(100), + [#mqtt_admin{password=Password, tags= <<"administrator">>}] = emqx_dashboard_admin:lookup_user(<<"admin">>), %% To ensure that state persists even if the process dies - exit(whereis(emqx_dashboard_admin), kill), + application:stop(emqx_dashboard), + application:start(emqx_dashboard), + + ct:sleep(100), %% It get's restarted by the app automatically [#mqtt_admin{password=PasswordAfterRestart}] = emqx_dashboard_admin:lookup_user(<<"admin">>), @@ -147,6 +151,14 @@ t_default_password_persists_after_leaving_cluster(_) -> debug(2, Slave), + rpc:call(Slave, application, stop, [emqx_dashboard]), + + debug(3, Slave), + + rpc:call(Slave, application, start, [emqx_dashboard]), + + debug(4, Slave), + ?assertEqual( ok, rpc:call(Slave, emqx_dashboard_admin, check, [<<"admin">>, <<"new_password">>])), @@ -162,6 +174,7 @@ t_default_password_persists_after_leaving_cluster(_) -> t_rest_api(_Config) -> {ok, Res0} = http_get("users"), Users = get_http_data(Res0), + ct:pal("~p", [emqx_dashboard_admin:all_users()]), ?assert(lists:member(#{<<"username">> => <<"admin">>, <<"tags">> => <<"administrator">>}, Users)), @@ -277,7 +290,6 @@ setup_node(Node, Apps) -> fun(emqx) -> application:set_env(emqx, listeners, []), application:set_env(gen_rpc, port_discovery, manual), - mnesia:info(), ok; (emqx_management) -> application:set_env(emqx_management, listeners, []), diff --git a/src/emqx.erl b/src/emqx.erl index ff369e599..7fb3c734f 100644 --- a/src/emqx.erl +++ b/src/emqx.erl @@ -234,7 +234,7 @@ shutdown(Reason) -> ). reboot() -> - case application_controller:is_running(emqx_dashboard) of + case is_application_running(emqx_dashboard) of true -> application:stop(emqx_dashboard), %% dashboard must be started after mnesia lists:foreach(fun application:start/1 , default_started_applications()), @@ -244,6 +244,10 @@ reboot() -> lists:foreach(fun application:start/1 , default_started_applications()) end. +is_application_running(App) -> + StartedApps = proplists:get_value(started, application:info()), + proplists:is_defined(App, StartedApps). + -ifdef(EMQX_ENTERPRISE). default_started_applications() -> [gproc, esockd, ranch, cowboy, ekka, emqx].