feat(dashboard): dashboard admin password persistence

This commit is contained in:
Georgy Sychev 2022-03-23 19:14:44 +04:00
parent a9255032cd
commit b3de664c64
3 changed files with 37 additions and 8 deletions

View File

@ -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.

View File

@ -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, []),

View File

@ -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].