mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-22 17:28:25 +01:00
Update export/import of scram password to XEP-0227 1.1 (#3676)
This commit is contained in:
parent
ceeba3eea1
commit
af4b49f720
@ -24,17 +24,15 @@
|
||||
%%%----------------------------------------------------------------------
|
||||
|
||||
%%% Not implemented:
|
||||
%%% - PEP nodes export/import
|
||||
%%% - message archives export/import
|
||||
%%% - write mod_piefxis with ejabberdctl commands
|
||||
%%% - Export from mod_offline_sql.erl
|
||||
%%% - Export from mod_private_sql.erl
|
||||
%%% - XEP-227: 6. Security Considerations
|
||||
%%% - Other schemas of XInclude are not tested, and may not be imported correctly.
|
||||
%%% - If a host has many users, split that host in XML files with 50 users each.
|
||||
%%%% Headers
|
||||
|
||||
-module(ejabberd_piefxis).
|
||||
|
||||
-protocol({xep, 227, '1.0'}).
|
||||
-protocol({xep, 227, '1.1'}).
|
||||
|
||||
-export([import_file/1, export_server/1, export_host/2]).
|
||||
|
||||
@ -166,33 +164,66 @@ export_users([], _Server, _Fd) ->
|
||||
export_user(User, Server, Fd) ->
|
||||
Password = ejabberd_auth:get_password_s(User, Server),
|
||||
LServer = jid:nameprep(Server),
|
||||
Pass = case ejabberd_auth:password_format(LServer) of
|
||||
scram -> format_scram_password(Password);
|
||||
_ -> Password
|
||||
{PassPlain, PassScram} = case ejabberd_auth:password_format(LServer) of
|
||||
scram -> {[], [format_scram_password(Password)]};
|
||||
_ -> {[{<<"password">>, Password}], []}
|
||||
end,
|
||||
Els = get_offline(User, Server) ++
|
||||
Els =
|
||||
PassScram ++
|
||||
get_offline(User, Server) ++
|
||||
get_vcard(User, Server) ++
|
||||
get_privacy(User, Server) ++
|
||||
get_roster(User, Server) ++
|
||||
get_private(User, Server),
|
||||
print(Fd, fxml:element_to_binary(
|
||||
#xmlel{name = <<"user">>,
|
||||
attrs = [{<<"name">>, User},
|
||||
{<<"password">>, Pass}],
|
||||
attrs = [{<<"name">>, User} | PassPlain],
|
||||
children = Els})).
|
||||
|
||||
format_scram_password(#scram{hash = Hash, storedkey = StoredKey, serverkey = ServerKey,
|
||||
salt = Salt, iterationcount = IterationCount}) ->
|
||||
StoredKeyB64 = base64:encode(StoredKey),
|
||||
ServerKeyB64 = base64:encode(ServerKey),
|
||||
SaltB64 = base64:encode(Salt),
|
||||
IterationCountBin = (integer_to_binary(IterationCount)),
|
||||
Hash2 = case Hash of
|
||||
sha -> <<>>;
|
||||
sha256 -> <<"sha256,">>;
|
||||
sha512 -> <<"sha512,">>
|
||||
end,
|
||||
<<"scram:", Hash2/binary, StoredKeyB64/binary, ",", ServerKeyB64/binary, ",", SaltB64/binary, ",", IterationCountBin/binary>>.
|
||||
StoredKeyB64 = base64:encode(StoredKey),
|
||||
ServerKeyB64 = base64:encode(ServerKey),
|
||||
SaltB64 = base64:encode(Salt),
|
||||
IterationCountBin = (integer_to_binary(IterationCount)),
|
||||
MechanismB = case Hash of
|
||||
sha -> <<"SCRAM-SHA-1">>;
|
||||
sha256 -> <<"SCRAM-SHA-256">>;
|
||||
sha512 -> <<"SCRAM-SHA-512">>
|
||||
end,
|
||||
Children =
|
||||
[
|
||||
#xmlel{name = <<"iter-count">>,
|
||||
children = [{xmlcdata, IterationCountBin}]},
|
||||
#xmlel{name = <<"salt">>,
|
||||
children = [{xmlcdata, SaltB64}]},
|
||||
#xmlel{name = <<"server-key">>,
|
||||
children = [{xmlcdata, ServerKeyB64}]},
|
||||
#xmlel{name = <<"stored-key">>,
|
||||
children = [{xmlcdata, StoredKeyB64}]}
|
||||
],
|
||||
#xmlel{name = <<"scram-credentials">>,
|
||||
attrs = [{<<"xmlns">>, <<?NS_PIE/binary, "#scram">>},
|
||||
{<<"mechanism">>, MechanismB}],
|
||||
children = Children}.
|
||||
|
||||
parse_scram_password(#xmlel{attrs = Attrs} = El) ->
|
||||
Hash = case fxml:get_attr_s(<<"mechanism">>, Attrs) of
|
||||
<<"SCRAM-SHA-1">> -> sha;
|
||||
<<"SCRAM-SHA-256">> -> sha256;
|
||||
<<"SCRAM-SHA-512">> -> sha512
|
||||
end,
|
||||
StoredKeyB64 = fxml:get_path_s(El, [{elem, <<"stored-key">>}, cdata]),
|
||||
ServerKeyB64 = fxml:get_path_s(El, [{elem, <<"server-key">>}, cdata]),
|
||||
IterationCountBin = fxml:get_path_s(El, [{elem, <<"iter-count">>}, cdata]),
|
||||
SaltB64 = fxml:get_path_s(El, [{elem, <<"salt">>}, cdata]),
|
||||
#scram{
|
||||
storedkey = base64:decode(StoredKeyB64),
|
||||
serverkey = base64:decode(ServerKeyB64),
|
||||
salt = base64:decode(SaltB64),
|
||||
hash = Hash,
|
||||
iterationcount = (binary_to_integer(IterationCountBin))
|
||||
};
|
||||
|
||||
parse_scram_password(PassData) ->
|
||||
Split = binary:split(PassData, <<",">>, [global]),
|
||||
@ -408,21 +439,10 @@ process_users([_|Els], State) ->
|
||||
process_users([], State) ->
|
||||
{ok, State}.
|
||||
|
||||
process_user(#xmlel{name = <<"user">>, attrs = Attrs, children = Els},
|
||||
process_user(#xmlel{name = <<"user">>, attrs = Attrs, children = Els} = El,
|
||||
#state{server = LServer} = State) ->
|
||||
Name = fxml:get_attr_s(<<"name">>, Attrs),
|
||||
Password = fxml:get_attr_s(<<"password">>, Attrs),
|
||||
PasswordFormat = ejabberd_auth:password_format(LServer),
|
||||
Pass = case PasswordFormat of
|
||||
scram ->
|
||||
case Password of
|
||||
<<"scram:", PassData/binary>> ->
|
||||
parse_scram_password(PassData);
|
||||
P -> P
|
||||
end;
|
||||
_ -> Password
|
||||
end,
|
||||
|
||||
Pass = process_password(El, LServer),
|
||||
case jid:nodeprep(Name) of
|
||||
error ->
|
||||
stop("Invalid 'user': ~ts", [Name]);
|
||||
@ -430,13 +450,29 @@ process_user(#xmlel{name = <<"user">>, attrs = Attrs, children = Els},
|
||||
case ejabberd_auth:try_register(LUser, LServer, Pass) of
|
||||
ok ->
|
||||
process_user_els(Els, State#state{user = LUser});
|
||||
{error, invalid_password} when (Password == <<>>) ->
|
||||
{error, invalid_password} when (Pass == <<>>) ->
|
||||
process_user_els(Els, State#state{user = LUser});
|
||||
{error, Err} ->
|
||||
stop("Failed to create user '~ts': ~p", [Name, Err])
|
||||
end
|
||||
end.
|
||||
|
||||
process_password(#xmlel{name = <<"user">>, attrs = Attrs} = El, LServer) ->
|
||||
{PassPlain, PassOldScram} = case fxml:get_attr_s(<<"password">>, Attrs) of
|
||||
<<"scram:", PassData/binary>> -> {<<"">>, PassData};
|
||||
P -> {P, false}
|
||||
end,
|
||||
ScramCred = fxml:get_subtag(El, <<"scram-credentials">>),
|
||||
PasswordFormat = ejabberd_auth:password_format(LServer),
|
||||
case {PassPlain, PassOldScram, ScramCred, PasswordFormat} of
|
||||
{PassPlain, false, false, plain} -> PassPlain;
|
||||
{<<"">>, false, ScramCred, plain} -> parse_scram_password(ScramCred);
|
||||
{<<"">>, PassOldScram, false, plain} -> parse_scram_password(PassOldScram);
|
||||
{PassPlain, false, false, scram} -> PassPlain;
|
||||
{<<"">>, false, ScramCred, scram} -> parse_scram_password(ScramCred);
|
||||
{<<"">>, PassOldScram, false, scram} -> parse_scram_password(PassOldScram)
|
||||
end.
|
||||
|
||||
process_user_els([#xmlel{} = El|Els], State) ->
|
||||
case process_user_el(El, State) of
|
||||
{ok, NewState} ->
|
||||
|
Loading…
Reference in New Issue
Block a user