fix(jwt): support non-integer timestamp claims
This commit is contained in:
parent
f3ca2b20ed
commit
15c84ba152
|
@ -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
|
||||||
%%--------------------------------------------------------------------
|
%%--------------------------------------------------------------------
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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">>}]).
|
||||||
|
|
Loading…
Reference in New Issue