25
1
mirror of https://github.com/processone/ejabberd.git synced 2024-11-24 16:23:40 +01:00

JWT enhancement (#3460)

* ref: run the default JWT verifier as hook callback

* ref: add system timestamp to JWT debug log
This commit is contained in:
Pouriya 2020-12-28 12:36:45 +03:30 committed by GitHub
parent bd08f408ca
commit c056002f7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -33,6 +33,8 @@
store_type/1, plain_password_required/1, store_type/1, plain_password_required/1,
user_exists/2, use_cache/1 user_exists/2, use_cache/1
]). ]).
%% 'ejabberd_hooks' callback:
-export([check_decoded_jwt/5]).
-include_lib("xmpp/include/xmpp.hrl"). -include_lib("xmpp/include/xmpp.hrl").
-include("logger.hrl"). -include("logger.hrl").
@ -41,6 +43,12 @@
%%% API %%% API
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
start(Host) -> start(Host) ->
%% We add our default JWT verifier with hook priority 100.
%% So if you need to check or verify your custom JWT before the
%% default verifier, It's better to use this hook with priority
%% little than 100 and return bool() or {stop, bool()} in your own
%% callback function.
ejabberd_hooks:add(check_decoded_jwt, Host, ?MODULE, check_decoded_jwt, 100),
case ejabberd_option:jwt_key(Host) of case ejabberd_option:jwt_key(Host) of
undefined -> undefined ->
?ERROR_MSG("Option jwt_key is not configured for ~ts: " ?ERROR_MSG("Option jwt_key is not configured for ~ts: "
@ -49,7 +57,8 @@ start(Host) ->
ok ok
end. end.
stop(_Host) -> ok. stop(Host) ->
ejabberd_hooks:delete(check_decoded_jwt, Host, ?MODULE, check_decoded_jwt, 100).
plain_password_required(_Host) -> true. plain_password_required(_Host) -> true.
@ -81,36 +90,47 @@ user_exists(_User, _Host) -> {nocache, false}.
use_cache(_) -> use_cache(_) ->
false. false.
%%%----------------------------------------------------------------------
%%% 'ejabberd_hooks' callback
%%%----------------------------------------------------------------------
check_decoded_jwt(true, Fields, _Signature, Server, User) ->
JidField = ejabberd_option:jwt_jid_field(Server),
case maps:find(JidField, Fields) of
{ok, SJid} when is_binary(SJid) ->
try
JID = jid:decode(SJid),
JID#jid.luser == User andalso JID#jid.lserver == Server
catch error:{bad_jid, _} ->
false
end;
_ -> % error | {ok, _UnknownType}
false
end;
check_decoded_jwt(Acc, _, _, _, _) ->
Acc.
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% Internal functions %%% Internal functions
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
check_jwt_token(User, Server, Token) -> check_jwt_token(User, Server, Token) ->
JWK = ejabberd_option:jwt_key(Server), JWK = ejabberd_option:jwt_key(Server),
JidField = ejabberd_option:jwt_jid_field(Server),
try jose_jwt:verify(JWK, Token) of try jose_jwt:verify(JWK, Token) of
{true, {jose_jwt, Fields}, Signature} -> {true, {jose_jwt, Fields}, Signature} ->
?DEBUG("jwt verify: ~p - ~p~n", [Fields, Signature]), Now = erlang:system_time(second),
?DEBUG("jwt verify at system timestamp ~p: ~p - ~p~n", [Now, Fields, Signature]),
case maps:find(<<"exp">>, Fields) of case maps:find(<<"exp">>, Fields) of
error -> error ->
%% No expiry in token => We consider token invalid: %% No expiry in token => We consider token invalid:
false; false;
{ok, Exp} -> {ok, Exp} ->
Now = erlang:system_time(second),
if if
Exp > Now -> Exp > Now ->
case maps:find(JidField, Fields) of ejabberd_hooks:run_fold(
error -> check_decoded_jwt,
false; Server,
{ok, SJID} -> true,
try jid:decode(SJID) of [Fields, Signature, Server, User]
JID -> );
(JID#jid.luser == User) andalso
(JID#jid.lserver == Server) andalso
ejabberd_hooks:run_fold(check_decoded_jwt, Server, true, [Fields, Signature, User])
catch error:{bad_jid, _} ->
false
end
end;
true -> true ->
%% return false, if token has expired %% return false, if token has expired
false false
@ -122,4 +142,3 @@ check_jwt_token(User, Server, Token) ->
error:{badarg, _} -> error:{badarg, _} ->
false false
end. end.