515 lines
19 KiB
Erlang
515 lines
19 KiB
Erlang
%%--------------------------------------------------------------------
|
|
%% Copyright (c) 2020-2022 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_auth_jwt_SUITE).
|
|
|
|
-compile(export_all).
|
|
-compile(nowarn_export_all).
|
|
|
|
-include_lib("emqx/include/emqx_mqtt.hrl").
|
|
-include_lib("eunit/include/eunit.hrl").
|
|
-include_lib("common_test/include/ct.hrl").
|
|
-include_lib("snabbkaffe/include/snabbkaffe.hrl").
|
|
|
|
all() -> emqx_ct:all(?MODULE).
|
|
|
|
init_per_testcase(TestCase, Config) ->
|
|
?MODULE:TestCase(init, Config),
|
|
emqx_ct_helpers:start_apps([emqx_auth_jwt], fun set_special_configs/1),
|
|
Config.
|
|
|
|
end_per_testcase(TestCase, Config) ->
|
|
try ?MODULE:TestCase('end', Config) catch _:_ -> ok end,
|
|
emqx_ct_helpers:stop_apps([emqx_auth_jwt]).
|
|
|
|
set_special_configs(emqx) ->
|
|
application:set_env(emqx, allow_anonymous, false),
|
|
application:set_env(emqx, acl_nomatch, deny),
|
|
application:set_env(emqx, enable_acl_cache, false),
|
|
LoadedPluginPath = filename:join(["test", "emqx_SUITE_data", "loaded_plugins"]),
|
|
AclFilePath = filename:join(["test", "emqx_SUITE_data", "acl.conf"]),
|
|
application:set_env(emqx, plugins_loaded_file,
|
|
emqx_ct_helpers:deps_path(emqx, LoadedPluginPath)),
|
|
application:set_env(emqx, acl_file,
|
|
emqx_ct_helpers:deps_path(emqx, AclFilePath));
|
|
|
|
set_special_configs(emqx_auth_jwt) ->
|
|
application:set_env(emqx_auth_jwt, secret, "emqxsecret"),
|
|
application:set_env(emqx_auth_jwt, from, password);
|
|
|
|
set_special_configs(_) ->
|
|
ok.
|
|
|
|
sign(Payload, Header, Key) when is_map(Header) ->
|
|
Jwk = jose_jwk:from_oct(Key),
|
|
Jwt = emqx_json:encode(Payload),
|
|
{_, Token} = jose_jws:compact(jose_jwt:sign(Jwk, Header, Jwt)),
|
|
Token;
|
|
|
|
sign(Payload, Alg, Key) ->
|
|
Jwk = jose_jwk:from_oct(Key),
|
|
Jwt = emqx_json:encode(Payload),
|
|
{_, Token} = jose_jws:compact(jose_jwt:sign(Jwk, #{<<"alg">> => Alg}, Jwt)),
|
|
Token.
|
|
|
|
%%------------------------------------------------------------------------------
|
|
%% Testcases
|
|
%%------------------------------------------------------------------------------
|
|
|
|
t_check_auth(init, _Config) ->
|
|
application:unset_env(emqx_auth_jwt, verify_claims).
|
|
t_check_auth(_Config) ->
|
|
Plain = #{clientid => <<"client1">>, username => <<"plain">>, zone => external},
|
|
Jwt = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{exp, erlang:system_time(seconds) + 2}], <<"HS256">>, <<"emqxsecret">>),
|
|
ct:pal("Jwt: ~p~n", [Jwt]),
|
|
|
|
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt}),
|
|
ct:pal("Auth result: ~p~n", [Result0]),
|
|
?assertMatch({ok, #{auth_result := success, jwt_claims := #{<<"clientid">> := <<"client1">>}}}, Result0),
|
|
|
|
ct:sleep(3100),
|
|
Result1 = emqx_access_control:authenticate(Plain#{password => Jwt}),
|
|
ct:pal("Auth result after 3100ms: ~p~n", [Result1]),
|
|
?assertMatch({error, _}, Result1),
|
|
|
|
Jwt_Error = sign([{client_id, <<"client1">>},
|
|
{username, <<"plain">>}], <<"HS256">>, <<"secret">>),
|
|
ct:pal("invalid jwt: ~p~n", [Jwt_Error]),
|
|
Result2 = emqx_access_control:authenticate(Plain#{password => Jwt_Error}),
|
|
ct:pal("Auth result for the invalid jwt: ~p~n", [Result2]),
|
|
?assertEqual({error, invalid_signature}, Result2),
|
|
?assertMatch({error, _}, emqx_access_control:authenticate(Plain#{password => <<"asd">>})).
|
|
|
|
t_check_nbf(init, _Config) ->
|
|
application:unset_env(emqx_auth_jwt, verify_claims).
|
|
t_check_nbf(_Config) ->
|
|
Plain = #{clientid => <<"client1">>, username => <<"plain">>, zone => external},
|
|
Jwt = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{nbf, erlang:system_time(seconds) + 3}], <<"HS256">>, <<"emqxsecret">>),
|
|
ct:pal("Jwt: ~p~n", [Jwt]),
|
|
|
|
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt}),
|
|
ct:pal("Auth result: ~p~n", [Result0]),
|
|
?assertEqual({error, {invalid_signature, not_valid_yet}}, Result0).
|
|
|
|
t_check_iat(init, _Config) ->
|
|
application:unset_env(emqx_auth_jwt, verify_claims).
|
|
t_check_iat(_Config) ->
|
|
Plain = #{clientid => <<"client1">>, username => <<"plain">>, zone => external},
|
|
Jwt = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{iat, erlang:system_time(seconds) + 3}], <<"HS256">>, <<"emqxsecret">>),
|
|
ct:pal("Jwt: ~p~n", [Jwt]),
|
|
|
|
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt}),
|
|
ct:pal("Auth result: ~p~n", [Result0]),
|
|
?assertEqual({error, {invalid_signature, issued_in_future}}, Result0).
|
|
|
|
t_check_auth_invalid_exp(init, _Config) ->
|
|
application:unset_env(emqx_auth_jwt, verify_claims).
|
|
t_check_auth_invalid_exp(_Config) ->
|
|
Plain = #{clientid => <<"client1">>, username => <<"plain">>, zone => external},
|
|
Jwt0 = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{exp, [{foo, bar}]}], <<"HS256">>, <<"emqxsecret">>),
|
|
ct:pal("Jwt: ~p~n", [Jwt0]),
|
|
|
|
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt0}),
|
|
ct:pal("Auth result: ~p~n", [Result0]),
|
|
?assertMatch({error, _}, Result0),
|
|
|
|
Jwt1 = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{exp, <<"foobar">>}], <<"HS256">>, <<"emqxsecret">>),
|
|
ct:pal("Jwt: ~p~n", [Jwt1]),
|
|
|
|
Result1 = emqx_access_control:authenticate(Plain#{password => Jwt1}),
|
|
ct:pal("Auth result: ~p~n", [Result1]),
|
|
?assertMatch({error, _}, Result1).
|
|
|
|
t_check_auth_str_exp(init, _Config) ->
|
|
application:unset_env(emqx_auth_jwt, verify_claims).
|
|
t_check_auth_str_exp(_Config) ->
|
|
Plain = #{clientid => <<"client1">>, username => <<"plain">>, zone => external},
|
|
Exp = integer_to_binary(erlang:system_time(seconds) + 3),
|
|
|
|
Jwt0 = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{exp, Exp}], <<"HS256">>, <<"emqxsecret">>),
|
|
ct:pal("Jwt: ~p~n", [Jwt0]),
|
|
|
|
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt0}),
|
|
ct:pal("Auth result: ~p~n", [Result0]),
|
|
?assertMatch({ok, #{auth_result := success, jwt_claims := _}}, Result0),
|
|
|
|
Jwt1 = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{exp, <<"0">>}], <<"HS256">>, <<"emqxsecret">>),
|
|
ct:pal("Jwt: ~p~n", [Jwt1]),
|
|
|
|
Result1 = emqx_access_control:authenticate(Plain#{password => Jwt1}),
|
|
ct:pal("Auth result: ~p~n", [Result1]),
|
|
?assertMatch({error, _}, Result1),
|
|
|
|
Exp2 = float_to_binary(erlang:system_time(seconds) + 3.5),
|
|
|
|
Jwt2 = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{exp, Exp2}], <<"HS256">>, <<"emqxsecret">>),
|
|
ct:pal("Jwt: ~p~n", [Jwt2]),
|
|
|
|
Result2 = emqx_access_control:authenticate(Plain#{password => Jwt2}),
|
|
ct:pal("Auth result: ~p~n", [Result2]),
|
|
?assertMatch({ok, #{auth_result := success, jwt_claims := _}}, Result2).
|
|
|
|
t_check_auth_float_exp(init, _Config) ->
|
|
application:unset_env(emqx_auth_jwt, verify_claims).
|
|
t_check_auth_float_exp(_Config) ->
|
|
Plain = #{clientid => <<"client1">>, username => <<"plain">>, zone => external},
|
|
Exp = erlang:system_time(seconds) + 3.5,
|
|
|
|
Jwt0 = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{exp, Exp}], <<"HS256">>, <<"emqxsecret">>),
|
|
ct:pal("Jwt: ~p~n", [Jwt0]),
|
|
|
|
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt0}),
|
|
ct:pal("Auth result: ~p~n", [Result0]),
|
|
?assertMatch({ok, #{auth_result := success, jwt_claims := _}}, Result0),
|
|
|
|
Jwt1 = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{exp, 1.5}], <<"HS256">>, <<"emqxsecret">>),
|
|
ct:pal("Jwt: ~p~n", [Jwt1]),
|
|
|
|
Result1 = emqx_access_control:authenticate(Plain#{password => Jwt1}),
|
|
ct:pal("Auth result: ~p~n", [Result1]),
|
|
?assertMatch({error, _}, Result1).
|
|
|
|
t_check_claims(init, _Config) ->
|
|
application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]).
|
|
t_check_claims(_Config) ->
|
|
Plain = #{clientid => <<"client1">>, username => <<"plain">>, zone => external},
|
|
Jwt = sign([{client_id, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{sub, value},
|
|
{exp, erlang:system_time(seconds) + 3}], <<"HS256">>, <<"emqxsecret">>),
|
|
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt}),
|
|
ct:pal("Auth result: ~p~n", [Result0]),
|
|
?assertMatch({ok, #{auth_result := success, jwt_claims := _}}, Result0),
|
|
Jwt_Error = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>}], <<"HS256">>, <<"secret">>),
|
|
Result2 = emqx_access_control:authenticate(Plain#{password => Jwt_Error}),
|
|
ct:pal("Auth result for the invalid jwt: ~p~n", [Result2]),
|
|
?assertEqual({error, invalid_signature}, Result2).
|
|
|
|
t_check_claims_clientid(init, _Config) ->
|
|
application:set_env(emqx_auth_jwt, verify_claims, [{clientid, <<"%c">>}]).
|
|
t_check_claims_clientid(_Config) ->
|
|
Plain = #{clientid => <<"client23">>, username => <<"plain">>, zone => external},
|
|
Jwt = sign([{clientid, <<"client23">>},
|
|
{username, <<"plain">>},
|
|
{exp, erlang:system_time(seconds) + 3}], <<"HS256">>, <<"emqxsecret">>),
|
|
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt}),
|
|
ct:pal("Auth result: ~p~n", [Result0]),
|
|
?assertMatch({ok, #{auth_result := success, jwt_claims := _}}, Result0),
|
|
Jwt_Error = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>}], <<"HS256">>, <<"secret">>),
|
|
Result2 = emqx_access_control:authenticate(Plain#{password => Jwt_Error}),
|
|
ct:pal("Auth result for the invalid jwt: ~p~n", [Result2]),
|
|
?assertEqual({error, invalid_signature}, Result2).
|
|
|
|
t_check_claims_username(init, _Config) ->
|
|
application:set_env(emqx_auth_jwt, verify_claims, [{username, <<"%u">>}]).
|
|
t_check_claims_username(_Config) ->
|
|
Plain = #{clientid => <<"client23">>, username => <<"plain">>, zone => external},
|
|
Jwt = sign([{client_id, <<"client23">>},
|
|
{username, <<"plain">>},
|
|
{exp, erlang:system_time(seconds) + 3}], <<"HS256">>, <<"emqxsecret">>),
|
|
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt}),
|
|
ct:pal("Auth result: ~p~n", [Result0]),
|
|
?assertMatch({ok, #{auth_result := success, jwt_claims := _}}, Result0),
|
|
Jwt_Error = sign([{clientid, <<"client1">>},
|
|
{username, <<"plain">>}], <<"HS256">>, <<"secret">>),
|
|
Result3 = emqx_access_control:authenticate(Plain#{password => Jwt_Error}),
|
|
ct:pal("Auth result for the invalid jwt: ~p~n", [Result3]),
|
|
?assertEqual({error, invalid_signature}, Result3).
|
|
|
|
t_check_claims_kid_in_header(init, _Config) ->
|
|
application:set_env(emqx_auth_jwt, verify_claims, []).
|
|
t_check_claims_kid_in_header(_Config) ->
|
|
Plain = #{clientid => <<"client23">>, username => <<"plain">>, zone => external},
|
|
Jwt = sign([{clientid, <<"client23">>},
|
|
{username, <<"plain">>},
|
|
{exp, erlang:system_time(seconds) + 3}],
|
|
#{<<"alg">> => <<"HS256">>,
|
|
<<"kid">> => <<"a_kid_str">>}, <<"emqxsecret">>),
|
|
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt}),
|
|
ct:pal("Auth result: ~p~n", [Result0]),
|
|
?assertMatch({ok, #{auth_result := success, jwt_claims := _}}, Result0).
|
|
|
|
t_keys_update(init, _Config) ->
|
|
ok = meck:new(httpc, [passthrough, no_history]),
|
|
ok = meck:expect(
|
|
httpc,
|
|
request,
|
|
fun(get, _, _, _) ->
|
|
{ok,
|
|
{200,
|
|
[],
|
|
jiffy:encode(#{<<"keys">> => []})}}
|
|
end),
|
|
|
|
application:set_env(emqx_auth_jwt, verify_claims, []),
|
|
application:set_env(emqx_auth_jwt, refresh_interval, 100),
|
|
application:set_env(emqx_auth_jwt, jwks, "http://localhost:4001/keys.json").
|
|
t_keys_update(_Config) ->
|
|
?check_trace(
|
|
snabbkaffe:block_until(
|
|
?match_n_events(2, #{?snk_kind := emqx_auth_jwt_svr_jwks_updated}),
|
|
_Timeout = infinity,
|
|
_BackInTIme = 0),
|
|
fun(_, Trace) ->
|
|
?assertMatch([#{pid := Pid}, #{pid := Pid} | _],
|
|
?of_kind(emqx_auth_jwt_svr_jwks_updated, Trace))
|
|
end).
|
|
|
|
t_check_jwt_acl(init, _Config) ->
|
|
application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]).
|
|
t_check_jwt_acl(_Config) ->
|
|
Jwt = sign([{client_id, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{sub, value},
|
|
{acl, [{sub, [<<"a/b">>]},
|
|
{pub, [<<"c/d">>]},
|
|
{all, [<<"all">>]}]},
|
|
{exp, erlang:system_time(seconds) + 10}],
|
|
<<"HS256">>,
|
|
<<"emqxsecret">>),
|
|
|
|
{ok, C} = emqtt:start_link(
|
|
[{clean_start, true},
|
|
{proto_ver, v5},
|
|
{client_id, <<"client1">>},
|
|
{password, Jwt}]),
|
|
{ok, _} = emqtt:connect(C),
|
|
|
|
?assertMatch(
|
|
{ok, #{}, [0]},
|
|
emqtt:subscribe(C, <<"a/b">>, 0)),
|
|
|
|
?assertMatch(
|
|
ok,
|
|
emqtt:publish(C, <<"c/d">>, <<"hi">>, 0)),
|
|
|
|
?assertMatch(
|
|
{ok, #{}, [?RC_NOT_AUTHORIZED]},
|
|
emqtt:subscribe(C, <<"c/d">>, 0)),
|
|
|
|
ok = emqtt:publish(C, <<"a/b">>, <<"hi">>, 0),
|
|
|
|
receive
|
|
{publish, #{topic := <<"a/b">>}} ->
|
|
?assert(false, "Publish to `a/b` should not be allowed")
|
|
after 100 -> ok
|
|
end,
|
|
|
|
%% can pub/sub to all rules
|
|
?assertMatch(
|
|
{ok, #{}, [0]},
|
|
emqtt:subscribe(C, <<"all">>, 0)),
|
|
|
|
?assertMatch(
|
|
ok,
|
|
emqtt:publish(C, <<"all">>, <<"hi">>, 0)),
|
|
receive
|
|
{publish, #{topic := <<"all">>}} -> ok
|
|
after 2000 ->
|
|
?assert(false, "Publish to `all` should be allowed")
|
|
end,
|
|
ok = emqtt:disconnect(C).
|
|
|
|
t_check_jwt_acl_no_recs(init, _Config) ->
|
|
application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]).
|
|
t_check_jwt_acl_no_recs(_Config) ->
|
|
Jwt = sign([{client_id, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{sub, value},
|
|
{acl, []},
|
|
{exp, erlang:system_time(seconds) + 10}],
|
|
<<"HS256">>,
|
|
<<"emqxsecret">>),
|
|
|
|
{ok, C} = emqtt:start_link(
|
|
[{clean_start, true},
|
|
{proto_ver, v5},
|
|
{client_id, <<"client1">>},
|
|
{password, Jwt}]),
|
|
{ok, _} = emqtt:connect(C),
|
|
|
|
?assertMatch(
|
|
{ok, #{}, [?RC_NOT_AUTHORIZED]},
|
|
emqtt:subscribe(C, <<"a/b">>, 0)),
|
|
|
|
ok = emqtt:disconnect(C).
|
|
|
|
t_check_jwt_acl_no_acl_claim(init, _Config) ->
|
|
application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]).
|
|
t_check_jwt_acl_no_acl_claim(_Config) ->
|
|
Jwt = sign([{client_id, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{sub, value},
|
|
{exp, erlang:system_time(seconds) + 10}],
|
|
<<"HS256">>,
|
|
<<"emqxsecret">>),
|
|
|
|
{ok, C} = emqtt:start_link(
|
|
[{clean_start, true},
|
|
{proto_ver, v5},
|
|
{client_id, <<"client1">>},
|
|
{password, Jwt}]),
|
|
{ok, _} = emqtt:connect(C),
|
|
|
|
?assertMatch(
|
|
{ok, #{}, [?RC_NOT_AUTHORIZED]},
|
|
emqtt:subscribe(C, <<"a/b">>, 0)),
|
|
|
|
ok = emqtt:disconnect(C).
|
|
|
|
t_check_jwt_acl_no_jwt_claims_helper(_ClientInfo, _LastAuthResult) ->
|
|
{stop, #{auth_result => success, anonymous => false}}.
|
|
t_check_jwt_acl_no_jwt_claims(init, _Config) ->
|
|
ok;
|
|
t_check_jwt_acl_no_jwt_claims('end', _Config) ->
|
|
ok = emqx_hooks:del(
|
|
'client.authenticate',
|
|
{?MODULE, t_check_jwt_acl_no_jwt_claims_helper, []}
|
|
).
|
|
t_check_jwt_acl_no_jwt_claims(_Config) ->
|
|
%% bypass the jwt authentication checking
|
|
ok = emqx_hooks:add(
|
|
'client.authenticate',
|
|
{?MODULE, t_check_jwt_acl_no_jwt_claims_helper, []},
|
|
_Priority = 99999
|
|
),
|
|
|
|
{ok, C} = emqtt:start_link(
|
|
[{clean_start, true},
|
|
{proto_ver, v5},
|
|
{client_id, <<"client1">>},
|
|
{username, <<"client1">>},
|
|
{password, <<"password">>}]),
|
|
{ok, _} = emqtt:connect(C),
|
|
|
|
ok = snabbkaffe:start_trace(),
|
|
|
|
?assertMatch(
|
|
{ok, #{}, [?RC_NOT_AUTHORIZED]},
|
|
emqtt:subscribe(C, <<"a/b">>, 0)),
|
|
|
|
{ok, _} = ?block_until(#{?snk_kind := no_jwt_claim}, 1000),
|
|
Trace = snabbkaffe:collect_trace(),
|
|
?assertEqual(1, length(?of_kind(no_jwt_claim, Trace))),
|
|
|
|
snabbkaffe:stop(),
|
|
ok = emqtt:disconnect(C).
|
|
|
|
t_check_jwt_acl_expire(init, _Config) ->
|
|
application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]).
|
|
t_check_jwt_acl_expire(_Config) ->
|
|
Jwt = sign([{client_id, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{sub, value},
|
|
{acl, [{sub, [<<"a/b">>]}]},
|
|
{exp, erlang:system_time(seconds) + 1}],
|
|
<<"HS256">>,
|
|
<<"emqxsecret">>),
|
|
|
|
{ok, C} = emqtt:start_link(
|
|
[{clean_start, true},
|
|
{proto_ver, v5},
|
|
{client_id, <<"client1">>},
|
|
{password, Jwt}]),
|
|
{ok, _} = emqtt:connect(C),
|
|
|
|
?assertMatch(
|
|
{ok, #{}, [0]},
|
|
emqtt:subscribe(C, <<"a/b">>, 0)),
|
|
|
|
?assertMatch(
|
|
{ok, #{}, [0]},
|
|
emqtt:unsubscribe(C, <<"a/b">>)),
|
|
|
|
timer:sleep(2000),
|
|
|
|
?assertMatch(
|
|
{ok, #{}, [?RC_NOT_AUTHORIZED]},
|
|
emqtt:subscribe(C, <<"a/b">>, 0)),
|
|
|
|
Default = emqx_zone:get_env(external, acl_nomatch, deny),
|
|
emqx_zone:set_env(external, acl_nomatch, allow),
|
|
try
|
|
?assertMatch(
|
|
{ok, #{}, [?RC_NOT_AUTHORIZED]},
|
|
emqtt:subscribe(C, <<"a/b">>, 0))
|
|
after
|
|
emqx_zone:set_env(external, acl_nomatch, Default)
|
|
end,
|
|
|
|
ok = emqtt:disconnect(C).
|
|
|
|
t_check_jwt_acl_no_exp(init, _Config) ->
|
|
application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]).
|
|
t_check_jwt_acl_no_exp(_Config) ->
|
|
Jwt = sign([{client_id, <<"client1">>},
|
|
{username, <<"plain">>},
|
|
{sub, value},
|
|
{acl, [{sub, [<<"a/b">>]}]}],
|
|
<<"HS256">>,
|
|
<<"emqxsecret">>),
|
|
|
|
{ok, C} = emqtt:start_link(
|
|
[{clean_start, true},
|
|
{proto_ver, v5},
|
|
{client_id, <<"client1">>},
|
|
{password, Jwt}]),
|
|
{ok, _} = emqtt:connect(C),
|
|
|
|
?assertMatch(
|
|
{ok, #{}, [0]},
|
|
emqtt:subscribe(C, <<"a/b">>, 0)),
|
|
|
|
ok = emqtt:disconnect(C).
|
|
|
|
t_check_compatibility(init, _Config) -> ok.
|
|
t_check_compatibility(_Config) ->
|
|
|
|
%% We literary want emqx_auth_jwt:check call emqx_auth_jwt:check_auth, so check with meck
|
|
|
|
ok = meck:new(emqx_auth_jwt, [passthrough, no_history]),
|
|
ok = meck:expect(emqx_auth_jwt, check_auth, fun(a, b, c) -> ok end),
|
|
|
|
?assertEqual(
|
|
ok,
|
|
emqx_auth_jwt:check(a, b, c)
|
|
),
|
|
|
|
meck:validate(emqx_auth_jwt),
|
|
meck:unload(emqx_auth_jwt).
|