|
@@ -36,10 +36,14 @@
|
|
|
%%--------------------------------------------------------------------
|
|
%%--------------------------------------------------------------------
|
|
|
|
|
|
|
|
all() ->
|
|
all() ->
|
|
|
- [{group, http_inet},
|
|
|
|
|
|
|
+ [
|
|
|
|
|
+ {group, http_inet},
|
|
|
{group, http_inet6},
|
|
{group, http_inet6},
|
|
|
{group, https_inet},
|
|
{group, https_inet},
|
|
|
- {group, https_inet6}].
|
|
|
|
|
|
|
+ {group, https_inet6},
|
|
|
|
|
+ pub_sub_no_acl,
|
|
|
|
|
+ no_hook_if_config_unset
|
|
|
|
|
+ ].
|
|
|
|
|
|
|
|
groups() ->
|
|
groups() ->
|
|
|
Cases = emqx_ct:all(?MODULE),
|
|
Cases = emqx_ct:all(?MODULE),
|
|
@@ -47,23 +51,59 @@ groups() ->
|
|
|
|
|
|
|
|
init_per_group(GrpName, Cfg) ->
|
|
init_per_group(GrpName, Cfg) ->
|
|
|
[Scheme, Inet] = [list_to_atom(X) || X <- string:tokens(atom_to_list(GrpName), "_")],
|
|
[Scheme, Inet] = [list_to_atom(X) || X <- string:tokens(atom_to_list(GrpName), "_")],
|
|
|
|
|
+ ok = setup(Scheme, Inet),
|
|
|
|
|
+ Cfg.
|
|
|
|
|
+
|
|
|
|
|
+end_per_group(_GrpName, _Cfg) ->
|
|
|
|
|
+ teardown().
|
|
|
|
|
+
|
|
|
|
|
+init_per_testcase(pub_sub_no_acl, Cfg) ->
|
|
|
|
|
+ Scheme = http,
|
|
|
|
|
+ Inet = inet,
|
|
|
http_auth_server:start(Scheme, Inet),
|
|
http_auth_server:start(Scheme, Inet),
|
|
|
- Fun = fun(App) -> set_special_configs(App, Scheme, Inet) end,
|
|
|
|
|
|
|
+ Fun = fun(App) -> set_special_configs(App, Scheme, Inet, no_acl) end,
|
|
|
emqx_ct_helpers:start_apps([emqx_auth_http], Fun),
|
|
emqx_ct_helpers:start_apps([emqx_auth_http], Fun),
|
|
|
|
|
+ ?assert(is_hooked('client.authenticate')),
|
|
|
|
|
+ ?assertNot(is_hooked('client.check_acl')),
|
|
|
|
|
+ Cfg;
|
|
|
|
|
+init_per_testcase(no_hook_if_config_unset, Cfg) ->
|
|
|
|
|
+ setup(http, inet),
|
|
|
|
|
+ Cfg;
|
|
|
|
|
+init_per_testcase(_, Cfg) ->
|
|
|
|
|
+ %% init per group
|
|
|
Cfg.
|
|
Cfg.
|
|
|
|
|
|
|
|
-end_per_group(_GrpName, _Cfg) ->
|
|
|
|
|
|
|
+end_per_testcase(pub_sub_no_acl, _Cfg) ->
|
|
|
|
|
+ teardown();
|
|
|
|
|
+end_per_testcase(no_hook_if_config_unset, _Cfg) ->
|
|
|
|
|
+ teardown();
|
|
|
|
|
+end_per_testcase(_, _Cfg) ->
|
|
|
|
|
+ %% teardown per group
|
|
|
|
|
+ ok.
|
|
|
|
|
+
|
|
|
|
|
+setup(Scheme, Inet) ->
|
|
|
|
|
+ http_auth_server:start(Scheme, Inet),
|
|
|
|
|
+ Fun = fun(App) -> set_special_configs(App, Scheme, Inet, normal) end,
|
|
|
|
|
+ emqx_ct_helpers:start_apps([emqx_auth_http], Fun),
|
|
|
|
|
+ ?assert(is_hooked('client.authenticate')),
|
|
|
|
|
+ ?assert(is_hooked('client.check_acl')).
|
|
|
|
|
+
|
|
|
|
|
+teardown() ->
|
|
|
http_auth_server:stop(),
|
|
http_auth_server:stop(),
|
|
|
- emqx_ct_helpers:stop_apps([emqx_auth_http, emqx]).
|
|
|
|
|
|
|
+ application:stop(emqx_auth_http),
|
|
|
|
|
+ ?assertNot(is_hooked('client.authenticate')),
|
|
|
|
|
+ ?assertNot(is_hooked('client.check_acl')),
|
|
|
|
|
+ emqx_ct_helpers:stop_apps([emqx]).
|
|
|
|
|
|
|
|
-set_special_configs(emqx, _Schmea, _Inet) ->
|
|
|
|
|
|
|
+set_special_configs(emqx, _Scheme, _Inet, _AuthConfig) ->
|
|
|
application:set_env(emqx, allow_anonymous, true),
|
|
application:set_env(emqx, allow_anonymous, true),
|
|
|
application:set_env(emqx, enable_acl_cache, false),
|
|
application:set_env(emqx, enable_acl_cache, false),
|
|
|
LoadedPluginPath = filename:join(["test", "emqx_SUITE_data", "loaded_plugins"]),
|
|
LoadedPluginPath = filename:join(["test", "emqx_SUITE_data", "loaded_plugins"]),
|
|
|
application:set_env(emqx, plugins_loaded_file,
|
|
application:set_env(emqx, plugins_loaded_file,
|
|
|
emqx_ct_helpers:deps_path(emqx, LoadedPluginPath));
|
|
emqx_ct_helpers:deps_path(emqx, LoadedPluginPath));
|
|
|
|
|
|
|
|
-set_special_configs(emqx_auth_http, Scheme, Inet) ->
|
|
|
|
|
|
|
+set_special_configs(emqx_auth_http, Scheme, Inet, PluginConfig) ->
|
|
|
|
|
+ [application:unset_env(?APP, Par) || Par <- [acl_req, auth_req]],
|
|
|
ServerAddr = http_server(Scheme, Inet),
|
|
ServerAddr = http_server(Scheme, Inet),
|
|
|
|
|
|
|
|
AuthReq = #{method => get,
|
|
AuthReq = #{method => get,
|
|
@@ -83,7 +123,10 @@ set_special_configs(emqx_auth_http, Scheme, Inet) ->
|
|
|
|
|
|
|
|
application:set_env(emqx_auth_http, auth_req, maps:to_list(AuthReq)),
|
|
application:set_env(emqx_auth_http, auth_req, maps:to_list(AuthReq)),
|
|
|
application:set_env(emqx_auth_http, super_req, maps:to_list(SuperReq)),
|
|
application:set_env(emqx_auth_http, super_req, maps:to_list(SuperReq)),
|
|
|
- application:set_env(emqx_auth_http, acl_req, maps:to_list(AclReq)).
|
|
|
|
|
|
|
+ case PluginConfig of
|
|
|
|
|
+ normal -> ok = application:set_env(emqx_auth_http, acl_req, maps:to_list(AclReq));
|
|
|
|
|
+ no_acl -> ok
|
|
|
|
|
+ end.
|
|
|
|
|
|
|
|
%% @private
|
|
%% @private
|
|
|
set_https_client_opts() ->
|
|
set_https_client_opts() ->
|
|
@@ -104,7 +147,7 @@ http_server(https, inet6) -> "https://[::1]:8991".
|
|
|
%% Testcases
|
|
%% Testcases
|
|
|
%%------------------------------------------------------------------------------
|
|
%%------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
-t_check_acl(_) ->
|
|
|
|
|
|
|
+t_check_acl(Cfg) when is_list(Cfg) ->
|
|
|
SuperUser = ?USER(<<"superclient">>, <<"superuser">>, mqtt, {127,0,0,1}, external),
|
|
SuperUser = ?USER(<<"superclient">>, <<"superuser">>, mqtt, {127,0,0,1}, external),
|
|
|
deny = emqx_access_control:check_acl(SuperUser, subscribe, <<"users/testuser/1">>),
|
|
deny = emqx_access_control:check_acl(SuperUser, subscribe, <<"users/testuser/1">>),
|
|
|
deny = emqx_access_control:check_acl(SuperUser, publish, <<"anytopic">>),
|
|
deny = emqx_access_control:check_acl(SuperUser, publish, <<"anytopic">>),
|
|
@@ -125,7 +168,7 @@ t_check_acl(_) ->
|
|
|
deny = emqx_access_control:check_acl(User2, publish, <<"a/b/c">>),
|
|
deny = emqx_access_control:check_acl(User2, publish, <<"a/b/c">>),
|
|
|
deny = emqx_access_control:check_acl(User2, subscribe, <<"$SYS/testuser/1">>).
|
|
deny = emqx_access_control:check_acl(User2, subscribe, <<"$SYS/testuser/1">>).
|
|
|
|
|
|
|
|
-t_check_auth(_) ->
|
|
|
|
|
|
|
+t_check_auth(Cfg) when is_list(Cfg) ->
|
|
|
User1 = ?USER(<<"client1">>, <<"testuser1">>, mqtt, {127,0,0,1}, external, undefined),
|
|
User1 = ?USER(<<"client1">>, <<"testuser1">>, mqtt, {127,0,0,1}, external, undefined),
|
|
|
User2 = ?USER(<<"client2">>, <<"testuser2">>, mqtt, {127,0,0,1}, exteneral, undefined),
|
|
User2 = ?USER(<<"client2">>, <<"testuser2">>, mqtt, {127,0,0,1}, exteneral, undefined),
|
|
|
User3 = ?USER(<<"client3">>, undefined, mqtt, {127,0,0,1}, exteneral, undefined),
|
|
User3 = ?USER(<<"client3">>, undefined, mqtt, {127,0,0,1}, exteneral, undefined),
|
|
@@ -142,8 +185,7 @@ t_check_auth(_) ->
|
|
|
|
|
|
|
|
{error, bad_username_or_password} = emqx_access_control:authenticate(User3#{password => <<"pwd">>}).
|
|
{error, bad_username_or_password} = emqx_access_control:authenticate(User3#{password => <<"pwd">>}).
|
|
|
|
|
|
|
|
-t_sub_pub(_) ->
|
|
|
|
|
- ct:pal("start client"),
|
|
|
|
|
|
|
+pub_sub_no_acl(Cfg) when is_list(Cfg) ->
|
|
|
{ok, T1} = emqtt:start_link([{host, "localhost"},
|
|
{ok, T1} = emqtt:start_link([{host, "localhost"},
|
|
|
{clientid, <<"client1">>},
|
|
{clientid, <<"client1">>},
|
|
|
{username, <<"testuser1">>},
|
|
{username, <<"testuser1">>},
|
|
@@ -164,12 +206,52 @@ t_sub_pub(_) ->
|
|
|
emqtt:disconnect(T1),
|
|
emqtt:disconnect(T1),
|
|
|
emqtt:disconnect(T2).
|
|
emqtt:disconnect(T2).
|
|
|
|
|
|
|
|
-t_comment_config(_) ->
|
|
|
|
|
- AuthCount = length(emqx_hooks:lookup('client.authenticate')),
|
|
|
|
|
- AclCount = length(emqx_hooks:lookup('client.check_acl')),
|
|
|
|
|
|
|
+t_pub_sub(Cfg) when is_list(Cfg) ->
|
|
|
|
|
+ {ok, T1} = emqtt:start_link([{host, "localhost"},
|
|
|
|
|
+ {clientid, <<"client1">>},
|
|
|
|
|
+ {username, <<"testuser1">>},
|
|
|
|
|
+ {password, <<"pass1">>}]),
|
|
|
|
|
+ {ok, _} = emqtt:connect(T1),
|
|
|
|
|
+ emqtt:publish(T1, <<"topic">>, <<"body">>, [{qos, 0}, {retain, true}]),
|
|
|
|
|
+ timer:sleep(1000),
|
|
|
|
|
+ {ok, T2} = emqtt:start_link([{host, "localhost"},
|
|
|
|
|
+ {clientid, <<"client2">>},
|
|
|
|
|
+ {username, <<"testuser2">>},
|
|
|
|
|
+ {password, <<"pass2">>}]),
|
|
|
|
|
+ {ok, _} = emqtt:connect(T2),
|
|
|
|
|
+ emqtt:subscribe(T2, <<"topic">>),
|
|
|
|
|
+ receive
|
|
|
|
|
+ {publish, _Topic, Payload} ->
|
|
|
|
|
+ ?assertEqual(<<"body">>, Payload)
|
|
|
|
|
+ after 1000 -> false end,
|
|
|
|
|
+ emqtt:disconnect(T1),
|
|
|
|
|
+ emqtt:disconnect(T2).
|
|
|
|
|
+
|
|
|
|
|
+no_hook_if_config_unset(Cfg) when is_list(Cfg) ->
|
|
|
|
|
+ ?assert(is_hooked('client.authenticate')),
|
|
|
|
|
+ ?assert(is_hooked('client.check_acl')),
|
|
|
application:stop(?APP),
|
|
application:stop(?APP),
|
|
|
[application:unset_env(?APP, Par) || Par <- [acl_req, auth_req]],
|
|
[application:unset_env(?APP, Par) || Par <- [acl_req, auth_req]],
|
|
|
application:start(?APP),
|
|
application:start(?APP),
|
|
|
?assertEqual([], emqx_hooks:lookup('client.authenticate')),
|
|
?assertEqual([], emqx_hooks:lookup('client.authenticate')),
|
|
|
- ?assertEqual(AuthCount - 1, length(emqx_hooks:lookup('client.authenticate'))),
|
|
|
|
|
- ?assertEqual(AclCount - 1, length(emqx_hooks:lookup('client.check_acl'))).
|
|
|
|
|
|
|
+ ?assertNot(is_hooked('client.authenticate')),
|
|
|
|
|
+ ?assertNot(is_hooked('client.check_acl')).
|
|
|
|
|
+
|
|
|
|
|
+is_hooked(HookName) ->
|
|
|
|
|
+ Callbacks = emqx_hooks:lookup(HookName),
|
|
|
|
|
+ F = fun(Callback) ->
|
|
|
|
|
+ case emqx_hooks:callback_action(Callback) of
|
|
|
|
|
+ {emqx_auth_http, check, _} ->
|
|
|
|
|
+ 'client.authenticate' = HookName, % assert
|
|
|
|
|
+ true;
|
|
|
|
|
+ {emqx_acl_http, check_acl, _} ->
|
|
|
|
|
+ 'client.check_acl' = HookName, % assert
|
|
|
|
|
+ true;
|
|
|
|
|
+ _ ->
|
|
|
|
|
+ false
|
|
|
|
|
+ end
|
|
|
|
|
+ end,
|
|
|
|
|
+ case lists:filter(F, Callbacks) of
|
|
|
|
|
+ [_] -> true;
|
|
|
|
|
+ [] -> false
|
|
|
|
|
+ end.
|