Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert ejabberd_auth to gen_hook #3832

Merged
merged 1 commit into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 17 additions & 19 deletions src/auth/ejabberd_auth.erl
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,11 @@

%% Hook handlers
-export([remove_domain/3]).
-export([does_user_exist/4]).
-export([on_does_user_exist/3]).

-ignore_xref([
auth_methods/1, auth_modules/1, check_password/4, does_user_exist/4,
get_vh_registered_users/2, get_vh_registered_users_number/2,
start/1, stop/1]).
auth_methods/1, auth_modules/1, check_password/4, get_vh_registered_users/2,
get_vh_registered_users_number/2, start/1, stop/1]).

-include("mongoose.hrl").
-include("jlib.hrl").
Expand Down Expand Up @@ -103,27 +102,21 @@ start(HostType) ->
ensure_metrics(HostType),
F = fun(Mod) -> mongoose_gen_auth:start(Mod, HostType) end,
call_auth_modules_for_host_type(HostType, F, #{op => map}),
ejabberd_hooks:add(legacy_hooks(HostType)),
gen_hook:add_handlers(hooks(HostType)),
ok.

-spec stop(HostType :: mongooseim:host_type()) -> 'ok'.
stop(HostType) ->
ejabberd_hooks:delete(legacy_hooks(HostType)),
gen_hook:delete_handlers(hooks(HostType)),
F = fun(Mod) -> mongoose_gen_auth:stop(Mod, HostType) end,
call_auth_modules_for_host_type(HostType, F, #{op => map}),
ok.

legacy_hooks(HostType) ->
[
%% These hooks must run in between those of mod_cache_users
{does_user_exist, HostType, ?MODULE, does_user_exist, 50}
].

-spec hooks(mongooseim:host_type()) -> gen_hook:hook_list().
hooks(HostType) ->
[
%% These hooks must run in between those of mod_cache_users
{does_user_exist, HostType, fun ?MODULE:on_does_user_exist/3, #{}, 50},
%% It is important that this handler happens _before_ all other modules
{remove_domain, HostType, fun ?MODULE:remove_domain/3, #{}, 10}
].
Expand Down Expand Up @@ -316,14 +309,19 @@ does_user_exist(HostType, Jid, RequestType) ->

%% @doc does_user_exist hook handler
%% Returns 'false' in case of an error
-spec does_user_exist(boolean(), mongooseim:host_type(), jid:jid(), exist_type()) -> boolean().
does_user_exist(false, HostType, Jid, stored) ->
true =:= does_stored_user_exist(HostType, Jid);
does_user_exist(false, HostType, #jid{luser = LUser, lserver = LServer}, with_anonymous) ->
-spec on_does_user_exist(Acc, Params, Extra) -> {ok, Acc} when
Acc :: boolean(),
Params :: map(),
Extra :: map().
on_does_user_exist(false, #{jid := Jid, request_type := stored}, #{host_type := HostType}) ->
{ok, true =:= does_stored_user_exist(HostType, Jid)};
on_does_user_exist(false,
#{jid := #jid{luser = LUser, lserver = LServer}, request_type := with_anonymous},
#{host_type := HostType}) ->
F = fun(Mod) -> does_user_exist_in_module(HostType, LUser, LServer, Mod) end,
call_auth_modules_for_host_type(HostType, F, #{default => false, metric => does_user_exist});
does_user_exist(Status, _, _, _) ->
Status.
{ok, call_auth_modules_for_host_type(HostType, F, #{default => false, metric => does_user_exist})};
on_does_user_exist(Status, _, _) ->
{ok, Status}.

%% @doc Returns true if the user exists in the DB
%% In case of a backend error, it is propagated to the caller
Expand Down
70 changes: 38 additions & 32 deletions src/auth/ejabberd_auth_anonymous.erl
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
-export([start/1,
stop/1,
config_spec/0,
register_connection/5,
unregister_connection/5,
session_cleanup/5
register_connection/3,
unregister_connection/3,
session_cleanup/3
]).

-behaviour(mongoose_gen_auth).
Expand All @@ -51,8 +51,7 @@
-export([check_password/4,
check_password/6]).

-ignore_xref([register_connection/5, session_cleanup/5, unregister_connection/5,
login/3]).
-ignore_xref([login/3]).

-include("mongoose.hrl").
-include("jlib.hrl").
Expand All @@ -73,18 +72,22 @@ start(HostType) ->
{attributes, record_info(fields, anonymous)}]),
mnesia:add_table_copy(anonymous, node(), ram_copies),
%% The hooks are needed to add / remove users from the anonymous tables
ejabberd_hooks:add(sm_register_connection_hook, HostType, ?MODULE, register_connection, 100),
ejabberd_hooks:add(sm_remove_connection_hook, HostType, ?MODULE, unregister_connection, 100),
ejabberd_hooks:add(session_cleanup, HostType, ?MODULE, session_cleanup, 50),
gen_hook:add_handlers(hooks(HostType)),
ok.

-spec stop(mongooseim:host_type()) -> ok.
stop(HostType) ->
ejabberd_hooks:delete(sm_register_connection_hook, HostType, ?MODULE, register_connection, 100),
ejabberd_hooks:delete(sm_remove_connection_hook, HostType, ?MODULE, unregister_connection, 100),
ejabberd_hooks:delete(session_cleanup, HostType, ?MODULE, session_cleanup, 50),
gen_hook:delete_handlers(hooks(HostType)),
ok.

-spec hooks(mongooseim:host_type()) -> gen_hook:hook_list().
hooks(HostType) ->
[
{sm_register_connection_hook, HostType, fun ?MODULE:register_connection/3, #{}, 100},
{sm_remove_connection_hook, HostType, fun ?MODULE:unregister_connection/3, #{}, 100},
{session_cleanup, HostType, fun ?MODULE:session_cleanup/3, #{}, 50}
].

-spec config_spec() -> mongoose_config_spec:config_section().
config_spec() ->
#section{
Expand Down Expand Up @@ -132,32 +135,35 @@ remove_connection(SID, LUser, LServer) ->


%% @doc Register connection
-spec register_connection(Acc,
HostType :: mongooseim:host_type(),
SID :: ejabberd_sm:sid(),
JID :: jid:jid(),
Info :: ejabberd_sm:info()) -> Acc when Acc :: any().
register_connection(Acc, HostType, SID, #jid{luser = LUser, lserver = LServer},
#{auth_module := AuthModule})
-spec register_connection(Acc, Params, Extra) -> {ok, Acc} when
Acc :: term(),
Params :: map(),
Extra :: map().
register_connection(Acc,
#{sid := SID,
jid := #jid{luser = LUser, lserver = LServer},
info := #{auth_module := AuthModule}},
#{host_type := HostType})
when AuthModule =:= ejabberd_auth_anonymous; % login_anon
AuthModule =:= cyrsasl_anonymous -> % sasl_anon
mongoose_hooks:register_user(HostType, LServer, LUser),
US = {LUser, LServer},
mnesia:sync_dirty(fun() -> mnesia:write(#anonymous{us = US, sid = SID}) end),
Acc;
register_connection(Acc, _HostType, _SID, _JID, _Info) ->
Acc.
{ok, Acc};
register_connection(Acc, _Params, _Extra) ->
{ok, Acc}.

%% @doc Remove an anonymous user from the anonymous users table
-spec unregister_connection(Acc, SID :: ejabberd_sm:sid(), JID :: jid:jid(),
any(), ejabberd_sm:close_reason()) -> Acc
when Acc :: mongoose_acc:t().
unregister_connection(Acc, SID, #jid{luser = LUser, lserver = LServer}, _, _) ->
-spec unregister_connection(Acc, Params, Extra) -> {ok, Acc} when
Acc :: mongoose_acc:t(),
Params :: map(),
Extra :: map().
unregister_connection(Acc, #{sid := SID, jid := #jid{luser = LUser, lserver = LServer}}, _Extra) ->
purge_hook(does_anonymous_user_exist(LUser, LServer),
mongoose_acc:host_type(Acc),
LUser, LServer),
remove_connection(SID, LUser, LServer),
Acc.
{ok, Acc}.

%% @doc Launch the hook to purge user data only for anonymous users.
-spec purge_hook(boolean(), mongooseim:host_type(), jid:luser(), jid:lserver()) -> 'ok'.
Expand All @@ -170,13 +176,13 @@ purge_hook(true, HostType, LUser, LServer) ->
element => undefined }),
mongoose_hooks:anonymous_purge_hook(LServer, Acc, LUser).

-spec session_cleanup(Acc :: map(), LUser :: jid:luser(),
LServer :: jid:lserver(),
LResource :: jid:lresource(),
SID :: ejabberd_sm:sid()) -> any().
session_cleanup(Acc, LUser, LServer, _LResource, SID) ->
-spec session_cleanup(Acc, Params, Extra) -> {ok, Acc} when
Acc :: mongoose_acc:t(),
Params :: map(),
Extra :: map().
session_cleanup(Acc, #{sid := SID, user := LUser, server := LServer}, _Extra) ->
remove_connection(SID, LUser, LServer),
Acc.
{ok, Acc}.

%% ---------------------------------
%% Specific anonymous auth functions
Expand Down
12 changes: 8 additions & 4 deletions src/mongoose_hooks.erl
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,10 @@ auth_failed(HostType, Server, Username) ->
RequestType :: ejabberd_auth:exist_type(),
Result :: boolean().
does_user_exist(HostType, Jid, RequestType) ->
run_hook_for_host_type(does_user_exist, HostType, false,
[HostType, Jid, RequestType]).
Params = #{jid => Jid, request_type => RequestType},
Args = [HostType, Jid, RequestType],
ParamsWithLegacyArgs = ejabberd_hooks:add_args(Params, Args),
run_hook_for_host_type(does_user_exist, HostType, false, ParamsWithLegacyArgs).

-spec remove_domain(HostType, Domain) -> Result when
HostType :: binary(),
Expand Down Expand Up @@ -402,9 +404,11 @@ resend_offline_messages_hook(Acc, JID) ->
SID :: ejabberd_sm:sid(),
Result :: mongoose_acc:t().
session_cleanup(Server, Acc, User, Resource, SID) ->
Params = #{user => User, server => Server, resource => Resource, sid => SID},
Args = [User, Server, Resource, SID],
ParamsWithLegacyArgs = ejabberd_hooks:add_args(Params, Args),
HostType = mongoose_acc:host_type(Acc),
run_hook_for_host_type(session_cleanup, HostType, Acc,
[User, Server, Resource, SID]).
run_hook_for_host_type(session_cleanup, HostType, Acc, ParamsWithLegacyArgs).

%%% @doc The `set_vcard' hook is called when the caller wants to set the VCard.
-spec set_vcard(HostType, UserJID, VCard) -> Result when
Expand Down
4 changes: 3 additions & 1 deletion test/mongoose_cleanup_SUITE.erl
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ auth_anonymous(_Config) ->
{U, S, R, JID, SID} = get_fake_session(),
ejabberd_auth_anonymous:start(HostType),
Info = #{auth_module => cyrsasl_anonymous},
ejabberd_auth_anonymous:register_connection(#{}, HostType, SID, JID, Info),
ejabberd_auth_anonymous:register_connection(#{},
#{sid => SID, jid => JID, info => Info},
#{host_type => HostType}),
true = ejabberd_auth_anonymous:does_user_exist(HostType, U, S),
mongoose_hooks:session_cleanup(S, new_acc(S), U, R, SID),
false = ejabberd_auth_anonymous:does_user_exist(HostType, U, S).
Expand Down