diff --git a/apps/emqx_auth/include/emqx_authz.hrl b/apps/emqx_auth/include/emqx_authz.hrl index f017b9be5..9af795a82 100644 --- a/apps/emqx_auth/include/emqx_authz.hrl +++ b/apps/emqx_auth/include/emqx_authz.hrl @@ -163,3 +163,8 @@ -define(DEFAULT_RULE_QOS, [0, 1, 2]). -define(DEFAULT_RULE_RETAIN, all). + +-define(BUILTIN_SOURCES, [ + {client_info, emqx_authz_client_info}, + {file, emqx_authz_file} +]). diff --git a/apps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl b/apps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl index 5eca842f4..0d668bc20 100644 --- a/apps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl +++ b/apps/emqx_auth/src/emqx_authn/emqx_authn_chains.erl @@ -26,6 +26,7 @@ -include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/emqx_hooks.hrl"). -include_lib("stdlib/include/ms_transform.hrl"). +-include_lib("snabbkaffe/include/snabbkaffe.hrl"). -define(CONF_ROOT, ?EMQX_AUTHENTICATION_CONFIG_ROOT_NAME_ATOM). @@ -446,7 +447,7 @@ handle_continue(initialize_authentication, #{init_done := true} = State) -> {noreply, State}; handle_continue(initialize_authentication, #{providers := Providers} = State) -> InitDone = initialize_authentication(Providers), - {noreply, State#{init_done := InitDone}}. + {noreply, maybe_hook(State#{init_done := InitDone})}. handle_cast(Req, State) -> ?SLOG(error, #{msg => "unexpected_cast", cast => Req}), @@ -495,6 +496,7 @@ do_initialize_authentication(Providers, Chains, _HasProviders = true) -> Chains ), ok = unhook_deny(), + ?tp(info, authn_chains_initialization_done, #{}), true. initialize_chain_authentication(_Providers, _ChainName, []) -> diff --git a/apps/emqx_auth/src/emqx_authz/emqx_authz.erl b/apps/emqx_auth/src/emqx_authz/emqx_authz.erl index 30210ff72..1eed8a663 100644 --- a/apps/emqx_auth/src/emqx_authz/emqx_authz.erl +++ b/apps/emqx_auth/src/emqx_authz/emqx_authz.erl @@ -88,8 +88,7 @@ init() -> emqx_conf:add_handler(?CONF_KEY_PATH, ?MODULE), emqx_conf:add_handler(?ROOT_KEY, ?MODULE), ok = emqx_hooks:put('client.authorize', {?MODULE, authorize_deny, []}, ?HP_AUTHZ), - ok = register_source(client_info, emqx_authz_client_info), - ok = register_source(file, emqx_authz_file), + ok = register_builtin_sources(), ok. register_source(Type, Module) -> @@ -124,6 +123,14 @@ are_all_providers_registered() -> false end. +register_builtin_sources() -> + lists:foreach( + fun({Type, Module}) -> + register_source(Type, Module) + end, + ?BUILTIN_SOURCES + ). + configured_types() -> lists:map( fun(#{type := Type}) -> Type end, @@ -186,8 +193,14 @@ pre_config_update(Path, Cmd, Sources) -> {error, Reason} -> {error, Reason}; NSources -> {ok, NSources} catch - Error:Reason:Stack -> + throw:Reason -> ?SLOG(info, #{ + msg => "error_in_pre_config_update", + reason => Reason + }), + {error, Reason}; + Error:Reason:Stack -> + ?SLOG(warning, #{ msg => "error_in_pre_config_update", exception => Error, reason => Reason, @@ -572,10 +585,6 @@ maybe_convert_sources( maybe_convert_sources(RawConf, _Fun) -> RawConf. -% read_acl_file(#{<<"path">> := Path} = Source) -> -% {ok, Rules} = emqx_authz_file:read_file(Path), -% maps:remove(<<"path">>, Source#{<<"rules">> => Rules}). - %%------------------------------------------------------------------------------ %% Extended Features %%------------------------------------------------------------------------------ @@ -682,7 +691,7 @@ maybe_read_source_files_safe(Source0) -> catch Error:Reason:Stacktrace -> ?SLOG(error, #{ - msg => "error_in_maybe_read_source_files", + msg => "error_when_reading_source_files", exception => Error, reason => Reason, stacktrace => Stacktrace diff --git a/apps/emqx_auth/test/emqx_authn/emqx_authn_init_SUITE.erl b/apps/emqx_auth/test/emqx_authn/emqx_authn_init_SUITE.erl index 48542ebfc..80f37be26 100644 --- a/apps/emqx_auth/test/emqx_authn/emqx_authn_init_SUITE.erl +++ b/apps/emqx_auth/test/emqx_authn/emqx_authn_init_SUITE.erl @@ -19,6 +19,7 @@ -compile(export_all). -compile(nowarn_export_all). +-include_lib("emqx/include/asserts.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). @@ -48,9 +49,11 @@ init_per_testcase(_Case, Config) -> work_dir => ?config(priv_dir, Config) } ), + ok = snabbkaffe:start_trace(), [{apps, Apps} | Config]. end_per_testcase(_Case, Config) -> + ok = snabbkaffe:stop(), _ = application:stop(emqx_auth), ok = emqx_cth_suite:stop(?config(apps, Config)), ok. @@ -66,10 +69,14 @@ t_initialize(_Config) -> emqx_access_control:authenticate(?CLIENTINFO) ), - ok = emqx_authn_test_lib:register_fake_providers([{password_based, built_in_database}]), + ?assertWaitEvent( + ok = emqx_authn_test_lib:register_fake_providers([{password_based, built_in_database}]), + #{?snk_kind := authn_chains_initialization_done}, + 100 + ), ?assertMatch( - {error, not_authorized}, + {error, bad_username_or_password}, emqx_access_control:authenticate(?CLIENTINFO) ), diff --git a/apps/emqx_auth/test/emqx_authz/emqx_authz_SUITE.erl b/apps/emqx_auth/test/emqx_authz/emqx_authz_SUITE.erl index 2e45c5c11..1af7d4d1d 100644 --- a/apps/emqx_auth/test/emqx_authz/emqx_authz_SUITE.erl +++ b/apps/emqx_auth/test/emqx_authz/emqx_authz_SUITE.erl @@ -20,7 +20,6 @@ -include("emqx_authz.hrl"). -include_lib("emqx/include/emqx.hrl"). --include_lib("emqx/include/emqx_mqtt.hrl"). -include_lib("eunit/include/eunit.hrl"). -include_lib("common_test/include/ct.hrl"). -include_lib("emqx/include/emqx_placeholder.hrl"). @@ -35,33 +34,18 @@ groups() -> []. init_per_suite(Config) -> - meck:new(emqx_resource, [non_strict, passthrough, no_history, no_link]), - meck:expect(emqx_resource, create_local, fun(_, _, _, _) -> {ok, meck_data} end), - meck:expect(emqx_resource, remove_local, fun(_) -> ok end), - meck:expect( - emqx_authz_file, - acl_conf_file, - fun() -> - emqx_common_test_helpers:deps_path(emqx_auth, "etc/acl.conf") - end - ), Apps = emqx_cth_suite:start( [ emqx, {emqx_conf, "authorization { cache { enable = false }, no_match = deny, sources = [] }"}, - emqx_auth, - emqx_auth_http, - emqx_auth_mnesia, - emqx_auth_redis, - emqx_auth_postgresql, - emqx_auth_mysql, - emqx_auth_mongodb + emqx_auth ], #{ work_dir => filename:join(?config(priv_dir, Config), ?MODULE) } ), + ok = emqx_authz_test_lib:register_fake_sources([http, redis, mongodb, mysql, postgresql]), [{suite_apps, Apps} | Config]. end_per_suite(Config) -> @@ -73,8 +57,8 @@ end_per_suite(Config) -> <<"sources">> => [] } ), + ok = emqx_authz_test_lib:deregister_sources(), emqx_cth_suite:stop(?config(suite_apps, Config)), - meck:unload(emqx_resource), ok. init_per_testcase(TestCase, Config) when @@ -102,7 +86,7 @@ end_per_testcase(_TestCase, _Config) -> emqx_common_test_helpers:call_janitor(), ok. --define(SOURCE1, #{ +-define(SOURCE_HTTP, #{ <<"type">> => <<"http">>, <<"enable">> => true, <<"url">> => <<"https://example.com:443/a/b?c=d">>, @@ -111,7 +95,7 @@ end_per_testcase(_TestCase, _Config) -> <<"method">> => <<"get">>, <<"request_timeout">> => <<"5s">> }). --define(SOURCE2, #{ +-define(SOURCE_MONGODB, #{ <<"type">> => <<"mongodb">>, <<"enable">> => true, <<"mongo_type">> => <<"single">>, @@ -123,7 +107,7 @@ end_per_testcase(_TestCase, _Config) -> <<"collection">> => <<"authz">>, <<"filter">> => #{<<"a">> => <<"b">>} }). --define(SOURCE3, #{ +-define(SOURCE_MYSQL, #{ <<"type">> => <<"mysql">>, <<"enable">> => true, <<"server">> => <<"127.0.0.1:27017">>, @@ -135,7 +119,7 @@ end_per_testcase(_TestCase, _Config) -> <<"ssl">> => #{<<"enable">> => false}, <<"query">> => <<"abcb">> }). --define(SOURCE4, #{ +-define(SOURCE_POSTGRESQL, #{ <<"type">> => <<"postgresql">>, <<"enable">> => true, <<"server">> => <<"127.0.0.1:27017">>, @@ -147,7 +131,7 @@ end_per_testcase(_TestCase, _Config) -> <<"ssl">> => #{<<"enable">> => false}, <<"query">> => <<"abcb">> }). --define(SOURCE5, #{ +-define(SOURCE_REDIS, #{ <<"type">> => <<"redis">>, <<"redis_type">> => <<"single">>, <<"enable">> => true, @@ -160,22 +144,22 @@ end_per_testcase(_TestCase, _Config) -> <<"cmd">> => <<"HGETALL mqtt_authz:", ?PH_USERNAME/binary>> }). --define(FILE_SOURCE(Rules), #{ +-define(SOURCE_FILE(Rules), #{ <<"type">> => <<"file">>, <<"enable">> => true, <<"rules">> => Rules }). --define(SOURCE6, - ?FILE_SOURCE( +-define(SOURCE_FILE1, + ?SOURCE_FILE( << "{allow,{username,\"^dashboard?\"},subscribe,[\"$SYS/#\"]}." "\n{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}." >> ) ). --define(SOURCE7, - ?FILE_SOURCE( +-define(SOURCE_FILE2, + ?SOURCE_FILE( << "{allow,{username,\"some_client\"},publish,[\"some_client/lwt\"]}.\n" "{deny, all}." @@ -183,15 +167,6 @@ end_per_testcase(_TestCase, _Config) -> ) ). --define(BAD_FILE_SOURCE2, #{ - <<"type">> => <<"file">>, - <<"enable">> => true, - <<"rules">> => - << - "{not_allow,{username,\"some_client\"},publish,[\"some_client/lwt\"]}." - >> -}). - %%------------------------------------------------------------------------------ %% Testcases %%------------------------------------------------------------------------------ @@ -199,24 +174,23 @@ end_per_testcase(_TestCase, _Config) -> -define(UPDATE_ERROR(Err), {error, {pre_config_update, emqx_authz, Err}}). t_bad_file_source(_) -> - BadContent = ?FILE_SOURCE(<<"{allow,{username,\"bar\"}, publish, [\"test\"]}">>), + BadContent = ?SOURCE_FILE(<<"{allow,{username,\"bar\"}, publish, [\"test\"]}">>), BadContentErr = {bad_acl_file_content, {1, erl_parse, ["syntax error before: ", []]}}, - BadRule = ?FILE_SOURCE(<<"{allow,{username,\"bar\"},publish}.">>), + BadRule = ?SOURCE_FILE(<<"{allow,{username,\"bar\"},publish}.">>), BadRuleErr = {invalid_authorization_rule, {allow, {username, "bar"}, publish}}, - BadPermission = ?FILE_SOURCE(<<"{not_allow,{username,\"bar\"},publish,[\"test\"]}.">>), + BadPermission = ?SOURCE_FILE(<<"{not_allow,{username,\"bar\"},publish,[\"test\"]}.">>), BadPermissionErr = {invalid_authorization_permission, not_allow}, - BadAction = ?FILE_SOURCE(<<"{allow,{username,\"bar\"},pubsub,[\"test\"]}.">>), + BadAction = ?SOURCE_FILE(<<"{allow,{username,\"bar\"},pubsub,[\"test\"]}.">>), BadActionErr = {invalid_authorization_action, pubsub}, lists:foreach( fun({Source, Error}) -> File = emqx_authz_file:acl_conf_file(), - {ok, Bin1} = file:read_file(File), + ?assertEqual({error, enoent}, file:read_file(File)), ?assertEqual(?UPDATE_ERROR(Error), emqx_authz:update(?CMD_REPLACE, [Source])), ?assertEqual(?UPDATE_ERROR(Error), emqx_authz:update(?CMD_PREPEND, Source)), ?assertEqual(?UPDATE_ERROR(Error), emqx_authz:update(?CMD_APPEND, Source)), - %% Check file content not changed if update failed - {ok, Bin2} = file:read_file(File), - ?assertEqual(Bin1, Bin2) + %% Check file is not created if update failed; + ?assertEqual({error, enoent}, file:read_file(File)) end, [ {BadContent, BadContentErr}, @@ -230,14 +204,32 @@ t_bad_file_source(_) -> emqx_conf:get([authorization, sources], []) ). +t_good_file_source(_) -> + RuleBin = <<"{allow,{username,\"bar\"}, publish, [\"test\"]}.">>, + GoodFileSource = ?SOURCE_FILE(RuleBin), + File = emqx_authz_file:acl_conf_file(), + lists:foreach( + fun({Command, Argument}) -> + _ = file:delete(File), + ?assertMatch({ok, _}, emqx_authz:update(Command, Argument)), + ?assertEqual({ok, RuleBin}, file:read_file(File)), + {ok, _} = emqx_authz:update(?CMD_REPLACE, []) + end, + [ + {?CMD_REPLACE, [GoodFileSource]}, + {?CMD_PREPEND, GoodFileSource}, + {?CMD_APPEND, GoodFileSource} + ] + ). + t_update_source(_) -> %% replace all - {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE3]), - {ok, _} = emqx_authz:update(?CMD_PREPEND, ?SOURCE2), - {ok, _} = emqx_authz:update(?CMD_PREPEND, ?SOURCE1), - {ok, _} = emqx_authz:update(?CMD_APPEND, ?SOURCE4), - {ok, _} = emqx_authz:update(?CMD_APPEND, ?SOURCE5), - {ok, _} = emqx_authz:update(?CMD_APPEND, ?SOURCE6), + {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE_MYSQL]), + {ok, _} = emqx_authz:update(?CMD_PREPEND, ?SOURCE_MONGODB), + {ok, _} = emqx_authz:update(?CMD_PREPEND, ?SOURCE_HTTP), + {ok, _} = emqx_authz:update(?CMD_APPEND, ?SOURCE_POSTGRESQL), + {ok, _} = emqx_authz:update(?CMD_APPEND, ?SOURCE_REDIS), + {ok, _} = emqx_authz:update(?CMD_APPEND, ?SOURCE_FILE1), ?assertMatch( [ @@ -251,19 +243,23 @@ t_update_source(_) -> emqx_conf:get([authorization, sources], []) ), - {ok, _} = emqx_authz:update({?CMD_REPLACE, http}, ?SOURCE1#{<<"enable">> := true}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, mongodb}, ?SOURCE2#{<<"enable">> := true}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, mysql}, ?SOURCE3#{<<"enable">> := true}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, postgresql}, ?SOURCE4#{<<"enable">> := true}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, redis}, ?SOURCE5#{<<"enable">> := true}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, file}, ?SOURCE6#{<<"enable">> := true}), + {ok, _} = emqx_authz:update({?CMD_REPLACE, http}, ?SOURCE_HTTP#{<<"enable">> := true}), + {ok, _} = emqx_authz:update({?CMD_REPLACE, mongodb}, ?SOURCE_MONGODB#{<<"enable">> := true}), + {ok, _} = emqx_authz:update({?CMD_REPLACE, mysql}, ?SOURCE_MYSQL#{<<"enable">> := true}), + {ok, _} = emqx_authz:update({?CMD_REPLACE, postgresql}, ?SOURCE_POSTGRESQL#{ + <<"enable">> := true + }), + {ok, _} = emqx_authz:update({?CMD_REPLACE, redis}, ?SOURCE_REDIS#{<<"enable">> := true}), + {ok, _} = emqx_authz:update({?CMD_REPLACE, file}, ?SOURCE_FILE1#{<<"enable">> := true}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, http}, ?SOURCE1#{<<"enable">> := false}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, mongodb}, ?SOURCE2#{<<"enable">> := false}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, mysql}, ?SOURCE3#{<<"enable">> := false}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, postgresql}, ?SOURCE4#{<<"enable">> := false}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, redis}, ?SOURCE5#{<<"enable">> := false}), - {ok, _} = emqx_authz:update({?CMD_REPLACE, file}, ?SOURCE6#{<<"enable">> := false}), + {ok, _} = emqx_authz:update({?CMD_REPLACE, http}, ?SOURCE_HTTP#{<<"enable">> := false}), + {ok, _} = emqx_authz:update({?CMD_REPLACE, mongodb}, ?SOURCE_MONGODB#{<<"enable">> := false}), + {ok, _} = emqx_authz:update({?CMD_REPLACE, mysql}, ?SOURCE_MYSQL#{<<"enable">> := false}), + {ok, _} = emqx_authz:update({?CMD_REPLACE, postgresql}, ?SOURCE_POSTGRESQL#{ + <<"enable">> := false + }), + {ok, _} = emqx_authz:update({?CMD_REPLACE, redis}, ?SOURCE_REDIS#{<<"enable">> := false}), + {ok, _} = emqx_authz:update({?CMD_REPLACE, file}, ?SOURCE_FILE1#{<<"enable">> := false}), ?assertMatch( [ @@ -295,7 +291,12 @@ t_replace_all(_) -> Conf = emqx:get_raw_config(RootKey), emqx_authz_utils:update_config(RootKey, Conf#{ <<"sources">> => [ - ?SOURCE6, ?SOURCE5, ?SOURCE4, ?SOURCE3, ?SOURCE2, ?SOURCE1 + ?SOURCE_FILE1, + ?SOURCE_REDIS, + ?SOURCE_POSTGRESQL, + ?SOURCE_MYSQL, + ?SOURCE_MONGODB, + ?SOURCE_HTTP ] }), %% config @@ -335,7 +336,7 @@ t_replace_all(_) -> {ok, _}, emqx_authz_utils:update_config( RootKey, - Conf#{<<"sources">> => [?SOURCE1#{<<"enable">> => false}]} + Conf#{<<"sources">> => [?SOURCE_HTTP#{<<"enable">> => false}]} ) ), %% hooks status @@ -351,7 +352,7 @@ t_replace_all(_) -> ok. t_delete_source(_) -> - {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE1]), + {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE_HTTP]), ?assertMatch([#{type := http, enable := true}], emqx_conf:get([authorization, sources], [])), @@ -363,12 +364,12 @@ t_move_source(_) -> {ok, _} = emqx_authz:update( ?CMD_REPLACE, [ - ?SOURCE1, - ?SOURCE2, - ?SOURCE3, - ?SOURCE4, - ?SOURCE5, - ?SOURCE6 + ?SOURCE_HTTP, + ?SOURCE_MONGODB, + ?SOURCE_MYSQL, + ?SOURCE_POSTGRESQL, + ?SOURCE_REDIS, + ?SOURCE_FILE1 ] ), ?assertMatch( @@ -437,15 +438,26 @@ t_move_source(_) -> ok. +t_pre_config_update_crash(_) -> + ok = meck:new(emqx_authz_fake_source, [non_strict, passthrough, no_history]), + ok = meck:expect(emqx_authz_fake_source, write_files, fun(_) -> meck:exception(error, oops) end), + ?assertEqual( + {error, {pre_config_update, emqx_authz, oops}}, + emqx_authz:update(?CMD_APPEND, ?SOURCE_HTTP) + ), + ok = meck:unload(emqx_authz_fake_source). + t_get_enabled_authzs_none_enabled(_Config) -> ?assertEqual([], emqx_authz:get_enabled_authzs()). t_get_enabled_authzs_some_enabled(_Config) -> - {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE4, ?SOURCE5#{<<"enable">> := false}]), + {ok, _} = emqx_authz:update(?CMD_REPLACE, [ + ?SOURCE_POSTGRESQL, ?SOURCE_REDIS#{<<"enable">> := false} + ]), ?assertEqual([postgresql], emqx_authz:get_enabled_authzs()). t_subscribe_deny_disconnect_publishes_last_will_testament(_Config) -> - {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE7]), + {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE_FILE2]), {ok, C} = emqtt:start_link([ {username, <<"some_client">>}, {will_topic, <<"some_client/lwt">>}, @@ -473,7 +485,7 @@ t_subscribe_deny_disconnect_publishes_last_will_testament(_Config) -> ok. t_publish_deny_disconnect_publishes_last_will_testament(_Config) -> - {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE7]), + {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE_FILE2]), {ok, C} = emqtt:start_link([ {username, <<"some_client">>}, {will_topic, <<"some_client/lwt">>}, @@ -530,7 +542,7 @@ t_publish_last_will_testament_denied_topic(_Config) -> %% and then gets banned and kicked out while connected. Should not %% publish LWT. t_publish_last_will_testament_banned_client_connecting(_Config) -> - {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE7]), + {ok, _} = emqx_authz:update(?CMD_REPLACE, [?SOURCE_FILE2]), Username = <<"some_client">>, ClientId = <<"some_clientid">>, LWTPayload = <<"should not be published">>, diff --git a/apps/emqx_auth/test/emqx_authz/emqx_authz_api_sources_SUITE.erl b/apps/emqx_auth/test/emqx_authz/emqx_authz_api_sources_SUITE.erl index 1ead754ec..e9dfa6a7b 100644 --- a/apps/emqx_auth/test/emqx_authz/emqx_authz_api_sources_SUITE.erl +++ b/apps/emqx_auth/test/emqx_authz/emqx_authz_api_sources_SUITE.erl @@ -29,7 +29,7 @@ -define(PGSQL_HOST, "pgsql"). -define(REDIS_SINGLE_HOST, "redis"). --define(SOURCE1, #{ +-define(SOURCE_REDIS1, #{ <<"type">> => <<"http">>, <<"enable">> => true, <<"url">> => <<"https://fake.com:443/acl?username=", ?PH_USERNAME/binary>>, @@ -38,7 +38,7 @@ <<"method">> => <<"get">>, <<"request_timeout">> => <<"5s">> }). --define(SOURCE2, #{ +-define(SOURCE_MONGODB, #{ <<"type">> => <<"mongodb">>, <<"enable">> => true, <<"mongo_type">> => <<"single">>, @@ -50,7 +50,7 @@ <<"collection">> => <<"fake">>, <<"filter">> => #{<<"a">> => <<"b">>} }). --define(SOURCE3, #{ +-define(SOURCE_MYSQL, #{ <<"type">> => <<"mysql">>, <<"enable">> => true, <<"server">> => <>, @@ -62,7 +62,7 @@ <<"ssl">> => #{<<"enable">> => false}, <<"query">> => <<"abcb">> }). --define(SOURCE4, #{ +-define(SOURCE_POSTGRESQL, #{ <<"type">> => <<"postgresql">>, <<"enable">> => true, <<"server">> => <>, @@ -74,7 +74,7 @@ <<"ssl">> => #{<<"enable">> => false}, <<"query">> => <<"abcb">> }). --define(SOURCE5, #{ +-define(SOURCE_REDIS2, #{ <<"type">> => <<"redis">>, <<"enable">> => true, <<"servers">> => <>, @@ -85,7 +85,7 @@ <<"ssl">> => #{<<"enable">> => false}, <<"cmd">> => <<"HGETALL mqtt_authz:", ?PH_USERNAME/binary>> }). --define(SOURCE6, #{ +-define(SOURCE_FILE, #{ <<"type">> => <<"file">>, <<"enable">> => true, <<"rules">> => @@ -120,12 +120,6 @@ init_per_suite(Config) -> {emqx_conf, "authorization { cache { enable = false }, no_match = deny, sources = [] }"}, emqx_auth, - emqx_auth_http, - emqx_auth_mnesia, - emqx_auth_redis, - emqx_auth_postgresql, - emqx_auth_mysql, - emqx_auth_mongodb, emqx_management, {emqx_dashboard, "dashboard.listeners.http { enable = true, bind = 18083 }"} ], @@ -133,6 +127,7 @@ init_per_suite(Config) -> work_dir => filename:join(?config(priv_dir, Config), ?MODULE) } ), + ok = emqx_authz_test_lib:register_fake_sources([http, mongodb, mysql, postgresql, redis]), _ = emqx_common_test_http:create_default_app(), [{suite_apps, Apps} | Config]. @@ -192,9 +187,11 @@ t_api(_) -> begin {ok, 204, _} = request(post, uri(["authorization", "sources"]), Source) end - || Source <- lists:reverse([?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5, ?SOURCE6]) + || Source <- lists:reverse([ + ?SOURCE_MONGODB, ?SOURCE_MYSQL, ?SOURCE_POSTGRESQL, ?SOURCE_REDIS2, ?SOURCE_FILE + ]) ], - {ok, 204, _} = request(post, uri(["authorization", "sources"]), ?SOURCE1), + {ok, 204, _} = request(post, uri(["authorization", "sources"]), ?SOURCE_REDIS1), {ok, 200, Result2} = request(get, uri(["authorization", "sources"]), []), Sources = get_sources(Result2), @@ -214,7 +211,7 @@ t_api(_) -> {ok, 204, _} = request( put, uri(["authorization", "sources", "http"]), - ?SOURCE1#{<<"enable">> := false} + ?SOURCE_REDIS1#{<<"enable">> := false} ), {ok, 200, Result3} = request(get, uri(["authorization", "sources", "http"]), []), ?assertMatch( @@ -238,7 +235,7 @@ t_api(_) -> {ok, 204, _} = request( put, uri(["authorization", "sources", "mongodb"]), - ?SOURCE2#{ + ?SOURCE_MONGODB#{ <<"ssl">> => #{ <<"enable">> => <<"true">>, <<"cacertfile">> => Cacertfile, @@ -279,7 +276,7 @@ t_api(_) -> {ok, 204, _} = request( put, uri(["authorization", "sources", "mongodb"]), - ?SOURCE2#{ + ?SOURCE_MONGODB#{ <<"ssl">> => #{ <<"enable">> => <<"true">>, <<"cacertfile">> => Cacert, @@ -329,19 +326,19 @@ t_api(_) -> {ok, 204, _} = request( put, uri(["authorization", "sources", "mysql"]), - ?SOURCE3#{<<"server">> := <<"192.168.1.100:3306">>} + ?SOURCE_MYSQL#{<<"server">> := <<"192.168.1.100:3306">>} ), {ok, 204, _} = request( put, uri(["authorization", "sources", "postgresql"]), - ?SOURCE4#{<<"server">> := <<"fake">>} + ?SOURCE_POSTGRESQL#{<<"server">> := <<"fake">>} ), {ok, 204, _} = request( put, uri(["authorization", "sources", "redis"]), - ?SOURCE5#{ + ?SOURCE_REDIS2#{ <<"servers">> := [ <<"192.168.1.100:6379">>, <<"192.168.1.100:6380">> @@ -413,7 +410,7 @@ t_api(_) -> #{<<"type">> => <<"built_in_database">>, <<"enable">> => false} ), - {ok, 204, _} = request(post, uri(["authorization", "sources"]), ?SOURCE6), + {ok, 204, _} = request(post, uri(["authorization", "sources"]), ?SOURCE_FILE), {ok, Client} = emqtt:start_link( [ @@ -505,7 +502,9 @@ t_api(_) -> ok. t_source_move(_) -> - {ok, _} = emqx_authz:update(replace, [?SOURCE1, ?SOURCE2, ?SOURCE3, ?SOURCE4, ?SOURCE5]), + {ok, _} = emqx_authz:update(replace, [ + ?SOURCE_REDIS1, ?SOURCE_MONGODB, ?SOURCE_MYSQL, ?SOURCE_POSTGRESQL, ?SOURCE_REDIS2 + ]), ?assertMatch( [ #{type := http}, diff --git a/apps/emqx_auth/test/emqx_authz/emqx_authz_fake_source.erl b/apps/emqx_auth/test/emqx_authz/emqx_authz_fake_source.erl new file mode 100644 index 000000000..88a54f972 --- /dev/null +++ b/apps/emqx_auth/test/emqx_authz/emqx_authz_fake_source.erl @@ -0,0 +1,46 @@ +%%-------------------------------------------------------------------- +%% Copyright (c) 2022-2023 EMQ Technologies Co., Ltd. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%%-------------------------------------------------------------------- + +-module(emqx_authz_fake_source). + +-behaviour(emqx_authz_source). + +%% APIs +-export([ + description/0, + create/1, + update/1, + destroy/1, + authorize/4 +]). + +%%-------------------------------------------------------------------- +%% emqx_authz callbacks +%%-------------------------------------------------------------------- + +description() -> + "Fake AuthZ". + +create(Source) -> + Source. + +update(Source) -> + Source. + +destroy(_Source) -> ok. + +authorize(_Client, _PubSub, _Topic, _Source) -> + nomatch. diff --git a/apps/emqx_auth/test/emqx_authz/emqx_authz_test_lib.erl b/apps/emqx_auth/test/emqx_authz/emqx_authz_test_lib.erl index 33035c766..cd8fca4df 100644 --- a/apps/emqx_auth/test/emqx_authz/emqx_authz_test_lib.erl +++ b/apps/emqx_auth/test/emqx_authz/emqx_authz_test_lib.erl @@ -51,6 +51,24 @@ setup_config(BaseConfig, SpecialParams) -> {error, Reason} -> {error, Reason} end. +register_fake_sources(SourceTypes) -> + lists:foreach( + fun(Type) -> + emqx_authz_source_registry:register(Type, emqx_authz_fake_source) + end, + SourceTypes + ). + +deregister_sources() -> + {BuiltInTypes, _} = lists:unzip(?BUILTIN_SOURCES), + SourceTypes = emqx_authz_source_registry:get(), + lists:foreach( + fun(Type) -> + emqx_authz_source_registry:register(Type, emqx_authz_fake_source) + end, + SourceTypes -- BuiltInTypes + ). + %%-------------------------------------------------------------------- %% Table-based test helpers %%--------------------------------------------------------------------