Merge pull request #8862 from lafirest/fix/jwt_exp

fix(jwt): support non-integer timestamp claims
This commit is contained in:
lafirest 2022-09-01 17:09:31 +08:00 committed by GitHub
commit 168df705fa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 68 additions and 19 deletions

View File

@ -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]},

View File

@ -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}]},
{<<".*">>,[]}]}.

View File

@ -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.

View File

@ -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

View File

@ -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">>}]).