Merge pull request #8286 from DDDHuang/fix_rm_dashboard_user
fix: dashboard users api, cannot delete self
This commit is contained in:
commit
c64f589ef5
|
@ -1,7 +1,13 @@
|
||||||
%% -*- mode: erlang -*-
|
%% -*- mode: erlang -*-
|
||||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||||
{VSN,
|
{VSN,
|
||||||
[{"5.0.0",[{load_module,emqx_dashboard_api,brutal_purge,soft_purge,[]}]},
|
[{"5.0.0", [
|
||||||
|
{load_module,emqx_dashboard_api,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_dashboard_token,brutal_purge,soft_purge,[]}
|
||||||
|
]},
|
||||||
{<<".*">>,[]}],
|
{<<".*">>,[]}],
|
||||||
[{"5.0.0",[{load_module,emqx_dashboard_api,brutal_purge,soft_purge,[]}]},
|
[{"5.0.0", [
|
||||||
|
{load_module,emqx_dashboard_api,brutal_purge,soft_purge,[]},
|
||||||
|
{load_module,emqx_dashboard_token,brutal_purge,soft_purge,[]}
|
||||||
|
]},
|
||||||
{<<".*">>,[]}]}.
|
{<<".*">>,[]}]}.
|
||||||
|
|
|
@ -272,22 +272,59 @@ user(put, #{bindings := #{username := Username}, body := Params}) ->
|
||||||
{error, Reason} ->
|
{error, Reason} ->
|
||||||
{404, ?USER_NOT_FOUND, Reason}
|
{404, ?USER_NOT_FOUND, Reason}
|
||||||
end;
|
end;
|
||||||
user(delete, #{bindings := #{username := Username}}) ->
|
user(delete, #{bindings := #{username := Username}, headers := Headers}) ->
|
||||||
case Username == emqx_dashboard_admin:default_username() of
|
case Username == emqx_dashboard_admin:default_username() of
|
||||||
true ->
|
true ->
|
||||||
?SLOG(info, #{msg => "Dashboard delete admin user failed", username => Username}),
|
?SLOG(info, #{msg => "Dashboard delete admin user failed", username => Username}),
|
||||||
Message = list_to_binary(io_lib:format("Cannot delete user ~p", [Username])),
|
Message = list_to_binary(io_lib:format("Cannot delete user ~p", [Username])),
|
||||||
{400, ?NOT_ALLOWED, Message};
|
{400, ?NOT_ALLOWED, Message};
|
||||||
false ->
|
false ->
|
||||||
case emqx_dashboard_admin:remove_user(Username) of
|
case is_self_auth(Username, Headers) of
|
||||||
{error, Reason} ->
|
true ->
|
||||||
{404, ?USER_NOT_FOUND, Reason};
|
{400, ?NOT_ALLOWED, <<"Cannot delete self">>};
|
||||||
{ok, _} ->
|
false ->
|
||||||
?SLOG(info, #{msg => "Dashboard delete admin user", username => Username}),
|
case emqx_dashboard_admin:remove_user(Username) of
|
||||||
{204}
|
{error, Reason} ->
|
||||||
|
{404, ?USER_NOT_FOUND, Reason};
|
||||||
|
{ok, _} ->
|
||||||
|
?SLOG(info, #{
|
||||||
|
msg => "Dashboard delete admin user", username => Username
|
||||||
|
}),
|
||||||
|
{204}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
is_self_auth(Username, #{<<"authorization">> := Token}) ->
|
||||||
|
is_self_auth(Username, Token);
|
||||||
|
is_self_auth(Username, #{<<"Authorization">> := Token}) ->
|
||||||
|
is_self_auth(Username, Token);
|
||||||
|
is_self_auth(Username, <<"basic ", Token/binary>>) ->
|
||||||
|
is_self_auth_basic(Username, Token);
|
||||||
|
is_self_auth(Username, <<"Basic ", Token/binary>>) ->
|
||||||
|
is_self_auth_basic(Username, Token);
|
||||||
|
is_self_auth(Username, <<"bearer ", Token/binary>>) ->
|
||||||
|
is_self_auth_token(Username, Token);
|
||||||
|
is_self_auth(Username, <<"Bearer ", Token/binary>>) ->
|
||||||
|
is_self_auth_token(Username, Token).
|
||||||
|
|
||||||
|
is_self_auth_basic(Username, Token) ->
|
||||||
|
UP = base64:decode(Token),
|
||||||
|
case binary:match(UP, Username) of
|
||||||
|
{0, N} ->
|
||||||
|
binary:part(UP, {N, 1}) == <<":">>;
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end.
|
||||||
|
|
||||||
|
is_self_auth_token(Username, Token) ->
|
||||||
|
case emqx_dashboard_token:owner(Token) of
|
||||||
|
{ok, Owner} ->
|
||||||
|
Owner == Username;
|
||||||
|
{error, _NotFound} ->
|
||||||
|
false
|
||||||
|
end.
|
||||||
|
|
||||||
change_pwd(put, #{bindings := #{username := Username}, body := Params}) ->
|
change_pwd(put, #{bindings := #{username := Username}, body := Params}) ->
|
||||||
LogMeta = #{msg => "Dashboard change password", username => Username},
|
LogMeta = #{msg => "Dashboard change password", username => Username},
|
||||||
OldPwd = maps:get(<<"old_pwd">>, Params),
|
OldPwd = maps:get(<<"old_pwd">>, Params),
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
sign/2,
|
sign/2,
|
||||||
verify/1,
|
verify/1,
|
||||||
lookup/1,
|
lookup/1,
|
||||||
|
owner/1,
|
||||||
destroy/1,
|
destroy/1,
|
||||||
destroy_by_username/1
|
destroy_by_username/1
|
||||||
]).
|
]).
|
||||||
|
@ -161,6 +162,14 @@ lookup_by_username(Username) ->
|
||||||
{atomic, List} = mria:ro_transaction(?DASHBOARD_SHARD, Fun),
|
{atomic, List} = mria:ro_transaction(?DASHBOARD_SHARD, Fun),
|
||||||
List.
|
List.
|
||||||
|
|
||||||
|
-spec owner(Token :: binary()) -> {ok, Username :: binary()} | {error, not_found}.
|
||||||
|
owner(Token) ->
|
||||||
|
Fun = fun() -> mnesia:read(?TAB, Token) end,
|
||||||
|
case mria:ro_transaction(?DASHBOARD_SHARD, Fun) of
|
||||||
|
{atomic, [#?ADMIN_JWT{username = Username}]} -> {ok, Username};
|
||||||
|
{atomic, []} -> {error, not_found}
|
||||||
|
end.
|
||||||
|
|
||||||
jwk(Username, Password, Salt) ->
|
jwk(Username, Password, Salt) ->
|
||||||
Key = crypto:hash(md5, <<Salt/binary, Username/binary, Password/binary>>),
|
Key = crypto:hash(md5, <<Salt/binary, Username/binary, Password/binary>>),
|
||||||
#{
|
#{
|
||||||
|
|
|
@ -44,23 +44,17 @@
|
||||||
-define(APP_MANAGEMENT, emqx_management).
|
-define(APP_MANAGEMENT, emqx_management).
|
||||||
|
|
||||||
-define(OVERVIEWS, [
|
-define(OVERVIEWS, [
|
||||||
'alarms/activated',
|
"alarms",
|
||||||
'alarms/deactivated',
|
"banned",
|
||||||
banned,
|
"stats",
|
||||||
brokers,
|
"metrics",
|
||||||
stats,
|
"listeners",
|
||||||
metrics,
|
"clients",
|
||||||
listeners,
|
"subscriptions"
|
||||||
clients,
|
|
||||||
subscriptions,
|
|
||||||
routes,
|
|
||||||
plugins
|
|
||||||
]).
|
]).
|
||||||
|
|
||||||
all() ->
|
all() ->
|
||||||
%% TODO: V5 API
|
emqx_common_test_helpers:all(?MODULE).
|
||||||
%% emqx_common_test_helpers:all(?MODULE).
|
|
||||||
[t_cli, t_lookup_by_username_jwt, t_clean_expired_jwt, t_rest_api].
|
|
||||||
|
|
||||||
end_suite() ->
|
end_suite() ->
|
||||||
end_suite([]).
|
end_suite([]).
|
||||||
|
@ -98,37 +92,40 @@ t_overview(_) ->
|
||||||
mnesia:clear_table(?ADMIN),
|
mnesia:clear_table(?ADMIN),
|
||||||
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, <<"simple_description">>),
|
emqx_dashboard_admin:add_user(<<"admin">>, <<"public">>, <<"simple_description">>),
|
||||||
[
|
[
|
||||||
?assert(
|
{ok, _} = request_dashboard(get, api_path([Overview]), auth_header_())
|
||||||
request_dashboard(
|
|
||||||
get,
|
|
||||||
api_path(erlang:atom_to_list(Overview)),
|
|
||||||
auth_header_()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|| Overview <- ?OVERVIEWS
|
|| Overview <- ?OVERVIEWS
|
||||||
].
|
].
|
||||||
|
|
||||||
t_admins_add_delete(_) ->
|
t_admins_add_delete(_) ->
|
||||||
mnesia:clear_table(?ADMIN),
|
mnesia:clear_table(?ADMIN),
|
||||||
Desc = <<"simple description">>,
|
Desc = <<"simple description">>,
|
||||||
ok = emqx_dashboard_admin:add_user(<<"username">>, <<"password">>, Desc),
|
{ok, _} = emqx_dashboard_admin:add_user(<<"username">>, <<"password">>, Desc),
|
||||||
ok = emqx_dashboard_admin:add_user(<<"username1">>, <<"password1">>, Desc),
|
{ok, _} = emqx_dashboard_admin:add_user(<<"username1">>, <<"password1">>, Desc),
|
||||||
Admins = emqx_dashboard_admin:all_users(),
|
Admins = emqx_dashboard_admin:all_users(),
|
||||||
?assertEqual(2, length(Admins)),
|
?assertEqual(2, length(Admins)),
|
||||||
ok = emqx_dashboard_admin:remove_user(<<"username1">>),
|
{ok, _} = emqx_dashboard_admin:remove_user(<<"username1">>),
|
||||||
Users = emqx_dashboard_admin:all_users(),
|
Users = emqx_dashboard_admin:all_users(),
|
||||||
?assertEqual(1, length(Users)),
|
?assertEqual(1, length(Users)),
|
||||||
ok = emqx_dashboard_admin:change_password(
|
{ok, _} = emqx_dashboard_admin:change_password(
|
||||||
<<"username">>,
|
<<"username">>,
|
||||||
<<"password">>,
|
<<"password">>,
|
||||||
<<"pwd">>
|
<<"pwd">>
|
||||||
),
|
),
|
||||||
timer:sleep(10),
|
timer:sleep(10),
|
||||||
Header = auth_header_(<<"username">>, <<"pwd">>),
|
{ok, _} = emqx_dashboard_admin:remove_user(<<"username">>).
|
||||||
?assert(request_dashboard(get, api_path("brokers"), Header)),
|
|
||||||
|
|
||||||
ok = emqx_dashboard_admin:remove_user(<<"username">>),
|
t_admin_delete_self_failed(_) ->
|
||||||
?assertNotEqual(true, request_dashboard(get, api_path("brokers"), Header)).
|
mnesia:clear_table(?ADMIN),
|
||||||
|
Desc = <<"simple description">>,
|
||||||
|
_ = emqx_dashboard_admin:add_user(<<"username1">>, <<"password">>, Desc),
|
||||||
|
Admins = emqx_dashboard_admin:all_users(),
|
||||||
|
?assertEqual(1, length(Admins)),
|
||||||
|
Header = auth_header_(<<"username1">>, <<"password">>),
|
||||||
|
{error, {_, 400, _}} = request_dashboard(delete, api_path(["users", "username1"]), Header),
|
||||||
|
Token = erlang:iolist_to_binary(["Basic ", base64:encode("username1:password")]),
|
||||||
|
Header2 = {"Authorization", Token},
|
||||||
|
{error, {_, 400, _}} = request_dashboard(delete, api_path(["users", "username1"]), Header2),
|
||||||
|
mnesia:clear_table(?ADMIN).
|
||||||
|
|
||||||
t_rest_api(_Config) ->
|
t_rest_api(_Config) ->
|
||||||
mnesia:clear_table(?ADMIN),
|
mnesia:clear_table(?ADMIN),
|
||||||
|
|
Loading…
Reference in New Issue