Revert "Add support for JWT authorization"
This commit is contained in:
parent
3544537906
commit
47a5bc3f09
|
@ -32,8 +32,6 @@ File format:
|
|||
scenarios, especially when the emqx-bridge-mqtt plugin is configured as shared
|
||||
subscription. [#7462]
|
||||
* Add some compression functions to rule-engine: gzip, gunzip, zip, unzip, zip_compress, zip_uncompress
|
||||
* Add support for JWT authorization [#7596]
|
||||
Now MQTT clients may be authorized with respect to a specific claim containing publish/subscribe topic whitelists.
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
|
|
@ -46,11 +46,6 @@ auth.jwt.verify_claims = off
|
|||
## - %u: username
|
||||
## - %c: clientid
|
||||
# auth.jwt.verify_claims.username = %u
|
||||
|
||||
## Name of the claim containg ACL rules
|
||||
##
|
||||
## Value: String
|
||||
#auth.jwt.acl_claim_name = acl
|
||||
```
|
||||
|
||||
Load the Plugin
|
||||
|
@ -67,33 +62,6 @@ Example
|
|||
mosquitto_pub -t 'pub' -m 'hello' -i test -u test -P eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoiYm9iIiwiYWdlIjoyOX0.bIV_ZQ8D5nQi0LT8AVkpM4Pd6wmlbpR9S8nOLJAsA8o
|
||||
```
|
||||
|
||||
ACL
|
||||
---
|
||||
JWT may contain lists of topics allowed for subscribing/publishing (ACL rules):
|
||||
|
||||
Payload example:
|
||||
```json
|
||||
{
|
||||
"sub": "emqx",
|
||||
"name": "John Doe",
|
||||
"iat": 1516239022,
|
||||
"exp": 1516239122,
|
||||
"acl": {
|
||||
"sub": [
|
||||
"a/b",
|
||||
"c/+",
|
||||
"%u/%c"
|
||||
],
|
||||
"pub": [
|
||||
"a/b",
|
||||
"c/+",
|
||||
"%u/%c"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Algorithms
|
||||
----------
|
||||
|
||||
|
|
|
@ -47,8 +47,3 @@ auth.jwt.verify_claims = off
|
|||
## For example, to verify that the username in the JWT payload is the same
|
||||
## as the client (MQTT protocol) username
|
||||
#auth.jwt.verify_claims.username = %u
|
||||
|
||||
## Name of the claim containg ACL rules
|
||||
##
|
||||
## Value: String
|
||||
#auth.jwt.acl_claim_name = acl
|
||||
|
|
|
@ -47,13 +47,3 @@
|
|||
end, [], cuttlefish_variable:filter_by_prefix("auth.jwt.verify_claims", Conf))
|
||||
end
|
||||
end}.
|
||||
|
||||
{mapping, "auth.jwt.acl_claim_name", "emqx_auth_jwt.acl_claim_name", [
|
||||
{default, "acl"},
|
||||
{datatype, string}
|
||||
]}.
|
||||
|
||||
{translation, "emqx_auth_jwt.acl_claim_name", fun(Conf) ->
|
||||
list_to_binary(cuttlefish:conf_get("auth.jwt.acl_claim_name", Conf))
|
||||
end}.
|
||||
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
%% -*- mode: erlang -*-
|
||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||
%% -*-: erlang -*-
|
||||
{VSN,
|
||||
[{<<"4\\.3\\.[0-1]">>,
|
||||
[{restart_application, emqx_auth_jwt}]},
|
||||
{<<".*">>,[]}],
|
||||
[{<<"4\\.3\\.[0-1]">>,
|
||||
[{restart_application, emqx_auth_jwt}]},
|
||||
{<<".*">>,[]}]}.
|
||||
[
|
||||
{<<"4\\.3\\.[0-1]">>, [
|
||||
{load_module, emqx_auth_jwt_svr, brutal_purge, soft_purge, []}
|
||||
]},
|
||||
{<<".*">>, []}
|
||||
],
|
||||
[
|
||||
{<<"4\\.3\\.[0-1]">>, [
|
||||
{load_module, emqx_auth_jwt_svr, brutal_purge, soft_purge, []}
|
||||
]},
|
||||
{<<".*">>, []}
|
||||
]
|
||||
}.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2020-2021 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.
|
||||
|
@ -22,8 +22,7 @@
|
|||
-logger_header("[JWT]").
|
||||
|
||||
-export([ register_metrics/0
|
||||
, check_auth/3
|
||||
, check_acl/5
|
||||
, check/3
|
||||
, description/0
|
||||
]).
|
||||
|
||||
|
@ -47,14 +46,16 @@ register_metrics() ->
|
|||
%% Authentication callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
check_auth(ClientInfo, AuthResult, #{from := From, checklists := Checklists}) ->
|
||||
check(ClientInfo, AuthResult, #{pid := Pid,
|
||||
from := From,
|
||||
checklists := Checklists}) ->
|
||||
case maps:find(From, ClientInfo) of
|
||||
error ->
|
||||
ok = emqx_metrics:inc(?AUTH_METRICS(ignore));
|
||||
{ok, undefined} ->
|
||||
ok = emqx_metrics:inc(?AUTH_METRICS(ignore));
|
||||
{ok, Token} ->
|
||||
case emqx_auth_jwt_svr:verify(Token) of
|
||||
case emqx_auth_jwt_svr:verify(Pid, Token) of
|
||||
{error, not_found} ->
|
||||
ok = emqx_metrics:inc(?AUTH_METRICS(ignore));
|
||||
{error, not_token} ->
|
||||
|
@ -67,38 +68,12 @@ check_auth(ClientInfo, AuthResult, #{from := From, checklists := Checklists}) ->
|
|||
end
|
||||
end.
|
||||
|
||||
check_acl(ClientInfo = #{jwt_claims := Claims},
|
||||
PubSub,
|
||||
Topic,
|
||||
_NoMatchAction,
|
||||
#{acl_claim_name := AclClaimName}) ->
|
||||
Deadline = erlang:system_time(second),
|
||||
case Claims of
|
||||
#{AclClaimName := Acl, <<"exp">> := Exp}
|
||||
when is_integer(Exp) andalso Exp >= Deadline ->
|
||||
verify_acl(ClientInfo, Acl, PubSub, Topic);
|
||||
_ -> ignore
|
||||
end.
|
||||
|
||||
description() -> "Authentication with JWT".
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Verify Claims
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
verify_acl(ClientInfo, #{<<"sub">> := SubTopics}, subscribe, Topic) when is_list(SubTopics) ->
|
||||
verify_acl(ClientInfo, SubTopics, Topic);
|
||||
verify_acl(ClientInfo, #{<<"pub">> := PubTopics}, publish, Topic) when is_list(PubTopics) ->
|
||||
verify_acl(ClientInfo, PubTopics, Topic);
|
||||
verify_acl(_ClientInfo, _Acl, _PubSub, _Topic) -> {stop, deny}.
|
||||
|
||||
verify_acl(_ClientInfo, [], _Topic) -> {stop, deny};
|
||||
verify_acl(ClientInfo, [AclTopic | AclTopics], Topic) ->
|
||||
case match_topic(ClientInfo, AclTopic, Topic) of
|
||||
true -> {stop, allow};
|
||||
false -> verify_acl(ClientInfo, AclTopics, Topic)
|
||||
end.
|
||||
|
||||
verify_claims(Checklists, Claims, ClientInfo) ->
|
||||
case do_verify_claims(feedvar(Checklists, ClientInfo), Claims) of
|
||||
{error, Reason} ->
|
||||
|
@ -122,9 +97,3 @@ feedvar(Checklists, #{username := Username, clientid := ClientId}) ->
|
|||
({K, <<"%c">>}) -> {K, ClientId};
|
||||
({K, Expected}) -> {K, Expected}
|
||||
end, Checklists).
|
||||
|
||||
match_topic(ClientInfo, AclTopic, Topic) ->
|
||||
AclTopicWords = emqx_topic:words(AclTopic),
|
||||
TopicWords = emqx_topic:words(Topic),
|
||||
AclTopicRendered = emqx_access_rule:feed_var(ClientInfo, AclTopicWords),
|
||||
emqx_topic:match(TopicWords, AclTopicRendered).
|
||||
|
|
|
@ -31,20 +31,16 @@
|
|||
start(_Type, _Args) ->
|
||||
{ok, Sup} = supervisor:start_link({local, ?MODULE}, ?MODULE, []),
|
||||
|
||||
{ok, _} = start_auth_server(jwks_svr_options()),
|
||||
{ok, Pid} = start_auth_server(jwks_svr_options()),
|
||||
ok = emqx_auth_jwt:register_metrics(),
|
||||
AuthEnv0 = auth_env(),
|
||||
AuthEnv1 = AuthEnv0#{pid => Pid},
|
||||
|
||||
AuthEnv = auth_env(),
|
||||
_ = emqx:hook('client.authenticate', {emqx_auth_jwt, check_auth, [AuthEnv]}),
|
||||
|
||||
AclEnv = acl_env(),
|
||||
_ = emqx:hook('client.check_acl', {emqx_auth_jwt, check_acl, [AclEnv]}),
|
||||
_ = emqx:hook('client.authenticate', {emqx_auth_jwt, check, [AuthEnv1]}),
|
||||
{ok, Sup, AuthEnv1}.
|
||||
|
||||
{ok, Sup}.
|
||||
|
||||
stop(_State) ->
|
||||
emqx:unhook('client.authenticate', {emqx_auth_jwt, check_auth}),
|
||||
emqx:unhook('client.check_acl', {emqx_auth_jwt, check_acl}).
|
||||
stop(AuthEnv) ->
|
||||
emqx:unhook('client.authenticate', {emqx_auth_jwt, check, [AuthEnv]}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Dummy supervisor
|
||||
|
@ -73,9 +69,6 @@ auth_env() ->
|
|||
, checklists => Checklists
|
||||
}.
|
||||
|
||||
acl_env() ->
|
||||
#{acl_claim_name => env(acl_claim_name, <<"acl">>)}.
|
||||
|
||||
jwks_svr_options() ->
|
||||
[{K, V} || {K, V}
|
||||
<- [{secret, env(secret, undefined)},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2020-2021 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.
|
||||
|
@ -26,7 +26,7 @@
|
|||
%% APIs
|
||||
-export([start_link/1]).
|
||||
|
||||
-export([verify/1]).
|
||||
-export([verify/2]).
|
||||
|
||||
%% gen_server callbacks
|
||||
-export([ init/1
|
||||
|
@ -44,9 +44,8 @@
|
|||
| {interval, pos_integer()}.
|
||||
|
||||
-define(INTERVAL, 300000).
|
||||
-define(TAB, ?MODULE).
|
||||
|
||||
-record(state, {addr, tref, intv}).
|
||||
-record(state, {static, remote, addr, tref, intv}).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% APIs
|
||||
|
@ -56,13 +55,13 @@
|
|||
start_link(Options) ->
|
||||
gen_server:start_link(?MODULE, [Options], []).
|
||||
|
||||
-spec verify(binary())
|
||||
-spec verify(pid(), binary())
|
||||
-> {error, term()}
|
||||
| {ok, Payload :: map()}.
|
||||
verify(JwsCompacted) when is_binary(JwsCompacted) ->
|
||||
verify(S, JwsCompacted) when is_binary(JwsCompacted) ->
|
||||
case catch jose_jws:peek(JwsCompacted) of
|
||||
{'EXIT', _} -> {error, not_token};
|
||||
_ -> do_verify(JwsCompacted)
|
||||
_ -> gen_server:call(S, {verify, JwsCompacted})
|
||||
end.
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
|
@ -71,12 +70,12 @@ verify(JwsCompacted) when is_binary(JwsCompacted) ->
|
|||
|
||||
init([Options]) ->
|
||||
ok = jose:json_module(jiffy),
|
||||
_ = ets:new(?TAB, [set, protected, named_table]),
|
||||
{Static, Remote} = do_init_jwks(Options),
|
||||
true = ets:insert(?TAB, [{static, Static}, {remote, Remote}]),
|
||||
Intv = proplists:get_value(interval, Options, ?INTERVAL),
|
||||
{ok, reset_timer(
|
||||
#state{
|
||||
static = Static,
|
||||
remote = Remote,
|
||||
addr = proplists:get_value(jwks_addr, Options),
|
||||
intv = Intv})}.
|
||||
|
||||
|
@ -106,6 +105,9 @@ do_init_jwks(Options) ->
|
|||
Remote = K2J(jwks_addr, fun request_jwks/1),
|
||||
{[J ||J <- [OctJwk, PemJwk], J /= undefined], Remote}.
|
||||
|
||||
handle_call({verify, JwsCompacted}, _From, State) ->
|
||||
handle_verify(JwsCompacted, State);
|
||||
|
||||
handle_call(_Req, _From, State) ->
|
||||
{reply, ok, State}.
|
||||
|
||||
|
@ -114,7 +116,7 @@ handle_cast(_Msg, State) ->
|
|||
|
||||
handle_info({timeout, _TRef, refresh}, State = #state{addr = Addr}) ->
|
||||
NState = try
|
||||
true = ets:insert(?TAB, {remote, request_jwks(Addr)})
|
||||
State#state{remote = request_jwks(Addr)}
|
||||
catch _:_ ->
|
||||
State
|
||||
end,
|
||||
|
@ -134,10 +136,24 @@ code_change(_OldVsn, State, _Extra) ->
|
|||
%% Internal funcs
|
||||
%%--------------------------------------------------------------------
|
||||
|
||||
keys(Type) ->
|
||||
case ets:lookup(?TAB, Type) of
|
||||
[{_, Keys}] -> Keys;
|
||||
[] -> []
|
||||
handle_verify(JwsCompacted,
|
||||
State = #state{static = Static, remote = Remote}) ->
|
||||
try
|
||||
Jwks = case emqx_json:decode(jose_jws:peek_protected(JwsCompacted), [return_maps]) of
|
||||
#{<<"kid">> := Kid} when Remote /= undefined ->
|
||||
[J || J <- Remote, maps:get(<<"kid">>, J#jose_jwk.fields, undefined) =:= Kid];
|
||||
_ -> Static
|
||||
end,
|
||||
case Jwks of
|
||||
[] -> {reply, {error, not_found}, State};
|
||||
_ ->
|
||||
{reply, do_verify(JwsCompacted, Jwks), State}
|
||||
end
|
||||
catch
|
||||
Class : Reason : Stk ->
|
||||
?LOG(error, "Handle JWK crashed: ~p, ~p, stacktrace: ~p~n",
|
||||
[Class, Reason, Stk]),
|
||||
{reply, {error, invalid_signature}, State}
|
||||
end.
|
||||
|
||||
request_jwks(Addr) ->
|
||||
|
@ -165,26 +181,6 @@ cancel_timer(State = #state{tref = TRef}) ->
|
|||
_ = erlang:cancel_timer(TRef),
|
||||
State#state{tref = undefined}.
|
||||
|
||||
do_verify(JwsCompacted) ->
|
||||
try
|
||||
Remote = keys(remote),
|
||||
Jwks = case emqx_json:decode(jose_jws:peek_protected(JwsCompacted), [return_maps]) of
|
||||
#{<<"kid">> := Kid} when Remote /= undefined ->
|
||||
[J || J <- Remote, maps:get(<<"kid">>, J#jose_jwk.fields, undefined) =:= Kid];
|
||||
_ -> keys(static)
|
||||
end,
|
||||
case Jwks of
|
||||
[] -> {error, not_found};
|
||||
_ ->
|
||||
do_verify(JwsCompacted, Jwks)
|
||||
end
|
||||
catch
|
||||
Class : Reason : Stk ->
|
||||
?LOG(error, "verify JWK crashed: ~p, ~p, stacktrace: ~p~n",
|
||||
[Class, Reason, Stk]),
|
||||
{error, invalid_signature}
|
||||
end.
|
||||
|
||||
do_verify(_JwsCompated, []) ->
|
||||
{error, invalid_signature};
|
||||
do_verify(JwsCompacted, [Jwk|More]) ->
|
||||
|
@ -218,12 +214,11 @@ check_claims(Claims) ->
|
|||
do_check_claim([], Claims) ->
|
||||
Claims;
|
||||
do_check_claim([{K, F}|More], Claims) ->
|
||||
case Claims of
|
||||
#{K := V} ->
|
||||
case maps:take(K, Claims) of
|
||||
error -> do_check_claim(More, Claims);
|
||||
{V, NClaims} ->
|
||||
case F(V) of
|
||||
true -> do_check_claim(More, Claims);
|
||||
true -> do_check_claim(More, NClaims);
|
||||
_ -> {false, K}
|
||||
end;
|
||||
_ ->
|
||||
do_check_claim(More, Claims)
|
||||
end
|
||||
end.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2020-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2020-2021 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.
|
||||
|
@ -20,13 +20,22 @@
|
|||
-compile(nowarn_export_all).
|
||||
|
||||
-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").
|
||||
|
||||
-define(APP, emqx_auth_jwt).
|
||||
|
||||
all() -> emqx_ct:all(?MODULE).
|
||||
all() ->
|
||||
[{group, emqx_auth_jwt}].
|
||||
|
||||
groups() ->
|
||||
[{emqx_auth_jwt, [sequence], [ t_check_auth
|
||||
, t_check_claims
|
||||
, t_check_claims_clientid
|
||||
, t_check_claims_username
|
||||
, t_check_claims_kid_in_header
|
||||
]}
|
||||
].
|
||||
|
||||
init_per_suite(Config) ->
|
||||
emqx_ct_helpers:start_apps([emqx_auth_jwt], fun set_special_configs/1),
|
||||
|
@ -35,14 +44,6 @@ init_per_suite(Config) ->
|
|||
end_per_suite(_Config) ->
|
||||
emqx_ct_helpers:stop_apps([emqx_auth_jwt]).
|
||||
|
||||
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(_Case, _Config) ->
|
||||
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),
|
||||
|
@ -77,9 +78,7 @@ sign(Payload, Alg, Key) ->
|
|||
%% Testcases
|
||||
%%------------------------------------------------------------------------------
|
||||
|
||||
t_check_auth(init, _Config) ->
|
||||
application:unset_env(emqx_auth_jwt, verify_claims).
|
||||
t_check_auth(_Config) ->
|
||||
t_check_auth(_) ->
|
||||
Plain = #{clientid => <<"client1">>, username => <<"plain">>, zone => external},
|
||||
Jwt = sign([{clientid, <<"client1">>},
|
||||
{username, <<"plain">>},
|
||||
|
@ -103,9 +102,10 @@ t_check_auth(_Config) ->
|
|||
?assertEqual({error, invalid_signature}, Result2),
|
||||
?assertMatch({error, _}, emqx_access_control:authenticate(Plain#{password => <<"asd">>})).
|
||||
|
||||
t_check_claims(init, _Config) ->
|
||||
application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]).
|
||||
t_check_claims(_Config) ->
|
||||
t_check_claims(_) ->
|
||||
application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]),
|
||||
application:stop(emqx_auth_jwt), application:start(emqx_auth_jwt),
|
||||
|
||||
Plain = #{clientid => <<"client1">>, username => <<"plain">>, zone => external},
|
||||
Jwt = sign([{client_id, <<"client1">>},
|
||||
{username, <<"plain">>},
|
||||
|
@ -120,9 +120,9 @@ t_check_claims(_Config) ->
|
|||
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) ->
|
||||
t_check_claims_clientid(_) ->
|
||||
application:set_env(emqx_auth_jwt, verify_claims, [{clientid, <<"%c">>}]),
|
||||
application:stop(emqx_auth_jwt), application:start(emqx_auth_jwt),
|
||||
Plain = #{clientid => <<"client23">>, username => <<"plain">>, zone => external},
|
||||
Jwt = sign([{clientid, <<"client23">>},
|
||||
{username, <<"plain">>},
|
||||
|
@ -136,9 +136,10 @@ t_check_claims_clientid(_Config) ->
|
|||
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) ->
|
||||
t_check_claims_username(_) ->
|
||||
application:set_env(emqx_auth_jwt, verify_claims, [{username, <<"%u">>}]),
|
||||
application:stop(emqx_auth_jwt), application:start(emqx_auth_jwt),
|
||||
|
||||
Plain = #{clientid => <<"client23">>, username => <<"plain">>, zone => external},
|
||||
Jwt = sign([{client_id, <<"client23">>},
|
||||
{username, <<"plain">>},
|
||||
|
@ -152,9 +153,8 @@ t_check_claims_username(_Config) ->
|
|||
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) ->
|
||||
t_check_claims_kid_in_header(_) ->
|
||||
application:set_env(emqx_auth_jwt, verify_claims, []),
|
||||
Plain = #{clientid => <<"client23">>, username => <<"plain">>, zone => external},
|
||||
Jwt = sign([{clientid, <<"client23">>},
|
||||
{username, <<"plain">>},
|
||||
|
@ -164,125 +164,3 @@ t_check_claims_kid_in_header(_Config) ->
|
|||
Result0 = emqx_access_control:authenticate(Plain#{password => Jwt}),
|
||||
ct:pal("Auth result: ~p~n", [Result0]),
|
||||
?assertMatch({ok, #{auth_result := success, jwt_claims := _}}, Result0).
|
||||
|
||||
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">>]}]},
|
||||
{exp, os: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,
|
||||
|
||||
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, os: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, os: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_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, os: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)),
|
||||
|
||||
ok = emqtt:disconnect(C).
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||
{VSN,
|
||||
[{"4.3.14",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_sys,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
|
@ -11,8 +10,7 @@
|
|||
{load_module,emqx_app,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.13",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
|
@ -29,8 +27,7 @@
|
|||
{load_module,emqx_misc,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_connection,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.12",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_frame,brutal_purge,soft_purge,[]},
|
||||
|
@ -55,8 +52,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.11",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -83,8 +79,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.10",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -111,8 +106,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.9",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -143,8 +137,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.8",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -175,8 +168,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.7",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -208,8 +200,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.6",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -453,8 +444,7 @@
|
|||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{<<".*">>,[]}],
|
||||
[{"4.3.14",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_sys,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
|
@ -462,8 +452,7 @@
|
|||
{load_module,emqx_app,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.13",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
|
@ -480,8 +469,7 @@
|
|||
{load_module,emqx_cm,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_connection,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.12",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_frame,brutal_purge,soft_purge,[]},
|
||||
|
@ -505,8 +493,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.11",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -532,8 +519,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.10",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -559,8 +545,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.9",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -590,8 +575,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.8",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -621,8 +605,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.7",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
@ -653,8 +636,7 @@
|
|||
{load_module,emqx_message,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_limiter,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.6",
|
||||
[{load_module,emqx_access_rule,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
[{load_module,emqx_shared_sub,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_hooks,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_plugins,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_pmon,brutal_purge,soft_purge,[]},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
%%--------------------------------------------------------------------
|
||||
%% Copyright (c) 2017-2022 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||
%% Copyright (c) 2017-2021 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.
|
||||
|
@ -19,7 +19,6 @@
|
|||
%% APIs
|
||||
-export([ match/3
|
||||
, compile/1
|
||||
, feed_var/2
|
||||
]).
|
||||
|
||||
-export_type([rule/0]).
|
||||
|
|
Loading…
Reference in New Issue