aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rebar.config2
-rw-r--r--src/cyrsasl_scram.erl6
-rw-r--r--src/ejabberd_admin.erl6
-rw-r--r--src/ejabberd_auth.erl862
-rw-r--r--src/ejabberd_auth_anonymous.erl86
-rw-r--r--src/ejabberd_auth_external.erl263
-rw-r--r--src/ejabberd_auth_ldap.erl64
-rw-r--r--src/ejabberd_auth_mnesia.erl453
-rw-r--r--src/ejabberd_auth_pam.erl47
-rw-r--r--src/ejabberd_auth_riak.erl264
-rw-r--r--src/ejabberd_auth_sql.erl448
-rw-r--r--src/ejabberd_piefxis.erl6
-rw-r--r--src/ejabberd_web_admin.erl10
-rw-r--r--src/extauth.erl2
-rw-r--r--src/mod_admin_extra.erl10
-rw-r--r--src/mod_announce.erl4
-rw-r--r--src/mod_configure.erl6
-rw-r--r--src/mod_register.erl4
-rw-r--r--src/mod_register_web.erl4
-rw-r--r--src/mod_shared_roster.erl4
-rw-r--r--src/mod_stats.erl4
-rw-r--r--src/prosody2ejabberd.erl2
-rw-r--r--test/suite.erl3
23 files changed, 900 insertions, 1660 deletions
diff --git a/rebar.config b/rebar.config
index b553931e6..7def98c79 100644
--- a/rebar.config
+++ b/rebar.config
@@ -20,7 +20,7 @@
{deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.2.1"}}},
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", "470539a"}},
- {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", "f31d039"}},
+ {cache_tab, ".*", {git, "https://github.com/processone/cache_tab", "51eee22"}},
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.11"}}},
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.8"}}},
{fast_xml, ".*", {git, "https://github.com/processone/fast_xml", {tag, "1.1.21"}}},
diff --git a/src/cyrsasl_scram.erl b/src/cyrsasl_scram.erl
index 8cbc821c7..b496be0a4 100644
--- a/src/cyrsasl_scram.erl
+++ b/src/cyrsasl_scram.erl
@@ -111,7 +111,11 @@ mech_step(#state{step = 2} = State, ClientIn) ->
{error, saslprep_failed, UserName};
true ->
{StoredKey, ServerKey, Salt, IterationCount} =
- if is_tuple(Pass) -> Pass;
+ if is_record(Pass, scram) ->
+ {misc:decode_base64(Pass#scram.storedkey),
+ misc:decode_base64(Pass#scram.serverkey),
+ misc:decode_base64(Pass#scram.salt),
+ Pass#scram.iterationcount};
true ->
TempSalt =
randoms:bytes(?SALT_LENGTH),
diff --git a/src/ejabberd_admin.erl b/src/ejabberd_admin.erl
index a615b2fee..c0429fb0c 100644
--- a/src/ejabberd_admin.erl
+++ b/src/ejabberd_admin.erl
@@ -478,9 +478,9 @@ update_module(ModuleNameString) ->
register(User, Host, Password) ->
case ejabberd_auth:try_register(User, Host, Password) of
- {atomic, ok} ->
+ ok ->
{ok, io_lib:format("User ~s@~s successfully registered", [User, Host])};
- {atomic, exists} ->
+ {error, exists} ->
Msg = io_lib:format("User ~s@~s already registered", [User, Host]),
{error, conflict, 10090, Msg};
{error, Reason} ->
@@ -494,7 +494,7 @@ unregister(User, Host) ->
{ok, ""}.
registered_users(Host) ->
- Users = ejabberd_auth:get_vh_registered_users(Host),
+ Users = ejabberd_auth:get_users(Host),
SUsers = lists:sort(Users),
lists:map(fun({U, _S}) -> U end, SUsers).
diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl
index 9751142a5..23ed0eeae 100644
--- a/src/ejabberd_auth.erl
+++ b/src/ejabberd_auth.erl
@@ -22,9 +22,6 @@
%%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
%%%
%%%----------------------------------------------------------------------
-
-%% TODO: Use the functions in ejabberd auth to add and remove users.
-
-module(ejabberd_auth).
-behaviour(gen_server).
@@ -37,10 +34,10 @@
set_password/3, check_password/4,
check_password/6, check_password_with_authmodule/4,
check_password_with_authmodule/6, try_register/3,
- dirty_get_registered_users/0, get_vh_registered_users/1,
- get_vh_registered_users/2, export/1, import_info/0,
- get_vh_registered_users_number/1, import/5, import_start/2,
- get_vh_registered_users_number/2, get_password/2,
+ get_users/0, get_users/1, password_to_scram/1,
+ get_users/2, export/1, import_info/0,
+ count_users/1, import/5, import_start/2,
+ count_users/2, get_password/2,
get_password_s/2, get_password_with_authmodule/2,
is_user_exists/2, is_user_exists_in_other_modules/3,
remove_user/2, remove_user/3, plain_password_required/1,
@@ -54,10 +51,13 @@
-include("ejabberd.hrl").
-include("logger.hrl").
+-define(AUTH_CACHE, auth_cache).
+-define(SALT_LENGTH, 16).
+
-record(state, {host_modules = #{} :: map()}).
--type scrammed_password() :: {binary(), binary(), binary(), non_neg_integer()}.
--type password() :: binary() | scrammed_password().
+-type password() :: binary() | #scram{}.
+-type digest_fun() :: fun((binary()) -> binary()).
-export_type([password/0]).
%%%----------------------------------------------------------------------
@@ -69,24 +69,29 @@
-callback start(binary()) -> any().
-callback stop(binary()) -> any().
--callback plain_password_required() -> boolean().
--callback store_type() -> plain | external | scram.
+-callback plain_password_required(binary()) -> boolean().
+-callback store_type(binary()) -> plain | external | scram.
-callback set_password(binary(), binary(), binary()) -> ok | {error, atom()}.
--callback remove_user(binary(), binary()) -> any().
--callback remove_user(binary(), binary(), binary()) -> any().
+-callback remove_user(binary(), binary()) -> ok | {error, any()}.
-callback is_user_exists(binary(), binary()) -> boolean() | {error, atom()}.
-callback check_password(binary(), binary(), binary(), binary()) -> boolean().
--callback check_password(binary(), binary(), binary(), binary(), binary(),
- fun((binary()) -> binary())) -> boolean().
--callback try_register(binary(), binary(), binary()) -> {atomic, atom()} |
- {error, atom()}.
--callback dirty_get_registered_users() -> [{binary(), binary()}].
--callback get_vh_registered_users(binary()) -> [{binary(), binary()}].
--callback get_vh_registered_users(binary(), opts()) -> [{binary(), binary()}].
--callback get_vh_registered_users_number(binary()) -> number().
--callback get_vh_registered_users_number(binary(), opts()) -> number().
--callback get_password(binary(), binary()) -> false | password().
--callback get_password_s(binary(), binary()) -> password().
+-callback try_register(binary(), binary(), password()) -> ok | {error, atom()}.
+-callback get_users(binary(), opts()) -> [{binary(), binary()}].
+-callback count_users(binary(), opts()) -> number().
+-callback get_password(binary(), binary()) -> {ok, password()} | error.
+-callback use_cache(binary()) -> boolean().
+-callback cache_nodes(binary()) -> boolean().
+
+-optional_callbacks([set_password/3,
+ remove_user/2,
+ is_user_exists/2,
+ check_password/4,
+ try_register/3,
+ get_users/2,
+ count_users/2,
+ get_password/2,
+ use_cache/1,
+ cache_nodes/1]).
-spec start_link() -> {ok, pid()} | {error, any()}.
start_link() ->
@@ -99,9 +104,13 @@ init([]) ->
HostModules = lists:foldl(
fun(Host, Acc) ->
Modules = auth_modules(Host),
- start(Host, Modules),
maps:put(Host, Modules, Acc)
end, #{}, ?MYHOSTS),
+ lists:foreach(
+ fun({Host, Modules}) ->
+ start(Host, Modules)
+ end, maps:to_list(HostModules)),
+ init_cache(HostModules),
{ok, #state{host_modules = HostModules}}.
handle_call(_Request, _From, State) ->
@@ -112,11 +121,13 @@ handle_cast({host_up, Host}, #state{host_modules = HostModules} = State) ->
Modules = auth_modules(Host),
start(Host, Modules),
NewHostModules = maps:put(Host, Modules, HostModules),
+ init_cache(NewHostModules),
{noreply, State#state{host_modules = NewHostModules}};
handle_cast({host_down, Host}, #state{host_modules = HostModules} = State) ->
Modules = maps:get(Host, HostModules, []),
stop(Host, Modules),
NewHostModules = maps:remove(Host, HostModules),
+ init_cache(NewHostModules),
{noreply, State#state{host_modules = NewHostModules}};
handle_cast(config_reloaded, #state{host_modules = HostModules} = State) ->
NewHostModules = lists:foldl(
@@ -127,6 +138,7 @@ handle_cast(config_reloaded, #state{host_modules = HostModules} = State) ->
stop(Host, OldModules -- NewModules),
maps:put(Host, NewModules, Acc)
end, HostModules, ?MYHOSTS),
+ init_cache(NewHostModules),
{noreply, State#state{host_modules = NewHostModules}};
handle_cast(Msg, State) ->
?WARNING_MSG("unexpected cast: ~p", [Msg]),
@@ -162,306 +174,266 @@ host_down(Host) ->
config_reloaded() ->
gen_server:cast(?MODULE, config_reloaded).
+-spec plain_password_required(binary()) -> boolean().
plain_password_required(Server) ->
- lists:any(fun (M) -> M:plain_password_required() end,
+ lists:any(fun (M) -> M:plain_password_required(Server) end,
auth_modules(Server)).
+-spec store_type(binary()) -> plain | scram | external.
store_type(Server) ->
-%% @doc Check if the user and password can login in server.
-%% @spec (User::string(), Server::string(), Password::string()) ->
-%% true | false
- lists:foldl(fun (_, external) -> external;
- (M, scram) ->
- case M:store_type() of
- external -> external;
- _Else -> scram
- end;
- (M, plain) -> M:store_type()
- end,
- plain, auth_modules(Server)).
+ lists:foldl(
+ fun(_, external) -> external;
+ (M, scram) ->
+ case M:store_type(Server) of
+ external -> external;
+ _ -> scram
+ end;
+ (M, plain) ->
+ M:store_type(Server)
+ end, plain, auth_modules(Server)).
-spec check_password(binary(), binary(), binary(), binary()) -> boolean().
-
check_password(User, AuthzId, Server, Password) ->
- case check_password_with_authmodule(User, AuthzId, Server,
- Password)
- of
- {true, _AuthModule} -> true;
- false -> false
- end.
+ check_password(User, AuthzId, Server, Password, <<"">>, undefined).
-%% @doc Check if the user and password can login in server.
-%% @spec (User::string(), AuthzId::string(), Server::string(), Password::string(),
-%% Digest::string(), DigestGen::function()) ->
-%% true | false
-spec check_password(binary(), binary(), binary(), binary(), binary(),
- fun((binary()) -> binary())) -> boolean().
-
-check_password(User, AuthzId, Server, Password, Digest,
- DigestGen) ->
- case check_password_with_authmodule(User, AuthzId, Server,
- Password, Digest, DigestGen)
- of
- {true, _AuthModule} -> true;
- false -> false
+ digest_fun() | undefined) -> boolean().
+check_password(User, AuthzId, Server, Password, Digest, DigestGen) ->
+ case check_password_with_authmodule(
+ User, AuthzId, Server, Password, Digest, DigestGen) of
+ {true, _AuthModule} -> true;
+ false -> false
end.
-%% @doc Check if the user and password can login in server.
-%% The user can login if at least an authentication method accepts the user
-%% and the password.
-%% The first authentication method that accepts the credentials is returned.
-%% @spec (User::string(), AuthzId::string(), Server::string(), Password::string()) ->
-%% {true, AuthModule} | false
-%% where
-%% AuthModule = ejabberd_auth_anonymous | ejabberd_auth_external
-%% | ejabberd_auth_mnesia | ejabberd_auth_ldap
-%% | ejabberd_auth_sql | ejabberd_auth_pam | ejabberd_auth_riak
--spec check_password_with_authmodule(binary(), binary(), binary(), binary()) -> false |
- {true, atom()}.
-
-check_password_with_authmodule(User, AuthzId, Server,
- Password) ->
- check_password_loop(auth_modules(Server),
- [User, AuthzId, Server, Password]).
-
--spec check_password_with_authmodule(binary(), binary(), binary(), binary(), binary(),
- fun((binary()) -> binary())) -> false |
- {true, atom()}.
-
-check_password_with_authmodule(User, AuthzId, Server, Password,
- Digest, DigestGen) ->
- check_password_loop(auth_modules(Server),
- [User, AuthzId, Server, Password, Digest, DigestGen]).
-
-check_password_loop([], _Args) -> false;
-check_password_loop([AuthModule | AuthModules], Args) ->
- case apply(AuthModule, check_password, Args) of
- true -> {true, AuthModule};
- false -> check_password_loop(AuthModules, Args)
+-spec check_password_with_authmodule(binary(), binary(),
+ binary(), binary()) -> false | {true, atom()}.
+check_password_with_authmodule(User, AuthzId, Server, Password) ->
+ check_password_with_authmodule(
+ User, AuthzId, Server, Password, <<"">>, undefined).
+
+-spec check_password_with_authmodule(
+ binary(), binary(), binary(), binary(), binary(),
+ digest_fun() | undefined) -> false | {true, atom()}.
+check_password_with_authmodule(User, AuthzId, Server, Password, Digest, DigestGen) ->
+ case validate_credentials(User, Server) of
+ {ok, LUser, LServer} ->
+ lists:foldl(
+ fun(Mod, false) ->
+ case db_check_password(
+ LUser, AuthzId, LServer, Password,
+ Digest, DigestGen, Mod) of
+ true -> {true, Mod};
+ false -> false
+ end;
+ (_, Acc) ->
+ Acc
+ end, false, auth_modules(LServer));
+ _ ->
+ false
end.
--spec set_password(binary(), binary(), binary()) -> ok |
- {error, atom()}.
-
-%% @spec (User::string(), Server::string(), Password::string()) ->
-%% ok | {error, ErrorType}
-%% where ErrorType = empty_password | not_allowed | invalid_jid
-set_password(_User, _Server, <<"">>) ->
- {error, empty_password};
+-spec set_password(binary(), binary(), password()) -> ok | {error, atom()}.
set_password(User, Server, Password) ->
-%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, not_allowed}
- lists:foldl(fun (M, {error, _}) ->
- M:set_password(User, Server, Password);
- (_M, Res) -> Res
- end,
- {error, not_allowed}, auth_modules(Server)).
-
--spec try_register(binary(), binary(), binary()) -> {atomic, atom()} |
- {error, atom()}.
-
-try_register(_User, _Server, <<"">>) ->
- {error, not_allowed};
+ case validate_credentials(User, Server, Password) of
+ {ok, LUser, LServer} ->
+ lists:foldl(
+ fun(M, {error, _}) ->
+ db_set_password(LUser, LServer, Password, M);
+ (_, ok) ->
+ ok
+ end, {error, not_allowed}, auth_modules(LServer));
+ Err ->
+ Err
+ end.
+
+-spec try_register(binary(), binary(), password()) -> ok | {error, atom()}.
try_register(User, Server, Password) ->
- case is_user_exists(User, Server) of
- true -> {atomic, exists};
- false ->
- LServer = jid:nameprep(Server),
- case ejabberd_router:is_my_host(LServer) of
- true ->
- Res = lists:foldl(fun (_M, {atomic, ok} = Res) -> Res;
- (M, _) ->
- M:try_register(User, Server, Password)
- end,
- {error, not_allowed}, auth_modules(Server)),
- case Res of
- {atomic, ok} ->
- ejabberd_hooks:run(register_user, Server,
- [User, Server]),
- {atomic, ok};
- _ -> Res
- end;
- false -> {error, not_allowed}
- end
+ case validate_credentials(User, Server, Password) of
+ {ok, LUser, LServer} ->
+ case is_user_exists(LUser, LServer) of
+ true ->
+ {error, exists};
+ false ->
+ case ejabberd_router:is_my_host(LServer) of
+ true ->
+ case lists:foldl(
+ fun(_, ok) ->
+ ok;
+ (Mod, _) ->
+ db_try_register(
+ User, Server, Password, Mod)
+ end, {error, not_allowed},
+ auth_modules(LServer)) of
+ ok ->
+ ejabberd_hooks:run(
+ register_user, Server, [User, Server]);
+ {error, _} = Err ->
+ Err
+ end;
+ false ->
+ {error, not_allowed}
+ end
+ end;
+ Err ->
+ Err
end.
-%% Registered users list do not include anonymous users logged
--spec dirty_get_registered_users() -> [{binary(), binary()}].
-
-dirty_get_registered_users() ->
- lists:flatmap(fun (M) -> M:dirty_get_registered_users()
- end,
- auth_modules()).
-
--spec get_vh_registered_users(binary()) -> [{binary(), binary()}].
-
-%% Registered users list do not include anonymous users logged
-get_vh_registered_users(Server) ->
- lists:flatmap(fun (M) ->
- M:get_vh_registered_users(Server)
- end,
- auth_modules(Server)).
-
--spec get_vh_registered_users(binary(), opts()) -> [{binary(), binary()}].
-
-get_vh_registered_users(Server, Opts) ->
- lists:flatmap(fun (M) ->
- case erlang:function_exported(M,
- get_vh_registered_users,
- 2)
- of
- true -> M:get_vh_registered_users(Server, Opts);
- false -> M:get_vh_registered_users(Server)
- end
- end,
- auth_modules(Server)).
-
-get_vh_registered_users_number(Server) ->
- lists:sum(lists:map(fun (M) ->
- case erlang:function_exported(M,
- get_vh_registered_users_number,
- 1)
- of
- true ->
- M:get_vh_registered_users_number(Server);
- false ->
- length(M:get_vh_registered_users(Server))
- end
- end,
- auth_modules(Server))).
-
--spec get_vh_registered_users_number(binary(), opts()) -> number().
-
-get_vh_registered_users_number(Server, Opts) ->
-%% @doc Get the password of the user.
-%% @spec (User::string(), Server::string()) -> Password::string()
- lists:sum(lists:map(fun (M) ->
- case erlang:function_exported(M,
- get_vh_registered_users_number,
- 2)
- of
- true ->
- M:get_vh_registered_users_number(Server,
- Opts);
- false ->
- length(M:get_vh_registered_users(Server))
- end
- end,
- auth_modules(Server))).
+-spec get_users() -> [{binary(), binary()}].
+get_users() ->
+ lists:flatmap(
+ fun({Host, Mod}) ->
+ db_get_users(Host, [], Mod)
+ end, auth_modules()).
+
+-spec get_users(binary()) -> [{binary(), binary()}].
+get_users(Server) ->
+ get_users(Server, []).
+
+-spec get_users(binary(), opts()) -> [{binary(), binary()}].
+get_users(Server, Opts) ->
+ case jid:nameprep(Server) of
+ error -> [];
+ LServer ->
+ lists:flatmap(
+ fun(M) -> db_get_users(LServer, Opts, M) end,
+ auth_modules(LServer))
+ end.
--spec get_password(binary(), binary()) -> false | password().
+-spec count_users(binary()) -> non_neg_integer().
+count_users(Server) ->
+ count_users(Server, []).
+
+-spec count_users(binary(), opts()) -> non_neg_integer().
+count_users(Server, Opts) ->
+ case jid:nameprep(Server) of
+ error -> 0;
+ LServer ->
+ lists:sum(
+ lists:map(
+ fun(M) -> db_count_users(LServer, Opts, M) end,
+ auth_modules(LServer)))
+ end.
+-spec get_password(binary(), binary()) -> false | password().
get_password(User, Server) ->
- lists:foldl(fun (M, false) ->
- M:get_password(User, Server);
- (_M, Password) -> Password
- end,
- false, auth_modules(Server)).
+ case validate_credentials(User, Server) of
+ {ok, LUser, LServer} ->
+ case lists:foldl(
+ fun(M, error) -> db_get_password(LUser, LServer, M);
+ (_M, Acc) -> Acc
+ end, error, auth_modules(LServer)) of
+ {ok, Password} ->
+ Password;
+ error ->
+ false
+ end;
+ _ ->
+ false
+ end.
-spec get_password_s(binary(), binary()) -> password().
-
get_password_s(User, Server) ->
case get_password(User, Server) of
false -> <<"">>;
Password -> Password
end.
-%% @doc Get the password of the user and the auth module.
-%% @spec (User::string(), Server::string()) ->
-%% {Password::string(), AuthModule::atom()} | {false, none}
-spec get_password_with_authmodule(binary(), binary()) -> {false | password(), module()}.
-
get_password_with_authmodule(User, Server) ->
-%% Returns true if the user exists in the DB or if an anonymous user is logged
-%% under the given name
- lists:foldl(fun (M, {false, _}) ->
- {M:get_password(User, Server), M};
- (_M, {Password, AuthModule}) -> {Password, AuthModule}
- end,
- {false, none}, auth_modules(Server)).
+ case validate_credentials(User, Server) of
+ {ok, LUser, LServer} ->
+ case lists:foldl(
+ fun(M, {error, _}) ->
+ {db_get_password(LUser, LServer, M), M};
+ (_M, Acc) ->
+ Acc
+ end, {error, undefined}, auth_modules(LServer)) of
+ {{ok, Password}, Module} ->
+ {Password, Module};
+ {error, Module} ->
+ {false, Module}
+ end;
+ _ ->
+ {false, undefined}
+ end.
-spec is_user_exists(binary(), binary()) -> boolean().
-
is_user_exists(_User, <<"">>) ->
false;
-
is_user_exists(User, Server) ->
-%% Check if the user exists in all authentications module except the module
-%% passed as parameter
-%% @spec (Module::atom(), User, Server) -> true | false | maybe
- lists:any(fun (M) ->
- case M:is_user_exists(User, Server) of
- {error, Error} ->
- ?ERROR_MSG("The authentication module ~p returned "
- "an error~nwhen checking user ~p in server "
- "~p~nError message: ~p",
- [M, User, Server, Error]),
- false;
- Else -> Else
+ case validate_credentials(User, Server) of
+ {ok, LUser, LServer} ->
+ lists:any(
+ fun(M) ->
+ case db_is_user_exists(LUser, LServer, M) of
+ {error, _} ->
+ false;
+ Else ->
+ Else
end
- end,
- auth_modules(Server)).
+ end, auth_modules(LServer));
+ _ ->
+ false
+ end.
-spec is_user_exists_in_other_modules(atom(), binary(), binary()) -> boolean() | maybe.
-
is_user_exists_in_other_modules(Module, User, Server) ->
- is_user_exists_in_other_modules_loop(auth_modules(Server)
- -- [Module],
- User, Server).
+ is_user_exists_in_other_modules_loop(
+ auth_modules(Server) -- [Module], User, Server).
-is_user_exists_in_other_modules_loop([], _User,
- _Server) ->
+is_user_exists_in_other_modules_loop([], _User, _Server) ->
false;
-is_user_exists_in_other_modules_loop([AuthModule
- | AuthModules],
- User, Server) ->
- case AuthModule:is_user_exists(User, Server) of
- true -> true;
- false ->
- is_user_exists_in_other_modules_loop(AuthModules, User,
- Server);
- {error, Error} ->
- ?DEBUG("The authentication module ~p returned "
- "an error~nwhen checking user ~p in server "
- "~p~nError message: ~p",
- [AuthModule, User, Server, Error]),
- maybe
+is_user_exists_in_other_modules_loop([AuthModule | AuthModules], User, Server) ->
+ case db_is_user_exists(User, Server, AuthModule) of
+ true ->
+ true;
+ false ->
+ is_user_exists_in_other_modules_loop(AuthModules, User, Server);
+ {error, _} ->
+ maybe
end.
-spec remove_user(binary(), binary()) -> ok.
-
-%% @spec (User, Server) -> ok
-%% @doc Remove user.
-%% Note: it may return ok even if there was some problem removing the user.
remove_user(User, Server) ->
- lists:foreach(fun (M) -> M:remove_user(User, Server)
- end,
- auth_modules(Server)),
- ejabberd_hooks:run(remove_user, jid:nameprep(Server),
- [User, Server]),
- ok.
-
-%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request | error
-%% @doc Try to remove user if the provided password is correct.
-%% The removal is attempted in each auth method provided:
-%% when one returns 'ok' the loop stops;
-%% if no method returns 'ok' then it returns the error message indicated by the last method attempted.
--spec remove_user(binary(), binary(), binary()) -> any().
+ case validate_credentials(User, Server) of
+ {ok, LUser, LServer} ->
+ lists:foreach(
+ fun(Mod) -> db_remove_user(LUser, LServer, Mod) end,
+ auth_modules(LServer)),
+ ejabberd_hooks:run(remove_user, LServer, [LUser, LServer]);
+ _Err ->
+ ok
+ end.
+-spec remove_user(binary(), binary(), password()) -> ok | {error, atom()}.
remove_user(User, Server, Password) ->
- R = lists:foldl(fun (_M, ok = Res) -> Res;
- (M, _) -> M:remove_user(User, Server, Password)
- end,
- error, auth_modules(Server)),
- case R of
- ok ->
- ejabberd_hooks:run(remove_user, jid:nameprep(Server),
- [User, Server]);
- _ -> none
- end,
- R.
-
-%% @spec (IOList) -> non_negative_float()
+ case validate_credentials(User, Server, Password) of
+ {ok, LUser, LServer} ->
+ case lists:foldl(
+ fun (_, ok) ->
+ ok;
+ (Mod, _) ->
+ case db_check_password(
+ LUser, <<"">>, LServer, Password,
+ <<"">>, undefined, Mod) of
+ true ->
+ db_remove_user(LUser, LServer, Mod);
+ false ->
+ {error, not_allowed}
+ end
+ end, {error, not_allowed}, auth_modules(Server)) of
+ ok ->
+ ejabberd_hooks:run(
+ remove_user, LServer, [LUser, LServer]);
+ Err ->
+ Err
+ end;
+ Err ->
+ Err
+ end.
+
%% @doc Calculate informational entropy.
+-spec entropy(iodata()) -> float().
entropy(B) ->
case binary_to_list(B) of
"" -> 0.0;
@@ -497,15 +469,266 @@ backend_type(Mod) ->
_ -> Mod
end.
+-spec password_format(binary() | global) -> plain | scram.
password_format(LServer) ->
ejabberd_config:get_option({auth_password_format, LServer}, plain).
%%%----------------------------------------------------------------------
+%%% Backend calls
+%%%----------------------------------------------------------------------
+db_try_register(User, Server, Password, Mod) ->
+ case erlang:function_exported(Mod, try_register, 3) of
+ true ->
+ Password1 = case Mod:store_type(Server) of
+ scram -> password_to_scram(Password);
+ _ -> Password
+ end,
+ case use_cache(Mod, Server) of
+ true ->
+ case ets_cache:update(
+ ?AUTH_CACHE, {User, Server}, {ok, Password},
+ fun() -> Mod:try_register(User, Server, Password1) end,
+ cache_nodes(Mod, Server)) of
+ {ok, _} -> ok;
+ {error, _} = Err -> Err
+ end;
+ false ->
+ Mod:try_register(User, Server, Password1)
+ end;
+ false ->
+ {error, not_allowed}
+ end.
+
+db_set_password(User, Server, Password, Mod) ->
+ case erlang:function_exported(Mod, set_password, 3) of
+ true ->
+ Password1 = case Mod:store_type(Server) of
+ scram -> password_to_scram(Password);
+ _ -> Password
+ end,
+ case use_cache(Mod, Server) of
+ true ->
+ case ets_cache:update(
+ ?AUTH_CACHE, {User, Server}, {ok, Password},
+ fun() -> Mod:set_password(User, Server, Password1) end,
+ cache_nodes(Mod, Server)) of
+ {ok, _} -> ok;
+ {error, _} = Err -> Err
+ end;
+ false ->
+ Mod:set_password(User, Server, Password1)
+ end;
+ false ->
+ {error, not_allowed}
+ end.
+
+db_get_password(User, Server, Mod) ->
+ UseCache = use_cache(Mod, Server),
+ case erlang:function_exported(Mod, get_password, 2) of
+ false when UseCache ->
+ ets_cache:lookup(?AUTH_CACHE, {User, Server});
+ false ->
+ error;
+ true when UseCache ->
+ ets_cache:lookup(
+ ?AUTH_CACHE, {User, Server},
+ fun() -> Mod:get_password(User, Server) end);
+ true ->
+ Mod:get_password(User, Server)
+ end.
+
+db_is_user_exists(User, Server, Mod) ->
+ case db_get_password(User, Server, Mod) of
+ {ok, _} ->
+ true;
+ error ->
+ case Mod:store_type(Server) of
+ external ->
+ Mod:is_user_exists(User, Server);
+ _ ->
+ false
+ end
+ end.
+
+db_check_password(User, AuthzId, Server, ProvidedPassword,
+ Digest, DigestFun, Mod) ->
+ case db_get_password(User, Server, Mod) of
+ {ok, ValidPassword} ->
+ match_passwords(ProvidedPassword, ValidPassword, Digest, DigestFun);
+ error ->
+ case {Mod:store_type(Server), use_cache(Mod, Server)} of
+ {external, true} ->
+ case ets_cache:update(
+ ?AUTH_CACHE, {User, Server}, {ok, ProvidedPassword},
+ fun() ->
+ case Mod:check_password(
+ User, AuthzId, Server, ProvidedPassword) of
+ true ->
+ {ok, ProvidedPassword};
+ false ->
+ error
+ end
+ end, cache_nodes(Mod, Server)) of
+ {ok, _} ->
+ true;
+ error ->
+ false
+ end;
+ {external, false} ->
+ Mod:check_password(User, AuthzId, Server, ProvidedPassword);
+ _ ->
+ false
+ end
+ end.
+
+db_remove_user(User, Server, Mod) ->
+ case erlang:function_exported(Mod, remove_user, 2) of
+ true ->
+ case Mod:remove_user(User, Server) of
+ ok ->
+ case use_cache(Mod, Server) of
+ true ->
+ ets_cache:delete(?AUTH_CACHE, {User, Server},
+ cache_nodes(Mod, Server));
+ false ->
+ ok
+ end;
+ {error, _} = Err ->
+ Err
+ end;
+ false ->
+ {error, not_allowed}
+ end.
+
+db_get_users(Server, Opts, Mod) ->
+ case erlang:function_exported(Mod, get_users, 2) of
+ true ->
+ Mod:get_users(Server, Opts);
+ false ->
+ case use_cache(Mod, Server) of
+ true ->
+ ets_cache:fold(
+ fun({User, S}, {ok, _}, Users) when S == Server ->
+ [{User, Server}|Users];
+ (_, _, Users) ->
+ Users
+ end, [], ?AUTH_CACHE);
+ false ->
+ []
+ end
+ end.
+
+db_count_users(Server, Opts, Mod) ->
+ case erlang:function_exported(Mod, count_users, 2) of
+ true ->
+ Mod:count_users(Server, Opts);
+ false ->
+ case use_cache(Mod, Server) of
+ true ->
+ ets_cache:fold(
+ fun({_, S}, {ok, _}, Num) when S == Server ->
+ Num + 1;
+ (_, _, Num) ->
+ Num
+ end, 0, ?AUTH_CACHE);
+ false ->
+ 0
+ end
+ end.
+
+%%%----------------------------------------------------------------------
+%%% SCRAM stuff
+%%%----------------------------------------------------------------------
+is_password_scram_valid(Password, Scram) ->
+ case jid:resourceprep(Password) of
+ error ->
+ false;
+ _ ->
+ IterationCount = Scram#scram.iterationcount,
+ Salt = misc:decode_base64(Scram#scram.salt),
+ SaltedPassword = scram:salted_password(Password, Salt, IterationCount),
+ StoredKey = scram:stored_key(scram:client_key(SaltedPassword)),
+ misc:decode_base64(Scram#scram.storedkey) == StoredKey
+ end.
+
+password_to_scram(Password) ->
+ password_to_scram(Password, ?SCRAM_DEFAULT_ITERATION_COUNT).
+
+password_to_scram(#scram{} = Password, _IterationCount) ->
+ Password;
+password_to_scram(Password, IterationCount) ->
+ Salt = randoms:bytes(?SALT_LENGTH),
+ SaltedPassword = scram:salted_password(Password, Salt, IterationCount),
+ StoredKey = scram:stored_key(scram:client_key(SaltedPassword)),
+ ServerKey = scram:server_key(SaltedPassword),
+ #scram{storedkey = misc:encode_base64(StoredKey),
+ serverkey = misc:encode_base64(ServerKey),
+ salt = misc:encode_base64(Salt),
+ iterationcount = IterationCount}.
+
+%%%----------------------------------------------------------------------
+%%% Cache stuff
+%%%----------------------------------------------------------------------
+-spec init_cache(map()) -> ok.
+init_cache(HostModules) ->
+ case use_cache(HostModules) of
+ true ->
+ ets_cache:new(?AUTH_CACHE, cache_opts());
+ false ->
+ ets_cache:delete(?AUTH_CACHE)
+ end.
+
+-spec cache_opts() -> [proplists:property()].
+cache_opts() ->
+ MaxSize = ejabberd_config:get_option(
+ auth_cache_size,
+ ejabberd_config:cache_size(global)),
+ CacheMissed = ejabberd_config:get_option(
+ auth_cache_missed,
+ ejabberd_config:cache_missed(global)),
+ LifeTime = case ejabberd_config:get_option(
+ auth_cache_life_time,
+ ejabberd_config:cache_life_time(global)) of
+ infinity -> infinity;
+ I -> timer:seconds(I)
+ end,
+ [{max_size, MaxSize}, {cache_missed, CacheMissed}, {life_time, LifeTime}].
+
+-spec use_cache(map()) -> boolean().
+use_cache(HostModules) ->
+ lists:any(
+ fun({Host, Modules}) ->
+ lists:any(fun(Module) ->
+ use_cache(Module, Host)
+ end, Modules)
+ end, maps:to_list(HostModules)).
+
+-spec use_cache(module(), binary()) -> boolean().
+use_cache(Mod, LServer) ->
+ case erlang:function_exported(Mod, use_cache, 1) of
+ true -> Mod:use_cache(LServer);
+ false ->
+ ejabberd_config:get_option(
+ {auth_use_cache, LServer},
+ ejabberd_config:use_cache(LServer))
+ end.
+
+-spec cache_nodes(module(), binary()) -> [node()].
+cache_nodes(Mod, LServer) ->
+ case erlang:function_exported(Mod, cache_nodes, 1) of
+ true -> Mod:cache_nodes(LServer);
+ false -> ejabberd_cluster:get_nodes()
+ end.
+
+%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
--spec auth_modules() -> [module()].
+-spec auth_modules() -> [{binary(), module()}].
auth_modules() ->
- lists:usort(lists:flatmap(fun auth_modules/1, ?MYHOSTS)).
+ lists:flatmap(
+ fun(Host) ->
+ [{Host, Mod} || Mod <- auth_modules(Host)]
+ end, ?MYHOSTS).
-spec auth_modules(binary()) -> [module()].
auth_modules(Server) ->
@@ -516,6 +739,65 @@ auth_modules(Server) ->
(misc:atom_to_binary(M))/binary>>)
|| M <- Methods].
+-spec match_passwords(password(), password(),
+ binary(), digest_fun() | undefined) -> boolean().
+match_passwords(Password, #scram{} = Scram, <<"">>, undefined) ->
+ is_password_scram_valid(Password, Scram);
+match_passwords(Password, #scram{} = Scram, Digest, DigestFun) ->
+ StoredKey = misc:decode_base64(Scram#scram.storedkey),
+ DigRes = if Digest /= <<"">> ->
+ Digest == DigestFun(StoredKey);
+ true -> false
+ end,
+ if DigRes ->
+ true;
+ true ->
+ StoredKey == Password andalso Password /= <<"">>
+ end;
+match_passwords(ProvidedPassword, ValidPassword, <<"">>, undefined) ->
+ ProvidedPassword == ValidPassword andalso ProvidedPassword /= <<"">>;
+match_passwords(ProvidedPassword, ValidPassword, Digest, DigestFun) ->
+ DigRes = if Digest /= <<"">> ->
+ Digest == DigestFun(ValidPassword);
+ true -> false
+ end,
+ if DigRes ->
+ true;
+ true ->
+ ValidPassword == ProvidedPassword andalso ProvidedPassword /= <<"">>
+ end.
+
+-spec validate_credentials(binary(), binary()) ->
+ {ok, binary(), binary()} | {error, invalid_jid}.
+validate_credentials(User, Server) ->
+ validate_credentials(User, Server, #scram{}).
+
+-spec validate_credentials(binary(), binary(), password()) ->
+ {ok, binary(), binary()} | {error, invalid_jid | invalid_password}.
+validate_credentials(_User, _Server, <<"">>) ->
+ {error, invalid_password};
+validate_credentials(User, Server, Password) ->
+ case jid:nodeprep(User) of
+ error ->
+ {error, invalid_jid};
+ LUser ->
+ case jid:nameprep(Server) of
+ error ->
+ {error, invalid_jid};
+ LServer ->
+ if is_record(Password, scram) ->
+ {ok, LUser, LServer};
+ true ->
+ case jid:resourceprep(Password) of
+ error ->
+ {error, invalid_password};
+ _ ->
+ {ok, LUser, LServer}
+ end
+ end
+ end
+ end.
+
export(Server) ->
ejabberd_auth_mnesia:export(Server).
@@ -536,6 +818,10 @@ import(_LServer, {sql, _}, sql, <<"users">>, _) ->
-spec opt_type(auth_method) -> fun((atom() | [atom()]) -> [atom()]);
(auth_password_format) -> fun((plain | scram) -> plain | scram);
+ (auth_use_cache) -> fun((boolean()) -> boolean());
+ (auth_cache_missed) -> fun((boolean()) -> boolean());
+ (auth_cache_life_time) -> fun((timeout()) -> timeout());
+ (auth_cache_size) -> fun((timeout()) -> timeout());
(atom()) -> [atom()].
opt_type(auth_method) ->
fun (V) when is_list(V) ->
@@ -546,4 +832,20 @@ opt_type(auth_password_format) ->
fun (plain) -> plain;
(scram) -> scram
end;
-opt_type(_) -> [auth_method, auth_password_format].
+opt_type(auth_use_cache) ->
+ fun(B) when is_boolean(B) -> B end;
+opt_type(auth_cache_missed) ->
+ fun(B) when is_boolean(B) -> B end;
+opt_type(auth_cache_life_time) ->
+ fun(I) when is_integer(I), I>0 -> I;
+ (unlimited) -> infinity;
+ (infinity) -> infinity
+ end;
+opt_type(auth_cache_size) ->
+ fun(I) when is_integer(I), I>0 -> I;
+ (unlimited) -> infinity;
+ (infinity) -> infinity
+ end;
+opt_type(_) ->
+ [auth_method, auth_password_format, auth_use_cache,
+ auth_cache_missed, auth_cache_life_time, auth_cache_size].
diff --git a/src/ejabberd_auth_anonymous.erl b/src/ejabberd_auth_anonymous.erl
index 5bb2daed7..b3ae1f6dd 100644
--- a/src/ejabberd_auth_anonymous.erl
+++ b/src/ejabberd_auth_anonymous.erl
@@ -40,15 +40,9 @@
unregister_connection/3
]).
--export([login/2, set_password/3, check_password/4,
- check_password/6, try_register/3,
- dirty_get_registered_users/0, get_vh_registered_users/1,
- get_vh_registered_users/2,
- get_vh_registered_users_number/1,
- get_vh_registered_users_number/2, get_password_s/2,
- get_password/2, get_password/3, is_user_exists/2,
- remove_user/2, remove_user/3, store_type/0,
- plain_password_required/0, opt_type/1]).
+-export([login/2, check_password/4, is_user_exists/2,
+ get_users/2, count_users/2, store_type/1,
+ plain_password_required/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -139,15 +133,7 @@ unregister_connection(_SID,
%% ---------------------------------
%% Specific anonymous auth functions
%% ---------------------------------
-
-%% When anonymous login is enabled, check the password for permenant users
-%% before allowing access
-check_password(User, AuthzId, Server, Password) ->
- check_password(User, AuthzId, Server, Password, undefined,
- undefined).
-
-check_password(User, _AuthzId, Server, _Password, _Digest,
- _DigestGen) ->
+check_password(User, _AuthzId, Server, _Password) ->
case
ejabberd_auth:is_user_exists_in_other_modules(?MODULE,
User, Server)
@@ -173,68 +159,20 @@ login(User, Server) ->
end
end.
-%% When anonymous login is enabled, check that the user is permanent before
-%% changing its password
-set_password(User, Server, _Password) ->
- case anonymous_user_exist(User, Server) of
- true -> ok;
- false -> {error, not_allowed}
- end.
-
-%% When anonymous login is enabled, check if permanent users are allowed on
-%% the server:
-try_register(_User, _Server, _Password) ->
- {error, not_allowed}.
-
-dirty_get_registered_users() -> [].
-
-get_vh_registered_users(Server) ->
- [{U, S}
- || {U, S, _R}
- <- ejabberd_sm:get_vh_session_list(Server)].
-
-get_vh_registered_users(Server, _) ->
- get_vh_registered_users(Server).
-
-get_vh_registered_users_number(Server) ->
- length(get_vh_registered_users(Server)).
+get_users(Server, _) ->
+ [{U, S} || {U, S, _R} <- ejabberd_sm:get_vh_session_list(Server)].
-get_vh_registered_users_number(Server, _) ->
- get_vh_registered_users_number(Server).
-
-%% Return password of permanent user or false for anonymous users
-get_password(User, Server) ->
- get_password(User, Server, <<"">>).
-
-get_password(User, Server, DefaultValue) ->
- case anonymous_user_exist(User, Server) or
- login(User, Server)
- of
- %% We return the default value if the user is anonymous
- true -> DefaultValue;
- %% We return the permanent user password otherwise
- false -> false
- end.
-
-get_password_s(User, Server) ->
- case get_password(User, Server) of
- false ->
- <<"">>;
- Password ->
- Password
- end.
+count_users(Server, Opts) ->
+ length(get_users(Server, Opts)).
is_user_exists(User, Server) ->
anonymous_user_exist(User, Server).
-remove_user(_User, _Server) -> {error, not_allowed}.
-
-remove_user(_User, _Server, _Password) -> not_allowed.
-
-plain_password_required() -> false.
+plain_password_required(_) ->
+ false.
-store_type() ->
- plain.
+store_type(_) ->
+ external.
-spec opt_type(allow_multiple_connection) -> fun((boolean()) -> boolean());
(anonymous_protocol) -> fun((sasl_anon | login_anon | both) ->
diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl
index 5bdd704a0..5b2b26c1a 100644
--- a/src/ejabberd_auth_external.erl
+++ b/src/ejabberd_auth_external.erl
@@ -32,14 +32,8 @@
-behaviour(ejabberd_auth).
-export([start/1, stop/1, set_password/3, check_password/4,
- check_password/6, try_register/3,
- dirty_get_registered_users/0, get_vh_registered_users/1,
- get_vh_registered_users/2,
- get_vh_registered_users_number/1,
- get_vh_registered_users_number/2, get_password/2,
- get_password_s/2, is_user_exists/2, remove_user/2,
- remove_user/3, store_type/0, plain_password_required/0,
- opt_type/1]).
+ try_register/3, is_user_exists/2, remove_user/2,
+ store_type/1, plain_password_required/1, opt_type/1]).
-include("ejabberd.hrl").
-include("logger.hrl").
@@ -49,275 +43,60 @@
%%%----------------------------------------------------------------------
start(Host) ->
Cmd = ejabberd_config:get_option({extauth_program, Host}, "extauth"),
- extauth:start(Host, Cmd),
- check_cache_last_options(Host),
- ejabberd_auth_mnesia:start(Host).
+ extauth:start(Host, Cmd).
stop(Host) ->
- extauth:stop(Host),
- ejabberd_auth_mnesia:stop(Host).
+ extauth:stop(Host).
-check_cache_last_options(Server) ->
- case get_cache_option(Server) of
- false -> no_cache;
- {true, _CacheTime} ->
- case get_mod_last_configured(Server) of
- no_mod_last ->
- ?ERROR_MSG("In host ~p extauth is used, extauth_cache "
- "is enabled but mod_last is not enabled.",
- [Server]),
- no_cache;
- _ -> cache
- end
- end.
-
-plain_password_required() -> true.
+plain_password_required(_) -> true.
-store_type() -> external.
+store_type(_) -> external.
check_password(User, AuthzId, Server, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
false;
true ->
- case get_cache_option(Server) of
- false ->
- check_password_extauth(User, AuthzId, Server, Password);
- {true, CacheTime} ->
- check_password_cache(User, AuthzId, Server, Password,
- CacheTime)
- end
+ check_password_extauth(User, AuthzId, Server, Password)
end.
-check_password(User, AuthzId, Server, Password, _Digest,
- _DigestGen) ->
- check_password(User, AuthzId, Server, Password).
-
set_password(User, Server, Password) ->
case extauth:set_password(User, Server, Password) of
- true ->
- set_password_mnesia(User, Server, Password), ok;
- _ -> {error, unknown_problem}
+ true -> ok;
+ _ -> {error, db_failure}
end.
try_register(User, Server, Password) ->
- case get_cache_option(Server) of
- false -> try_register_extauth(User, Server, Password);
- {true, _CacheTime} ->
- try_register_external_cache(User, Server, Password)
- end.
-
-dirty_get_registered_users() ->
- ejabberd_auth_mnesia:dirty_get_registered_users().
-
-get_vh_registered_users(Server) ->
- ejabberd_auth_mnesia:get_vh_registered_users(Server).
-
-get_vh_registered_users(Server, Data) ->
- ejabberd_auth_mnesia:get_vh_registered_users(Server,
- Data).
-
-get_vh_registered_users_number(Server) ->
- ejabberd_auth_mnesia:get_vh_registered_users_number(Server).
-
-get_vh_registered_users_number(Server, Data) ->
- ejabberd_auth_mnesia:get_vh_registered_users_number(Server,
- Data).
-
-%% The password can only be returned if cache is enabled, cached info exists and is fresh enough.
-get_password(User, Server) ->
- case get_cache_option(Server) of
- false -> false;
- {true, CacheTime} ->
- get_password_cache(User, Server, CacheTime)
- end.
-
-get_password_s(User, Server) ->
- case get_password(User, Server) of
- false -> <<"">>;
- Other -> Other
- end.
+ extauth:try_register(User, Server, Password).
-%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
try extauth:is_user_exists(User, Server) of
- Res -> Res
+ Res -> Res
catch
- _:Error -> {error, Error}
+ _:Error ->
+ ?ERROR_MSG("external authentication program failure: ~p",
+ [Error]),
+ {error, db_failure}
end.
remove_user(User, Server) ->
case extauth:remove_user(User, Server) of
- false -> false;
- true ->
- case get_cache_option(Server) of
- false -> false;
- {true, _CacheTime} ->
- ejabberd_auth_mnesia:remove_user(User, Server)
- end
+ false -> {error, not_allowed};
+ true -> ok
end.
-remove_user(User, Server, Password) ->
- case extauth:remove_user(User, Server, Password) of
- false -> false;
- true ->
- case get_cache_option(Server) of
- false -> false;
- {true, _CacheTime} ->
- ejabberd_auth_mnesia:remove_user(User, Server,
- Password)
- end
- end.
-
-%%%
-%%% Extauth cache management
-%%%
-
-%% @spec (Host::string()) -> false | {true, CacheTime::integer()}
-get_cache_option(Host) ->
- case ejabberd_config:get_option({extauth_cache, Host}, false) of
- false -> false;
- CacheTime -> {true, CacheTime}
- end.
-
-%% @spec (User, AuthzId, Server, Password) -> true | false
check_password_extauth(User, _AuthzId, Server, Password) ->
extauth:check_password(User, Server, Password) andalso
Password /= <<"">>.
-%% @spec (User, Server, Password) -> true | false
-try_register_extauth(User, Server, Password) ->
- extauth:try_register(User, Server, Password).
-
-check_password_cache(User, AuthzId, Server, Password, 0) ->
- check_password_external_cache(User, AuthzId, Server, Password);
-check_password_cache(User, AuthzId, Server, Password,
- CacheTime) ->
- case get_last_access(User, Server) of
- online ->
- check_password_mnesia(User, AuthzId, Server, Password);
- never ->
- check_password_external_cache(User, AuthzId, Server, Password);
- mod_last_required ->
- ?ERROR_MSG("extauth is used, extauth_cache is enabled "
- "but mod_last is not enabled in that "
- "host",
- []),
- check_password_external_cache(User, AuthzId, Server, Password);
- TimeStamp ->
- case is_fresh_enough(TimeStamp, CacheTime) of
- %% If no need to refresh, check password against Mnesia
- true ->
- case check_password_mnesia(User, AuthzId, Server, Password) of
- %% If password valid in Mnesia, accept it
- true -> true;
- %% Else (password nonvalid in Mnesia), check in extauth and cache result
- false ->
- check_password_external_cache(User, AuthzId, Server, Password)
- end;
- %% Else (need to refresh), check in extauth and cache result
- false ->
- check_password_external_cache(User, AuthzId, Server, Password)
- end
- end.
-
-get_password_mnesia(User, Server) ->
- ejabberd_auth_mnesia:get_password(User, Server).
-
--spec get_password_cache(User::binary(), Server::binary(), CacheTime::integer()) -> Password::string() | false.
-get_password_cache(User, Server, CacheTime) ->
- case get_last_access(User, Server) of
- online -> get_password_mnesia(User, Server);
- never -> false;
- mod_last_required ->
- ?ERROR_MSG("extauth is used, extauth_cache is enabled "
- "but mod_last is not enabled in that "
- "host",
- []),
- false;
- TimeStamp ->
- case is_fresh_enough(TimeStamp, CacheTime) of
- true -> get_password_mnesia(User, Server);
- false -> false
- end
- end.
-
-%% Check the password using extauth; if success then cache it
-check_password_external_cache(User, AuthzId, Server, Password) ->
- case check_password_extauth(User, AuthzId, Server, Password) of
- true ->
- set_password_mnesia(User, Server, Password), true;
- false -> false
- end.
-
-%% Try to register using extauth; if success then cache it
-try_register_external_cache(User, Server, Password) ->
- case try_register_extauth(User, Server, Password) of
- {atomic, ok} = R ->
- set_password_mnesia(User, Server, Password), R;
- _ -> {error, not_allowed}
- end.
-
-%% @spec (User, AuthzId, Server, Password) -> true | false
-check_password_mnesia(User, AuthzId, Server, Password) ->
- ejabberd_auth_mnesia:check_password(User, AuthzId, Server,
- Password).
-
-%% @spec (User, Server, Password) -> ok | {error, invalid_jid}
-set_password_mnesia(User, Server, Password) ->
-%% @spec (TimeLast, CacheTime) -> true | false
-%% TimeLast = online | never | integer()
-%% CacheTime = integer() | false
- ejabberd_auth_mnesia:set_password(User, Server,
- Password).
-
-is_fresh_enough(TimeStampLast, CacheTime) ->
- Now = p1_time_compat:system_time(seconds),
- TimeStampLast + CacheTime > Now.
-
-%% Code copied from mod_configure.erl
-%% Code copied from web/ejabberd_web_admin.erl
-%% TODO: Update time format to XEP-0202: Entity Time
--spec(get_last_access(User::binary(), Server::binary()) -> (online | never | mod_last_required | integer())).
-get_last_access(User, Server) ->
- case ejabberd_sm:get_user_resources(User, Server) of
- [] ->
- case get_last_info(User, Server) of
- mod_last_required -> mod_last_required;
- not_found -> never;
- {ok, Timestamp, _Status} -> Timestamp
- end;
- _ -> online
- end.
-%% @spec (User, Server) -> {ok, Timestamp, Status} | not_found | mod_last_required
-
-get_last_info(User, Server) ->
- case get_mod_last_enabled(Server) of
- mod_last -> mod_last:get_last_info(User, Server);
- no_mod_last -> mod_last_required
- end.
-
-%% @spec (Server) -> mod_last | no_mod_last
-get_mod_last_enabled(Server) ->
- case gen_mod:is_loaded(Server, mod_last) of
- true -> mod_last;
- false -> no_mod_last
- end.
-
-get_mod_last_configured(Server) ->
- case is_configured(Server, mod_last) of
- true -> mod_last;
- false -> no_mod_last
- end.
-
-is_configured(Host, Module) ->
- Os = ejabberd_config:get_option({modules, Host}, []),
- lists:keymember(Module, 1, Os).
-
-spec opt_type(extauth_cache) -> fun((false | non_neg_integer()) ->
false | non_neg_integer());
(extauth_program) -> fun((binary()) -> string());
(atom()) -> [atom()].
opt_type(extauth_cache) ->
+ ?WARNING_MSG("option 'extauth_cache' is deprecated and has no effect, "
+ "use authentication or global cache configuration "
+ "options: auth_use_cache, auth_cache_life_time, "
+ "use_cache, cache_life_time, and so on", []),
fun (false) -> false;
(I) when is_integer(I), I >= 0 -> I
end;
diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl
index 8a4532e38..15abebedc 100644
--- a/src/ejabberd_auth_ldap.erl
+++ b/src/ejabberd_auth_ldap.erl
@@ -37,13 +37,9 @@
handle_cast/2, terminate/2, code_change/3]).
-export([start/1, stop/1, start_link/1, set_password/3,
- check_password/4, check_password/6, try_register/3,
- dirty_get_registered_users/0, get_vh_registered_users/1,
- get_vh_registered_users/2,
- get_vh_registered_users_number/1,
- get_vh_registered_users_number/2, get_password/2,
- get_password_s/2, is_user_exists/2, remove_user/2,
- remove_user/3, store_type/0, plain_password_required/0,
+ check_password/4, is_user_exists/2,
+ get_users/2, count_users/2,
+ store_type/1, plain_password_required/1,
opt_type/1]).
-include("ejabberd.hrl").
@@ -112,9 +108,9 @@ init(Host) ->
State#state.password, State#state.tls_options),
{ok, State}.
-plain_password_required() -> true.
+plain_password_required(_) -> true.
-store_type() -> external.
+store_type(_) -> external.
check_password(User, AuthzId, Server, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
@@ -129,60 +125,34 @@ check_password(User, AuthzId, Server, Password) ->
end
end.
-check_password(User, AuthzId, Server, Password, _Digest,
- _DigestGen) ->
- check_password(User, AuthzId, Server, Password).
-
set_password(User, Server, Password) ->
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
case find_user_dn(User, State) of
- false -> {error, user_not_found};
+ false -> {error, notfound};
DN ->
- eldap_pool:modify_passwd(State#state.eldap_id, DN,
- Password)
+ case eldap_pool:modify_passwd(State#state.eldap_id, DN,
+ Password) of
+ ok -> ok;
+ _Err -> {error, db_failure}
+ end
end.
-%% @spec (User, Server, Password) -> {error, not_allowed}
-try_register(_User, _Server, _Password) ->
- {error, not_allowed}.
-
-dirty_get_registered_users() ->
- Servers = ejabberd_config:get_vh_by_auth_method(ldap),
- lists:flatmap(fun (Server) ->
- get_vh_registered_users(Server)
- end,
- Servers).
-
-get_vh_registered_users(Server) ->
- case catch get_vh_registered_users_ldap(Server) of
+get_users(Server, []) ->
+ case catch get_users_ldap(Server) of
{'EXIT', _} -> [];
Result -> Result
end.
-get_vh_registered_users(Server, _) ->
- get_vh_registered_users(Server).
-
-get_vh_registered_users_number(Server) ->
- length(get_vh_registered_users(Server)).
-
-get_vh_registered_users_number(Server, _) ->
- get_vh_registered_users_number(Server).
-
-get_password(_User, _Server) -> false.
-
-get_password_s(_User, _Server) -> <<"">>.
+count_users(Server, Opts) ->
+ length(get_users(Server, Opts)).
%% @spec (User, Server) -> true | false | {error, Error}
is_user_exists(User, Server) ->
case catch is_user_exists_ldap(User, Server) of
- {'EXIT', Error} -> {error, Error};
+ {'EXIT', _Error} -> {error, db_failure};
Result -> Result
end.
-remove_user(_User, _Server) -> {error, not_allowed}.
-
-remove_user(_User, _Server, _Password) -> not_allowed.
-
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
@@ -199,7 +169,7 @@ check_password_ldap(User, Server, Password) ->
end
end.
-get_vh_registered_users_ldap(Server) ->
+get_users_ldap(Server) ->
{ok, State} = eldap_utils:get_state(Server, ?MODULE),
UIDs = State#state.uids,
Eldap_ID = State#state.eldap_id,
diff --git a/src/ejabberd_auth_mnesia.erl b/src/ejabberd_auth_mnesia.erl
index 592b9c566..02c22f9d5 100644
--- a/src/ejabberd_auth_mnesia.erl
+++ b/src/ejabberd_auth_mnesia.erl
@@ -31,15 +31,11 @@
-behaviour(ejabberd_auth).
--export([start/1, stop/1, set_password/3, check_password/4,
- check_password/6, try_register/3,
- dirty_get_registered_users/0, get_vh_registered_users/1,
- get_vh_registered_users/2, init_db/0,
- get_vh_registered_users_number/1,
- get_vh_registered_users_number/2, get_password/2,
- get_password_s/2, is_user_exists/2, remove_user/2,
- remove_user/3, store_type/0, export/1, import/2,
- plain_password_required/0]).
+-export([start/1, stop/1, set_password/3, try_register/3,
+ get_users/2, init_db/0,
+ count_users/2, get_password/2,
+ remove_user/2, store_type/1, export/1, import/2,
+ plain_password_required/1, use_cache/1]).
-export([need_transform/1, transform/1]).
-include("ejabberd.hrl").
@@ -52,8 +48,6 @@
-record(reg_users_counter, {vhost = <<"">> :: binary(),
count = 0 :: integer() | '$1'}).
--define(SALT_LENGTH, 16).
-
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
@@ -67,14 +61,14 @@ stop(_Host) ->
init_db() ->
ejabberd_mnesia:create(?MODULE, passwd,
- [{disc_copies, [node()]},
+ [{disc_only_copies, [node()]},
{attributes, record_info(fields, passwd)}]),
ejabberd_mnesia:create(?MODULE, reg_users_counter,
[{ram_copies, [node()]},
{attributes, record_info(fields, reg_users_counter)}]).
update_reg_users_counter_table(Server) ->
- Set = get_vh_registered_users(Server),
+ Set = get_users(Server, []),
Size = length(Set),
LServer = jid:nameprep(Server),
F = fun () ->
@@ -83,309 +77,153 @@ update_reg_users_counter_table(Server) ->
end,
mnesia:sync_dirty(F).
-plain_password_required() ->
- is_scrammed().
-
-store_type() ->
- ejabberd_auth:password_format(?MYNAME).
-
-check_password(User, AuthzId, Server, Password) ->
- if AuthzId /= <<>> andalso AuthzId /= User ->
- false;
- true ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- US = {LUser, LServer},
- case catch mnesia:dirty_read({passwd, US}) of
- [#passwd{password = Password}] when is_binary(Password) ->
- Password /= <<"">>;
- [#passwd{password = Scram}] when is_record(Scram, scram) ->
- is_password_scram_valid(Password, Scram);
- _ -> false
- end
+use_cache(_) ->
+ case mnesia:table_info(passwd, storage_type) of
+ disc_only_copies -> true;
+ _ -> false
end.
-check_password(User, AuthzId, Server, Password, Digest,
- DigestGen) ->
- if AuthzId /= <<>> andalso AuthzId /= User ->
- false;
- true ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- US = {LUser, LServer},
- case catch mnesia:dirty_read({passwd, US}) of
- [#passwd{password = Passwd}] when is_binary(Passwd) ->
- DigRes = if Digest /= <<"">> ->
- Digest == DigestGen(Passwd);
- true -> false
- end,
- if DigRes -> true;
- true -> (Passwd == Password) and (Password /= <<"">>)
- end;
- [#passwd{password = Scram}] when is_record(Scram, scram) ->
- Passwd = misc:decode_base64(Scram#scram.storedkey),
- DigRes = if Digest /= <<"">> ->
- Digest == DigestGen(Passwd);
- true -> false
- end,
- if DigRes -> true;
- true -> (Passwd == Password) and (Password /= <<"">>)
- end;
- _ -> false
- end
- end.
+plain_password_required(Server) ->
+ store_type(Server) == scram.
+
+store_type(Server) ->
+ ejabberd_auth:password_format(Server).
-%% @spec (User::string(), Server::string(), Password::string()) ->
-%% ok | {error, invalid_jid}
set_password(User, Server, Password) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- LPassword = jid:resourceprep(Password),
- US = {LUser, LServer},
- if (LUser == error) or (LServer == error) ->
- {error, invalid_jid};
- LPassword == error ->
- {error, invalid_password};
- true ->
- F = fun () ->
- Password2 = case is_scrammed() and is_binary(Password)
- of
- true -> password_to_scram(Password);
- false -> Password
- end,
- mnesia:write(#passwd{us = US, password = Password2})
- end,
- {atomic, ok} = mnesia:transaction(F),
- ok
+ US = {User, Server},
+ F = fun () ->
+ mnesia:write(#passwd{us = US, password = Password})
+ end,
+ case mnesia:transaction(F) of
+ {atomic, ok} ->
+ ok;
+ {aborted, Reason} ->
+ ?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]),
+ {error, db_failure}
end.
-%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid} | {error, not_allowed} | {error, Reason}
-try_register(User, Server, PasswordList) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- Password = if is_list(PasswordList); is_binary(PasswordList) ->
- iolist_to_binary(PasswordList);
- true -> PasswordList
- end,
- LPassword = jid:resourceprep(Password),
- US = {LUser, LServer},
- if (LUser == error) or (LServer == error) ->
- {error, invalid_jid};
- (LPassword == error) and not is_record(Password, scram) ->
- {error, invalid_password};
- true ->
- F = fun () ->
- case mnesia:read({passwd, US}) of
- [] ->
- Password2 = case is_scrammed() and
- is_binary(Password)
- of
- true -> password_to_scram(Password);
- false -> Password
- end,
- mnesia:write(#passwd{us = US,
- password = Password2}),
- mnesia:dirty_update_counter(reg_users_counter,
- LServer, 1),
- ok;
- [_E] -> exists
- end
- end,
- mnesia:transaction(F)
+try_register(User, Server, Password) ->
+ US = {User, Server},
+ F = fun () ->
+ case mnesia:read({passwd, US}) of
+ [] ->
+ mnesia:write(#passwd{us = US, password = Password}),
+ mnesia:dirty_update_counter(reg_users_counter, Server, 1),
+ ok;
+ [_] ->
+ {error, exists}
+ end
+ end,
+ case mnesia:transaction(F) of
+ {atomic, Res} ->
+ Res;
+ {aborted, Reason} ->
+ ?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]),
+ {error, db_failure}
end.
-%% Get all registered users in Mnesia
-dirty_get_registered_users() ->
- mnesia:dirty_all_keys(passwd).
-
-get_vh_registered_users(Server) ->
- LServer = jid:nameprep(Server),
+get_users(Server, []) ->
mnesia:dirty_select(passwd,
[{#passwd{us = '$1', _ = '_'},
- [{'==', {element, 2, '$1'}, LServer}], ['$1']}]).
-
-get_vh_registered_users(Server,
- [{from, Start}, {to, End}])
- when is_integer(Start) and is_integer(End) ->
- get_vh_registered_users(Server,
- [{limit, End - Start + 1}, {offset, Start}]);
-get_vh_registered_users(Server,
- [{limit, Limit}, {offset, Offset}])
- when is_integer(Limit) and is_integer(Offset) ->
- case get_vh_registered_users(Server) of
- [] -> [];
- Users ->
- Set = lists:keysort(1, Users),
- L = length(Set),
- Start = if Offset < 1 -> 1;
- Offset > L -> L;
- true -> Offset
- end,
- lists:sublist(Set, Start, Limit)
+ [{'==', {element, 2, '$1'}, Server}], ['$1']}]);
+get_users(Server, [{from, Start}, {to, End}])
+ when is_integer(Start) and is_integer(End) ->
+ get_users(Server, [{limit, End - Start + 1}, {offset, Start}]);
+get_users(Server, [{limit, Limit}, {offset, Offset}])
+ when is_integer(Limit) and is_integer(Offset) ->
+ case get_users(Server, []) of
+ [] ->
+ [];
+ Users ->
+ Set = lists:keysort(1, Users),
+ L = length(Set),
+ Start = if Offset < 1 -> 1;
+ Offset > L -> L;
+ true -> Offset
+ end,
+ lists:sublist(Set, Start, Limit)
end;
-get_vh_registered_users(Server, [{prefix, Prefix}])
- when is_binary(Prefix) ->
- Set = [{U, S}
- || {U, S} <- get_vh_registered_users(Server),
- str:prefix(Prefix, U)],
+get_users(Server, [{prefix, Prefix}]) when is_binary(Prefix) ->
+ Set = [{U, S} || {U, S} <- get_users(Server, []), str:prefix(Prefix, U)],
lists:keysort(1, Set);
-get_vh_registered_users(Server,
- [{prefix, Prefix}, {from, Start}, {to, End}])
- when is_binary(Prefix) and is_integer(Start) and
- is_integer(End) ->
- get_vh_registered_users(Server,
- [{prefix, Prefix}, {limit, End - Start + 1},
- {offset, Start}]);
-get_vh_registered_users(Server,
- [{prefix, Prefix}, {limit, Limit}, {offset, Offset}])
- when is_binary(Prefix) and is_integer(Limit) and
- is_integer(Offset) ->
- case [{U, S}
- || {U, S} <- get_vh_registered_users(Server),
- str:prefix(Prefix, U)]
- of
- [] -> [];
- Users ->
- Set = lists:keysort(1, Users),
- L = length(Set),
- Start = if Offset < 1 -> 1;
- Offset > L -> L;
- true -> Offset
- end,
- lists:sublist(Set, Start, Limit)
+get_users(Server, [{prefix, Prefix}, {from, Start}, {to, End}])
+ when is_binary(Prefix) and is_integer(Start) and is_integer(End) ->
+ get_users(Server, [{prefix, Prefix}, {limit, End - Start + 1},
+ {offset, Start}]);
+get_users(Server, [{prefix, Prefix}, {limit, Limit}, {offset, Offset}])
+ when is_binary(Prefix) and is_integer(Limit) and is_integer(Offset) ->
+ case [{U, S} || {U, S} <- get_users(Server, []), str:prefix(Prefix, U)] of
+ [] ->
+ [];
+ Users ->
+ Set = lists:keysort(1, Users),
+ L = length(Set),
+ Start = if Offset < 1 -> 1;
+ Offset > L -> L;
+ true -> Offset
+ end,
+ lists:sublist(Set, Start, Limit)
end;
-get_vh_registered_users(Server, _) ->
- get_vh_registered_users(Server).
-
-get_vh_registered_users_number(Server) ->
- LServer = jid:nameprep(Server),
- Query = mnesia:dirty_select(reg_users_counter,
- [{#reg_users_counter{vhost = LServer,
- count = '$1'},
- [], ['$1']}]),
- case Query of
- [Count] -> Count;
- _ -> 0
- end.
-
-get_vh_registered_users_number(Server,
- [{prefix, Prefix}])
- when is_binary(Prefix) ->
- Set = [{U, S}
- || {U, S} <- get_vh_registered_users(Server),
- str:prefix(Prefix, U)],
+get_users(Server, _) ->
+ get_users(Server, []).
+
+count_users(Server, []) ->
+ case mnesia:dirty_select(
+ reg_users_counter,
+ [{#reg_users_counter{vhost = Server, count = '$1'},
+ [], ['$1']}]) of
+ [Count] -> Count;
+ _ -> 0
+ end;
+count_users(Server, [{prefix, Prefix}]) when is_binary(Prefix) ->
+ Set = [{U, S} || {U, S} <- get_users(Server, []), str:prefix(Prefix, U)],
length(Set);
-get_vh_registered_users_number(Server, _) ->
- get_vh_registered_users_number(Server).
+count_users(Server, _) ->
+ count_users(Server, []).
get_password(User, Server) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- US = {LUser, LServer},
- case catch mnesia:dirty_read(passwd, US) of
- [#passwd{password = Password}]
- when is_binary(Password) ->
- Password;
- [#passwd{password = Scram}]
- when is_record(Scram, scram) ->
- {misc:decode_base64(Scram#scram.storedkey),
- misc:decode_base64(Scram#scram.serverkey),
- misc:decode_base64(Scram#scram.salt),
- Scram#scram.iterationcount};
- _ -> false
- end.
-
-get_password_s(User, Server) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- US = {LUser, LServer},
- case catch mnesia:dirty_read(passwd, US) of
- [#passwd{password = Password}]
- when is_binary(Password) ->
- Password;
- [#passwd{password = Scram}]
- when is_record(Scram, scram) ->
- <<"">>;
- _ -> <<"">>
- end.
-
-%% @spec (User, Server) -> true | false | {error, Error}
-is_user_exists(User, Server) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- US = {LUser, LServer},
- case catch mnesia:dirty_read({passwd, US}) of
- [] -> false;
- [_] -> true;
- Other -> {error, Other}
+ case mnesia:dirty_read(passwd, {User, Server}) of
+ [#passwd{password = Password}] ->
+ {ok, Password};
+ _ ->
+ error
end.
-%% @spec (User, Server) -> ok
-%% @doc Remove user.
-%% Note: it returns ok even if there was some problem removing the user.
remove_user(User, Server) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- US = {LUser, LServer},
+ US = {User, Server},
F = fun () ->
mnesia:delete({passwd, US}),
- mnesia:dirty_update_counter(reg_users_counter, LServer,
- -1)
- end,
- mnesia:transaction(F),
- ok.
-
-%% @spec (User, Server, Password) -> ok | not_exists | not_allowed | bad_request
-%% @doc Remove user if the provided password is correct.
-remove_user(User, Server, Password) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- US = {LUser, LServer},
- F = fun () ->
- case mnesia:read({passwd, US}) of
- [#passwd{password = Password}]
- when is_binary(Password) ->
- mnesia:delete({passwd, US}),
- mnesia:dirty_update_counter(reg_users_counter, LServer,
- -1),
- ok;
- [#passwd{password = Scram}]
- when is_record(Scram, scram) ->
- case is_password_scram_valid(Password, Scram) of
- true ->
- mnesia:delete({passwd, US}),
- mnesia:dirty_update_counter(reg_users_counter,
- LServer, -1),
- ok;
- false -> not_allowed
- end;
- _ -> not_exists
- end
+ mnesia:dirty_update_counter(reg_users_counter, Server, -1),
+ ok
end,
case mnesia:transaction(F) of
- {atomic, ok} -> ok;
- {atomic, Res} -> Res;
- _ -> bad_request
+ {atomic, ok} ->
+ ok;
+ {aborted, Reason} ->
+ ?ERROR_MSG("Mnesia transaction failed: ~p", [Reason]),
+ {error, db_failure}
end.
need_transform(#passwd{us = {U, S}, password = Pass}) ->
if is_binary(Pass) ->
- IsScrammed = is_scrammed(),
- if IsScrammed ->
+ case store_type(S) of
+ scram ->
?INFO_MSG("Passwords in Mnesia table 'passwd' "
- "will be SCRAM'ed", []);
- true ->
- ok
- end,
- IsScrammed;
+ "will be SCRAM'ed", []),
+ true;
+ plain ->
+ false
+ end;
is_record(Pass, scram) ->
- case is_scrammed() of
- true ->
- next;
- false ->
+ case store_type(S) of
+ scram ->
+ false;
+ plain ->
?WARNING_MSG("Some passwords were stored in the database "
"as SCRAM, but 'auth_password_format' "
- "is not configured as 'scram'.", []),
+ "is not configured as 'scram': some "
+ "authentication mechanisms such as DIGEST-MD5 "
+ "would *fail*", []),
false
end;
is_list(U) orelse is_list(S) orelse is_list(Pass) ->
@@ -410,61 +248,24 @@ transform(#passwd{us = {U, S}, password = Pass} = R)
transform(R#passwd{us = NewUS, password = NewPass});
transform(#passwd{us = {U, S}, password = Password} = P)
when is_binary(Password) ->
- case is_scrammed() of
- true ->
+ case store_type(S) of
+ scram ->
case jid:resourceprep(Password) of
error ->
?ERROR_MSG("SASLprep failed for password of user ~s@~s",
[U, S]),
P;
_ ->
- Scram = password_to_scram(Password),
+ Scram = ejabberd_auth:password_to_scram(Password),
P#passwd{password = Scram}
end;
- false ->
+ plain ->
P
end;
transform(#passwd{password = Password} = P)
when is_record(Password, scram) ->
P.
-%%%
-%%% SCRAM
-%%%
-
-is_scrammed() ->
- scram == store_type().
-
-password_to_scram(Password) ->
- password_to_scram(Password,
- ?SCRAM_DEFAULT_ITERATION_COUNT).
-
-password_to_scram(Password, IterationCount) ->
- Salt = randoms:bytes(?SALT_LENGTH),
- SaltedPassword = scram:salted_password(Password, Salt,
- IterationCount),
- StoredKey =
- scram:stored_key(scram:client_key(SaltedPassword)),
- ServerKey = scram:server_key(SaltedPassword),
- #scram{storedkey = misc:encode_base64(StoredKey),
- serverkey = misc:encode_base64(ServerKey),
- salt = misc:encode_base64(Salt),
- iterationcount = IterationCount}.
-
-is_password_scram_valid(Password, Scram) ->
- case jid:resourceprep(Password) of
- error ->
- false;
- _ ->
- IterationCount = Scram#scram.iterationcount,
- Salt = misc:decode_base64(Scram#scram.salt),
- SaltedPassword = scram:salted_password(Password, Salt,
- IterationCount),
- StoredKey =
- scram:stored_key(scram:client_key(SaltedPassword)),
- misc:decode_base64(Scram#scram.storedkey) == StoredKey
- end.
-
export(_Server) ->
[{passwd,
fun(Host, #passwd{us = {LUser, LServer}, password = Password})
diff --git a/src/ejabberd_auth_pam.erl b/src/ejabberd_auth_pam.erl
index 9d2fc819b..f865f36f6 100644
--- a/src/ejabberd_auth_pam.erl
+++ b/src/ejabberd_auth_pam.erl
@@ -30,14 +30,8 @@
-behaviour(ejabberd_auth).
--export([start/1, stop/1, set_password/3, check_password/4,
- check_password/6, try_register/3,
- dirty_get_registered_users/0, get_vh_registered_users/1,
- get_vh_registered_users/2,
- get_vh_registered_users_number/1,
- get_vh_registered_users_number/2, get_password/2,
- get_password_s/2, is_user_exists/2, remove_user/2,
- remove_user/3, store_type/0, plain_password_required/0,
+-export([start/1, stop/1, check_password/4,
+ is_user_exists/2, store_type/1, plain_password_required/1,
opt_type/1]).
start(_Host) ->
@@ -46,13 +40,6 @@ start(_Host) ->
stop(_Host) ->
ok.
-set_password(_User, _Server, _Password) ->
- {error, not_allowed}.
-
-check_password(User, AuthzId, Server, Password, _Digest,
- _DigestGen) ->
- check_password(User, AuthzId, Server, Password).
-
check_password(User, AuthzId, Host, Password) ->
if AuthzId /= <<>> andalso AuthzId /= User ->
false;
@@ -70,25 +57,6 @@ check_password(User, AuthzId, Host, Password) ->
end
end.
-try_register(_User, _Server, _Password) ->
- {error, not_allowed}.
-
-dirty_get_registered_users() -> [].
-
-get_vh_registered_users(_Host) -> [].
-
-get_vh_registered_users(_Host, _) -> [].
-
-get_vh_registered_users_number(_Host) -> 0.
-
-get_vh_registered_users_number(_Host, _) -> 0.
-
-get_password(_User, _Server) -> false.
-
-get_password_s(_User, _Server) -> <<"">>.
-
-%% @spec (User, Server) -> true | false | {error, Error}
-%% TODO: Improve this function to return an error instead of 'false' when connection to PAM failed
is_user_exists(User, Host) ->
Service = get_pam_service(Host),
UserInfo = case get_pam_userinfotype(Host) of
@@ -97,16 +65,13 @@ is_user_exists(User, Host) ->
end,
case catch epam:acct_mgmt(Service, UserInfo) of
true -> true;
- _ -> false
+ false -> false;
+ _Err -> {error, db_failure}
end.
-remove_user(_User, _Server) -> {error, not_allowed}.
-
-remove_user(_User, _Server, _Password) -> not_allowed.
-
-plain_password_required() -> true.
+plain_password_required(_) -> true.
-store_type() -> external.
+store_type(_) -> external.
%%====================================================================
%% Internal functions
diff --git a/src/ejabberd_auth_riak.erl b/src/ejabberd_auth_riak.erl
index 74f0f73ca..fccaba102 100644
--- a/src/ejabberd_auth_riak.erl
+++ b/src/ejabberd_auth_riak.erl
@@ -32,15 +32,10 @@
-behaviour(ejabberd_auth).
%% External exports
--export([start/1, stop/1, set_password/3, check_password/4,
- check_password/6, try_register/3,
- dirty_get_registered_users/0, get_vh_registered_users/1,
- get_vh_registered_users/2,
- get_vh_registered_users_number/1,
- get_vh_registered_users_number/2, get_password/2,
- get_password_s/2, is_user_exists/2, remove_user/2,
- remove_user/3, store_type/0, export/1, import/2,
- plain_password_required/0]).
+-export([start/1, stop/1, set_password/3, try_register/3,
+ get_users/2, count_users/2,
+ get_password/2, remove_user/2, store_type/1, export/1, import/2,
+ plain_password_required/1]).
-export([passwd_schema/0]).
-include("ejabberd.hrl").
@@ -49,258 +44,65 @@
-record(passwd, {us = {<<"">>, <<"">>} :: {binary(), binary()} | '$1',
password = <<"">> :: binary() | scram() | '_'}).
--define(SALT_LENGTH, 16).
-
start(_Host) ->
ok.
stop(_Host) ->
ok.
-plain_password_required() ->
- case is_scrammed() of
- false -> false;
- true -> true
- end.
+plain_password_required(Server) ->
+ store_type(Server) == scram.
-store_type() ->
- case is_scrammed() of
- false -> plain; %% allows: PLAIN DIGEST-MD5 SCRAM
- true -> scram %% allows: PLAIN SCRAM
- end.
+store_type(Server) ->
+ ejabberd_auth:password_format(Server).
passwd_schema() ->
{record_info(fields, passwd), #passwd{}}.
-check_password(User, AuthzId, Server, Password) ->
- if AuthzId /= <<>> andalso AuthzId /= User ->
- false;
- true ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
- {ok, #passwd{password = Password}} when is_binary(Password) ->
- Password /= <<"">>;
- {ok, #passwd{password = Scram}} when is_record(Scram, scram) ->
- is_password_scram_valid(Password, Scram);
- _ ->
- false
- end
- end.
-
-check_password(User, AuthzId, Server, Password, Digest,
- DigestGen) ->
- if AuthzId /= <<>> andalso AuthzId /= User ->
- false;
- true ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
- {ok, #passwd{password = Passwd}} when is_binary(Passwd) ->
- DigRes = if Digest /= <<"">> ->
- Digest == DigestGen(Passwd);
- true -> false
- end,
- if DigRes -> true;
- true -> (Passwd == Password) and (Password /= <<"">>)
- end;
- {ok, #passwd{password = Scram}}
- when is_record(Scram, scram) ->
- Passwd = misc:decode_base64(Scram#scram.storedkey),
- DigRes = if Digest /= <<"">> ->
- Digest == DigestGen(Passwd);
- true -> false
- end,
- if DigRes -> true;
- true -> (Passwd == Password) and (Password /= <<"">>)
- end;
- _ -> false
- end
- end.
-
set_password(User, Server, Password) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- LPassword = jid:resourceprep(Password),
- US = {LUser, LServer},
- if (LUser == error) or (LServer == error) ->
- {error, invalid_jid};
- LPassword == error ->
- {error, invalid_password};
- true ->
- Password2 = case is_scrammed() and is_binary(Password)
- of
- true -> password_to_scram(Password);
- false -> Password
- end,
- ok = ejabberd_riak:put(#passwd{us = US, password = Password2},
- passwd_schema(),
- [{'2i', [{<<"host">>, LServer}]}])
- end.
-
-try_register(User, Server, PasswordList) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- Password = if is_list(PasswordList); is_binary(PasswordList) ->
- iolist_to_binary(PasswordList);
- true -> PasswordList
- end,
- LPassword = jid:resourceprep(Password),
- US = {LUser, LServer},
- if (LUser == error) or (LServer == error) ->
- {error, invalid_jid};
- LPassword == error and not is_record(Password, scram) ->
- {error, invalid_password};
- true ->
- case ejabberd_riak:get(passwd, passwd_schema(), US) of
- {error, notfound} ->
- Password2 = case is_scrammed() and
- is_binary(Password)
- of
- true -> password_to_scram(Password);
- false -> Password
- end,
- {atomic, ejabberd_riak:put(
- #passwd{us = US,
- password = Password2},
- passwd_schema(),
- [{'2i', [{<<"host">>, LServer}]}])};
- {ok, _} ->
- exists;
- Err ->
- {atomic, Err}
- end
+ ejabberd_riak:put(#passwd{us = {User, Server}, password = Password},
+ passwd_schema(),
+ [{'2i', [{<<"host">>, Server}]}]).
+
+try_register(User, Server, Password) ->
+ US = {User, Server},
+ case ejabberd_riak:get(passwd, passwd_schema(), US) of
+ {error, notfound} ->
+ ejabberd_riak:put(#passwd{us = US, password = Password},
+ passwd_schema(),
+ [{'2i', [{<<"host">>, Server}]}]);
+ {ok, _} ->
+ {error, exists};
+ {error, _} = Err ->
+ Err
end.
-dirty_get_registered_users() ->
- lists:flatmap(
- fun(Server) ->
- get_vh_registered_users(Server)
- end, ejabberd_config:get_vh_by_auth_method(riak)).
-
-get_vh_registered_users(Server) ->
- LServer = jid:nameprep(Server),
- case ejabberd_riak:get_keys_by_index(passwd, <<"host">>, LServer) of
+get_users(Server, _) ->
+ case ejabberd_riak:get_keys_by_index(passwd, <<"host">>, Server) of
{ok, Users} ->
Users;
_ ->
[]
end.
-get_vh_registered_users(Server, _) ->
- get_vh_registered_users(Server).
-
-get_vh_registered_users_number(Server) ->
- LServer = jid:nameprep(Server),
- case ejabberd_riak:count_by_index(passwd, <<"host">>, LServer) of
+count_users(Server, _) ->
+ case ejabberd_riak:count_by_index(passwd, <<"host">>, Server) of
{ok, N} ->
N;
_ ->
0
end.
-get_vh_registered_users_number(Server, _) ->
- get_vh_registered_users_number(Server).
-
get_password(User, Server) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
- {ok, #passwd{password = Password}}
- when is_binary(Password) ->
- Password;
- {ok, #passwd{password = Scram}}
- when is_record(Scram, scram) ->
- {misc:decode_base64(Scram#scram.storedkey),
- misc:decode_base64(Scram#scram.serverkey),
- misc:decode_base64(Scram#scram.salt),
- Scram#scram.iterationcount};
- _ -> false
- end.
-
-get_password_s(User, Server) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
- {ok, #passwd{password = Password}}
- when is_binary(Password) ->
- Password;
- {ok, #passwd{password = Scram}}
- when is_record(Scram, scram) ->
- <<"">>;
- _ -> <<"">>
- end.
-
-is_user_exists(User, Server) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
- {error, notfound} -> false;
- {ok, _} -> true;
- Err -> Err
+ case ejabberd_riak:get(passwd, passwd_schema(), {User, Server}) of
+ {ok, Password} ->
+ {ok, Password};
+ {error, _} ->
+ error
end.
remove_user(User, Server) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- ejabberd_riak:delete(passwd, {LUser, LServer}),
- ok.
-
-remove_user(User, Server, Password) ->
- LUser = jid:nodeprep(User),
- LServer = jid:nameprep(Server),
- case ejabberd_riak:get(passwd, passwd_schema(), {LUser, LServer}) of
- {ok, #passwd{password = Password}}
- when is_binary(Password) ->
- ejabberd_riak:delete(passwd, {LUser, LServer}),
- ok;
- {ok, #passwd{password = Scram}}
- when is_record(Scram, scram) ->
- case is_password_scram_valid(Password, Scram) of
- true ->
- ejabberd_riak:delete(passwd, {LUser, LServer}),
- ok;
- false -> not_allowed
- end;
- _ -> not_exists
- end.
-
-%%%
-%%% SCRAM
-%%%
-
-is_scrammed() ->
- scram == ejabberd_auth:password_format(?MYNAME).
-
-password_to_scram(Password) ->
- password_to_scram(Password,
- ?SCRAM_DEFAULT_ITERATION_COUNT).
-
-password_to_scram(Password, IterationCount) ->
- Salt = randoms:bytes(?SALT_LENGTH),
- SaltedPassword = scram:salted_password(Password, Salt,
- IterationCount),
- StoredKey =
- scram:stored_key(scram:client_key(SaltedPassword)),
- ServerKey = scram:server_key(SaltedPassword),
- #scram{storedkey = misc:encode_base64(StoredKey),
- serverkey = misc:encode_base64(ServerKey),
- salt = misc:encode_base64(Salt),
- iterationcount = IterationCount}.
-
-is_password_scram_valid(Password, Scram) ->
- case jid:resourceprep(Password) of
- error ->
- false;
- _ ->
- IterationCount = Scram#scram.iterationcount,
- Salt = misc:decode_base64(Scram#scram.salt),
- SaltedPassword = scram:salted_password(Password, Salt,
- IterationCount),
- StoredKey =
- scram:stored_key(scram:client_key(SaltedPassword)),
- misc:decode_base64(Scram#scram.storedkey) == StoredKey
- end.
+ ejabberd_riak:delete(passwd, {User, Server}).
export(_Server) ->
[{passwd,
diff --git a/src/ejabberd_auth_sql.erl b/src/ejabberd_auth_sql.erl
index 8514b9cf1..d682634f0 100644
--- a/src/ejabberd_auth_sql.erl
+++ b/src/ejabberd_auth_sql.erl
@@ -31,14 +31,9 @@
-behaviour(ejabberd_auth).
--export([start/1, stop/1, set_password/3, check_password/4,
- check_password/6, try_register/3,
- dirty_get_registered_users/0, get_vh_registered_users/1,
- get_vh_registered_users/2,
- get_vh_registered_users_number/1,
- get_vh_registered_users_number/2, get_password/2,
- get_password_s/2, is_user_exists/2, remove_user/2,
- remove_user/3, store_type/0, plain_password_required/0,
+-export([start/1, stop/1, set_password/3, try_register/3,
+ get_users/2, count_users/2, get_password/2,
+ remove_user/2, store_type/1, plain_password_required/1,
convert_to_scram/1]).
-include("ejabberd.hrl").
@@ -54,397 +49,82 @@ start(_Host) -> ok.
stop(_Host) -> ok.
-plain_password_required() ->
- case is_scrammed() of
- false -> false;
- true -> true
- end.
-
-store_type() ->
- case is_scrammed() of
- false -> plain; %% allows: PLAIN DIGEST-MD5 SCRAM
- true -> scram %% allows: PLAIN SCRAM
- end.
+plain_password_required(Server) ->
+ store_type(Server) == scram.
-%% @spec (User, AuthzId, Server, Password) -> true | false | {error, Error}
-check_password(User, AuthzId, Server, Password) ->
- if AuthzId /= <<>> andalso AuthzId /= User ->
- false;
- true ->
- LServer = jid:nameprep(Server),
- LUser = jid:nodeprep(User),
- if (LUser == error) or (LServer == error) ->
- false;
- (LUser == <<>>) or (LServer == <<>>) ->
- false;
- true ->
- case is_scrammed() of
- true ->
- try sql_queries:get_password_scram(LServer, LUser) of
- {selected,
- [{StoredKey, ServerKey, Salt, IterationCount}]} ->
- Scram =
- #scram{storedkey = StoredKey,
- serverkey = ServerKey,
- salt = Salt,
- iterationcount = IterationCount},
- is_password_scram_valid_stored(Password, Scram, LUser, LServer);
- {selected, []} ->
- false; %% Account does not exist
- {error, _Error} ->
- false %% Typical error is that table doesn't exist
- catch
- _:_ ->
- false %% Typical error is database not accessible
- end;
- false ->
- try sql_queries:get_password(LServer, LUser) of
- {selected, [{Password}]} ->
- Password /= <<"">>;
- {selected, [{_Password2}]} ->
- false; %% Password is not correct
- {selected, []} ->
- false; %% Account does not exist
- {error, _Error} ->
- false %% Typical error is that table doesn't exist
- catch
- _:_ ->
- false %% Typical error is database not accessible
- end
- end
- end
- end.
+store_type(Server) ->
+ ejabberd_auth:password_format(Server).
-%% @spec (User, AuthzId, Server, Password, Digest, DigestGen) -> true | false | {error, Error}
-check_password(User, AuthzId, Server, Password, Digest,
- DigestGen) ->
- if AuthzId /= <<>> andalso AuthzId /= User ->
- false;
- true ->
- LServer = jid:nameprep(Server),
- LUser = jid:nodeprep(User),
- if (LUser == error) or (LServer == error) ->
- false;
- (LUser == <<>>) or (LServer == <<>>) ->
- false;
- true ->
- case is_scrammed() of
- false ->
- try sql_queries:get_password(LServer, LUser) of
- %% Account exists, check if password is valid
- {selected, [{Passwd}]} ->
- DigRes = if Digest /= <<"">> ->
- Digest == DigestGen(Passwd);
- true -> false
- end,
- if DigRes -> true;
- true -> (Passwd == Password) and (Password /= <<"">>)
- end;
- {selected, []} ->
- false; %% Account does not exist
- {error, _Error} ->
- false %% Typical error is that table doesn't exist
- catch
- _:_ ->
- false %% Typical error is database not accessible
- end;
- true ->
- false
- end
- end
- end.
-
-%% @spec (User::string(), Server::string(), Password::string()) ->
-%% ok | {error, invalid_jid}
set_password(User, Server, Password) ->
- LServer = jid:nameprep(Server),
- LUser = jid:nodeprep(User),
- LPassword = jid:resourceprep(Password),
- if (LUser == error) or (LServer == error) ->
- {error, invalid_jid};
- (LUser == <<>>) or (LServer == <<>>) ->
- {error, invalid_jid};
- LPassword == error ->
- {error, invalid_password};
- true ->
- case is_scrammed() of
- true ->
- Scram = password_to_scram(Password),
- case catch sql_queries:set_password_scram_t(
- LServer,
- LUser,
- Scram#scram.storedkey,
- Scram#scram.serverkey,
- Scram#scram.salt,
- Scram#scram.iterationcount
- )
- of
- {atomic, ok} -> ok;
- Other -> {error, Other}
- end;
- false ->
- case catch sql_queries:set_password_t(LServer,
- LUser, Password)
- of
- {atomic, ok} -> ok;
- Other -> {error, Other}
- end
- end
+ Res = if is_record(Password, scram) ->
+ sql_queries:set_password_scram_t(
+ Server, User,
+ Password#scram.storedkey, Password#scram.serverkey,
+ Password#scram.salt, Password#scram.iterationcount);
+ true ->
+ sql_queries:set_password_t(Server, User, Password)
+ end,
+ case Res of
+ {atomic, _} ->
+ ok;
+ {aborted, Reason} ->
+ ?ERROR_MSG("failed to write to SQL table: ~p", [Reason]),
+ {error, db_failure}
end.
-%% @spec (User, Server, Password) -> {atomic, ok} | {atomic, exists} | {error, invalid_jid}
try_register(User, Server, Password) ->
- LServer = jid:nameprep(Server),
- LUser = jid:nodeprep(User),
- LPassword = jid:resourceprep(Password),
- if (LUser == error) or (LServer == error) ->
- {error, invalid_jid};
- (LUser == <<>>) or (LServer == <<>>) ->
- {error, invalid_jid};
- LPassword == error and not is_record(Password, scram) ->
- {error, invalid_password};
- true ->
- case is_scrammed() of
- true ->
- Scram = case is_record(Password, scram) of
- true -> Password;
- false -> password_to_scram(Password)
- end,
- case catch sql_queries:add_user_scram(
- LServer,
- LUser,
- Scram#scram.storedkey,
- Scram#scram.serverkey,
- Scram#scram.salt,
- Scram#scram.iterationcount
- ) of
- {updated, 1} -> {atomic, ok};
- _ -> {atomic, exists}
- end;
- false ->
- case catch sql_queries:add_user(LServer, LUser,
- Password) of
- {updated, 1} -> {atomic, ok};
- _ -> {atomic, exists}
- end
- end
+ Res = if is_record(Password, scram) ->
+ sql_queries:add_user_scram(
+ Server, User,
+ Password#scram.storedkey, Password#scram.serverkey,
+ Password#scram.salt, Password#scram.iterationcount);
+ true ->
+ sql_queries:add_user(Server, User, Password)
+ end,
+ case Res of
+ {updated, 1} -> ok;
+ _ -> {error, exists}
end.
-dirty_get_registered_users() ->
- Servers = ejabberd_config:get_vh_by_auth_method(sql),
- lists:flatmap(fun (Server) ->
- get_vh_registered_users(Server)
- end,
- Servers).
-
-get_vh_registered_users(Server) ->
- case jid:nameprep(Server) of
- error -> [];
- <<>> -> [];
- LServer ->
- case catch sql_queries:list_users(LServer) of
- {selected, Res} ->
- [{U, LServer} || {U} <- Res];
- _ -> []
- end
+get_users(Server, Opts) ->
+ case sql_queries:list_users(Server, Opts) of
+ {selected, Res} ->
+ [{U, Server} || {U} <- Res];
+ _ -> []
end.
-get_vh_registered_users(Server, Opts) ->
- case jid:nameprep(Server) of
- error -> [];
- <<>> -> [];
- LServer ->
- case catch sql_queries:list_users(LServer, Opts) of
- {selected, Res} ->
- [{U, LServer} || {U} <- Res];
- _ -> []
- end
- end.
-
-get_vh_registered_users_number(Server) ->
- case jid:nameprep(Server) of
- error -> 0;
- <<>> -> 0;
- LServer ->
- case catch sql_queries:users_number(LServer) of
- {selected, [{Res}]} ->
- Res;
- _ -> 0
- end
- end.
-
-get_vh_registered_users_number(Server, Opts) ->
- case jid:nameprep(Server) of
- error -> 0;
- <<>> -> 0;
- LServer ->
- case catch sql_queries:users_number(LServer, Opts) of
- {selected, [{Res}]} ->
- Res;
- _Other -> 0
- end
+count_users(Server, Opts) ->
+ case sql_queries:users_number(Server, Opts) of
+ {selected, [{Res}]} ->
+ Res;
+ _Other -> 0
end.
get_password(User, Server) ->
- LServer = jid:nameprep(Server),
- LUser = jid:nodeprep(User),
- if (LUser == error) or (LServer == error) ->
- false;
- (LUser == <<>>) or (LServer == <<>>) ->
- false;
- true ->
- case is_scrammed() of
- true ->
- case catch sql_queries:get_password_scram(
- LServer, LUser) of
- {selected,
- [{StoredKey, ServerKey, Salt, IterationCount}]} ->
- {misc:decode_base64(StoredKey),
- misc:decode_base64(ServerKey),
- misc:decode_base64(Salt),
- IterationCount};
- _ -> false
- end;
- false ->
- case catch sql_queries:get_password(LServer, LUser)
- of
- {selected, [{Password}]} -> Password;
- _ -> false
- end
- end
- end.
-
-get_password_s(User, Server) ->
- LServer = jid:nameprep(Server),
- LUser = jid:nodeprep(User),
- if (LUser == error) or (LServer == error) ->
- <<"">>;
- (LUser == <<>>) or (LServer == <<>>) ->
- <<"">>;
- true ->
- case is_scrammed() of
- false ->
- case catch sql_queries:get_password(LServer, LUser) of
- {selected, [{Password}]} -> Password;
- _ -> <<"">>
- end;
- true -> <<"">>
- end
+ case sql_queries:get_password_scram(Server, User) of
+ {selected, [{Password, <<>>, <<>>, 0}]} ->
+ {ok, Password};
+ {selected, [{StoredKey, ServerKey, Salt, IterationCount}]} ->
+ {ok, #scram{storedkey = StoredKey,
+ serverkey = ServerKey,
+ salt = Salt,
+ iterationcount = IterationCount}};
+ {selected, []} ->
+ error;
+ Err ->
+ ?ERROR_MSG("Failed to read password for user ~s@~s: ~p",
+ [User, Server, Err]),
+ error
end.
-%% @spec (User, Server) -> true | false | {error, Error}
-is_user_exists(User, Server) ->
- LServer = jid:nameprep(Server),
- LUser = jid:nodeprep(User),
- if (LUser == error) or (LServer == error) ->
- false;
- (LUser == <<>>) or (LServer == <<>>) ->
- false;
- true ->
- try sql_queries:get_password(LServer, LUser) of
- {selected, [{_Password}]} ->
- true; %% Account exists
- {selected, []} ->
- false; %% Account does not exist
- {error, Error} -> {error, Error}
- catch
- _:B -> {error, B}
- end
- end.
-
-%% @spec (User, Server) -> ok | error
-%% @doc Remove user.
-%% Note: it may return ok even if there was some problem removing the user.
remove_user(User, Server) ->
- LServer = jid:nameprep(Server),
- LUser = jid:nodeprep(User),
- if (LUser == error) or (LServer == error) ->
- error;
- (LUser == <<>>) or (LServer == <<>>) ->
- error;
- true ->
- catch sql_queries:del_user(LServer, LUser),
- ok
- end.
-
-%% @spec (User, Server, Password) -> ok | error | not_exists | not_allowed
-%% @doc Remove user if the provided password is correct.
-remove_user(User, Server, Password) ->
- LServer = jid:nameprep(Server),
- LUser = jid:nodeprep(User),
- if (LUser == error) or (LServer == error) ->
- error;
- (LUser == <<>>) or (LServer == <<>>) ->
- error;
- true ->
- case is_scrammed() of
- true ->
- case check_password(User, <<"">>, Server, Password) of
- true ->
- remove_user(User, Server),
- ok;
- false -> not_allowed
- end;
- false ->
- F = fun () ->
- Result = sql_queries:del_user_return_password(
- LServer, LUser, Password),
- case Result of
- {selected, [{Password}]} -> ok;
- {selected, []} -> not_exists;
- _ -> not_allowed
- end
- end,
- {atomic, Result} = sql_queries:sql_transaction(
- LServer, F),
- Result
- end
- end.
-
-%%%
-%%% SCRAM
-%%%
-
-is_scrammed() ->
- scram == ejabberd_auth:password_format(?MYNAME).
-
-password_to_scram(Password) ->
- password_to_scram(Password,
- ?SCRAM_DEFAULT_ITERATION_COUNT).
-
-password_to_scram(Password, IterationCount) ->
- Salt = randoms:bytes(?SALT_LENGTH),
- SaltedPassword = scram:salted_password(Password, Salt,
- IterationCount),
- StoredKey =
- scram:stored_key(scram:client_key(SaltedPassword)),
- ServerKey = scram:server_key(SaltedPassword),
- #scram{storedkey = misc:encode_base64(StoredKey),
- serverkey = misc:encode_base64(ServerKey),
- salt = misc:encode_base64(Salt),
- iterationcount = IterationCount}.
-
-is_password_scram_valid_stored(Pass, {scram,Pass,<<>>,<<>>,0}, LUser, LServer) ->
- ?INFO_MSG("Apparently, SQL auth method and scram password formatting are "
- "enabled, but the password of user '~s' in the 'users' table is not "
- "scrammed. You may want to execute this command: "
- "ejabberdctl convert_to_scram ~s", [LUser, LServer]),
- false;
-is_password_scram_valid_stored(Password, Scram, _, _) ->
- is_password_scram_valid(Password, Scram).
-
-is_password_scram_valid(Password, Scram) ->
- case jid:resourceprep(Password) of
- error ->
- false;
- _ ->
- IterationCount = Scram#scram.iterationcount,
- Salt = misc:decode_base64(Scram#scram.salt),
- SaltedPassword = scram:salted_password(Password, Salt,
- IterationCount),
- StoredKey =
- scram:stored_key(scram:client_key(SaltedPassword)),
- misc:decode_base64(Scram#scram.storedkey) == StoredKey
+ case sql_queries:del_user(Server, User) of
+ {updated, _} ->
+ ok;
+ Err ->
+ ?ERROR_MSG("failed to delete user ~s@~s: ~p",
+ [User, Server, Err]),
+ {error, db_failure}
end.
-define(BATCH_SIZE, 1000).
@@ -485,7 +165,7 @@ convert_to_scram(Server) ->
"password of user ~s@~s",
[LUser, LServer]);
_ ->
- Scram = password_to_scram(Password),
+ Scram = ejabberd_auth:password_to_scram(Password),
set_password_scram_t(
LUser,
Scram#scram.storedkey,
diff --git a/src/ejabberd_piefxis.erl b/src/ejabberd_piefxis.erl
index aea280591..ecb4908a7 100644
--- a/src/ejabberd_piefxis.erl
+++ b/src/ejabberd_piefxis.erl
@@ -135,7 +135,7 @@ export_host(Dir, FnH, Host) ->
{ok, Fd} ->
print(Fd, make_piefxis_xml_head()),
print(Fd, make_piefxis_host_head(Host)),
- Users = ejabberd_auth:get_vh_registered_users(Host),
+ Users = ejabberd_auth:get_users(Host),
case export_users(Users, Host, Fd) of
ok ->
print(Fd, make_piefxis_host_tail()),
@@ -402,9 +402,9 @@ process_user(#xmlel{name = <<"user">>, attrs = Attrs, children = Els},
stop("Invalid 'user': ~s", [Name]);
LUser ->
case ejabberd_auth:try_register(LUser, LServer, Pass) of
- {atomic, _} ->
+ ok ->
process_user_els(Els, State#state{user = LUser});
- Err ->
+ {error, Err} ->
stop("Failed to create user '~s': ~p", [Name, Err])
end
end.
diff --git a/src/ejabberd_web_admin.erl b/src/ejabberd_web_admin.erl
index 5050ac095..6fdac1971 100644
--- a/src/ejabberd_web_admin.erl
+++ b/src/ejabberd_web_admin.erl
@@ -1370,7 +1370,7 @@ list_vhosts2(Lang, Hosts) ->
OnlineUsers =
length(ejabberd_sm:get_vh_session_list(Host)),
RegisteredUsers =
- ejabberd_auth:get_vh_registered_users_number(Host),
+ ejabberd_auth:count_users(Host),
?XE(<<"tr">>,
[?XE(<<"td">>,
[?AC(<<"../server/", Host/binary,
@@ -1388,7 +1388,7 @@ list_vhosts2(Lang, Hosts) ->
list_users(Host, Query, Lang, URLFunc) ->
Res = list_users_parse_query(Query, Host),
- Users = ejabberd_auth:get_vh_registered_users(Host),
+ Users = ejabberd_auth:get_users(Host),
SUsers = lists:sort([{S, U} || {U, S} <- Users]),
FUsers = case length(SUsers) of
N when N =< 100 ->
@@ -1469,7 +1469,7 @@ list_users_parse_query(Query, Host) ->
end.
list_users_in_diapason(Host, Diap, Lang, URLFunc) ->
- Users = ejabberd_auth:get_vh_registered_users(Host),
+ Users = ejabberd_auth:get_users(Host),
SUsers = lists:sort([{S, U} || {U, S} <- Users]),
[S1, S2] = ejabberd_regexp:split(Diap, <<"-">>),
N1 = binary_to_integer(S1),
@@ -1565,7 +1565,7 @@ su_to_list({Server, User}) ->
get_stats(global, Lang) ->
OnlineUsers = ejabberd_sm:connected_users_number(),
RegisteredUsers = lists:foldl(fun (Host, Total) ->
- ejabberd_auth:get_vh_registered_users_number(Host)
+ ejabberd_auth:count_users(Host)
+ Total
end,
0, ?MYHOSTS),
@@ -1589,7 +1589,7 @@ get_stats(Host, Lang) ->
OnlineUsers =
length(ejabberd_sm:get_vh_session_list(Host)),
RegisteredUsers =
- ejabberd_auth:get_vh_registered_users_number(Host),
+ ejabberd_auth:count_users(Host),
[?XAE(<<"table">>, [],
[?XE(<<"tbody">>,
[?XE(<<"tr">>,
diff --git a/src/extauth.erl b/src/extauth.erl
index 54f44953c..70f32bf8f 100644
--- a/src/extauth.erl
+++ b/src/extauth.erl
@@ -83,7 +83,7 @@ try_register(User, Server, Password) ->
case call_port(Server,
[<<"tryregister">>, User, Server, Password])
of
- true -> {atomic, ok};
+ true -> ok;
false -> {error, not_allowed}
end.
diff --git a/src/mod_admin_extra.erl b/src/mod_admin_extra.erl
index 133b2fd29..982772af0 100644
--- a/src/mod_admin_extra.erl
+++ b/src/mod_admin_extra.erl
@@ -810,14 +810,14 @@ histogram([], _Integral, _Current, Count, Hist) ->
delete_old_users(Days) ->
%% Get the list of registered users
- Users = ejabberd_auth:dirty_get_registered_users(),
+ Users = ejabberd_auth:get_users(),
{removed, N, UR} = delete_old_users(Days, Users),
{ok, io_lib:format("Deleted ~p users: ~p", [N, UR])}.
delete_old_users_vhost(Host, Days) ->
%% Get the list of registered users
- Users = ejabberd_auth:get_vh_registered_users(Host),
+ Users = ejabberd_auth:get_users(Host),
{removed, N, UR} = delete_old_users(Days, Users),
{ok, io_lib:format("Deleted ~p users: ~p", [N, UR])}.
@@ -1285,7 +1285,7 @@ subscribe_roster({Name1, Server1, Group1, Nick1}, [{Name2, Server2, Group2, Nick
subscribe_roster({Name1, Server1, Group1, Nick1}, Roster).
push_alltoall(S, G) ->
- Users = ejabberd_auth:get_vh_registered_users(S),
+ Users = ejabberd_auth:get_users(S),
Users2 = build_list_users(G, Users, []),
subscribe_all(Users2),
ok.
@@ -1499,14 +1499,14 @@ stats(Name) ->
case Name of
<<"uptimeseconds">> -> trunc(element(1, erlang:statistics(wall_clock))/1000);
<<"processes">> -> length(erlang:processes());
- <<"registeredusers">> -> lists:foldl(fun(Host, Sum) -> ejabberd_auth:get_vh_registered_users_number(Host) + Sum end, 0, ?MYHOSTS);
+ <<"registeredusers">> -> lists:foldl(fun(Host, Sum) -> ejabberd_auth:count_users(Host) + Sum end, 0, ?MYHOSTS);
<<"onlineusersnode">> -> length(ejabberd_sm:dirty_get_my_sessions_list());
<<"onlineusers">> -> length(ejabberd_sm:dirty_get_sessions_list())
end.
stats(Name, Host) ->
case Name of
- <<"registeredusers">> -> ejabberd_auth:get_vh_registered_users_number(Host);
+ <<"registeredusers">> -> ejabberd_auth:count_users(Host);
<<"onlineusers">> -> length(ejabberd_sm:get_vh_session_list(Host))
end.
diff --git a/src/mod_announce.erl b/src/mod_announce.erl
index 35d179c0c..379cd3ca0 100644
--- a/src/mod_announce.erl
+++ b/src/mod_announce.erl
@@ -633,7 +633,7 @@ announce_all(#message{to = To} = Packet) ->
Dest = jid:make(User, Server),
ejabberd_router:route(
xmpp:set_from_to(add_store_hint(Packet), Local, Dest))
- end, ejabberd_auth:get_vh_registered_users(To#jid.lserver)).
+ end, ejabberd_auth:get_users(To#jid.lserver)).
announce_all_hosts_all(#message{to = To} = Packet) ->
Local = jid:make(To#jid.server),
@@ -642,7 +642,7 @@ announce_all_hosts_all(#message{to = To} = Packet) ->
Dest = jid:make(User, Server),
ejabberd_router:route(
xmpp:set_from_to(add_store_hint(Packet), Local, Dest))
- end, ejabberd_auth:dirty_get_registered_users()).
+ end, ejabberd_auth:get_users()).
announce_online(#message{to = To} = Packet) ->
announce_online1(ejabberd_sm:get_vh_session_list(To#jid.lserver),
diff --git a/src/mod_configure.erl b/src/mod_configure.erl
index b9db1e511..f3eb496d8 100644
--- a/src/mod_configure.erl
+++ b/src/mod_configure.erl
@@ -547,7 +547,7 @@ get_local_items({_, Host}, [<<"all users">>], _Server,
get_local_items({_, Host},
[<<"all users">>, <<$@, Diap/binary>>], _Server,
_Lang) ->
- Users = ejabberd_auth:get_vh_registered_users(Host),
+ Users = ejabberd_auth:get_users(Host),
SUsers = lists:sort([{S, U} || {U, S} <- Users]),
try
[S1, S2] = ejabberd_regexp:split(Diap, <<"-">>),
@@ -661,7 +661,7 @@ get_online_vh_users(Host) ->
end.
get_all_vh_users(Host) ->
- case catch ejabberd_auth:get_vh_registered_users(Host)
+ case catch ejabberd_auth:get_users(Host)
of
{'EXIT', _Reason} -> [];
Users ->
@@ -1194,7 +1194,7 @@ get_form(_Host, ?NS_ADMINL(<<"user-stats">>), Lang) ->
required = true}]}};
get_form(Host,
?NS_ADMINL(<<"get-registered-users-num">>), Lang) ->
- Num = integer_to_binary(ejabberd_auth:get_vh_registered_users_number(Host)),
+ Num = integer_to_binary(ejabberd_auth:count_users(Host)),
{result, completed,
#xdata{type = form,
fields = [?HFIELD(),
diff --git a/src/mod_register.erl b/src/mod_register.erl
index af4ba02f4..5167370c1 100644
--- a/src/mod_register.erl
+++ b/src/mod_register.erl
@@ -323,7 +323,7 @@ try_register(User, Server, Password, SourceRaw, Lang) ->
case ejabberd_auth:try_register(User, Server,
Password)
of
- {atomic, ok} ->
+ ok ->
send_welcome_message(JID),
send_registration_notifications(
?MODULE, JID, Source),
@@ -331,7 +331,7 @@ try_register(User, Server, Password, SourceRaw, Lang) ->
Error ->
remove_timeout(Source),
case Error of
- {atomic, exists} ->
+ {error, exists} ->
Txt = <<"User already exists">>,
{error, xmpp:err_conflict(Txt, Lang)};
{error, invalid_jid} ->
diff --git a/src/mod_register_web.erl b/src/mod_register_web.erl
index cd19bb65a..d5e4112c3 100644
--- a/src/mod_register_web.erl
+++ b/src/mod_register_web.erl
@@ -510,8 +510,8 @@ register_account2(Username, Host, Password) ->
case ejabberd_auth:try_register(Username, Host,
Password)
of
- {atomic, Res} ->
- {success, Res, {Username, Host, Password}};
+ ok ->
+ {success, ok, {Username, Host, Password}};
Other -> Other
end.
diff --git a/src/mod_shared_roster.erl b/src/mod_shared_roster.erl
index 67b5870a2..c25b13f66 100644
--- a/src/mod_shared_roster.erl
+++ b/src/mod_shared_roster.erl
@@ -450,7 +450,7 @@ get_online_users(Host) ->
get_group_users(Host1, Group1) ->
{Host, Group} = split_grouphost(Host1, Group1),
case get_group_opt(Host, Group, all_users, false) of
- true -> ejabberd_auth:get_vh_registered_users(Host);
+ true -> ejabberd_auth:get_users(Host);
false -> []
end
++
@@ -462,7 +462,7 @@ get_group_users(Host1, Group1) ->
get_group_users(Host, Group, GroupOpts) ->
case proplists:get_value(all_users, GroupOpts, false) of
- true -> ejabberd_auth:get_vh_registered_users(Host);
+ true -> ejabberd_auth:get_users(Host);
false -> []
end
++
diff --git a/src/mod_stats.erl b/src/mod_stats.erl
index 92a6627c5..2bdbdbd33 100644
--- a/src/mod_stats.erl
+++ b/src/mod_stats.erl
@@ -119,7 +119,7 @@ get_local_stat(Server, [], Name)
get_local_stat(Server, [], Name)
when Name == <<"users/total">> ->
case catch
- ejabberd_auth:get_vh_registered_users_number(Server)
+ ejabberd_auth:count_users(Server)
of
{'EXIT', _Reason} ->
?STATERR(500, <<"Internal Server Error">>);
@@ -134,7 +134,7 @@ get_local_stat(_Server, [], Name)
get_local_stat(_Server, [], Name)
when Name == <<"users/all-hosts/total">> ->
NumUsers = lists:foldl(fun (Host, Total) ->
- ejabberd_auth:get_vh_registered_users_number(Host)
+ ejabberd_auth:count_users(Host)
+ Total
end,
0, ?MYHOSTS),
diff --git a/src/prosody2ejabberd.erl b/src/prosody2ejabberd.erl
index 17bbc1d0a..f575724c6 100644
--- a/src/prosody2ejabberd.erl
+++ b/src/prosody2ejabberd.erl
@@ -129,7 +129,7 @@ convert_data(Host, "accounts", User, [Data]) ->
Pass
end,
case ejabberd_auth:try_register(User, Host, Password) of
- {atomic, ok} ->
+ ok ->
ok;
Err ->
?ERROR_MSG("failed to register user ~s@~s: ~p",
diff --git a/test/suite.erl b/test/suite.erl
index 76be5f806..6bd96002a 100644
--- a/test/suite.erl
+++ b/test/suite.erl
@@ -468,8 +468,7 @@ re_register(Config) ->
User = ?config(user, Config),
Server = ?config(server, Config),
Pass = ?config(password, Config),
- {atomic, ok} = ejabberd_auth:try_register(User, Server, Pass),
- ok.
+ ok = ejabberd_auth:try_register(User, Server, Pass).
match_failure(Received, [Match]) when is_list(Match)->
ct:fail("Received input:~n~n~p~n~ndon't match expected patterns:~n~n~s", [Received, Match]);