فهرست منبع

chore(rbac): fix CI errors & update change

firest 2 سال پیش
والد
کامیت
4ba34f8f3e

+ 0 - 4
apps/emqx_dashboard_rbac/src/emqx_dashboard_rbac.erl

@@ -59,12 +59,8 @@ valid_role(Type, Role) ->
 %% ===================================================================
 check_rbac(?ROLE_SUPERUSER, _, _, _) ->
     true;
-%%check_rbac(?ROLE_API_SUPERUSER, _, _, _) ->
-%%    true;
 check_rbac(?ROLE_VIEWER, <<"GET">>, _, _) ->
     true;
-%%check_rbac(?ROLE_API_VIEWER, <<"GET">>, _, _) ->
-%%    true;
 check_rbac(?ROLE_API_PUBLISHER, <<"POST">>, <<"/publish">>, _) ->
     true;
 check_rbac(?ROLE_API_PUBLISHER, <<"POST">>, <<"/publish/bulk">>, _) ->

+ 17 - 1
apps/emqx_management/src/emqx_mgmt_auth.erl

@@ -38,7 +38,7 @@
 -export([authorize/4]).
 -export([post_config_update/5]).
 
--export([backup_tables/0]).
+-export([backup_tables/0, validate_mnesia_backup/1]).
 
 %% Internal exports (RPC)
 -export([
@@ -82,6 +82,22 @@ mnesia(boot) ->
 
 backup_tables() -> [?APP].
 
+validate_mnesia_backup({schema, _Tab, CreateList} = Schema) ->
+    case emqx_mgmt_data_backup:default_validate_mnesia_backup(Schema) of
+        ok ->
+            ok;
+        _ ->
+            case proplists:get_value(attributes, CreateList) of
+                %% Since v5.4.0 the `desc` has changed to `extra`
+                [name, api_key, api_secret_hash, enable, desc, expired_at, created_at] ->
+                    ok;
+                Fields ->
+                    {error, {unknow_fields, Fields}}
+            end
+    end;
+validate_mnesia_backup(_Other) ->
+    ok.
+
 post_config_update([api_key], _Req, NewConf, _OldConf, _AppEnvs) ->
     #{bootstrap_file := File} = NewConf,
     case init_bootstrap_file(File) of

+ 87 - 1
apps/emqx_management/test/emqx_mgmt_api_api_keys_SUITE.erl

@@ -39,7 +39,7 @@ groups() ->
     [
         {parallel, [parallel], [t_create, t_update, t_delete, t_authorize, t_create_unexpired_app]},
         {parallel, [parallel], ?EE_CASES},
-        {sequence, [], [t_bootstrap_file, t_create_failed]}
+        {sequence, [], [t_bootstrap_file, t_bootstrap_file_with_role, t_create_failed]}
     ].
 
 init_per_suite(Config) ->
@@ -86,6 +86,92 @@ t_bootstrap_file(_) ->
     update_file(<<>>),
     ok.
 
+-if(?EMQX_RELEASE_EDITION == ee).
+t_bootstrap_file_with_role(_) ->
+    Search = fun(Name) ->
+        lists:search(
+            fun(#{api_key := AppName}) ->
+                AppName =:= Name
+            end,
+            emqx_mgmt_auth:list()
+        )
+    end,
+
+    Bin = <<"role-1:role-1:viewer\nrole-2:role-2:administrator\nrole-3:role-3">>,
+    File = "./bootstrap_api_keys.txt",
+    ok = file:write_file(File, Bin),
+    update_file(File),
+
+    ?assertMatch(
+        {value, #{api_key := <<"role-1">>, role := <<"viewer">>}},
+        Search(<<"role-1">>)
+    ),
+
+    ?assertMatch(
+        {value, #{api_key := <<"role-2">>, role := <<"administrator">>}},
+        Search(<<"role-2">>)
+    ),
+
+    ?assertMatch(
+        {value, #{api_key := <<"role-3">>, role := <<"administrator">>}},
+        Search(<<"role-3">>)
+    ),
+
+    %% bad role
+    BadBin = <<"role-4:secret-11:bad\n">>,
+    ok = file:write_file(File, BadBin),
+    update_file(File),
+    ?assertEqual(
+        false,
+        Search(<<"role-4">>)
+    ),
+    ok.
+-else.
+t_bootstrap_file_with_role(_) ->
+    Search = fun(Name) ->
+        lists:search(
+            fun(#{api_key := AppName}) ->
+                AppName =:= Name
+            end,
+            emqx_mgmt_auth:list()
+        )
+    end,
+
+    Bin = <<"role-1:role-1:administrator\nrole-2:role-2">>,
+    File = "./bootstrap_api_keys.txt",
+    ok = file:write_file(File, Bin),
+    update_file(File),
+
+    ?assertMatch(
+        {value, #{api_key := <<"role-1">>, role := <<"administrator">>}},
+        Search(<<"role-1">>)
+    ),
+
+    ?assertMatch(
+        {value, #{api_key := <<"role-2">>, role := <<"administrator">>}},
+        Search(<<"role-2">>)
+    ),
+
+    %% only administrator
+    OtherRoleBin = <<"role-3:role-3:viewer\n">>,
+    ok = file:write_file(File, OtherRoleBin),
+    update_file(File),
+    ?assertEqual(
+        false,
+        Search(<<"role-3">>)
+    ),
+
+    %% bad role
+    BadBin = <<"role-4:secret-11:bad\n">>,
+    ok = file:write_file(File, BadBin),
+    update_file(File),
+    ?assertEqual(
+        false,
+        Search(<<"role-4">>)
+    ),
+    ok.
+-endif.
+
 auth_authorize(Path, Key, Secret) ->
     FakePath = erlang:list_to_binary(emqx_dashboard_swagger:relative_uri("/fake")),
     FakeReq = #{method => <<"GET">>, path => FakePath},

+ 5 - 0
changes/ee/feat-11811.en.md

@@ -0,0 +1,5 @@
+Improve the format for the REST API key bootstrap file to support initialize key with a role.
+
+The new form is:`api_key:api_secret:role`.
+
+`role` is optional and its default value is `administrator`.

+ 5 - 2
rel/i18n/emqx_mgmt_api_key_schema.hocon

@@ -9,8 +9,11 @@ api_key.label:
 bootstrap_file.desc:
 """The bootstrap file provides API keys for EMQX.
 EMQX will load these keys on startup to authorize API requests.
-It contains key-value pairs in the format:`api_key:api_secret`.
-Each line specifies an API key and its associated secret."""
+It contains colon-separated values in the format: `api_key:api_secret:role`.
+Each line specifies an API key and its associated secret, and the role of this key.
+The 'role' part should be the pre-defined access scope group name,
+for example, `administrator` or `viewer`.
+The 'role' is introduced in 5.4, to be backward compatible, if it is missing, the key is implicitly granted `administrator` role."""
 
 bootstrap_file.label:
 """Initialize api_key file."""