diff --git a/apps/emqx/src/emqx_config_handler.erl b/apps/emqx/src/emqx_config_handler.erl index a189fc9e5..f38c5563a 100644 --- a/apps/emqx/src/emqx_config_handler.erl +++ b/apps/emqx/src/emqx_config_handler.erl @@ -678,7 +678,7 @@ return_change_result(ConfKeyPath, {{update, Req}, Opts}) -> case Req =/= ?TOMBSTONE_CONFIG_CHANGE_REQ of true -> #{ - config => emqx_config:get(ConfKeyPath), + config => emqx_config:get(ConfKeyPath, undefined), raw_config => return_rawconf(ConfKeyPath, Opts) }; false -> diff --git a/apps/emqx_dashboard/src/emqx_dashboard_schema.erl b/apps/emqx_dashboard/src/emqx_dashboard_schema.erl index 7427e81da..59be9706e 100644 --- a/apps/emqx_dashboard/src/emqx_dashboard_schema.erl +++ b/apps/emqx_dashboard/src/emqx_dashboard_schema.erl @@ -68,7 +68,7 @@ fields("dashboard") -> importance => ?IMPORTANCE_HIDDEN } )} - ]; + ] ++ sso_fields(); fields("listeners") -> [ {"http", @@ -299,3 +299,18 @@ https_converter(Conf = #{}, _Opts) -> Conf1#{<<"ssl_options">> => SslOpts}; https_converter(Conf, _Opts) -> Conf. + +-if(?EMQX_RELEASE_EDITION == ee). +sso_fields() -> + [ + {sso, + ?HOCON( + ?R_REF(emqx_dashboard_sso_schema, sso), + #{required => {false, recursively}} + )} + ]. + +-else. +sso_fields() -> + []. +-endif. diff --git a/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_api.erl b/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_api.erl index 0887d3c24..5ac24f1f4 100644 --- a/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_api.erl +++ b/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_api.erl @@ -40,6 +40,7 @@ -define(BAD_REQUEST, 'BAD_REQUEST'). -define(BACKEND_NOT_FOUND, 'BACKEND_NOT_FOUND'). -define(TAGS, <<"Dashboard Single Sign-On">>). +-define(MOD_KEY_PATH, [dashboard, sso]). namespace() -> "dashboard_sso". @@ -139,7 +140,7 @@ fields(backend_status) -> %%-------------------------------------------------------------------- running(get, _Request) -> - SSO = emqx:get_config([dashboard_sso], #{}), + SSO = emqx:get_config(?MOD_KEY_PATH, #{}), {200, lists:filtermap( fun @@ -175,7 +176,7 @@ login(post, #{bindings := #{backend := Backend}, body := Body} = Request) -> end. sso(get, _Request) -> - SSO = emqx:get_config([dashboard_sso], #{}), + SSO = emqx:get_config(?MOD_KEY_PATH, #{}), {200, lists:map( fun(Backend) -> @@ -185,7 +186,7 @@ sso(get, _Request) -> )}. backend(get, #{bindings := #{backend := Type}}) -> - case emqx:get_config([dashboard_sso, Type], undefined) of + case emqx:get_config(?MOD_KEY_PATH ++ [Type], undefined) of undefined -> {404, #{code => ?BACKEND_NOT_FOUND, message => <<"Backend not found">>}}; Backend -> diff --git a/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_manager.erl b/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_manager.erl index afa27cb47..10ae07b3f 100644 --- a/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_manager.erl +++ b/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_manager.erl @@ -35,12 +35,14 @@ update/2, delete/1, pre_config_update/3, - post_config_update/5 + post_config_update/5, + propagated_post_config_update/5 ]). -import(emqx_dashboard_sso, [provider/1]). --define(MOD_KEY_PATH, [dashboard_sso]). +-define(MOD_KEY_PATH, [dashboard, sso]). +-define(MOD_KEY_PATH(Sub), [dashboard, sso, Sub]). -define(RESOURCE_GROUP, <<"emqx_dashboard_sso">>). -define(DEFAULT_RESOURCE_OPTS, #{ start_after_created => false @@ -66,7 +68,7 @@ running() -> Acc end, [], - emqx:get_config([emqx_dashboard_sso]) + emqx:get_config(?MOD_KEY_PATH) ). update(Backend, Config) -> @@ -110,7 +112,7 @@ call(Req) -> %%------------------------------------------------------------------------------ init([]) -> process_flag(trap_exit, true), - emqx_conf:add_handler(?MOD_KEY_PATH, ?MODULE), + add_handler(), emqx_utils_ets:new( dashboard_sso, [ @@ -138,7 +140,7 @@ handle_info(_Info, State) -> {noreply, State}. terminate(_Reason, _State) -> - emqx_conf:remove_handler(?MOD_KEY_PATH), + remove_handler(), ok. code_change(_OldVsn, State, _Extra) -> @@ -151,7 +153,7 @@ format_status(_Opt, Status) -> %% Internal functions %%------------------------------------------------------------------------------ start_backend_services() -> - Backends = emqx_conf:get([dashboard_sso], #{}), + Backends = emqx_conf:get(?MOD_KEY_PATH, #{}), lists:foreach( fun({Backend, Config}) -> Provider = provider(Backend), @@ -174,7 +176,7 @@ start_backend_services() -> ). update_config(Backend, UpdateReq) -> - case emqx_conf:update([dashboard_sso], UpdateReq, #{override_to => cluster}) of + case emqx_conf:update(?MOD_KEY_PATH(Backend), UpdateReq, #{override_to => cluster}) of {ok, UpdateResult} -> #{post_config_update := #{?MODULE := Result}} = UpdateResult, ?SLOG(info, #{ @@ -192,25 +194,38 @@ update_config(Backend, UpdateReq) -> Error end. -pre_config_update(_Path, {update, Backend, Config}, OldConf) -> - BackendBin = bin(Backend), - {ok, OldConf#{BackendBin => Config}}; -pre_config_update(_Path, {delete, Backend}, OldConf) -> - BackendBin = bin(Backend), - case maps:find(BackendBin, OldConf) of - error -> - throw(not_exists); - {ok, _} -> - {ok, maps:remove(BackendBin, OldConf)} - end. +pre_config_update(_, {update, _Backend, Config}, _OldConf) -> + {ok, Config}; +pre_config_update(_, {delete, _Backend}, undefined) -> + throw(not_exists); +pre_config_update(_, {delete, _Backend}, _OldConf) -> + {ok, null}. -post_config_update(_Path, UpdateReq, NewConf, _OldConf, _AppEnvs) -> +post_config_update(_, UpdateReq, NewConf, _OldConf, _AppEnvs) -> Result = call({update_config, UpdateReq, NewConf}), {ok, Result}. -on_config_update({update, Backend, _Config}, NewConf) -> +propagated_post_config_update( + ?MOD_KEY_PATH(BackendBin) = Path, _UpdateReq, undefined, OldConf, AppEnvs +) -> + case atom(BackendBin) of + {ok, Backend} -> + post_config_update(Path, {delete, Backend}, undefined, OldConf, AppEnvs); + Error -> + Error + end; +propagated_post_config_update( + ?MOD_KEY_PATH(BackendBin) = Path, _UpdateReq, NewConf, OldConf, AppEnvs +) -> + case atom(BackendBin) of + {ok, Backend} -> + post_config_update(Path, {update, Backend, undefined}, NewConf, OldConf, AppEnvs); + Error -> + Error + end. + +on_config_update({update, Backend, _RawConfig}, Config) -> Provider = provider(Backend), - Config = maps:get(Backend, NewConf), case lookup(Backend) of undefined -> on_backend_updated( @@ -267,3 +282,12 @@ on_backend_updated(Error, _) -> bin(A) when is_atom(A) -> atom_to_binary(A, utf8); bin(L) when is_list(L) -> list_to_binary(L); bin(X) -> X. + +atom(B) -> + emqx_utils:safe_to_existing_atom(B). + +add_handler() -> + ok = emqx_conf:add_handler(?MOD_KEY_PATH('?'), ?MODULE). + +remove_handler() -> + ok = emqx_conf:remove_handler(?MOD_KEY_PATH('?')). diff --git a/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_schema.erl b/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_schema.erl index b45bca8e5..92f9ba519 100644 --- a/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_schema.erl +++ b/apps/emqx_dashboard_sso/src/emqx_dashboard_sso_schema.erl @@ -8,33 +8,32 @@ -include_lib("typerefl/include/types.hrl"). %% Hocon --export([namespace/0, roots/0, fields/1, tags/0, desc/1]). +-export([fields/1, desc/1]). + -export([ common_backend_schema/1, backend_schema/1, username_password_schema/0 ]). + -import(hoconsc, [ref/2, mk/2, enum/1]). %%------------------------------------------------------------------------------ %% Hocon Schema %%------------------------------------------------------------------------------ -namespace() -> dashboard_sso. - -tags() -> - [<<"Dashboard Single Sign-On">>]. - -roots() -> [dashboard_sso]. - -fields(dashboard_sso) -> +fields(sso) -> lists:map( fun({Type, Module}) -> - {Type, mk(emqx_dashboard_sso:hocon_ref(Module), #{required => {false, recursively}})} + {Type, + mk( + emqx_dashboard_sso:hocon_ref(Module), + #{required => {false, recursively}} + )} end, maps:to_list(emqx_dashboard_sso:backends()) ). -desc(dashboard_sso) -> +desc(sso) -> "Dashboard Single Sign-On"; desc(_) -> undefined. diff --git a/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_ldap_SUITE.erl b/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_ldap_SUITE.erl index 85cb23693..671276e59 100644 --- a/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_ldap_SUITE.erl +++ b/apps/emqx_dashboard_sso/test/emqx_dashboard_sso_ldap_SUITE.erl @@ -29,7 +29,7 @@ all() -> init_per_suite(Config) -> _ = application:load(emqx_conf), - emqx_config:save_schema_mod_and_names(emqx_dashboard_sso_schema), + emqx_config:save_schema_mod_and_names(emqx_dashboard_schema), emqx_mgmt_api_test_util:init_suite([emqx_dashboard, emqx_dashboard_sso]), Config. diff --git a/apps/emqx_enterprise/src/emqx_enterprise_schema.erl b/apps/emqx_enterprise/src/emqx_enterprise_schema.erl index c238dcea4..a801825e0 100644 --- a/apps/emqx_enterprise/src/emqx_enterprise_schema.erl +++ b/apps/emqx_enterprise/src/emqx_enterprise_schema.erl @@ -11,8 +11,7 @@ -define(EE_SCHEMA_MODULES, [ emqx_license_schema, emqx_schema_registry_schema, - emqx_ft_schema, - emqx_dashboard_sso_schema + emqx_ft_schema ]). namespace() ->