From c86887491c67438020888980b1878de1e402b06f Mon Sep 17 00:00:00 2001 From: Ilya Averyanov Date: Fri, 19 Nov 2021 14:29:24 +0300 Subject: [PATCH] fix(authn): transfer chain tab to emqx_authentication_sup To preserve configuration after emqx_authentication crashes. --- apps/emqx/src/emqx_authentication.erl | 26 +++++++++++-- apps/emqx/test/emqx_authentication_SUITE.erl | 16 ++++++++ apps/emqx_authn/src/emqx_authn_app.erl | 40 ++++++++++++++++---- 3 files changed, 71 insertions(+), 11 deletions(-) diff --git a/apps/emqx/src/emqx_authentication.erl b/apps/emqx/src/emqx_authentication.erl index 821f3d290..d9e2eebd3 100644 --- a/apps/emqx/src/emqx_authentication.erl +++ b/apps/emqx/src/emqx_authentication.erl @@ -401,9 +401,7 @@ list_users(ChainName, AuthenticatorID, Params) -> %%-------------------------------------------------------------------- init(_Opts) -> - _ = ets:new(?CHAINS_TAB, [ named_table, set, public - , {keypos, #chain.name} - , {read_concurrency, true}]), + ok = create_chain_table(), ok = emqx_config_handler:add_handler([authentication], ?MODULE), ok = emqx_config_handler:add_handler([listeners, '?', '?', authentication], ?MODULE), {ok, #{hooked => false, providers => #{}}}. @@ -578,6 +576,28 @@ code_change(_OldVsn, State, _Extra) -> reply(Reply, State) -> {reply, Reply, State}. +%%-------------------------------------------------------------------- +%% Internal functions +%%-------------------------------------------------------------------- + +create_chain_table() -> + Status = try + _ = ets:new(?CHAINS_TAB, [named_table, set, public, + {keypos, #chain.name}, + {read_concurrency, true}]), + created + catch + error:badarg -> already_exists + end, + + case Status of + created -> + ets:give_away(?CHAINS_TAB, whereis(emqx_authentication_sup), undefined), + ok; + already_exists -> + ok + end. + global_chain(mqtt) -> 'mqtt:global'; global_chain('mqtt-sn') -> diff --git a/apps/emqx/test/emqx_authentication_SUITE.erl b/apps/emqx/test/emqx_authentication_SUITE.erl index 5270b1b13..e04b8566b 100644 --- a/apps/emqx/test/emqx_authentication_SUITE.erl +++ b/apps/emqx/test/emqx_authentication_SUITE.erl @@ -258,6 +258,22 @@ t_update_config({'end', Config}) -> ?AUTHN:deregister_providers([?config("auth1"), ?config("auth2")]), ok. +t_restart({'init', Config}) -> Config; +t_restart(Config) when is_list(Config) -> + ?assertEqual({ok, []}, ?AUTHN:list_chain_names()), + + ?AUTHN:create_chain(test_chain), + ?assertEqual({ok, [test_chain]}, ?AUTHN:list_chain_names()), + + ok = supervisor:terminate_child(emqx_authentication_sup, ?AUTHN), + {ok, _} = supervisor:restart_child(emqx_authentication_sup, ?AUTHN), + + ?assertEqual({ok, [test_chain]}, ?AUTHN:list_chain_names()); + +t_restart({'end', Config}) -> + ?AUTHN:delete_chain(test_chain), + ok. + t_convert_certs({_, Config}) -> Config; t_convert_certs(Config) when is_list(Config) -> Global = <<"mqtt:global">>, diff --git a/apps/emqx_authn/src/emqx_authn_app.erl b/apps/emqx_authn/src/emqx_authn_app.erl index f6e02a665..a2f6ce02a 100644 --- a/apps/emqx_authn/src/emqx_authn_app.erl +++ b/apps/emqx_authn/src/emqx_authn_app.erl @@ -34,12 +34,11 @@ start(_StartType, _StartArgs) -> ok = mria_rlog:wait_for_shards([?AUTH_SHARD], infinity), {ok, Sup} = emqx_authn_sup:start_link(), - ok = ?AUTHN:register_providers(emqx_authn:providers()), ok = initialize(), {ok, Sup}. stop(_State) -> - ok = ?AUTHN:deregister_providers(provider_types()), + ok = deinitialize(), ok. %%------------------------------------------------------------------------------ @@ -47,12 +46,37 @@ stop(_State) -> %%------------------------------------------------------------------------------ initialize() -> - RawConfigs = emqx:get_raw_config([authentication], []), - Config = emqx_authn:check_configs(RawConfigs), - ?AUTHN:initialize_authentication(?GLOBAL, Config), - lists:foreach(fun({ListenerID, ListenerConfig}) -> - ?AUTHN:initialize_authentication(ListenerID, maps:get(authentication, ListenerConfig, [])) - end, emqx_listeners:list()). + ok = ?AUTHN:register_providers(emqx_authn:providers()), + + lists:foreach( + fun({ChainName, RawAuthConfigs}) -> + AuthConfig = emqx_authn:check_configs(RawAuthConfigs), + ?AUTHN:initialize_authentication( + ChainName, + AuthConfig) + end, + chain_configs()). + +deinitialize() -> + ok = ?AUTHN:deregister_providers(provider_types()). + +chain_configs() -> + [global_chain_config() | listener_chain_configs()]. + +global_chain_config() -> + {?GLOBAL, emqx:get_raw_config([<<"authentication">>], [])}. + +listener_chain_configs() -> + lists:map( + fun({ListenerID, _}) -> + {ListenerID, emqx:get_raw_config(auth_config_path(ListenerID), [])} + end, + emqx_listeners:list()). + +auth_config_path(ListenerID) -> + [<<"listeners">>] + ++ binary:split(atom_to_binary(ListenerID), <<":">>) + ++ [<<"authentication">>]. provider_types() -> lists:map(fun({Type, _Module}) -> Type end, emqx_authn:providers()).