From efa3e32ee5bce06b30acc27426422a1b0a03aef3 Mon Sep 17 00:00:00 2001 From: zhongwencool Date: Mon, 24 Jan 2022 13:43:38 +0800 Subject: [PATCH] fix(auth_mnesia): don't force update default user. --- .../emqx_auth_mnesia/src/emqx_auth_mnesia.erl | 23 ++++++----- .../src/emqx_auth_mnesia_app.erl | 4 +- .../src/emqx_auth_mnesia_cli.erl | 40 +++++++++++++++++-- .../test/emqx_auth_mnesia_SUITE.erl | 22 ++++++++++ .../src/emqx_mgmt_api_subscriptions.erl | 3 +- 5 files changed, 74 insertions(+), 18 deletions(-) diff --git a/apps/emqx_auth_mnesia/src/emqx_auth_mnesia.erl b/apps/emqx_auth_mnesia/src/emqx_auth_mnesia.erl index 74c7c71ee..30bf14bf9 100644 --- a/apps/emqx_auth_mnesia/src/emqx_auth_mnesia.erl +++ b/apps/emqx_auth_mnesia/src/emqx_auth_mnesia.erl @@ -32,27 +32,32 @@ , description/0 ]). --export([match_password/3]). +-export([ match_password/3 + , hash_type/0 + ]). init(#{clientid_list := ClientidList, username_list := UsernameList}) -> ok = ekka_mnesia:create_table(?TABLE, [ {disc_copies, [node()]}, {attributes, record_info(fields, emqx_user)}, {storage_properties, [{ets, [{read_concurrency, true}]}]}]), - _ = [ add_default_user({{clientid, iolist_to_binary(Clientid)}, iolist_to_binary(Password)}) - || {Clientid, Password} <- ClientidList], - _ = [ add_default_user({{username, iolist_to_binary(Username)}, iolist_to_binary(Password)}) - || {Username, Password} <- UsernameList], - ok = ekka_mnesia:copy_table(?TABLE, disc_copies). + lists:foreach(fun({Clientid, Password}) -> + emqx_auth_mnesia_cli:add_default_user(clientid, iolist_to_binary(Clientid), iolist_to_binary(Password)) + end, ClientidList), -%% @private -add_default_user({Login, Password}) when is_tuple(Login) -> - emqx_auth_mnesia_cli:force_add_user(Login, Password). + lists:foreach(fun({Username, Password}) -> + emqx_auth_mnesia_cli:add_default_user(username, iolist_to_binary(Username), iolist_to_binary(Password)) + end, UsernameList), + + ok = ekka_mnesia:copy_table(?TABLE, disc_copies). -spec(register_metrics() -> ok). register_metrics() -> lists:foreach(fun emqx_metrics:ensure/1, ?AUTH_METRICS). +hash_type() -> + application:get_env(emqx_auth_mnesia, password_hash, sha256). + check(ClientInfo = #{ clientid := Clientid , password := NPassword }, AuthResult, #{hash_type := HashType}) -> diff --git a/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_app.erl b/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_app.erl index 49bdfa75e..aed2eca4e 100644 --- a/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_app.erl +++ b/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_app.erl @@ -57,9 +57,7 @@ load_auth_hook() -> UsernameList = application:get_env(?APP, username_list, []), ok = emqx_auth_mnesia:init(#{clientid_list => ClientidList, username_list => UsernameList}), ok = emqx_auth_mnesia:register_metrics(), - Params = #{ - hash_type => application:get_env(emqx_auth_mnesia, password_hash, sha256) - }, + Params = #{hash_type => emqx_auth_mnesia:hash_type()}, emqx:hook('client.authenticate', fun emqx_auth_mnesia:check/3, [Params]). load_acl_hook() -> diff --git a/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl b/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl index 55e3e4966..d206f3e07 100644 --- a/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl +++ b/apps/emqx_auth_mnesia/src/emqx_auth_mnesia_cli.erl @@ -23,6 +23,7 @@ %% Auth APIs -export([ add_user/2 , force_add_user/2 + , add_default_user/3 , update_user/2 , remove_user/1 , lookup_user/1 @@ -57,6 +58,39 @@ insert_user(User = #emqx_user{login = Login}) -> [_|_] -> mnesia:abort(existed) end. +-spec(add_default_user(clientid | username, tuple(), binary()) -> ok | {error, any()}). +add_default_user(Type, Key, Password) -> + Login = {Type, Key}, + case add_user(Login, Password) of + ok -> ok; + {error, existed} -> + NewPwd = encrypted_data(Password), + [#emqx_user{password = OldPwd}] = emqx_auth_mnesia_cli:lookup_user(Login), + HashType = emqx_auth_mnesia:hash_type(), + case emqx_auth_mnesia:match_password(NewPwd, HashType, [OldPwd]) of + true -> ok; + false -> + %% We can't force add default, + %% otherwise passwords that have been updated via HTTP API will be reset after reboot. + TypeCtl = + case Type of + clientid -> clientid; + username -> user + end, + ?LOG(warning, + "[Auth Mnesia] auth.client.x.~p=~s's password in the emqx_auth_mnesia.conf\n" + "does not match the password in the database(mnesia).\n" + "1. If you have already changed the password via the HTTP API, this warning has no effect.\n" + "You can remove the warning from emqx_auth_mnesia.conf to resolve the warning.\n" + "2. If you just want to update the password by manually changing the configuration file,\n" + "you need to delete the old user and password using `emqx_ctl ~p delete ~s` first\n" + "the new password in emqx_auth_mnesia.conf can take effect after reboot.", + [Type, Key, TypeCtl, Key]), + ok + end; + Error -> Error + end. + force_add_user(Login, Password) -> User = #emqx_user{ login = Login, @@ -74,7 +108,7 @@ insert_or_update_user(NewPwd, User = #emqx_user{login = Login}) -> case mnesia:read(?TABLE, Login) of [] -> mnesia:write(User); [#emqx_user{password = Pwd}] -> - case emqx_auth_mnesia:match_password(NewPwd, hash_type(), [Pwd]) of + case emqx_auth_mnesia:match_password(NewPwd, emqx_auth_mnesia:hash_type(), [Pwd]) of true -> ok; false -> ok = mnesia:write(User), @@ -136,7 +170,7 @@ ret({atomic, Res}) -> Res; ret({aborted, Error}) -> {error, Error}. encrypted_data(Password) -> - HashType = hash_type(), + HashType = emqx_auth_mnesia:hash_type(), SaltBin = salt(), <>. @@ -219,5 +253,3 @@ auth_username_cli(_) -> {"user add ", "Add username auth rule"}, {"user update ", "Update username auth rule"}, {"user delete ", "Delete username auth rule"}]). -hash_type() -> - application:get_env(emqx_auth_mnesia, password_hash, sha256). diff --git a/apps/emqx_auth_mnesia/test/emqx_auth_mnesia_SUITE.erl b/apps/emqx_auth_mnesia/test/emqx_auth_mnesia_SUITE.erl index 12b473815..b16b4c54a 100644 --- a/apps/emqx_auth_mnesia/test/emqx_auth_mnesia_SUITE.erl +++ b/apps/emqx_auth_mnesia/test/emqx_auth_mnesia_SUITE.erl @@ -103,6 +103,17 @@ t_boot(_Config) -> %% change default pwd NewPwd = <<"emqx654321">>, + ok = emqx_ct_helpers:start_apps([emqx_auth_mnesia], + fun(_) -> set_default(ClientId, UserName, NewPwd, sha256) end), + ?assertEqual(Failed, + emqx_auth_mnesia:check(#{clientid => ClientId, password => NewPwd}, + #{}, #{hash_type => sha256})), + ?assertEqual(Failed, + emqx_auth_mnesia:check(#{clientid => <<"NotExited">>, username => UserName, password => NewPwd}, + #{}, #{hash_type => sha256})), + clean_all_users(), + emqx_ct_helpers:stop_apps([emqx_auth_mnesia]), + ok = emqx_ct_helpers:start_apps([emqx_auth_mnesia], fun(_) -> set_default(ClientId, UserName, NewPwd, sha256) end), ?assertEqual(Ok, @@ -115,6 +126,17 @@ t_boot(_Config) -> %% change hash_type NewPwd2 = <<"emqx6543210">>, + ok = emqx_ct_helpers:start_apps([emqx_auth_mnesia], + fun(_) -> set_default(ClientId, UserName, NewPwd2, plain) end), + ?assertEqual(Failed, + emqx_auth_mnesia:check(#{clientid => ClientId, password => NewPwd2}, + #{}, #{hash_type => plain})), + ?assertEqual(Failed, + emqx_auth_mnesia:check(#{clientid => <<"NotExited">>, username => UserName, password => NewPwd2}, + #{}, #{hash_type => plain})), + clean_all_users(), + emqx_ct_helpers:stop_apps([emqx_auth_mnesia]), + ok = emqx_ct_helpers:start_apps([emqx_auth_mnesia], fun(_) -> set_default(ClientId, UserName, NewPwd2, plain) end), ?assertEqual(Ok, diff --git a/apps/emqx_management/src/emqx_mgmt_api_subscriptions.erl b/apps/emqx_management/src/emqx_mgmt_api_subscriptions.erl index 01e14987f..6b35d7a0a 100644 --- a/apps/emqx_management/src/emqx_mgmt_api_subscriptions.erl +++ b/apps/emqx_management/src/emqx_mgmt_api_subscriptions.erl @@ -98,8 +98,7 @@ add_meta(Params, List) -> page => Page, limit => Limit, hasnext => Start + Limit - 1 < Count, - count => Count - }, + count => Count}, data => Data, code => 0 }.