Use new ets_cache API in ejabberd_auth

This commit is contained in:
Evgeny Khramtsov 2019-06-30 17:15:43 +03:00
parent a2a061c1c8
commit 253ec13971
9 changed files with 98 additions and 95 deletions

View File

@ -20,7 +20,7 @@
{deps, [{lager, ".*", {git, "https://github.com/erlang-lager/lager", "3.6.10"}}, {deps, [{lager, ".*", {git, "https://github.com/erlang-lager/lager", "3.6.10"}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", "2887223"}}, {p1_utils, ".*", {git, "https://github.com/processone/p1_utils", "2887223"}},
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.19"}}}, {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", "8c4487c"}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.1.1"}}}, {fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.1.1"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.16"}}}, {stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.16"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", "7fd02f3a2f"}}, {fast_xml, ".*", {git, "https://github.com/processone/fast_xml", "7fd02f3a2f"}},

View File

@ -72,14 +72,16 @@
-callback reload(binary()) -> any(). -callback reload(binary()) -> any().
-callback plain_password_required(binary()) -> boolean(). -callback plain_password_required(binary()) -> boolean().
-callback store_type(binary()) -> plain | external | scram. -callback store_type(binary()) -> plain | external | scram.
-callback set_password(binary(), binary(), binary()) -> ok | {error, atom()}. -callback set_password(binary(), binary(), password()) ->
-callback remove_user(binary(), binary()) -> ok | {error, any()}. {ets_cache:tag(), {ok, password()} | {error, db_failure}}.
-callback user_exists(binary(), binary()) -> boolean() | {error, atom()}. -callback remove_user(binary(), binary()) -> ok | {error, db_failure | not_allowed}.
-callback check_password(binary(), binary(), binary(), binary()) -> boolean(). -callback user_exists(binary(), binary()) -> {ets_cache:tag(), boolean() | {error, db_failure}}.
-callback try_register(binary(), binary(), password()) -> ok | {error, atom()}. -callback check_password(binary(), binary(), binary(), binary()) -> {ets_cache:tag(), boolean()}.
-callback try_register(binary(), binary(), password()) ->
{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()}].
-callback count_users(binary(), opts()) -> number(). -callback count_users(binary(), opts()) -> number().
-callback get_password(binary(), binary()) -> {ok, password()} | error. -callback get_password(binary(), binary()) -> {ets_cache:tag(), {ok, password()} | error}.
-callback use_cache(binary()) -> boolean(). -callback use_cache(binary()) -> boolean().
-callback cache_nodes(binary()) -> boolean(). -callback cache_nodes(binary()) -> boolean().
@ -610,9 +612,6 @@ db_user_exists(User, Server, Mod) ->
cache_tab(Mod), {User, Server}, cache_tab(Mod), {User, Server},
fun() -> fun() ->
case Mod:user_exists(User, Server) of case Mod:user_exists(User, Server) of
true -> {ok, exists};
false -> error;
{error, _} = Err -> Err;
{CacheTag, true} -> {CacheTag, {ok, exists}}; {CacheTag, true} -> {CacheTag, {ok, exists}};
{CacheTag, false} -> {CacheTag, error}; {CacheTag, false} -> {CacheTag, error};
{_, {error, _}} = Err -> Err {_, {error, _}} = Err -> Err
@ -645,8 +644,6 @@ db_check_password(User, AuthzId, Server, ProvidedPassword,
fun() -> fun() ->
case Mod:check_password( case Mod:check_password(
User, AuthzId, Server, ProvidedPassword) of User, AuthzId, Server, ProvidedPassword) of
true -> {ok, ProvidedPassword};
false -> error;
{CacheTag, true} -> {CacheTag, {ok, ProvidedPassword}}; {CacheTag, true} -> {CacheTag, {ok, ProvidedPassword}};
{CacheTag, false} -> {CacheTag, error} {CacheTag, false} -> {CacheTag, error}
end end
@ -667,7 +664,7 @@ db_check_password(User, AuthzId, Server, ProvidedPassword,
db_remove_user(User, Server, Mod) -> db_remove_user(User, Server, Mod) ->
case erlang:function_exported(Mod, remove_user, 2) of case erlang:function_exported(Mod, remove_user, 2) of
true -> true ->
case ets_cache:untag(Mod:remove_user(User, Server)) of case Mod:remove_user(User, Server) of
ok -> ok ->
case use_cache(Mod, Server) of case use_cache(Mod, Server) of
true -> true ->
@ -686,7 +683,7 @@ db_remove_user(User, Server, Mod) ->
db_get_users(Server, Opts, Mod) -> db_get_users(Server, Opts, Mod) ->
case erlang:function_exported(Mod, get_users, 2) of case erlang:function_exported(Mod, get_users, 2) of
true -> true ->
ets_cache:untag(Mod:get_users(Server, Opts)); Mod:get_users(Server, Opts);
false -> false ->
case use_cache(Mod, Server) of case use_cache(Mod, Server) of
true -> true ->
@ -704,7 +701,7 @@ db_get_users(Server, Opts, Mod) ->
db_count_users(Server, Opts, Mod) -> db_count_users(Server, Opts, Mod) ->
case erlang:function_exported(Mod, count_users, 2) of case erlang:function_exported(Mod, count_users, 2) of
true -> true ->
ets_cache:untag(Mod:count_users(Server, Opts)); Mod:count_users(Server, Opts);
false -> false ->
case use_cache(Mod, Server) of case use_cache(Mod, Server) of
true -> true ->

View File

@ -148,16 +148,14 @@ unregister_connection(_SID,
%% Specific anonymous auth functions %% Specific anonymous auth functions
%% --------------------------------- %% ---------------------------------
check_password(User, _AuthzId, Server, _Password) -> check_password(User, _AuthzId, Server, _Password) ->
case {nocache,
ejabberd_auth:user_exists_in_other_modules(?MODULE, case ejabberd_auth:user_exists_in_other_modules(?MODULE, User, Server) of
User, Server) %% If user exists in other module, reject anonnymous authentication
of true -> false;
%% If user exists in other module, reject anonnymous authentication %% If we are not sure whether the user exists in other module, reject anon auth
true -> false; maybe -> false;
%% If we are not sure whether the user exists in other module, reject anon auth false -> login(User, Server)
maybe -> false; end}.
false -> login(User, Server)
end.
login(User, Server) -> login(User, Server) ->
case is_login_anonymous_enabled(Server) of case is_login_anonymous_enabled(Server) of
@ -180,7 +178,7 @@ count_users(Server, Opts) ->
length(get_users(Server, Opts)). length(get_users(Server, Opts)).
user_exists(User, Server) -> user_exists(User, Server) ->
anonymous_user_exist(User, Server). {nocache, anonymous_user_exist(User, Server)}.
plain_password_required(_) -> plain_password_required(_) ->
false. false.

View File

@ -53,27 +53,27 @@ store_type(_) -> external.
check_password(User, AuthzId, Server, Password) -> check_password(User, AuthzId, Server, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User -> if AuthzId /= <<>> andalso AuthzId /= User ->
false; {nocache, false};
true -> true ->
check_password_extauth(User, AuthzId, Server, Password) check_password_extauth(User, AuthzId, Server, Password)
end. end.
set_password(User, Server, Password) -> set_password(User, Server, Password) ->
case extauth:set_password(User, Server, Password) of case extauth:set_password(User, Server, Password) of
Res when is_boolean(Res) -> ok; Res when is_boolean(Res) -> {cache, {ok, Password}};
{error, Reason} -> failure(User, Server, set_password, Reason) {error, Reason} -> failure(User, Server, set_password, Reason)
end. end.
try_register(User, Server, Password) -> try_register(User, Server, Password) ->
case extauth:try_register(User, Server, Password) of case extauth:try_register(User, Server, Password) of
true -> ok; true -> {cache, {ok, Password}};
false -> {error, not_allowed}; false -> {cache, {error, not_allowed}};
{error, Reason} -> failure(User, Server, try_register, Reason) {error, Reason} -> failure(User, Server, try_register, Reason)
end. end.
user_exists(User, Server) -> user_exists(User, Server) ->
case extauth:user_exists(User, Server) of case extauth:user_exists(User, Server) of
Res when is_boolean(Res) -> Res; Res when is_boolean(Res) -> {cache, Res};
{error, Reason} -> failure(User, Server, user_exists, Reason) {error, Reason} -> failure(User, Server, user_exists, Reason)
end. end.
@ -81,23 +81,25 @@ remove_user(User, Server) ->
case extauth:remove_user(User, Server) of case extauth:remove_user(User, Server) of
false -> {error, not_allowed}; false -> {error, not_allowed};
true -> ok; true -> ok;
{error, Reason} -> failure(User, Server, remove_user, Reason) {error, Reason} ->
{_, Err} = failure(User, Server, remove_user, Reason),
Err
end. end.
check_password_extauth(User, _AuthzId, Server, Password) -> check_password_extauth(User, _AuthzId, Server, Password) ->
if Password /= <<"">> -> if Password /= <<"">> ->
case extauth:check_password(User, Server, Password) of case extauth:check_password(User, Server, Password) of
Res when is_boolean(Res) -> Res; Res when is_boolean(Res) -> {cache, Res};
{error, Reason} -> {error, Reason} ->
_ = failure(User, Server, check_password, Reason), {Tag, _} = failure(User, Server, check_password, Reason),
false {Tag, false}
end; end;
true -> true ->
false {nocache, false}
end. end.
-spec failure(binary(), binary(), atom(), any()) -> {error, db_failure}. -spec failure(binary(), binary(), atom(), any()) -> {nocache, {error, db_failure}}.
failure(User, Server, Fun, Reason) -> failure(User, Server, Fun, Reason) ->
?ERROR_MSG("External authentication program failed when calling " ?ERROR_MSG("External authentication program failed when calling "
"'~s' for ~s@~s: ~p", [Fun, User, Server, Reason]), "'~s' for ~s@~s: ~p", [Fun, User, Server, Reason]),
{error, db_failure}. {nocache, {error, db_failure}}.

View File

@ -111,26 +111,25 @@ store_type(_) -> external.
check_password(User, AuthzId, Server, Password) -> check_password(User, AuthzId, Server, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User -> if AuthzId /= <<>> andalso AuthzId /= User ->
false; {nocache, false};
Password == <<"">> ->
{nocache, false};
true -> true ->
if Password == <<"">> -> false; case catch check_password_ldap(User, Server, Password) of
true -> {'EXIT', _} -> {nocache, false};
case catch check_password_ldap(User, Server, Password) of Result -> {cache, Result}
{'EXIT', _} -> false;
Result -> Result
end
end end
end. end.
set_password(User, Server, Password) -> set_password(User, Server, Password) ->
{ok, State} = eldap_utils:get_state(Server, ?MODULE), {ok, State} = eldap_utils:get_state(Server, ?MODULE),
case find_user_dn(User, State) of case find_user_dn(User, State) of
false -> {error, notfound}; false -> {cache, {error, db_failure}};
DN -> DN ->
case eldap_pool:modify_passwd(State#state.eldap_id, DN, case eldap_pool:modify_passwd(State#state.eldap_id, DN,
Password) of Password) of
ok -> ok; ok -> {cache, {ok, Password}};
_Err -> {error, db_failure} _Err -> {nocache, {error, db_failure}}
end end
end. end.
@ -146,8 +145,8 @@ count_users(Server, Opts) ->
%% @spec (User, Server) -> true | false | {error, Error} %% @spec (User, Server) -> true | false | {error, Error}
user_exists(User, Server) -> user_exists(User, Server) ->
case catch user_exists_ldap(User, Server) of case catch user_exists_ldap(User, Server) of
{'EXIT', _Error} -> {error, db_failure}; {'EXIT', _Error} -> {nocache, {error, db_failure}};
Result -> Result Result -> {cache, Result}
end. end.
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------

View File

@ -93,10 +93,10 @@ set_password(User, Server, Password) ->
end, end,
case mnesia:transaction(F) of case mnesia:transaction(F) of
{atomic, ok} -> {atomic, ok} ->
ok; {cache, {ok, Password}};
{aborted, Reason} -> {aborted, Reason} ->
?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]), ?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]),
{error, db_failure} {nocache, {error, db_failure}}
end. end.
try_register(User, Server, Password) -> try_register(User, Server, Password) ->
@ -106,17 +106,17 @@ try_register(User, Server, Password) ->
[] -> [] ->
mnesia:write(#passwd{us = US, password = Password}), mnesia:write(#passwd{us = US, password = Password}),
mnesia:dirty_update_counter(reg_users_counter, Server, 1), mnesia:dirty_update_counter(reg_users_counter, Server, 1),
ok; {ok, Password};
[_] -> [_] ->
{error, exists} {error, exists}
end end
end, end,
case mnesia:transaction(F) of case mnesia:transaction(F) of
{atomic, Res} -> {atomic, Res} ->
Res; {cache, Res};
{aborted, Reason} -> {aborted, Reason} ->
?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]), ?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]),
{error, db_failure} {nocache, {error, db_failure}}
end. end.
get_users(Server, []) -> get_users(Server, []) ->
@ -181,9 +181,9 @@ count_users(Server, _) ->
get_password(User, Server) -> get_password(User, Server) ->
case mnesia:dirty_read(passwd, {User, Server}) of case mnesia:dirty_read(passwd, {User, Server}) of
[#passwd{password = Password}] -> [#passwd{password = Password}] ->
{ok, Password}; {cache, {ok, Password}};
_ -> _ ->
error {cache, error}
end. end.
remove_user(User, Server) -> remove_user(User, Server) ->

View File

@ -39,19 +39,18 @@ stop(_Host) ->
check_password(User, AuthzId, Host, Password) -> check_password(User, AuthzId, Host, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User -> if AuthzId /= <<>> andalso AuthzId /= User ->
false; false;
true -> true ->
Service = get_pam_service(Host), Service = get_pam_service(Host),
UserInfo = case get_pam_userinfotype(Host) of UserInfo = case get_pam_userinfotype(Host) of
username -> User; username -> User;
jid -> <<User/binary, "@", Host/binary>> jid -> <<User/binary, "@", Host/binary>>
end, end,
case catch epam:authenticate(Service, UserInfo, case catch epam:authenticate(Service, UserInfo, Password) of
Password) true -> {cache, true};
of false -> {cache, false};
true -> true; _ -> {nocache, false}
_ -> false end
end
end. end.
user_exists(User, Host) -> user_exists(User, Host) ->
@ -61,9 +60,9 @@ user_exists(User, Host) ->
jid -> <<User/binary, "@", Host/binary>> jid -> <<User/binary, "@", Host/binary>>
end, end,
case catch epam:acct_mgmt(Service, UserInfo) of case catch epam:acct_mgmt(Service, UserInfo) of
true -> true; true -> {cache, true};
false -> false; false -> {cache, false};
_Err -> {error, db_failure} _Err -> {nocache, {error, db_failure}}
end. end.
plain_password_required(_) -> true. plain_password_required(_) -> true.

View File

@ -56,21 +56,27 @@ passwd_schema() ->
{record_info(fields, passwd), #passwd{}}. {record_info(fields, passwd), #passwd{}}.
set_password(User, Server, Password) -> set_password(User, Server, Password) ->
ejabberd_riak:put(#passwd{us = {User, Server}, password = Password}, case ejabberd_riak:put(#passwd{us = {User, Server}, password = Password},
passwd_schema(), passwd_schema(),
[{'2i', [{<<"host">>, Server}]}]). [{'2i', [{<<"host">>, Server}]}]) of
ok -> {cache, {ok, Password}};
{error, _} -> {nocache, {error, db_failure}}
end.
try_register(User, Server, Password) -> try_register(User, Server, Password) ->
US = {User, Server}, US = {User, Server},
case ejabberd_riak:get(passwd, passwd_schema(), US) of case ejabberd_riak:get(passwd, passwd_schema(), US) of
{error, notfound} -> {error, notfound} ->
ejabberd_riak:put(#passwd{us = US, password = Password}, case ejabberd_riak:put(#passwd{us = US, password = Password},
passwd_schema(), passwd_schema(),
[{'2i', [{<<"host">>, Server}]}]); [{'2i', [{<<"host">>, Server}]}]) of
ok -> {cache, {ok, Password}};
{error, _} -> {nocache, {error, db_failure}}
end;
{ok, _} -> {ok, _} ->
{error, exists}; {cache, {error, exists}};
{error, _} = Err -> {error, _} ->
Err {nocache, {error, db_failure}}
end. end.
get_users(Server, _) -> get_users(Server, _) ->
@ -92,9 +98,11 @@ count_users(Server, _) ->
get_password(User, Server) -> get_password(User, Server) ->
case ejabberd_riak:get(passwd, passwd_schema(), {User, Server}) of case ejabberd_riak:get(passwd, passwd_schema(), {User, Server}) of
{ok, Password} -> {ok, Password} ->
{ok, Password}; {cache, {ok, Password}};
{error, notfound} ->
{cache, error};
{error, _} -> {error, _} ->
error {nocache, error}
end. end.
remove_user(User, Server) -> remove_user(User, Server) ->

View File

@ -68,9 +68,9 @@ set_password(User, Server, Password) ->
end, end,
case ejabberd_sql:sql_transaction(Server, F) of case ejabberd_sql:sql_transaction(Server, F) of
{atomic, _} -> {atomic, _} ->
ok; {cache, {ok, Password}};
{aborted, _} -> {aborted, _} ->
{error, db_failure} {nocache, {error, db_failure}}
end. end.
try_register(User, Server, Password) -> try_register(User, Server, Password) ->
@ -83,8 +83,8 @@ try_register(User, Server, Password) ->
add_user(Server, User, Password) add_user(Server, User, Password)
end, end,
case Res of case Res of
{updated, 1} -> ok; {updated, 1} -> {cache, {ok, Password}};
_ -> {error, exists} _ -> {nocache, {error, exists}}
end. end.
get_users(Server, Opts) -> get_users(Server, Opts) ->
@ -104,16 +104,16 @@ count_users(Server, Opts) ->
get_password(User, Server) -> get_password(User, Server) ->
case get_password_scram(Server, User) of case get_password_scram(Server, User) of
{selected, [{Password, <<>>, <<>>, 0}]} -> {selected, [{Password, <<>>, <<>>, 0}]} ->
{ok, Password}; {cache, {ok, Password}};
{selected, [{StoredKey, ServerKey, Salt, IterationCount}]} -> {selected, [{StoredKey, ServerKey, Salt, IterationCount}]} ->
{ok, #scram{storedkey = StoredKey, {cache, {ok, #scram{storedkey = StoredKey,
serverkey = ServerKey, serverkey = ServerKey,
salt = Salt, salt = Salt,
iterationcount = IterationCount}}; iterationcount = IterationCount}}};
{selected, []} -> {selected, []} ->
error; {cache, error};
_ -> _ ->
error {nocache, error}
end. end.
remove_user(User, Server) -> remove_user(User, Server) ->