Update to work with ejabberd 15.06

This commit is contained in:
Badlop 2015-06-26 17:52:51 +02:00
parent db91c97614
commit 6d655af0c4
2 changed files with 52 additions and 31 deletions

View File

@ -10,6 +10,8 @@
-behaviour(ejabberd_gen_auth). -behaviour(ejabberd_gen_auth).
-behaviour(ejabberd_config).
%% External exports %% External exports
-export([start/1, -export([start/1,
set_password/3, set_password/3,
@ -23,30 +25,34 @@
get_vh_registered_users_number/2, get_vh_registered_users_number/2,
get_password/2, get_password/2,
get_password_s/2, get_password_s/2,
does_user_exist/2, is_user_exists/2,
remove_user/2, remove_user/2,
remove_user/3, remove_user/3,
plain_password_required/0, plain_password_required/0,
store_type/1, store_type/1,
login/2, login/2,
get_password/3, get_password/3,
opt_type/1,
stop/1]). stop/1]).
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("logger.hrl").
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
%%% API %%% API
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
opt_type(auth_opts) -> fun (V) -> V end;
opt_type(_) -> [auth_opts].
-spec start(binary()) -> ok. -spec start(binary()) -> ok.
start(Host) -> start(Host) ->
AuthOpts = ejabberd_config:get_local_option(auth_opts, Host), AuthOpts = ejabberd_config:get_option({auth_opts, Host}, fun(V) -> V end),
{_, AuthHost} = lists:keyfind(host, 1, AuthOpts), {_, AuthHost} = lists:keyfind(host, 1, AuthOpts),
PoolSize = proplists:get_value(connection_pool_size, AuthOpts, 10), PoolSize = proplists:get_value(connection_pool_size, AuthOpts, 10),
Opts = proplists:get_value(connection_opts, AuthOpts, []), Opts = proplists:get_value(connection_opts, AuthOpts, []),
ChildMods = [fusco], ChildMods = [fusco],
ChildMFA = {fusco, start_link, [AuthHost, Opts]}, ChildMFA = {fusco, start_link, [binary_to_list(AuthHost), Opts]},
{ok, _} = supervisor:start_child(ejabberd_sup, {ok, _} = supervisor:start_child(ejabberd_sup,
{{ejabberd_auth_http_sup, Host}, {{ejabberd_auth_http_sup, Host},
@ -61,14 +67,14 @@ plain_password_required() ->
-spec store_type(binary()) -> plain | scram. -spec store_type(binary()) -> plain | scram.
store_type(Server) -> store_type(Server) ->
case scram:enabled(Server) of case scram2:enabled(Server) of
false -> plain; false -> plain;
true -> scram true -> scram
end. end.
-spec check_password(ejabberd:luser(), ejabberd:lserver(), binary()) -> boolean(). -spec check_password(ejabberd:luser(), ejabberd:lserver(), binary()) -> boolean().
check_password(LUser, LServer, Password) -> check_password(LUser, LServer, Password) ->
case scram:enabled(LServer) of case scram2:enabled(LServer) of
false -> false ->
case make_req(get, <<"check_password">>, LUser, LServer, Password) of case make_req(get, <<"check_password">>, LUser, LServer, Password) of
{ok, <<"true">>} -> true; {ok, <<"true">>} -> true;
@ -84,24 +90,39 @@ check_password(LUser, LServer, Password, Digest, DigestGen) ->
{error, _} -> {error, _} ->
false; false;
{ok, GotPasswd} -> {ok, GotPasswd} ->
case scram:enabled(LServer) of case scram2:enabled(LServer) of
true -> true ->
case scram:deserialize(GotPasswd) of case scram2:deserialize(GotPasswd) of
{ok, #scram{} = Scram} -> {ok, #scram{} = Scram} ->
scram:check_digest(Scram, Digest, DigestGen, Password); scram2:check_digest(Scram, Digest, DigestGen, Password);
_ -> _ ->
false false
end; end;
false -> false ->
ejabberd_auth:check_digest(Digest, DigestGen, Password, GotPasswd) check_digest(Digest, DigestGen, Password, GotPasswd)
end end
end. end.
-spec check_digest(binary(), fun(), binary(), binary()) -> boolean().
check_digest(Digest, DigestGen, Password, Passwd) ->
DigRes = if
Digest /= <<>> ->
Digest == DigestGen(Passwd);
true ->
false
end,
if DigRes ->
true;
true ->
(Passwd == Password) and (Password /= <<>>)
end.
-spec set_password(ejabberd:luser(), ejabberd:lserver(), binary()) -> ok | {error, term()}. -spec set_password(ejabberd:luser(), ejabberd:lserver(), binary()) -> ok | {error, term()}.
set_password(LUser, LServer, Password) -> set_password(LUser, LServer, Password) ->
PasswordFinal = case scram:enabled(LServer) of PasswordFinal = case scram2:enabled(LServer) of
true -> scram:serialize(scram:password_to_scram( true -> scram2:serialize(scram2:password_to_scram(
Password, scram:iterations(LServer))); Password, scram2:iterations(LServer)));
false -> Password false -> Password
end, end,
case make_req(post, <<"set_password">>, LUser, LServer, PasswordFinal) of case make_req(post, <<"set_password">>, LUser, LServer, PasswordFinal) of
@ -111,9 +132,9 @@ set_password(LUser, LServer, Password) ->
-spec try_register(ejabberd:luser(), ejabberd:lserver(), binary()) -> {atomic, ok | exists} | {error, term()}. -spec try_register(ejabberd:luser(), ejabberd:lserver(), binary()) -> {atomic, ok | exists} | {error, term()}.
try_register(LUser, LServer, Password) -> try_register(LUser, LServer, Password) ->
PasswordFinal = case scram:enabled(LServer) of PasswordFinal = case scram2:enabled(LServer) of
true -> scram:serialize(scram:password_to_scram( true -> scram2:serialize(scram2:password_to_scram(
Password, scram:iterations(LServer))); Password, scram2:iterations(LServer)));
false -> Password false -> Password
end, end,
case make_req(post, <<"register">>, LUser, LServer, PasswordFinal) of case make_req(post, <<"register">>, LUser, LServer, PasswordFinal) of
@ -149,11 +170,11 @@ get_password(LUser, LServer) ->
{error, _} -> {error, _} ->
false; false;
{ok, Password} -> {ok, Password} ->
case scram:enabled(LServer) of case scram2:enabled(LServer) of
true -> true ->
case scram:deserialize(Password) of case scram2:deserialize(Password) of
{ok, #scram{} = Scram} -> {ok, #scram{} = Scram} ->
scram:scram_to_tuple(Scram); scram2:scram_to_tuple(Scram);
_ -> _ ->
false false
end; end;
@ -169,8 +190,8 @@ get_password_s(User, Server) ->
_ -> <<>> _ -> <<>>
end. end.
-spec does_user_exist(ejabberd:luser(), ejabberd:lserver()) -> boolean(). -spec is_user_exists(ejabberd:luser(), ejabberd:lserver()) -> boolean().
does_user_exist(LUser, LServer) -> is_user_exists(LUser, LServer) ->
case make_req(get, <<"user_exists">>, LUser, LServer, <<"">>) of case make_req(get, <<"user_exists">>, LUser, LServer, <<"">>) of
{ok, <<"true">>} -> true; {ok, <<"true">>} -> true;
_ -> false _ -> false
@ -182,7 +203,7 @@ remove_user(LUser, LServer) ->
-spec remove_user(ejabberd:luser(), ejabberd:lserver(), binary()) -> ok | not_exists | not_allowed | bad_request. -spec remove_user(ejabberd:luser(), ejabberd:lserver(), binary()) -> ok | not_exists | not_allowed | bad_request.
remove_user(LUser, LServer, Password) -> remove_user(LUser, LServer, Password) ->
case scram:enabled(LServer) of case scram2:enabled(LServer) of
false -> false ->
remove_user_req(LUser, LServer, Password, <<"remove_user_validate">>); remove_user_req(LUser, LServer, Password, <<"remove_user_validate">>);
true -> true ->
@ -215,13 +236,13 @@ remove_user_req(LUser, LServer, Password, Method) ->
make_req(_, _, LUser, LServer, _) when LUser == error orelse LServer == error -> make_req(_, _, LUser, LServer, _) when LUser == error orelse LServer == error ->
{error, {prep_failed, LUser, LServer}}; {error, {prep_failed, LUser, LServer}};
make_req(Method, Path, LUser, LServer, Password) -> make_req(Method, Path, LUser, LServer, Password) ->
AuthOpts = ejabberd_config:get_local_option(auth_opts, LServer), AuthOpts = ejabberd_config:get_option({auth_opts, LServer}, fun(V) -> V end),
BasicAuth = case lists:keyfind(basic_auth, 1, AuthOpts) of BasicAuth = case lists:keyfind(basic_auth, 1, AuthOpts) of
{_, BasicAuth0} -> BasicAuth0; {_, BasicAuth0} -> BasicAuth0;
_ -> "" _ -> ""
end, end,
PathPrefix = case lists:keyfind(path_prefix, 1, AuthOpts) of PathPrefix = case lists:keyfind(path_prefix, 1, AuthOpts) of
{_, Prefix} -> ejabberd_binary:string_to_binary(Prefix); {_, Prefix} -> Prefix;
false -> <<"/">> false -> <<"/">>
end, end,
BasicAuth64 = base64:encode(BasicAuth), BasicAuth64 = base64:encode(BasicAuth),
@ -268,9 +289,9 @@ existing_pool_name(Host) ->
verify_scram_password(LUser, LServer, Password) -> verify_scram_password(LUser, LServer, Password) ->
case make_req(get, <<"get_password">>, LUser, LServer, <<"">>) of case make_req(get, <<"get_password">>, LUser, LServer, <<"">>) of
{ok, RawPassword} -> {ok, RawPassword} ->
case scram:deserialize(RawPassword) of case scram2:deserialize(RawPassword) of
{ok, #scram{} = ScramRecord} -> {ok, #scram{} = ScramRecord} ->
{ok, scram:check_password(Password, ScramRecord)}; {ok, scram2:check_password(Password, ScramRecord)};
_ -> _ ->
{error, bad_request} {error, bad_request}
end; end;

View File

@ -24,11 +24,12 @@
%%% %%%
%%%---------------------------------------------------------------------- %%%----------------------------------------------------------------------
-module(scram). -module(scram2).
-author('stephen.roettger@googlemail.com'). -author('stephen.roettger@googlemail.com').
-include("ejabberd.hrl"). -include("ejabberd.hrl").
-include("logger.hrl").
%% External exports %% External exports
%% ejabberd doesn't implement SASLPREP, so we use the similar RESOURCEPREP instead %% ejabberd doesn't implement SASLPREP, so we use the similar RESOURCEPREP instead
@ -56,7 +57,6 @@
-export([scram_to_tuple/1]). -export([scram_to_tuple/1]).
-define(SALT_LENGTH, 16). -define(SALT_LENGTH, 16).
-define(SCRAM_DEFAULT_ITERATION_COUNT, 4096).
-define(SCRAM_SERIAL_PREFIX, "==SCRAM==,"). -define(SCRAM_SERIAL_PREFIX, "==SCRAM==,").
-spec salted_password(binary(), binary(), non_neg_integer()) -> binary(). -spec salted_password(binary(), binary(), non_neg_integer()) -> binary().
@ -106,7 +106,7 @@ hi_round(Password, UPrev, IterationCount) ->
enabled(Host) -> enabled(Host) ->
case ejabberd_config:get_local_option(auth_opts, Host) of case ejabberd_config:get_option({auth_opts, Host}, fun(V) -> V end) of
undefined -> undefined ->
false; false;
AuthOpts -> AuthOpts ->
@ -116,7 +116,7 @@ enabled(Host) ->
iterations() -> ?SCRAM_DEFAULT_ITERATION_COUNT. iterations() -> ?SCRAM_DEFAULT_ITERATION_COUNT.
iterations(Host) -> iterations(Host) ->
case ejabberd_config:get_local_option(auth_opts, Host) of case ejabberd_config:get_option({auth_opts, Host}, fun(V) -> V end) of
undefined -> undefined ->
iterations(); iterations();
AuthOpts -> AuthOpts ->
@ -134,7 +134,7 @@ password_to_scram(#scram{} = Password, _) ->
password_to_scram(Password, IterationCount) -> password_to_scram(Password, IterationCount) ->
Salt = crypto:rand_bytes(?SALT_LENGTH), Salt = crypto:rand_bytes(?SALT_LENGTH),
SaltedPassword = salted_password(Password, Salt, IterationCount), SaltedPassword = salted_password(Password, Salt, IterationCount),
StoredKey = stored_key(scram:client_key(SaltedPassword)), StoredKey = stored_key(scram2:client_key(SaltedPassword)),
ServerKey = server_key(SaltedPassword), ServerKey = server_key(SaltedPassword),
#scram{storedkey = base64:encode(StoredKey), #scram{storedkey = base64:encode(StoredKey),
serverkey = base64:encode(ServerKey), serverkey = base64:encode(ServerKey),