feat(dashboard): dashboard admin password persistence
This commit is contained in:
parent
a9255032cd
commit
b3de664c64
|
@ -158,7 +158,8 @@ update_pwd(Username, Fun) ->
|
||||||
lookup_user(Username) when is_binary(Username) ->
|
lookup_user(Username) when is_binary(Username) ->
|
||||||
case binenv(default_user_username) of
|
case binenv(default_user_username) of
|
||||||
Username ->
|
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)
|
mnesia:dirty_read(mqtt_admin, Username)
|
||||||
end.
|
end.
|
||||||
|
@ -193,6 +194,7 @@ check(Username, Password) ->
|
||||||
init([]) ->
|
init([]) ->
|
||||||
%% Add default admin user
|
%% Add default admin user
|
||||||
{ok, _} = mnesia:subscribe({table, mqtt_admin, simple}),
|
{ok, _} = mnesia:subscribe({table, mqtt_admin, simple}),
|
||||||
|
add_default_user_hashed(binenv(default_user_username), hashed_default_passwd()),
|
||||||
{ok, state}.
|
{ok, state}.
|
||||||
|
|
||||||
handle_call(_Req, _From, State) ->
|
handle_call(_Req, _From, State) ->
|
||||||
|
@ -240,13 +242,24 @@ salt() ->
|
||||||
binenv(Key) ->
|
binenv(Key) ->
|
||||||
iolist_to_binary(application:get_env(emqx_dashboard, 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() ->
|
hashed_default_passwd() ->
|
||||||
case binenv(default_user_passwd_hashed) of
|
case binenv(default_user_passwd_hashed) of
|
||||||
Empty0 when ?EMPTY_KEY(Empty0) ->
|
Empty0 when ?EMPTY_KEY(Empty0) ->
|
||||||
case binenv(default_user_passwd) of
|
case binenv(default_user_passwd) of
|
||||||
Empty when ?EMPTY_KEY(Empty) ->
|
Empty when ?EMPTY_KEY(Empty) ->
|
||||||
undefined;
|
undefined;
|
||||||
Password -> hash(Password)
|
Password ->
|
||||||
|
Hashed = hash(Password),
|
||||||
|
application:set_env(emqx_dashboard, default_user_passwd_hashed, Hashed),
|
||||||
|
Hashed
|
||||||
end;
|
end;
|
||||||
HashedPassword -> HashedPassword
|
HashedPassword -> HashedPassword
|
||||||
end.
|
end.
|
||||||
|
|
|
@ -52,8 +52,8 @@ all() ->
|
||||||
groups() ->
|
groups() ->
|
||||||
[
|
[
|
||||||
{overview, [sequence], [t_overview]},
|
{overview, [sequence], [t_overview]},
|
||||||
{admins, [sequence], [t_default_password_persists_after_leaving_cluster]},
|
{admins, [sequence], [t_admins_add_delete, t_admins_persist_default_password, t_default_password_persists_after_leaving_cluster]},
|
||||||
{rest, [sequence], [t_rest_api, t_auth_exhaustive_attack]},
|
{rest, [sequence], [t_rest_api]},
|
||||||
{cli, [sequence], [t_cli]}
|
{cli, [sequence], [t_cli]}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
@ -90,10 +90,14 @@ t_admins_add_delete(_) ->
|
||||||
|
|
||||||
t_admins_persist_default_password(_) ->
|
t_admins_persist_default_password(_) ->
|
||||||
emqx_dashboard_admin:change_password(<<"admin">>, <<"new_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
|
%% 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
|
%% It get's restarted by the app automatically
|
||||||
[#mqtt_admin{password=PasswordAfterRestart}] = emqx_dashboard_admin:lookup_user(<<"admin">>),
|
[#mqtt_admin{password=PasswordAfterRestart}] = emqx_dashboard_admin:lookup_user(<<"admin">>),
|
||||||
|
@ -147,6 +151,14 @@ t_default_password_persists_after_leaving_cluster(_) ->
|
||||||
|
|
||||||
debug(2, Slave),
|
debug(2, Slave),
|
||||||
|
|
||||||
|
rpc:call(Slave, application, stop, [emqx_dashboard]),
|
||||||
|
|
||||||
|
debug(3, Slave),
|
||||||
|
|
||||||
|
rpc:call(Slave, application, start, [emqx_dashboard]),
|
||||||
|
|
||||||
|
debug(4, Slave),
|
||||||
|
|
||||||
?assertEqual(
|
?assertEqual(
|
||||||
ok,
|
ok,
|
||||||
rpc:call(Slave, emqx_dashboard_admin, check, [<<"admin">>, <<"new_password">>])),
|
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) ->
|
t_rest_api(_Config) ->
|
||||||
{ok, Res0} = http_get("users"),
|
{ok, Res0} = http_get("users"),
|
||||||
Users = get_http_data(Res0),
|
Users = get_http_data(Res0),
|
||||||
|
ct:pal("~p", [emqx_dashboard_admin:all_users()]),
|
||||||
?assert(lists:member(#{<<"username">> => <<"admin">>, <<"tags">> => <<"administrator">>},
|
?assert(lists:member(#{<<"username">> => <<"admin">>, <<"tags">> => <<"administrator">>},
|
||||||
Users)),
|
Users)),
|
||||||
|
|
||||||
|
@ -277,7 +290,6 @@ setup_node(Node, Apps) ->
|
||||||
fun(emqx) ->
|
fun(emqx) ->
|
||||||
application:set_env(emqx, listeners, []),
|
application:set_env(emqx, listeners, []),
|
||||||
application:set_env(gen_rpc, port_discovery, manual),
|
application:set_env(gen_rpc, port_discovery, manual),
|
||||||
mnesia:info(),
|
|
||||||
ok;
|
ok;
|
||||||
(emqx_management) ->
|
(emqx_management) ->
|
||||||
application:set_env(emqx_management, listeners, []),
|
application:set_env(emqx_management, listeners, []),
|
||||||
|
|
|
@ -234,7 +234,7 @@ shutdown(Reason) ->
|
||||||
).
|
).
|
||||||
|
|
||||||
reboot() ->
|
reboot() ->
|
||||||
case application_controller:is_running(emqx_dashboard) of
|
case is_application_running(emqx_dashboard) of
|
||||||
true ->
|
true ->
|
||||||
application:stop(emqx_dashboard), %% dashboard must be started after mnesia
|
application:stop(emqx_dashboard), %% dashboard must be started after mnesia
|
||||||
lists:foreach(fun application:start/1 , default_started_applications()),
|
lists:foreach(fun application:start/1 , default_started_applications()),
|
||||||
|
@ -244,6 +244,10 @@ reboot() ->
|
||||||
lists:foreach(fun application:start/1 , default_started_applications())
|
lists:foreach(fun application:start/1 , default_started_applications())
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
is_application_running(App) ->
|
||||||
|
StartedApps = proplists:get_value(started, application:info()),
|
||||||
|
proplists:is_defined(App, StartedApps).
|
||||||
|
|
||||||
-ifdef(EMQX_ENTERPRISE).
|
-ifdef(EMQX_ENTERPRISE).
|
||||||
default_started_applications() ->
|
default_started_applications() ->
|
||||||
[gproc, esockd, ranch, cowboy, ekka, emqx].
|
[gproc, esockd, ranch, cowboy, ekka, emqx].
|
||||||
|
|
Loading…
Reference in New Issue