Update to work with ejabberd 15.06
This commit is contained in:
parent
db91c97614
commit
6d655af0c4
|
@ -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;
|
||||||
|
|
|
@ -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),
|
||||||
|
|
Loading…
Reference in New Issue