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

JWT-only authentication for some users (#3012)

This commit is contained in:
Alexey Shchepin 2019-09-18 18:45:51 +03:00
parent f48b4124b1
commit 0fe1e40a9d
4 changed files with 52 additions and 18 deletions

View File

@ -76,7 +76,7 @@
{ets_cache:tag(), {ok, password()} | {error, db_failure | not_allowed}}. {ets_cache:tag(), {ok, password()} | {error, db_failure | not_allowed}}.
-callback remove_user(binary(), binary()) -> ok | {error, db_failure | not_allowed}. -callback remove_user(binary(), binary()) -> ok | {error, db_failure | not_allowed}.
-callback user_exists(binary(), binary()) -> {ets_cache:tag(), boolean() | {error, db_failure}}. -callback user_exists(binary(), binary()) -> {ets_cache:tag(), boolean() | {error, db_failure}}.
-callback check_password(binary(), binary(), binary(), binary()) -> {ets_cache:tag(), boolean()}. -callback check_password(binary(), binary(), binary(), binary()) -> {ets_cache:tag(), boolean() | {stop, boolean()}}.
-callback try_register(binary(), binary(), password()) -> -callback try_register(binary(), binary(), password()) ->
{ets_cache:tag(), {ok, password()} | {error, exists | db_failure | not_allowed}}. {ets_cache:tag(), {ok, password()} | {error, exists | db_failure | not_allowed}}.
-callback get_users(binary(), opts()) -> [{binary(), binary()}]. -callback get_users(binary(), opts()) -> [{binary(), binary()}].
@ -237,17 +237,20 @@ check_password_with_authmodule(User, AuthzId, Server, Password, Digest, DigestGe
error -> error ->
false; false;
LAuthzId -> LAuthzId ->
lists:foldl( untag_stop(
fun(Mod, false) -> lists:foldl(
case db_check_password( fun(Mod, false) ->
LUser, LAuthzId, LServer, Password, case db_check_password(
Digest, DigestGen, Mod) of LUser, LAuthzId, LServer, Password,
true -> {true, Mod}; Digest, DigestGen, Mod) of
false -> false true -> {true, Mod};
end; false -> false;
(_, Acc) -> {stop, true} -> {stop, {true, Mod}};
Acc {stop, false} -> {stop, false}
end, false, auth_modules(LServer)) end;
(_, Acc) ->
Acc
end, false, auth_modules(LServer)))
end; end;
_ -> _ ->
false false
@ -484,7 +487,11 @@ remove_user(User, Server, Password) ->
<<"">>, undefined, Mod) of <<"">>, undefined, Mod) of
true -> true ->
db_remove_user(LUser, LServer, Mod); db_remove_user(LUser, LServer, Mod);
{stop, true} ->
db_remove_user(LUser, LServer, Mod);
false -> false ->
{error, not_allowed};
{stop, false} ->
{error, not_allowed} {error, not_allowed}
end end
end, {error, not_allowed}, auth_modules(Server)) of end, {error, not_allowed}, auth_modules(Server)) of
@ -654,7 +661,9 @@ db_check_password(User, AuthzId, Server, ProvidedPassword,
case Mod:check_password( case Mod:check_password(
User, AuthzId, Server, ProvidedPassword) of User, AuthzId, Server, ProvidedPassword) of
{CacheTag, true} -> {CacheTag, {ok, ProvidedPassword}}; {CacheTag, true} -> {CacheTag, {ok, ProvidedPassword}};
{CacheTag, false} -> {CacheTag, error} {CacheTag, {stop, true}} -> {CacheTag, {ok, ProvidedPassword}};
{CacheTag, false} -> {CacheTag, error};
{CacheTag, {stop, false}} -> {CacheTag, error}
end end
end) of end) of
{ok, _} -> {ok, _} ->
@ -891,6 +900,9 @@ validate_credentials(User, Server, Password) ->
end end
end. end.
untag_stop({stop, Val}) -> Val;
untag_stop(Val) -> Val.
import_info() -> import_info() ->
[{<<"users">>, 3}]. [{<<"users">>, 3}].

View File

