diff --git a/apps/emqx_auth_jwt/src/emqx_auth_jwt.erl b/apps/emqx_auth_jwt/src/emqx_auth_jwt.erl index 040f9b629..1f304a65e 100644 --- a/apps/emqx_auth_jwt/src/emqx_auth_jwt.erl +++ b/apps/emqx_auth_jwt/src/emqx_auth_jwt.erl @@ -26,6 +26,8 @@ , description/0 ]). +-export([binary_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,40 @@ 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 binary_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". +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 %%-------------------------------------------------------------------- diff --git a/apps/emqx_auth_jwt/src/emqx_auth_jwt_svr.erl b/apps/emqx_auth_jwt/src/emqx_auth_jwt_svr.erl index ac07a8640..a9b35dbec 100644 --- a/apps/emqx_auth_jwt/src/emqx_auth_jwt_svr.erl +++ b/apps/emqx_auth_jwt/src/emqx_auth_jwt_svr.erl @@ -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:binary_to_number(Bin) of + {ok, Int} -> Fun(Int); _ -> false end; Str when is_list(Str) -> - case string:to_integer(Str) of - {Int, ""} -> Fun(Int); + case emqx_auth_jwt:binary_to_number(Str) of + {ok, Int} -> Fun(Int); _ -> false end end diff --git a/apps/emqx_auth_jwt/test/emqx_auth_jwt_SUITE.erl b/apps/emqx_auth_jwt/test/emqx_auth_jwt_SUITE.erl index c8eed8b41..934d80f41 100644 --- a/apps/emqx_auth_jwt/test/emqx_auth_jwt_SUITE.erl +++ b/apps/emqx_auth_jwt/test/emqx_auth_jwt_SUITE.erl @@ -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">>}]).