emqx/apps/emqx_dashboard_rbac/src/emqx_dashboard_rbac.erl

85 lines
2.3 KiB
Erlang

%%--------------------------------------------------------------------
%% Copyright (c) 2023-2024 EMQ Technologies Co., Ltd. All Rights Reserved.
%%--------------------------------------------------------------------
-module(emqx_dashboard_rbac).
-include_lib("emqx_dashboard/include/emqx_dashboard.hrl").
-export([
check_rbac/3,
role/1,
valid_dashboard_role/1,
valid_api_role/1
]).
-dialyzer({nowarn_function, role/1}).
%%=====================================================================
%% API
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, Username);
_ ->
false
end.
%% For compatibility
role(#?ADMIN{role = undefined}) ->
?ROLE_SUPERUSER;
role(#?ADMIN{role = Role}) ->
Role;
%% For compatibility
role([]) ->
?ROLE_SUPERUSER;
role(#{role := Role}) ->
Role;
role(Role) when is_binary(Role) ->
Role.
valid_dashboard_role(Role) ->
valid_role(dashboard, Role).
valid_api_role(Role) ->
valid_role(api, Role).
%% ===================================================================
valid_role(Type, Role) ->
case lists:member(Role, role_list(Type)) of
true ->
ok;
_ ->
{error, <<"Role does not exist">>}
end.
%% ===================================================================
check_rbac(?ROLE_SUPERUSER, _, _, _) ->
true;
check_rbac(?ROLE_VIEWER, <<"GET">>, _, _) ->
true;
check_rbac(?ROLE_API_PUBLISHER, <<"POST">>, <<"/publish">>, _) ->
true;
check_rbac(?ROLE_API_PUBLISHER, <<"POST">>, <<"/publish/bulk">>, _) ->
true;
%% everyone should allow to logout
check_rbac(?ROLE_VIEWER, <<"POST">>, <<"/logout">>, _) ->
true;
%% 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(dashboard) ->
[?ROLE_VIEWER, ?ROLE_SUPERUSER];
role_list(api) ->
[?ROLE_API_VIEWER, ?ROLE_API_PUBLISHER, ?ROLE_API_SUPERUSER].