Merge pull request #8862 from lafirest/fix/jwt_exp
fix(jwt): support non-integer timestamp claims
This commit is contained in:
commit
168df705fa
|
@ -1,6 +1,6 @@
|
|||
{application, emqx_auth_jwt,
|
||||
[{description, "EMQ X Authentication with JWT"},
|
||||
{vsn, "4.3.5"}, % strict semver, bump manually!
|
||||
{vsn, "4.3.6"}, % strict semver, bump manually!
|
||||
{modules, []},
|
||||
{registered, [emqx_auth_jwt_sup]},
|
||||
{applications, [kernel,stdlib,jose]},
|
||||
|
|
|
@ -1,11 +1,25 @@
|
|||
%% -*- mode: erlang -*-
|
||||
%% Unless you know what you are doing, DO NOT edit manually!!
|
||||
{VSN,
|
||||
[{"4.3.4",[{load_module,emqx_auth_jwt_svr,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.3",[{load_module,emqx_auth_jwt_svr,brutal_purge,soft_purge,[]}]},
|
||||
[{"4.3.5",
|
||||
[{load_module,emqx_auth_jwt,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_auth_jwt_svr,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.4",
|
||||
[{load_module,emqx_auth_jwt,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_auth_jwt_svr,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.3",
|
||||
[{load_module,emqx_auth_jwt,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_auth_jwt_svr,brutal_purge,soft_purge,[]}]},
|
||||
{<<"4\\.3\\.[0-2]">>,[{restart_application,emqx_auth_jwt}]},
|
||||
{<<".*">>,[]}],
|
||||
[{"4.3.4",[{load_module,emqx_auth_jwt_svr,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.3",[{load_module,emqx_auth_jwt_svr,brutal_purge,soft_purge,[]}]},
|
||||
[{"4.3.5",
|
||||
[{load_module,emqx_auth_jwt,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_auth_jwt_svr,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.4",
|
||||
[{load_module,emqx_auth_jwt,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_auth_jwt_svr,brutal_purge,soft_purge,[]}]},
|
||||
{"4.3.3",
|
||||
[{load_module,emqx_auth_jwt,brutal_purge,soft_purge,[]},
|
||||
{load_module,emqx_auth_jwt_svr,brutal_purge,soft_purge,[]}]},
|
||||
{<<"4\\.3\\.[0-2]">>,[{restart_application,emqx_auth_jwt}]},
|
||||
{<<".*">>,[]}]}.
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
, description/0
|
||||
]).
|
||||
|
||||
-export([string_to_number/1]).
|
||||
|
||||
%%--------------------------------------------------------------------
|
||||
%% Authentication callbacks
|
||||
%%--------------------------------------------------------------------
|
||||
|
@ -56,16 +58,12 @@ check_acl(ClientInfo = #{jwt_claims := Claims},
|
|||
#{acl_claim_name := AclClaimName}) ->
|
||||
case Claims of
|
||||
#{AclClaimName := Acl, <<"exp">> := Exp} ->
|
||||
try is_expired(Exp) of
|
||||
case is_expired(Exp) of
|
||||
true ->
|
||||
?DEBUG("acl_deny_due_to_jwt_expired", []),
|
||||
deny;
|
||||
false ->
|
||||
verify_acl(ClientInfo, Acl, PubSub, Topic)
|
||||
catch
|
||||
_:_ ->
|
||||
?DEBUG("acl_deny_due_to_invalid_jwt_exp", []),
|
||||
deny
|
||||
end;
|
||||
#{AclClaimName := Acl} ->
|
||||
verify_acl(ClientInfo, Acl, PubSub, Topic);
|
||||
|
@ -75,14 +73,29 @@ check_acl(ClientInfo = #{jwt_claims := Claims},
|
|||
end.
|
||||
|
||||
is_expired(Exp) when is_binary(Exp) ->
|
||||
ExpInt = binary_to_integer(Exp),
|
||||
is_expired(ExpInt);
|
||||
is_expired(Exp) ->
|
||||
case string_to_number(Exp) of
|
||||
{ok, Val} ->
|
||||
is_expired(Val);
|
||||
_ ->
|
||||
?DEBUG("acl_deny_due_to_invalid_jwt_exp:~p", [Exp]),
|
||||
true
|
||||
end;
|
||||
is_expired(Exp) when is_integer(Exp) ->
|
||||
Now = erlang:system_time(second),
|
||||
Now > Exp.
|
||||
Now > Exp;
|
||||
is_expired(Exp) ->
|
||||
?DEBUG("acl_deny_due_to_invalid_jwt_exp:~p", [Exp]),
|
||||
true.
|
||||
|
||||
description() -> "Authentication with JWT".
|
||||
|
||||
string_to_number(Bin) when is_binary(Bin) ->
|
||||
string_to_number(Bin, fun erlang:binary_to_integer/1, fun erlang:binary_to_float/1);
|
||||
string_to_number(Str) when is_list(Str) ->
|
||||
string_to_number(Str, fun erlang:list_to_integer/1, fun erlang:list_to_float/1);
|
||||
string_to_number(_) ->
|
||||
false.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Verify Claims
|
||||
%%--------------------------------------------------------------------
|
||||
|
@ -127,3 +140,14 @@ match_topic(ClientInfo, AclTopic, Topic) ->
|
|||
TopicWords = emqx_topic:words(Topic),
|
||||
AclTopicRendered = emqx_access_rule:feed_var(ClientInfo, AclTopicWords),
|
||||
emqx_topic:match(TopicWords, AclTopicRendered).
|
||||
|
||||
string_to_number(Str, IntFun, FloatFun) ->
|
||||
try
|
||||
{ok, IntFun(Str)}
|
||||
catch _:_ ->
|
||||
try
|
||||
{ok, FloatFun(Str)}
|
||||
catch _:_ ->
|
||||
false
|
||||
end
|
||||
end.
|
||||
|
|
|
@ -215,13 +215,13 @@ with_int_value(Fun) ->
|
|||
case Value of
|
||||
Int when is_integer(Int) -> Fun(Int);
|
||||
Bin when is_binary(Bin) ->
|
||||
case string:to_integer(Bin) of
|
||||
{Int, <<>>} -> Fun(Int);
|
||||
case emqx_auth_jwt:string_to_number(Bin) of
|
||||
{ok, Num} -> Fun(Num);
|
||||
_ -> false
|
||||
end;
|
||||
Str when is_list(Str) ->
|
||||
case string:to_integer(Str) of
|
||||
{Int, ""} -> Fun(Int);
|
||||
case emqx_auth_jwt:string_to_number(Str) of
|
||||
{ok, Num} -> Fun(Num);
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
|
|
|
@ -164,7 +164,18 @@ t_check_auth_str_exp(_Config) ->
|
|||
|
||||
Result1 = emqx_access_control:authenticate(Plain#{password => Jwt1}),
|
||||
ct:pal("Auth result: ~p~n", [Result1]),
|
||||
?assertMatch({error, _}, Result1).
|
||||
?assertMatch({error, _}, Result1),
|
||||
|
||||
Exp2 = float_to_binary(os: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_claims(init, _Config) ->
|
||||
application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]).
|
||||
|
|
Loading…
Reference in New Issue