Przeglądaj źródła

chore(rbac): fix CI errors & update change

firest 2 lat temu
rodzic
commit
4ba34f8f3e

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

@@ -59,12 +59,8 @@ valid_role(Type, Role) ->
 %% ===================================================================
 %% ===================================================================
 check_rbac(?ROLE_SUPERUSER, _, _, _) ->
 check_rbac(?ROLE_SUPERUSER, _, _, _) ->
     true;
     true;
-%%check_rbac(?ROLE_API_SUPERUSER, _, _, _) ->
-%%    true;
 check_rbac(?ROLE_VIEWER, <<"GET">>, _, _) ->
 check_rbac(?ROLE_VIEWER, <<"GET">>, _, _) ->
     true;
     true;
-%%check_rbac(?ROLE_API_VIEWER, <<"GET">>, _, _) ->
-%%    true;
 check_rbac(?ROLE_API_PUBLISHER, <<"POST">>, <<"/publish">>, _) ->
 check_rbac(?ROLE_API_PUBLISHER, <<"POST">>, <<"/publish">>, _) ->
     true;
     true;
 check_rbac(?ROLE_API_PUBLISHER, <<"POST">>, <<"/publish/bulk">>, _) ->
 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([authorize/4]).
 -export([post_config_update/5]).
 -export([post_config_update/5]).
 
 
--export([backup_tables/0]).
+-export([backup_tables/0, validate_mnesia_backup/1]).
 
 
 %% Internal exports (RPC)
 %% Internal exports (RPC)
 -export([
 -export([
@@ -82,6 +82,22 @@ mnesia(boot) ->
 
 
 backup_tables() -> [?APP].
 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) ->
 post_config_update([api_key], _Req, NewConf, _OldConf, _AppEnvs) ->
     #{bootstrap_file := File} = NewConf,
     #{bootstrap_file := File} = NewConf,
     case init_bootstrap_file(File) of
     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], [t_create, t_update, t_delete, t_authorize, t_create_unexpired_app]},
         {parallel, [parallel], ?EE_CASES},
         {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) ->
 init_per_suite(Config) ->
@@ -86,6 +86,92 @@ t_bootstrap_file(_) ->
     update_file(<<>>),
     update_file(<<>>),
     ok.
     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) ->
 auth_authorize(Path, Key, Secret) ->
     FakePath = erlang:list_to_binary(emqx_dashboard_swagger:relative_uri("/fake")),
     FakePath = erlang:list_to_binary(emqx_dashboard_swagger:relative_uri("/fake")),
     FakeReq = #{method => <<"GET">>, path => FakePath},
     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:
 bootstrap_file.desc:
 """The bootstrap file provides API keys for EMQX.
 """The bootstrap file provides API keys for EMQX.
 EMQX will load these keys on startup to authorize API requests.
 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:
 bootstrap_file.label:
 """Initialize api_key file."""
 """Initialize api_key file."""