./ct_report/coverage/ejabberd_auth.COVER.html

1 %%% File : ejabberd_auth.erl
2 %%% Author : Alexey Shchepin <alexey@process-one.net>
3 %%% Purpose : Authentification
4 %%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@process-one.net>
5 %%%
6 %%%
7 %%% ejabberd, Copyright (C) 2002-2011 ProcessOne
8 %%%
9 %%% This program is free software; you can redistribute it and/or
10 %%% modify it under the terms of the GNU General Public License as
11 %%% published by the Free Software Foundation; either version 2 of the
12 %%% License, or (at your option) any later version.
13 %%%
14 %%% This program is distributed in the hope that it will be useful,
15 %%% but WITHOUT ANY WARRANTY; without even the implied warranty of
16 %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 %%% General Public License for more details.
18 %%%
19 %%% You should have received a copy of the GNU General Public License
20 %%% along with this program; if not, write to the Free Software
21 %%% Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 %%%
23 %%%----------------------------------------------------------------------
24
25 -module(ejabberd_auth).
26 -author('alexey@process-one.net').
27
28 %% External exports
29 -export([start/0,
30 start/1,
31 stop/1,
32 authorize/1,
33 set_password/2,
34 check_password/2,
35 check_password/4,
36 try_register/2,
37 get_vh_registered_users/1,
38 get_vh_registered_users/2,
39 get_vh_registered_users_number/1,
40 get_vh_registered_users_number/2,
41 get_password_s/1,
42 get_passterm_with_authmodule/2,
43 does_user_exist/1,
44 does_user_exist/3,
45 does_stored_user_exist/2,
46 does_method_support/2,
47 remove_user/1,
48 supports_sasl_module/2,
49 entropy/1,
50 config_spec/1
51 ]).
52
53 -export([check_digest/4]).
54
55 -export([auth_modules/1,
56 auth_methods/1,
57 auth_modules_for_host_type/1,
58 methods_to_modules/1]).
59
60 %% Library functions for reuse in ejabberd_auth_* modules
61 -export([authorize_with_check_password/2]).
62
63 %% Hook handlers
64 -export([remove_domain/3]).
65 -export([on_does_user_exist/3]).
66
67 -ignore_xref([
68 auth_methods/1, auth_modules/1, check_password/4, get_vh_registered_users/2,
69 get_vh_registered_users_number/2, start/1, stop/1]).
70
71 -include("mongoose.hrl").
72 -include("jlib.hrl").
73
74 -export_type([authmodule/0,
75 passterm/0,
76 exist_type/0]).
77
78 -type authmodule() :: module().
79 -type passterm() :: binary() | mongoose_scram:scram_tuple() | mongoose_scram:scram_map().
80 -type exist_type() :: stored | with_anonymous.
81
82 %% Types defined below are used in call_auth_modules_*
83 -type mod_res() :: any().
84 -type host_type_mod_fun() :: fun((mongooseim:host_type(), authmodule()) -> mod_res()).
85 -type mod_fun() :: fun((authmodule()) -> mod_res()).
86 -type mod_fold_fun() :: fun((authmodule(), mod_res()) -> continue |
87 {continue, mod_res()} |
88 {stop, mod_res()}).
89 -type call_opts() :: #{default => mod_res(), op => map, metric => atom()}.
90
91 -define(METRIC(Name), [backends, auth, Name]).
92
93 %%%----------------------------------------------------------------------
94 %%% API
95 %%%----------------------------------------------------------------------
96 -spec start() -> 'ok'.
97 start() ->
98 15 lists:foreach(fun start/1, ?ALL_HOST_TYPES).
99
100 -spec start(HostType :: mongooseim:host_type()) -> 'ok'.
101 start(HostType) ->
102 66 ensure_metrics(HostType),
103 66 F = fun(Mod) -> mongoose_gen_auth:start(Mod, HostType) end,
104 66 call_auth_modules_for_host_type(HostType, F, #{op => map}),
105 66 gen_hook:add_handlers(hooks(HostType)),
106 66 ok.
107
108 -spec stop(HostType :: mongooseim:host_type()) -> 'ok'.
109 stop(HostType) ->
110
:-(
gen_hook:delete_handlers(hooks(HostType)),
111
:-(
F = fun(Mod) -> mongoose_gen_auth:stop(Mod, HostType) end,
112
:-(
call_auth_modules_for_host_type(HostType, F, #{op => map}),
113
:-(
ok.
114
115 -spec hooks(mongooseim:host_type()) -> gen_hook:hook_list().
116 hooks(HostType) ->
117 66 [
118 %% These hooks must run in between those of mod_cache_users
119 {does_user_exist, HostType, fun ?MODULE:on_does_user_exist/3, #{}, 50},
120 %% It is important that this handler happens _before_ all other modules
121 {remove_domain, HostType, fun ?MODULE:remove_domain/3, #{}, 10}
122 ].
123
124 -spec supports_sasl_module(mongooseim:host_type(), cyrsasl:sasl_module()) -> boolean().
125 supports_sasl_module(HostType, SASLModule) ->
126 25 F = fun(Mod) ->
127 25 case mongoose_gen_auth:supports_sasl_module(Mod, HostType, SASLModule) of
128 23 true -> {stop, true};
129 2 false -> continue
130 end
131 end,
132 25 call_auth_modules_for_host_type(HostType, F, #{default => false}).
133
134 -spec authorize(mongoose_credentials:t()) -> {ok, mongoose_credentials:t()}
135 | {error, not_authorized}.
136 authorize(Creds) ->
137 1 F = fun(Mod, {_CurResult, CurCreds}) ->
138 1 case mongoose_gen_auth:authorize(Mod, CurCreds) of
139 {ok, NewCreds} ->
140 1 {stop, {ok, mongoose_credentials:register(NewCreds, Mod, success)}};
141 Error ->
142
:-(
NewCreds = mongoose_credentials:register(CurCreds, Mod, {failure, Error}),
143
:-(
{continue, {not_authorized, NewCreds}}
144 end
145 end,
146 1 Opts = #{default => {not_authorized, Creds}, metric => authorize},
147 1 case call_auth_modules_with_creds(Creds, F, Opts) of
148 1 Res = {ok, _Creds} -> Res;
149
:-(
{not_authorized, _Creds} -> {error, not_authorized}
150 end.
151
152 %% @doc Check if at least one authentication method accepts the user and the password.
153 -spec check_password(JID :: jid:jid() | error, Password :: binary()) -> boolean().
154 check_password(error, _Password) ->
155
:-(
false;
156 check_password(#jid{luser = LUser, lserver = LServer}, Password) ->
157
:-(
F = fun(HostType, Mod) ->
158
:-(
case mongoose_gen_auth:check_password(Mod, HostType, LUser, LServer, Password) of
159
:-(
true -> {stop, true};
160
:-(
false -> continue
161 end
162 end,
163
:-(
Opts = #{default => false, metric => check_password},
164
:-(
call_auth_modules_for_domain(LServer, F, Opts).
165
166 %% @doc Check if at least one authentication method accepts the user and the password.
167 -spec check_password(JID :: jid:jid() | error,
168 Password :: binary(),
169 Digest :: binary(),
170 DigestGen :: fun((binary()) -> binary())) -> boolean().
171 check_password(error, _, _, _) ->
172
:-(
false;
173 check_password(#jid{luser = LUser, lserver = LServer}, Password, Digest, DigestGen) ->
174
:-(
F = fun(HostType, Mod) ->
175
:-(
case mongoose_gen_auth:check_password(Mod, HostType, LUser, LServer,
176 Password, Digest, DigestGen) of
177
:-(
true -> {stop, true};
178
:-(
false -> continue
179 end
180 end,
181
:-(
Opts = #{default => false, metric => check_password},
182
:-(
call_auth_modules_for_domain(LServer, F, Opts).
183
184 -spec check_digest(binary(), fun((binary()) -> binary()), binary(), binary()) -> boolean().
185 check_digest(<<>>, _, <<>>, _) ->
186
:-(
false; %% empty digest and password
187 check_digest(Digest, DigestGen, _Password, Passwd) ->
188
:-(
Digest == DigestGen(Passwd).
189
190 -spec set_password(jid:jid() | error, binary()) ->
191 ok | {error, empty_password | not_allowed | invalid_jid}.
192 set_password(_, <<"">>) ->
193
:-(
{error, empty_password};
194 set_password(error, _) ->
195
:-(
{error, invalid_jid};
196 set_password(#jid{luser = LUser, lserver = LServer}, Password) ->
197
:-(
F = fun(HostType, Mod) ->
198
:-(
case mongoose_gen_auth:set_password(Mod, HostType, LUser, LServer, Password) of
199
:-(
ok -> {stop, ok};
200
:-(
{error, Error} -> {continue, {error, Error}}
201 end
202 end,
203
:-(
Opts = #{default => {error, not_allowed}},
204
:-(
case ejabberd_auth:does_user_exist(jid:make_bare(LUser, LServer)) of
205 true ->
206
:-(
call_auth_modules_for_domain(LServer, F, Opts);
207 false ->
208
:-(
{error, not_allowed}
209 end.
210
211 -spec try_register(jid:jid() | error, binary()) ->
212 ok | {error, exists | not_allowed | invalid_jid | null_password | limit_per_domain_exceeded}.
213 try_register(_, <<>>) ->
214
:-(
{error, null_password};
215 try_register(#jid{luser = <<>>}, _) ->
216
:-(
{error, invalid_jid};
217 try_register(error, _) ->
218
:-(
{error, invalid_jid};
219 try_register(JID, Password) ->
220
:-(
Exists = does_user_exist(JID),
221
:-(
do_try_register_if_does_not_exist(Exists, JID, Password).
222
223 -spec do_try_register_if_does_not_exist(boolean(), jid:jid(), binary()) ->
224 ok | {error, exists | not_allowed | invalid_jid | null_password | limit_per_domain_exceeded}.
225 do_try_register_if_does_not_exist(true, _, _) ->
226
:-(
{error, exists};
227 do_try_register_if_does_not_exist(_, JID, Password) ->
228
:-(
{LUser, LServer} = jid:to_lus(JID),
229
:-(
F = fun(HostType, Mod) ->
230
:-(
case mongoose_gen_auth:try_register(Mod, HostType, LUser, LServer, Password) of
231 ok ->
232
:-(
mongoose_hooks:register_user(HostType, LServer, LUser),
233
:-(
{stop, ok};
234 {error, _Error} ->
235
:-(
continue
236 end
237 end,
238
:-(
Opts = #{default => {error, not_allowed}, metric => try_register},
239
:-(
case is_user_number_below_limit(LServer) of
240 true ->
241
:-(
call_auth_modules_for_domain(LServer, F, Opts);
242 false ->
243
:-(
{error, limit_per_domain_exceeded}
244 end.
245
246 %% @doc Registered users list do not include anonymous users logged
247 -spec get_vh_registered_users(Server :: jid:server()) -> [jid:simple_bare_jid()].
248 get_vh_registered_users(Server) ->
249
:-(
get_vh_registered_users(Server, []).
250
251 -spec get_vh_registered_users(Server :: jid:server(), Opts :: [any()]) ->
252 [jid:simple_bare_jid()].
253 get_vh_registered_users(Server, Opts) ->
254
:-(
LServer = jid:nameprep(Server),
255
:-(
do_get_vh_registered_users(LServer, Opts).
256
257 do_get_vh_registered_users(error, _) ->
258
:-(
[];
259 do_get_vh_registered_users(LServer, Opts) ->
260
:-(
F = fun(HostType, Mod) ->
261
:-(
mongoose_gen_auth:get_registered_users(Mod, HostType, LServer, Opts)
262 end,
263
:-(
lists:append(call_auth_modules_for_domain(LServer, F, #{default => [], op => map})).
264
265 -spec get_vh_registered_users_number(Server :: jid:server()) -> integer().
266 get_vh_registered_users_number(Server) ->
267
:-(
get_vh_registered_users_number(Server, []).
268
269 -spec get_vh_registered_users_number(Server :: jid:server(), Opts :: list()) -> integer().
270 get_vh_registered_users_number(Server, Opts) ->
271
:-(
LServer = jid:nameprep(Server),
272
:-(
do_get_vh_registered_users_number(LServer, Opts).
273
274 do_get_vh_registered_users_number(error, _) ->
275
:-(
0;
276 do_get_vh_registered_users_number(LServer, Opts) ->
277
:-(
F = fun(HostType, Mod) ->
278
:-(
mongoose_gen_auth:get_registered_users_number(Mod, HostType, LServer, Opts)
279 end,
280
:-(
lists:sum(call_auth_modules_for_domain(LServer, F, #{default => [], op => map})).
281
282 -spec get_password_s(JID :: jid:jid() | error) -> binary().
283 get_password_s(#jid{luser = LUser, lserver = LServer}) ->
284
:-(
F = fun(HostType, Mod) ->
285
:-(
case mongoose_gen_auth:get_password_s(Mod, HostType, LUser, LServer) of
286
:-(
<<>> -> continue;
287
:-(
Password when is_binary(Password) -> {stop, Password}
288 end
289 end,
290
:-(
call_auth_modules_for_domain(LServer, F, #{default => <<>>}).
291
292 %% @doc Get the password(like thing) of the user and the auth module.
293 -spec get_passterm_with_authmodule(mongooseim:host_type(), error | jid:jid()) ->
294 {passterm(), authmodule()} | false.
295 get_passterm_with_authmodule(HostType, #jid{luser = LUser, lserver = LServer}) ->
296
:-(
F = fun(Mod) ->
297
:-(
case mongoose_gen_auth:get_password(Mod, HostType, LUser, LServer) of
298
:-(
false -> continue;
299
:-(
PassTerm -> {stop, {PassTerm, Mod}}
300 end
301 end,
302
:-(
call_auth_modules_for_host_type(HostType, F, #{default => false}).
303
304 %% @doc Returns true if the user exists in the DB
305 %% or if an anonymous user is logged under the given name
306 %% Returns 'false' in case of an error
307 -spec does_user_exist(JID :: jid:jid() | error) -> boolean().
308 does_user_exist(#jid{luser = LUser, lserver = LServer}) ->
309
:-(
F = fun(HostType, Mod) -> does_user_exist_in_module(HostType, LUser, LServer, Mod) end,
310
:-(
case call_auth_modules_for_domain(LServer, F, #{default => false, metric => does_user_exist}) of
311
:-(
{error, _Error} -> false;
312
:-(
Result -> Result
313 end;
314 does_user_exist(error) ->
315
:-(
false.
316
317 %% Hook interface
318 -spec does_user_exist(mongooseim:host_type(), jid:jid(), exist_type()) -> boolean().
319 does_user_exist(HostType, Jid, RequestType) ->
320
:-(
mongoose_hooks:does_user_exist(HostType, Jid, RequestType).
321
322 %% @doc does_user_exist hook handler
323 %% Returns 'false' in case of an error
324 -spec on_does_user_exist(Acc, Params, Extra) -> {ok, Acc} when
325 Acc :: boolean(),
326 Params :: map(),
327 Extra :: map().
328 on_does_user_exist(false, #{jid := Jid, request_type := stored}, #{host_type := HostType}) ->
329
:-(
{ok, true =:= does_stored_user_exist(HostType, Jid)};
330 on_does_user_exist(false,
331 #{jid := #jid{luser = LUser, lserver = LServer}, request_type := with_anonymous},
332 #{host_type := HostType}) ->
333
:-(
F = fun(Mod) -> does_user_exist_in_module(HostType, LUser, LServer, Mod) end,
334
:-(
{ok, call_auth_modules_for_host_type(HostType, F, #{default => false, metric => does_user_exist})};
335 on_does_user_exist(Status, _, _) ->
336
:-(
{ok, Status}.
337
338 %% @doc Returns true if the user exists in the DB
339 %% In case of a backend error, it is propagated to the caller
340 -spec does_stored_user_exist(mongooseim:host_type(), jid:jid() | error) ->
341 boolean() | {error, any()}.
342 does_stored_user_exist(HostType, #jid{luser = LUser, lserver = LServer}) ->
343
:-(
F = fun(ejabberd_auth_anonymous) -> continue;
344
:-(
(Mod) -> does_user_exist_in_module(HostType, LUser, LServer, Mod)
345 end,
346
:-(
call_auth_modules_for_host_type(HostType, F, #{default => false, metric => does_user_exist});
347 does_stored_user_exist(_HostType, error) ->
348
:-(
false.
349
350 does_user_exist_in_module(HostType, LUser, LServer, Mod) ->
351
:-(
case mongoose_gen_auth:does_user_exist(Mod, HostType, LUser, LServer) of
352
:-(
true -> {stop, true};
353
:-(
false -> continue;
354 {error, Reason} = Error ->
355
:-(
?LOG_ERROR(#{what => does_user_exist_failed,
356 text => <<"The authentication module returned an error">>,
357 auth_module => Mod, reason => Reason,
358
:-(
user => LUser, server => LServer}),
359
:-(
{continue, Error}
360 end.
361
362 -spec does_method_support(AuthMethod :: atom(), Feature :: atom()) -> boolean().
363 does_method_support(AuthMethod, Feature) ->
364 24 Module = auth_method_to_module(AuthMethod),
365 24 lists:member(Feature, mongoose_gen_auth:supported_features(Module)).
366
367 %% @doc Remove user.
368 %% Note: it may return ok even if there was some problem removing the user.
369 -spec remove_user(JID :: jid:jid()) -> ok | {error, not_allowed | user_does_not_exist};
370 (error) -> error.
371
:-(
remove_user(error) -> error;
372 remove_user(#jid{luser = LUser, lserver = LServer}) ->
373
:-(
JID = jid:make_bare(LUser, LServer),
374
:-(
F = fun(HostType, Mod) ->
375
:-(
case mongoose_gen_auth:remove_user(Mod, HostType, LUser, LServer) of
376
:-(
ok -> {continue, {ok, HostType}};
377
:-(
{error, _Error} -> continue
378 end
379 end,
380
:-(
case ejabberd_auth:does_user_exist(JID) of
381 true ->
382
:-(
case call_auth_modules_for_domain(LServer, F, #{default => {error, not_allowed}}) of
383 {ok, HostType} ->
384
:-(
Acc = mongoose_acc:new(#{location => ?LOCATION,
385 host_type => HostType,
386 lserver => LServer,
387 element => undefined}),
388
:-(
mongoose_hooks:remove_user(Acc, LServer, LUser),
389
:-(
ok;
390 Error ->
391
:-(
?LOG_ERROR(#{what => backend_disallows_user_removal,
392 user => LUser, server => LServer,
393
:-(
reason => Error}),
394
:-(
Error
395 end;
396 false ->
397
:-(
{error, user_does_not_exist}
398 end.
399
400 %% @doc Calculate informational entropy.
401 -spec entropy(iolist()) -> float().
402 entropy(IOList) ->
403
:-(
case binary_to_list(iolist_to_binary(IOList)) of
404 "" ->
405
:-(
0.0;
406 InputList ->
407
:-(
Set = lists:foldl(
408 fun(IOContent, Acc) ->
409
:-(
get_type_information(IOContent, Acc)
410 end, [0, 0, 0, 0, 0], InputList),
411
:-(
length(InputList) * math:log(lists:sum(Set))/math:log(2)
412 end.
413
414 -spec config_spec(atom()) -> mongoose_config_spec:config_section().
415 config_spec(Method) ->
416 288 mongoose_gen_auth:config_spec(auth_method_to_module(Method)).
417
418 %%%----------------------------------------------------------------------
419 %%% Internal functions
420 %%%----------------------------------------------------------------------
421 %% Return the list of authenticated modules for a given domain
422 %% TODO: rework is_anonymous_user/1 at mongoose_users module,
423 %% so there is no need for exporting auth_modules/1 function.
424 %% after that completely get rid of this interface, we should
425 %% use auth_modules_for_host_type/1 function instead.
426 -spec auth_modules(Server :: jid:lserver()) -> [authmodule()].
427 auth_modules(LServer) ->
428
:-(
case mongoose_domain_api:get_domain_host_type(LServer) of
429
:-(
{ok, HostType} -> auth_modules_for_host_type(HostType);
430
:-(
{error, not_found} -> []
431 end.
432
433 %% Return the list of authenticated modules for a given host type
434 -spec auth_modules_for_host_type(HostType :: mongooseim:host_type()) -> [authmodule()].
435 auth_modules_for_host_type(HostType) ->
436 92 Methods = auth_methods(HostType),
437 92 methods_to_modules(Methods).
438
439 -spec methods_to_modules([atom()]) -> [authmodule()].
440 methods_to_modules(Methods) ->
441 92 [auth_method_to_module(M) || M <- Methods].
442
443 -spec auth_methods(mongooseim:host_type()) -> [atom()].
444 auth_methods(HostType) ->
445 92 mongoose_config:get_opt([{auth, HostType}, methods]).
446
447 -spec auth_method_to_module(atom()) -> authmodule().
448 auth_method_to_module(Method) ->
449 404 list_to_atom("ejabberd_auth_" ++ atom_to_list(Method)).
450
451 -spec remove_domain(mongoose_domain_api:remove_domain_acc(), map(), map()) ->
452 {ok | stop, mongoose_domain_api:remove_domain_acc()}.
453 remove_domain(Acc, #{domain := Domain}, #{host_type := HostType}) ->
454
:-(
F = fun() ->
455
:-(
FAuth = fun(Mod) -> mongoose_gen_auth:remove_domain(Mod, HostType, Domain) end,
456
:-(
call_auth_modules_for_host_type(HostType, FAuth, #{op => map}),
457
:-(
Acc
458 end,
459
:-(
mongoose_domain_api:remove_domain_wrapper(Acc, F, ?MODULE).
460
461 ensure_metrics(Host) ->
462 66 Metrics = [authorize, check_password, try_register, does_user_exist],
463 66 [mongoose_metrics:ensure_metric(Host, ?METRIC(Metric), histogram)
464 66 || Metric <- Metrics].
465
466 %% Library functions for reuse in ejabberd_auth_* modules
467 -spec authorize_with_check_password(Module, Creds) -> {ok, Creds}
468 | {error, any()} when
469 Module :: authmodule(),
470 Creds :: mongoose_credentials:t().
471 authorize_with_check_password(Module, Creds) ->
472 1 User = mongoose_credentials:get(Creds, username),
473 1 LUser = jid:nodeprep(User),
474 1 LUser == error andalso error({nodeprep_error, User}),
475 1 LServer = mongoose_credentials:lserver(Creds),
476 1 HostType = mongoose_credentials:host_type(Creds),
477 1 Password = mongoose_credentials:get(Creds, password),
478 1 Digest = mongoose_credentials:get(Creds, digest, undefined),
479 1 DigestGen = mongoose_credentials:get(Creds, digest_gen, undefined),
480 1 Result = case {Digest, DigestGen} of
481 _ when Digest /= undefined andalso DigestGen /= undefined ->
482
:-(
mongoose_gen_auth:check_password(Module, HostType, LUser, LServer,
483 Password, Digest, DigestGen);
484 _ ->
485 1 mongoose_gen_auth:check_password(Module, HostType, LUser, LServer, Password)
486 end,
487 1 case Result of
488 1 true -> {ok, mongoose_credentials:set(Creds, auth_module, Module)};
489
:-(
false -> {error, not_authorized}
490 end.
491
492 -spec get_type_information(integer(), list()) -> list().
493 get_type_information(IOContent, [Digit, Printable, _, HiLetter, Other])
494 when IOContent >= $a andalso IOContent =< $z ->
495
:-(
[Digit, Printable, 26, HiLetter, Other];
496 get_type_information(IOContent, [_, Printable, LowLetter, HiLetter, Other])
497 when IOContent >= $0 andalso IOContent =< $9 ->
498
:-(
[9, Printable, LowLetter, HiLetter, Other];
499 get_type_information(IOContent, [Digit, Printable, LowLetter, _, Other])
500 when IOContent >= $A andalso IOContent =< $Z ->
501
:-(
[Digit, Printable, LowLetter, 26, Other];
502 get_type_information(IOContent, [Digit, _, LowLetter, HiLetter, Other])
503 when IOContent >= 16#21 andalso IOContent =< 16#7e ->
504
:-(
[Digit, 33, LowLetter, HiLetter, Other];
505 get_type_information(_IOContent, [Digit, Printable, LowLetter, HiLetter, _Other]) ->
506
:-(
[Digit, Printable, LowLetter, HiLetter, 128].
507
508 %% @doc If the domain corresponds to a valid host type, call auth modules for that host type
509 -spec call_auth_modules_for_domain(jid:lserver(), host_type_mod_fun(), call_opts()) ->
510 mod_res() | [mod_res()].
511 call_auth_modules_for_domain(Domain, F, Opts = #{default := Default}) ->
512
:-(
case mongoose_domain_api:get_domain_host_type(Domain) of
513 {ok, HostType} ->
514
:-(
StepF = bind_host_type(HostType, F),
515
:-(
case maps:take(metric, Opts) of
516 {Metric, NewOpts} ->
517
:-(
{Time, Result} = timer:tc(fun call_auth_modules_for_host_type/3,
518 [HostType, StepF, NewOpts]),
519
:-(
mongoose_metrics:update(HostType, ?METRIC(Metric), Time),
520
:-(
Result;
521 error ->
522
:-(
call_auth_modules_for_host_type(HostType, StepF, Opts)
523 end;
524 {error, not_found} ->
525
:-(
Default
526 end.
527
528 -spec bind_host_type(mongooseim:host_type(), host_type_mod_fun()) -> mod_fun().
529 bind_host_type(HostType, F) when is_function(F, 2) ->
530
:-(
fun(Mod) -> F(HostType, Mod) end.
531
532 -spec call_auth_modules_for_host_type(mongooseim:host_type(),
533 mod_fun() | mod_fold_fun(), call_opts()) ->
534 mod_res() | [mod_res()].
535 call_auth_modules_for_host_type(HostType, F, Opts) ->
536 91 Modules = auth_modules_for_host_type(HostType),
537 91 case maps:take(metric, Opts) of
538 {Metric, NewOpts} ->
539
:-(
{Time, Result} = timer:tc(fun call_auth_modules/3, [Modules, F, NewOpts]),
540
:-(
mongoose_metrics:update(HostType, ?METRIC(Metric), Time),
541
:-(
Result;
542 error ->
543 91 call_auth_modules(Modules, F, Opts)
544 end.
545
546 -spec call_auth_modules_with_creds(mongoose_credentials:t(),
547 mod_fun() | mod_fold_fun(), call_opts()) ->
548 mod_res() | [mod_res()].
549 call_auth_modules_with_creds(Creds, F, Opts) ->
550 1 Modules = mongoose_credentials:auth_modules(Creds),
551 1 case maps:take(metric, Opts) of
552 {Metric, NewOpts} ->
553 1 HostType = mongoose_credentials:host_type(Creds),
554 1 {Time, Result} = timer:tc(fun call_auth_modules/3,
555 [Modules, F, NewOpts]),
556 1 mongoose_metrics:update(HostType, ?METRIC(Metric), Time),
557 1 Result;
558 error ->
559
:-(
call_auth_modules(Modules, F, Opts)
560 end.
561
562
563 %% @doc Perform a map or a fold operation with function F over the provided Modules
564 -spec call_auth_modules([authmodule()], mod_fun() | mod_fold_fun(), call_opts()) ->
565 mod_res() | [mod_res()].
566 call_auth_modules(Modules, F, #{op := map}) when is_function(F, 1) ->
567 66 lists:map(F, Modules);
568 call_auth_modules(Modules, F, Opts) when is_function(F, 1) ->
569 25 call_auth_modules(Modules, fun(Mod, _) -> F(Mod) end, Opts);
570 call_auth_modules(Modules, F, #{default := Default}) when is_function(F, 2) ->
571 26 fold_auth_modules(Modules, F, Default).
572
573 %% @doc Apply function F to all consecutive auth modules with an accumulator and a stop condition
574 -spec fold_auth_modules([authmodule()], mod_fold_fun(), mod_res()) -> mod_res().
575 fold_auth_modules([], _F, FinalAcc) ->
576 2 FinalAcc;
577 fold_auth_modules([AuthModule | AuthModules], F, CurAcc) ->
578 26 case F(AuthModule, CurAcc) of
579 continue ->
580 2 fold_auth_modules(AuthModules, F, CurAcc);
581 {continue, NewAcc} ->
582
:-(
fold_auth_modules(AuthModules, F, NewAcc);
583 {stop, Value} ->
584 24 Value
585 end.
586
587 is_user_number_below_limit(Domain) ->
588
:-(
case mongoose_domain_api:get_domain_host_type(Domain) of
589 {ok, HostType} ->
590
:-(
Limit = mongoose_config:get_opt([{auth, HostType}, max_users_per_domain]),
591
:-(
Current = get_vh_registered_users_number(Domain),
592
:-(
Current < Limit;
593 {error, not_found} ->
594
:-(
true
595 end.
Line Hits Source