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

fix: allow viewers to change their own passwords

zhongwencool 2 лет назад
Родитель
Сommit
2388d36b09

+ 2 - 2
apps/emqx_dashboard/src/emqx_dashboard_token.erl

@@ -248,8 +248,8 @@ clean_expired_jwt(Now) ->
 
 -if(?EMQX_RELEASE_EDITION == ee).
 check_rbac(Req, JWT) ->
-    #?ADMIN_JWT{exptime = _ExpTime, extra = Extra, username = _Username} = JWT,
-    case emqx_dashboard_rbac:check_rbac(Req, Extra) of
+    #?ADMIN_JWT{exptime = _ExpTime, extra = Extra, username = Username} = JWT,
+    case emqx_dashboard_rbac:check_rbac(Req, Username, Extra) of
         true ->
             save_new_jwt(JWT);
         _ ->

+ 1 - 1
apps/emqx_dashboard_rbac/src/emqx_dashboard_rbac.app.src

@@ -1,6 +1,6 @@
 {application, emqx_dashboard_rbac, [
     {description, "EMQX Dashboard RBAC"},
-    {vsn, "0.1.0"},
+    {vsn, "0.1.1"},
     {registered, []},
     {applications, [
         kernel,

+ 15 - 8
apps/emqx_dashboard_rbac/src/emqx_dashboard_rbac.erl

@@ -6,18 +6,18 @@
 
 -include_lib("emqx_dashboard/include/emqx_dashboard.hrl").
 
--export([check_rbac/2, role/1, valid_role/1]).
+-export([check_rbac/3, role/1, valid_role/1]).
 
 -dialyzer({nowarn_function, role/1}).
 %%=====================================================================
 %% API
-check_rbac(Req, Extra) ->
+check_rbac(Req, Username, Extra) ->
     Role = role(Extra),
     Method = cowboy_req:method(Req),
     AbsPath = cowboy_req:path(Req),
     case emqx_dashboard_swagger:get_relative_uri(AbsPath) of
         {ok, Path} ->
-            check_rbac(Role, Method, Path);
+            check_rbac(Role, Method, Path, Username);
         _ ->
             false
     end.
@@ -41,14 +41,21 @@ valid_role(Role) ->
             {error, <<"Role does not exist">>}
     end.
 %% ===================================================================
-check_rbac(?ROLE_SUPERUSER, _, _) ->
+check_rbac(?ROLE_SUPERUSER, _, _, _) ->
     true;
-check_rbac(?ROLE_VIEWER, <<"GET">>, _) ->
+check_rbac(?ROLE_VIEWER, <<"GET">>, _, _) ->
     true;
-%% this API is a special case
-check_rbac(?ROLE_VIEWER, <<"POST">>, <<"/logout">>) ->
+%% everyone should allow to logout
+check_rbac(?ROLE_VIEWER, <<"POST">>, <<"/logout">>, _) ->
     true;
-check_rbac(_, _, _) ->
+%% viewer should allow to change self password,
+%% superuser should allow to change any user
+check_rbac(?ROLE_VIEWER, <<"POST">>, <<"/users/", SubPath/binary>>, Username) ->
+    case binary:split(SubPath, <<"/">>, [global]) of
+        [Username, <<"change_pwd">>] -> true;
+        _ -> false
+    end;
+check_rbac(_, _, _, _) ->
     false.
 
 role_list() ->

+ 28 - 0
apps/emqx_dashboard_rbac/test/emqx_dashboard_rbac_SUITE.erl

@@ -160,6 +160,34 @@ t_login_out(_) ->
     {ok, Username} = emqx_dashboard_admin:verify_token(FakeReq, Token),
     ok.
 
+t_change_pwd(_) ->
+    Viewer1 = <<"viewer1">>,
+    Viewer2 = <<"viewer2">>,
+    SuperUser = <<"super_user">>,
+    Password = <<"public_www1">>,
+    Desc = <<"desc">>,
+    {ok, _} = emqx_dashboard_admin:add_user(Viewer1, Password, ?ROLE_VIEWER, Desc),
+    {ok, _} = emqx_dashboard_admin:add_user(Viewer2, Password, ?ROLE_VIEWER, Desc),
+    {ok, _} = emqx_dashboard_admin:add_user(SuperUser, Password, ?ROLE_SUPERUSER, Desc),
+    {ok, ?ROLE_VIEWER, Viewer1Token} = emqx_dashboard_admin:sign_token(Viewer1, Password),
+    {ok, ?ROLE_SUPERUSER, SuperToken} = emqx_dashboard_admin:sign_token(SuperUser, Password),
+    %% viewer can change own password
+    ?assertEqual({ok, Viewer1}, change_pwd(Viewer1Token, Viewer1)),
+    %% viewer can't change other's password
+    ?assertEqual({error, unauthorized_role}, change_pwd(Viewer1Token, Viewer2)),
+    ?assertEqual({error, unauthorized_role}, change_pwd(Viewer1Token, SuperUser)),
+    %% superuser can change other's password
+    ?assertEqual({ok, SuperUser}, change_pwd(SuperToken, Viewer1)),
+    ?assertEqual({ok, SuperUser}, change_pwd(SuperToken, Viewer2)),
+    ?assertEqual({ok, SuperUser}, change_pwd(SuperToken, SuperUser)),
+    ok.
+
+change_pwd(Token, Username) ->
+    Path = "/users/" ++ binary_to_list(Username) ++ "/change_pwd",
+    Path1 = erlang:list_to_binary(emqx_dashboard_swagger:relative_uri(Path)),
+    Req = #{method => <<"POST">>, path => Path1},
+    emqx_dashboard_admin:verify_token(Req, Token).
+
 add_default_superuser() ->
     {ok, _NewUser} = emqx_dashboard_admin:add_user(
         ?DEFAULT_SUPERUSER,