./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([does_user_exist/4]).
66
67 -ignore_xref([
68 auth_methods/1, auth_modules/1, check_password/4, does_user_exist/4,
69 get_vh_registered_users/2, get_vh_registered_users_number/2,
70 remove_domain/3, start/1, stop/1]).
71
72 -include("mongoose.hrl").
73 -include("jlib.hrl").
74
75 -export_type([authmodule/0,
76 passterm/0,
77 exist_type/0]).
78
79 -type authmodule() :: module().
80 -type passterm() :: binary() | mongoose_scram:scram_tuple() | mongoose_scram:scram_map().
81 -type exist_type() :: stored | with_anonymous.
82
83 %% Types defined below are used in call_auth_modules_*
84 -type mod_res() :: any().
85 -type host_type_mod_fun() :: fun((mongooseim:host_type(), authmodule()) -> mod_res()).
86 -type mod_fun() :: fun((authmodule()) -> mod_res()).
87 -type mod_fold_fun() :: fun((authmodule(), mod_res()) -> continue |
88 {continue, mod_res()} |
89 {stop, mod_res()}).
90 -type call_opts() :: #{default => mod_res(), op => map, metric => atom()}.
91
92 -define(METRIC(Name), [backends, auth, Name]).
93
94 %%%----------------------------------------------------------------------
95 %%% API
96 %%%----------------------------------------------------------------------
97 -spec start() -> 'ok'.
98 start() ->
99 62 lists:foreach(fun start/1, ?ALL_HOST_TYPES).
100
101 -spec start(HostType :: mongooseim:host_type()) -> 'ok'.
102 start(HostType) ->
103 301 ensure_metrics(HostType),
104 301 F = fun(Mod) -> mongoose_gen_auth:start(Mod, HostType) end,
105 301 call_auth_modules_for_host_type(HostType, F, #{op => map}),
106 301 ejabberd_hooks:add(hooks(HostType)),
107 301 ok.
108
109 -spec stop(HostType :: mongooseim:host_type()) -> 'ok'.
110 stop(HostType) ->
111 1 ejabberd_hooks:delete(hooks(HostType)),
112 1 F = fun(Mod) -> mongoose_gen_auth:stop(Mod, HostType) end,
113 1 call_auth_modules_for_host_type(HostType, F, #{op => map}),
114 1 ok.
115
116 hooks(HostType) ->
117 302 [
118 %% These hooks must run in between those of mod_cache_users
119 {does_user_exist, HostType, ?MODULE, does_user_exist, 50},
120 %% It is important that this handler happens _before_ all other modules
121 {remove_domain, HostType, ?MODULE, remove_domain, 10}
122 ].
123
124 -spec supports_sasl_module(mongooseim:host_type(), cyrsasl:sasl_module()) -> boolean().
125 supports_sasl_module(HostType, SASLModule) ->
126 83220 F = fun(Mod) ->
127 83220 case mongoose_gen_auth:supports_sasl_module(Mod, HostType, SASLModule) of
128 26083 true -> {stop, true};
129 57137 false -> continue
130 end
131 end,
132 83220 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 3384 F = fun(Mod, {_CurResult, CurCreds}) ->
138 3384 case mongoose_gen_auth:authorize(Mod, CurCreds) of
139 {ok, NewCreds} ->
140 3375 {stop, {ok, mongoose_credentials:register(NewCreds, Mod, success)}};
141 Error ->
142 9 NewCreds = mongoose_credentials:register(CurCreds, Mod, {failure, Error}),
143 9 {continue, {not_authorized, NewCreds}}
144 end
145 end,
146 3384 Opts = #{default => {not_authorized, Creds}, metric => authorize},
147 3384 case call_auth_modules_with_creds(Creds, F, Opts) of
148 3375 Res = {ok, _Creds} -> Res;
149 9 {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 4 F = fun(HostType, Mod) ->
158 4 case mongoose_gen_auth:check_password(Mod, HostType, LUser, LServer, Password) of
159 2 true -> {stop, true};
160 2 false -> continue
161 end
162 end,
163 4 Opts = #{default => false, metric => check_password},
164 4 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 1 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 5 {error, empty_password};
194 set_password(error, _) ->
195 1 {error, invalid_jid};
196 set_password(#jid{luser = LUser, lserver = LServer}, Password) ->
197 13 F = fun(HostType, Mod) ->
198 11 case mongoose_gen_auth:set_password(Mod, HostType, LUser, LServer, Password) of
199 11 ok -> {stop, ok};
200
:-(
{error, Error} -> {continue, {error, Error}}
201 end
202 end,
203 13 Opts = #{default => {error, not_allowed}},
204 13 call_auth_modules_for_domain(LServer, F, Opts).
205
206 -spec try_register(jid:jid() | error, binary()) ->
207 ok | {error, exists | not_allowed | invalid_jid | null_password}.
208 try_register(_, <<"">>) ->
209 1 {error, null_password};
210 try_register(error, _) ->
211 1 {error, invalid_jid};
212 try_register(JID, Password) ->
213 2825 Exists = does_user_exist(JID),
214 2825 do_try_register_if_does_not_exist(Exists, JID, Password).
215
216 -spec do_try_register_if_does_not_exist(boolean(), jid:jid(), binary()) ->
217 ok | {error, exists | not_allowed | invalid_jid | null_password}.
218 do_try_register_if_does_not_exist(true, _, _) ->
219 12 {error, exists};
220 do_try_register_if_does_not_exist(_, JID, Password) ->
221 2813 {LUser, LServer} = jid:to_lus(JID),
222 2813 F = fun(HostType, Mod) ->
223 2813 case mongoose_gen_auth:try_register(Mod, HostType, LUser, LServer, Password) of
224 ok ->
225 2813 mongoose_hooks:register_user(HostType, LServer, LUser),
226 2813 {stop, ok};
227 {error, _Error} ->
228
:-(
continue
229 end
230 end,
231 2813 Opts = #{default => {error, not_allowed}, metric => try_register},
232 2813 call_auth_modules_for_domain(LServer, F, Opts).
233
234 %% @doc Registered users list do not include anonymous users logged
235 -spec get_vh_registered_users(Server :: jid:server()) -> [jid:simple_bare_jid()].
236 get_vh_registered_users(Server) ->
237 170 get_vh_registered_users(Server, []).
238
239 -spec get_vh_registered_users(Server :: jid:server(), Opts :: [any()]) ->
240 [jid:simple_bare_jid()].
241 get_vh_registered_users(Server, Opts) ->
242 175 LServer = jid:nameprep(Server),
243 175 do_get_vh_registered_users(LServer, Opts).
244
245 do_get_vh_registered_users(error, _) ->
246
:-(
[];
247 do_get_vh_registered_users(LServer, Opts) ->
248 175 F = fun(HostType, Mod) ->
249 174 mongoose_gen_auth:get_registered_users(Mod, HostType, LServer, Opts)
250 end,
251 175 lists:append(call_auth_modules_for_domain(LServer, F, #{default => [], op => map})).
252
253 -spec get_vh_registered_users_number(Server :: jid:server()) -> integer().
254 get_vh_registered_users_number(Server) ->
255 149 get_vh_registered_users_number(Server, []).
256
257 -spec get_vh_registered_users_number(Server :: jid:server(), Opts :: list()) -> integer().
258 get_vh_registered_users_number(Server, Opts) ->
259 150 LServer = jid:nameprep(Server),
260 150 do_get_vh_registered_users_number(LServer, Opts).
261
262 do_get_vh_registered_users_number(error, _) ->
263
:-(
0;
264 do_get_vh_registered_users_number(LServer, Opts) ->
265 150 F = fun(HostType, Mod) ->
266 149 mongoose_gen_auth:get_registered_users_number(Mod, HostType, LServer, Opts)
267 end,
268 150 lists:sum(call_auth_modules_for_domain(LServer, F, #{default => [], op => map})).
269
270 -spec get_password_s(JID :: jid:jid() | error) -> binary().
271 get_password_s(#jid{luser = LUser, lserver = LServer}) ->
272 8 F = fun(HostType, Mod) ->
273 7 case mongoose_gen_auth:get_password_s(Mod, HostType, LUser, LServer) of
274 1 <<>> -> continue;
275 6 Password when is_binary(Password) -> {stop, Password}
276 end
277 end,
278 8 call_auth_modules_for_domain(LServer, F, #{default => <<>>}).
279
280 %% @doc Get the password(like thing) of the user and the auth module.
281 -spec get_passterm_with_authmodule(mongooseim:host_type(), error | jid:jid()) ->
282 {passterm(), authmodule()} | false.
283 get_passterm_with_authmodule(HostType, #jid{luser = LUser, lserver = LServer}) ->
284 112 F = fun(Mod) ->
285 112 case mongoose_gen_auth:get_password(Mod, HostType, LUser, LServer) of
286 2 false -> continue;
287 110 PassTerm -> {stop, {PassTerm, Mod}}
288 end
289 end,
290 112 call_auth_modules_for_host_type(HostType, F, #{default => false}).
291
292 %% @doc Returns true if the user exists in the DB
293 %% or if an anonymous user is logged under the given name
294 %% Returns 'false' in case of an error
295 -spec does_user_exist(JID :: jid:jid() | error) -> boolean().
296 does_user_exist(#jid{luser = LUser, lserver = LServer}) ->
297 3505 F = fun(HostType, Mod) -> does_user_exist_in_module(HostType, LUser, LServer, Mod) end,
298 3505 case call_auth_modules_for_domain(LServer, F, #{default => false, metric => does_user_exist}) of
299
:-(
{error, _Error} -> false;
300 3505 Result -> Result
301 end;
302 does_user_exist(error) ->
303
:-(
false.
304
305 %% Hook interface
306 -spec does_user_exist(mongooseim:host_type(), jid:jid(), exist_type()) -> boolean().
307 does_user_exist(HostType, Jid, RequestType) ->
308 2703 mongoose_hooks:does_user_exist(HostType, Jid, RequestType).
309
310 %% @doc does_user_exist hook handler
311 %% Returns 'false' in case of an error
312 -spec does_user_exist(boolean(), mongooseim:host_type(), jid:jid(), exist_type()) -> boolean().
313 does_user_exist(false, HostType, Jid, stored) ->
314 605 true =:= does_stored_user_exist(HostType, Jid);
315 does_user_exist(false, HostType, #jid{luser = LUser, lserver = LServer}, with_anonymous) ->
316
:-(
F = fun(Mod) -> does_user_exist_in_module(HostType, LUser, LServer, Mod) end,
317
:-(
call_auth_modules_for_host_type(HostType, F, #{default => false, metric => does_user_exist});
318 does_user_exist(Status, _, _, _) ->
319
:-(
Status.
320
321 %% @doc Returns true if the user exists in the DB
322 %% In case of a backend error, it is propagated to the caller
323 -spec does_stored_user_exist(mongooseim:host_type(), jid:jid() | error) ->
324 boolean() | {error, any()}.
325 does_stored_user_exist(HostType, #jid{luser = LUser, lserver = LServer}) ->
326 605 F = fun(Mod) when Mod =/= ejabberd_auth_anonymous ->
327 605 does_user_exist_in_module(HostType, LUser, LServer, Mod)
328 end,
329 605 call_auth_modules_for_host_type(HostType, F, #{default => false, metric => does_user_exist});
330 does_stored_user_exist(_HostType, error) ->
331
:-(
false.
332
333 does_user_exist_in_module(HostType, LUser, LServer, Mod) ->
334 4088 case mongoose_gen_auth:does_user_exist(Mod, HostType, LUser, LServer) of
335 1027 true -> {stop, true};
336 3061 false -> continue;
337 {error, Reason} = Error ->
338
:-(
?LOG_ERROR(#{what => does_user_exist_failed,
339 text => <<"The authentication module returned an error">>,
340 auth_module => Mod, reason => Reason,
341
:-(
user => LUser, server => LServer}),
342
:-(
{continue, Error}
343 end.
344
345 -spec does_method_support(AuthMethod :: atom(), Feature :: atom()) -> boolean().
346 does_method_support(AuthMethod, Feature) ->
347 117 Module = auth_method_to_module(AuthMethod),
348 117 lists:member(Feature, mongoose_gen_auth:supported_features(Module)).
349
350 %% @doc Remove user.
351 %% Note: it may return ok even if there was some problem removing the user.
352 -spec remove_user(JID :: jid:jid()) -> ok | {error, not_allowed};
353 (error) -> error.
354 1 remove_user(error) -> error;
355 remove_user(#jid{luser = LUser, lserver = LServer}) ->
356 2871 F = fun(HostType, Mod) ->
357 2865 case mongoose_gen_auth:remove_user(Mod, HostType, LUser, LServer) of
358 2865 ok -> {continue, {ok, HostType}};
359
:-(
{error, _Error} -> continue
360 end
361 end,
362 2871 case call_auth_modules_for_domain(LServer, F, #{default => {error, not_allowed}}) of
363 {ok, HostType} ->
364 2865 Acc = mongoose_acc:new(#{ location => ?LOCATION,
365 host_type => HostType,
366 lserver => LServer,
367 element => undefined }),
368 2865 mongoose_hooks:remove_user(Acc, LServer, LUser),
369 2865 ok;
370 Error ->
371 6 ?LOG_ERROR(#{what => backend_disallows_user_removal,
372 user => LUser, server => LServer,
373
:-(
reason => Error}),
374 6 Error
375 end.
376
377 %% @doc Calculate informational entropy.
378 -spec entropy(iolist()) -> float().
379 entropy(IOList) ->
380
:-(
case binary_to_list(iolist_to_binary(IOList)) of
381 "" ->
382
:-(
0.0;
383 InputList ->
384
:-(
Set = lists:foldl(
385 fun(IOContent, Acc) ->
386
:-(
get_type_information(IOContent, Acc)
387 end, [0, 0, 0, 0, 0], InputList),
388
:-(
length(InputList) * math:log(lists:sum(Set))/math:log(2)
389 end.
390
391 -spec config_spec(atom()) -> mongoose_config_spec:config_section().
392 config_spec(Method) ->
393 1240 mongoose_gen_auth:config_spec(auth_method_to_module(Method)).
394
395 %%%----------------------------------------------------------------------
396 %%% Internal functions
397 %%%----------------------------------------------------------------------
398 %% Return the list of authenticated modules for a given domain
399 %% TODO: rework is_anonymous_user/1 at mongoose_users module,
400 %% so there is no need for exporting auth_modules/1 function.
401 %% after that completely get rid of this interface, we should
402 %% use auth_modules_for_host_type/1 function instead.
403 -spec auth_modules(Server :: jid:lserver()) -> [authmodule()].
404 auth_modules(LServer) ->
405 15 case mongoose_domain_api:get_domain_host_type(LServer) of
406 15 {ok, HostType} -> auth_modules_for_host_type(HostType);
407
:-(
{error, not_found} -> []
408 end.
409
410 %% Return the list of authenticated modules for a given host type
411 -spec auth_modules_for_host_type(HostType :: mongooseim:host_type()) -> [authmodule()].
412 auth_modules_for_host_type(HostType) ->
413 97523 Methods = auth_methods(HostType),
414 97523 methods_to_modules(Methods).
415
416 -spec methods_to_modules([atom()]) -> [authmodule()].
417 methods_to_modules(Methods) ->
418 97523 [auth_method_to_module(M) || M <- Methods].
419
420 -spec auth_methods(mongooseim:host_type()) -> [atom()].
421 auth_methods(HostType) ->
422 97523 mongoose_config:get_opt([{auth, HostType}, methods]).
423
424 -spec auth_method_to_module(atom()) -> authmodule().
425 auth_method_to_module(Method) ->
426 98880 list_to_atom("ejabberd_auth_" ++ atom_to_list(Method)).
427
428 -spec remove_domain(mongoose_hooks:simple_acc(), mongooseim:host_type(), jid:lserver()) ->
429 mongoose_hooks:simple_acc().
430 remove_domain(Acc, HostType, Domain) ->
431
:-(
F = fun(Mod) -> mongoose_gen_auth:remove_domain(Mod, HostType, Domain) end,
432
:-(
call_auth_modules_for_host_type(HostType, F, #{op => map}),
433
:-(
Acc.
434
435 ensure_metrics(Host) ->
436 301 Metrics = [authorize, check_password, try_register, does_user_exist],
437 301 [mongoose_metrics:ensure_metric(Host, ?METRIC(Metric), histogram)
438 301 || Metric <- Metrics].
439
440 %% Library functions for reuse in ejabberd_auth_* modules
441 -spec authorize_with_check_password(Module, Creds) -> {ok, Creds}
442 | {error, any()} when
443 Module :: authmodule(),
444 Creds :: mongoose_credentials:t().
445 authorize_with_check_password(Module, Creds) ->
446 3381 User = mongoose_credentials:get(Creds, username),
447 3381 LUser = jid:nodeprep(User),
448 3381 LUser == error andalso error({nodeprep_error, User}),
449 3381 LServer = mongoose_credentials:lserver(Creds),
450 3381 HostType = mongoose_credentials:host_type(Creds),
451 3381 Password = mongoose_credentials:get(Creds, password),
452 3381 Digest = mongoose_credentials:get(Creds, digest, undefined),
453 3381 DigestGen = mongoose_credentials:get(Creds, digest_gen, undefined),
454 3381 Result = case {Digest, DigestGen} of
455 _ when Digest /= undefined andalso DigestGen /= undefined ->
456 1 mongoose_gen_auth:check_password(Module, HostType, LUser, LServer,
457 Password, Digest, DigestGen);
458 _ ->
459 3380 mongoose_gen_auth:check_password(Module, HostType, LUser, LServer, Password)
460 end,
461 3381 case Result of
462 3372 true -> {ok, mongoose_credentials:set(Creds, auth_module, Module)};
463 9 false -> {error, not_authorized}
464 end.
465
466 -spec get_type_information(integer(), list()) -> list().
467 get_type_information(IOContent, [Digit, Printable, _, HiLetter, Other])
468 when IOContent >= $a andalso IOContent =< $z ->
469
:-(
[Digit, Printable, 26, HiLetter, Other];
470 get_type_information(IOContent, [_, Printable, LowLetter, HiLetter, Other])
471 when IOContent >= $0 andalso IOContent =< $9 ->
472
:-(
[9, Printable, LowLetter, HiLetter, Other];
473 get_type_information(IOContent, [Digit, Printable, LowLetter, _, Other])
474 when IOContent >= $A andalso IOContent =< $Z ->
475
:-(
[Digit, Printable, LowLetter, 26, Other];
476 get_type_information(IOContent, [Digit, _, LowLetter, HiLetter, Other])
477 when IOContent >= 16#21 andalso IOContent =< 16#7e ->
478
:-(
[Digit, 33, LowLetter, HiLetter, Other];
479 get_type_information(_IOContent, [Digit, Printable, LowLetter, HiLetter, _Other]) ->
480
:-(
[Digit, Printable, LowLetter, HiLetter, 128].
481
482 %% @doc If the domain corresponds to a valid host type, call auth modules for that host type
483 -spec call_auth_modules_for_domain(jid:lserver(), host_type_mod_fun(), call_opts()) ->
484 mod_res() | [mod_res()].
485 call_auth_modules_for_domain(Domain, F, Opts = #{default := Default}) ->
486 9539 case mongoose_domain_api:get_domain_host_type(Domain) of
487 {ok, HostType} ->
488 9506 StepF = bind_host_type(HostType, F),
489 9506 case maps:take(metric, Opts) of
490 {Metric, NewOpts} ->
491 6300 {Time, Result} = timer:tc(fun call_auth_modules_for_host_type/3,
492 [HostType, StepF, NewOpts]),
493 6300 mongoose_metrics:update(HostType, ?METRIC(Metric), Time),
494 6300 Result;
495 error ->
496 3206 call_auth_modules_for_host_type(HostType, StepF, Opts)
497 end;
498 {error, not_found} ->
499 33 Default
500 end.
501
502 -spec bind_host_type(mongooseim:host_type(), host_type_mod_fun()) -> mod_fun().
503 bind_host_type(HostType, F) when is_function(F, 2) ->
504 9506 fun(Mod) -> F(HostType, Mod) end.
505
506 -spec call_auth_modules_for_host_type(mongooseim:host_type(),
507 mod_fun() | mod_fold_fun(), call_opts()) ->
508 mod_res() | [mod_res()].
509 call_auth_modules_for_host_type(HostType, F, Opts) ->
510 93745 Modules = auth_modules_for_host_type(HostType),
511 93745 case maps:take(metric, Opts) of
512 {Metric, NewOpts} ->
513 605 {Time, Result} = timer:tc(fun call_auth_modules/3, [Modules, F, NewOpts]),
514 605 mongoose_metrics:update(HostType, ?METRIC(Metric), Time),
515 605 Result;
516 error ->
517 93140 call_auth_modules(Modules, F, Opts)
518 end.
519
520 -spec call_auth_modules_with_creds(mongoose_credentials:t(),
521 mod_fun() | mod_fold_fun(), call_opts()) ->
522 mod_res() | [mod_res()].
523 call_auth_modules_with_creds(Creds, F, Opts) ->
524 3384 Modules = mongoose_credentials:auth_modules(Creds),
525 3384 case maps:take(metric, Opts) of
526 {Metric, NewOpts} ->
527 3384 HostType = mongoose_credentials:host_type(Creds),
528 3384 {Time, Result} = timer:tc(fun call_auth_modules/3,
529 [Modules, F, NewOpts]),
530 3384 mongoose_metrics:update(HostType, ?METRIC(Metric), Time),
531 3384 Result;
532 error ->
533
:-(
call_auth_modules(Modules, F, Opts)
534 end.
535
536
537 %% @doc Perform a map or a fold operation with function F over the provided Modules
538 -spec call_auth_modules([authmodule()], mod_fun() | mod_fold_fun(), call_opts()) ->
539 mod_res() | [mod_res()].
540 call_auth_modules(Modules, F, #{op := map}) when is_function(F, 1) ->
541 625 lists:map(F, Modules);
542 call_auth_modules(Modules, F, Opts) when is_function(F, 1) ->
543 93120 call_auth_modules(Modules, fun(Mod, _) -> F(Mod) end, Opts);
544 call_auth_modules(Modules, F, #{default := Default}) when is_function(F, 2) ->
545 96504 fold_auth_modules(Modules, F, Default).
546
547 %% @doc Apply function F to all consecutive auth modules with an accumulator and a stop condition
548 -spec fold_auth_modules([authmodule()], mod_fold_fun(), mod_res()) -> mod_res().
549 fold_auth_modules([], _F, FinalAcc) ->
550 63077 FinalAcc;
551 fold_auth_modules([AuthModule | AuthModules], F, CurAcc) ->
552 96504 case F(AuthModule, CurAcc) of
553 continue ->
554 60203 fold_auth_modules(AuthModules, F, CurAcc);
555 {continue, NewAcc} ->
556 2874 fold_auth_modules(AuthModules, F, NewAcc);
557 {stop, Value} ->
558 33427 Value
559 end.
Line Hits Source