fix(jwt): support non-integer timestamp claims

This commit is contained in:
firest 2022-09-01 15:43:32 +08:00
parent f3ca2b20ed
commit 15c84ba152
3 changed files with 49 additions and 14 deletions

View File

@ -26,6 +26,8 @@
, description/0 , description/0
]). ]).
-export([binary_to_number/1]).
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Authentication callbacks %% Authentication callbacks
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
@ -56,16 +58,12 @@ check_acl(ClientInfo = #{jwt_claims := Claims},
#{acl_claim_name := AclClaimName}) -> #{acl_claim_name := AclClaimName}) ->
case Claims of case Claims of
#{AclClaimName := Acl, <<"exp">> := Exp} -> #{AclClaimName := Acl, <<"exp">> := Exp} ->
try is_expired(Exp) of case is_expired(Exp) of
true -> true ->
?DEBUG("acl_deny_due_to_jwt_expired", []), ?DEBUG("acl_deny_due_to_jwt_expired", []),
deny; deny;
false -> false ->
verify_acl(ClientInfo, Acl, PubSub, Topic) verify_acl(ClientInfo, Acl, PubSub, Topic)
catch
_:_ ->
?DEBUG("acl_deny_due_to_invalid_jwt_exp", []),
deny
end; end;
#{AclClaimName := Acl} -> #{AclClaimName := Acl} ->
verify_acl(ClientInfo, Acl, PubSub, Topic); verify_acl(ClientInfo, Acl, PubSub, Topic);
@ -75,14 +73,40 @@ check_acl(ClientInfo = #{jwt_claims := Claims},
end. end.
is_expired(Exp) when is_binary(Exp) -> is_expired(Exp) when is_binary(Exp) ->
ExpInt = binary_to_integer(Exp), case binary_to_number(Exp) of
is_expired(ExpInt); {ok, Val} ->
is_expired(Exp) -> 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 = 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". description() -> "Authentication with JWT".
binary_to_number(Bin) ->
Checker = fun([], _) ->
false;
([H | T], Self) ->
try
{ok, H(Bin)}
catch _:_ ->
Self(T, Self)
end
end,
Checker([fun erlang:binary_to_integer/1,
fun(In) ->
Val = erlang:binary_to_float(In),
erlang:round(Val)
end],
Checker).
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
%% Verify Claims %% Verify Claims
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------

View File

@ -215,13 +215,13 @@ with_int_value(Fun) ->
case Value of case Value of
Int when is_integer(Int) -> Fun(Int); Int when is_integer(Int) -> Fun(Int);
Bin when is_binary(Bin) -> Bin when is_binary(Bin) ->
case string:to_integer(Bin) of case emqx_auth_jwt:binary_to_number(Bin) of
{Int, <<>>} -> Fun(Int); {ok, Int} -> Fun(Int);
_ -> false _ -> false
end; end;
Str when is_list(Str) -> Str when is_list(Str) ->
case string:to_integer(Str) of case emqx_auth_jwt:binary_to_number(Str) of
{Int, ""} -> Fun(Int); {ok, Int} -> Fun(Int);
_ -> false _ -> false
end end
end end

View File

@ -164,7 +164,18 @@ t_check_auth_str_exp(_Config) ->
Result1 = emqx_access_control:authenticate(Plain#{password => Jwt1}), Result1 = emqx_access_control:authenticate(Plain#{password => Jwt1}),
ct:pal("Auth result: ~p~n", [Result1]), 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) -> t_check_claims(init, _Config) ->
application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]). application:set_env(emqx_auth_jwt, verify_claims, [{sub, <<"value">>}]).