Просмотр исходного кода

fix(auth_mnesia): don't force update default user.

zhongwencool 4 лет назад
Родитель
Сommit
efa3e32ee5

+ 14 - 9
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}) ->

+ 1 - 3
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() ->

+ 36 - 4
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(),
     <<SaltBin/binary, (hash(Password, SaltBin, HashType))/binary>>.
 
@@ -219,5 +253,3 @@ auth_username_cli(_) ->
                     {"user add <Username> <Password>", "Add username auth rule"},
                     {"user update <Username> <NewPassword>", "Update username auth rule"},
                     {"user delete <Username>", "Delete username auth rule"}]).
-hash_type() ->
-    application:get_env(emqx_auth_mnesia, password_hash, sha256).

+ 22 - 0
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,

+ 1 - 2
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
     }.