@ -31,7 +31,7 @@
-export([start/1, stop/1, check_password/4, -export([start/1, stop/1, check_password/4,
store_type/1, plain_password_required/1, store_type/1, plain_password_required/1,
user_exists/2 user_exists/2, use_cache/1
]). ]).
-include("xmpp.hrl"). -include("xmpp.hrl").
@ -55,7 +55,7 @@ plain_password_required(_Host) -> true.
store_type(_Host) -> external. store_type(_Host) -> external.
-spec check_password(binary(), binary(), binary(), binary()) -> {ets_cache:tag(), boolean()}. -spec check_password(binary(), binary(), binary(), binary()) -> {ets_cache:tag(), boolean() | {stop, boolean()}}.
check_password(User, AuthzId, Server, Token) -> check_password(User, AuthzId, Server, Token) ->
%% MREMOND: Should we move the AuthzId check at a higher level in %% MREMOND: Should we move the AuthzId check at a higher level in
%% the call stack? %% the call stack?
@ -64,12 +64,23 @@ check_password(User, AuthzId, Server, Token) ->
true -> true ->
if Token == <<"">> -> {nocache, false}; if Token == <<"">> -> {nocache, false};
true -> true ->
{nocache, check_jwt_token(User, Server, Token)} Res = check_jwt_token(User, Server, Token),
Rule = ejabberd_option:jwt_auth_only_rule(Server),
case acl:match_rule(Server, Rule,
jid:make(User, Server, <<"">>)) of
deny ->
{nocache, Res};
allow ->
{nocache, {stop, Res}}
end
end end
end. end.
user_exists(_User, _Host) -> {nocache, false}. user_exists(_User, _Host) -> {nocache, false}.
use_cache(_) ->
false.
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% Internal functions %%% Internal functions
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------

View File

@ -50,6 +50,7 @@
-export([host_config/0]). -export([host_config/0]).
-export([hosts/0]). -export([hosts/0]).
-export([include_config_file/0, include_config_file/1]). -export([include_config_file/0, include_config_file/1]).
-export([jwt_auth_only_rule/0, jwt_auth_only_rule/1]).
-export([jwt_key/0, jwt_key/1]). -export([jwt_key/0, jwt_key/1]).
-export([language/0, language/1]). -export([language/0, language/1]).
-export([ldap_backups/0, ldap_backups/1]). -export([ldap_backups/0, ldap_backups/1]).
@ -424,6 +425,13 @@ include_config_file() ->
include_config_file(Host) -> include_config_file(Host) ->
ejabberd_config:get_option({include_config_file, Host}). ejabberd_config:get_option({include_config_file, Host}).
-spec jwt_auth_only_rule() -> atom().
jwt_auth_only_rule() ->
jwt_auth_only_rule(global).
-spec jwt_auth_only_rule(global | binary()) -> atom().
jwt_auth_only_rule(Host) ->
ejabberd_config:get_option({jwt_auth_only_rule, Host}).
-spec jwt_key() -> jose_jwk:key() | 'undefined'. -spec jwt_key() -> jose_jwk:key() | 'undefined'.
jwt_key() -> jwt_key() ->
jwt_key(global). jwt_key(global).

View File

@ -409,7 +409,9 @@ opt_type(jwt_key) ->
{error, Reason} -> {error, Reason} ->
econf:fail({read_file, Reason, Path}) econf:fail({read_file, Reason, Path})
end end
end). end);
opt_type(jwt_auth_only_rule) ->
econf:atom().
%% We only define the types of options that cannot be derived %% We only define the types of options that cannot be derived
%% automatically by tools/opt_type.sh script %% automatically by tools/opt_type.sh script
@ -635,7 +637,8 @@ options() ->
{websocket_origin, []}, {websocket_origin, []},
{websocket_ping_interval, timer:seconds(60)}, {websocket_ping_interval, timer:seconds(60)},
{websocket_timeout, timer:minutes(5)}, {websocket_timeout, timer:minutes(5)},
{jwt_key, undefined}]. {jwt_key, undefined},
{jwt_auth_only_rule, none}].
-spec globals() -> [atom()]. -spec globals() -> [atom()].
globals() -> globals() ->