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:
|
%%% Not implemented:
|
||||||
|
%%% - PEP nodes export/import
|
||||||
|
%%% - message archives export/import
|
||||||
%%% - write mod_piefxis with ejabberdctl commands
|
%%% - 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.
|
%%% - 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.
|
%%% - If a host has many users, split that host in XML files with 50 users each.
|
||||||
%%%% Headers
|
|
||||||
|
|
||||||
-module(ejabberd_piefxis).
|
-module(ejabberd_piefxis).
|
||||||
|
|
||||||
-protocol({xep, 227, '1.0'}).
|
-protocol({xep, 227, '1.1'}).
|
||||||
|
|
||||||
-export([import_file/1, export_server/1, export_host/2]).
|
-export([import_file/1, export_server/1, export_host/2]).
|
||||||
|
|
||||||
|
@ -166,33 +164,66 @@ export_users([], _Server, _Fd) ->
|
||||||
export_user(User, Server, Fd) ->
|
export_user(User, Server, Fd) ->
|
||||||
Password = ejabberd_auth:get_password_s(User, Server),
|
Password = ejabberd_auth:get_password_s(User, Server),
|
||||||
LServer = jid:nameprep(Server),
|
LServer = jid:nameprep(Server),
|
||||||
Pass = case ejabberd_auth:password_format(LServer) of
|
{PassPlain, PassScram} = case ejabberd_auth:password_format(LServer) of
|
||||||
scram -> format_scram_password(Password);
|
scram -> {[], [format_scram_password(Password)]};
|
||||||
_ -> Password
|
_ -> {[{<<"password">>, Password}], []}
|
||||||
end,
|
end,
|
||||||
Els = get_offline(User, Server) ++
|
Els =
|
||||||
|
PassScram ++
|
||||||
|
get_offline(User, Server) ++
|
||||||
get_vcard(User, Server) ++
|
get_vcard(User, Server) ++
|
||||||
get_privacy(User, Server) ++
|
get_privacy(User, Server) ++
|
||||||
get_roster(User, Server) ++
|
get_roster(User, Server) ++
|
||||||
get_private(User, Server),
|
get_private(User, Server),
|
||||||
print(Fd, fxml:element_to_binary(
|
print(Fd, fxml:element_to_binary(
|
||||||
#xmlel{name = <<"user">>,
|
#xmlel{name = <<"user">>,
|
||||||
attrs = [{<<"name">>, User},
|
attrs = [{<<"name">>, User} | PassPlain],
|
||||||
{<<"password">>, Pass}],
|
|
||||||
children = Els})).
|
children = Els})).
|
||||||
|
|
||||||
format_scram_password(#scram{hash = Hash, storedkey = StoredKey, serverkey = ServerKey,
|
format_scram_password(#scram{hash = Hash, storedkey = StoredKey, serverkey = ServerKey,
|
||||||
salt = Salt, iterationcount = IterationCount}) ->
|
salt = Salt, iterationcount = IterationCount}) ->
|
||||||
StoredKeyB64 = base64:encode(StoredKey),
|
StoredKeyB64 = base64:encode(StoredKey),
|
||||||
ServerKeyB64 = base64:encode(ServerKey),
|
ServerKeyB64 = base64:encode(ServerKey),
|
||||||
SaltB64 = base64:encode(Salt),
|
SaltB64 = base64:encode(Salt),
|
||||||
IterationCountBin = (integer_to_binary(IterationCount)),
|
IterationCountBin = (integer_to_binary(IterationCount)),
|
||||||
Hash2 = case Hash of
|
MechanismB = case Hash of
|
||||||
sha -> <<>>;
|
sha -> <<"SCRAM-SHA-1">>;
|
||||||
sha256 -> <<"sha256,">>;
|
sha256 -> <<"SCRAM-SHA-256">>;
|
||||||
sha512 -> <<"sha512,">>
|
sha512 -> <<"SCRAM-SHA-512">>
|
||||||
end,
|
end,
|
||||||
<<"scram:", Hash2/binary, StoredKeyB64/binary, ",", ServerKeyB64/binary, ",", SaltB64/binary, ",", IterationCountBin/binary>>.
|
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) ->
|
parse_scram_password(PassData) ->
|
||||||
Split = binary:split(PassData, <<",">>, [global]),
|
Split = binary:split(PassData, <<",">>, [global]),
|
||||||
|
@ -408,21 +439,10 @@ process_users([_|Els], State) ->
|
||||||
process_users([], State) ->
|
process_users([], State) ->
|
||||||
{ok, 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) ->
|
#state{server = LServer} = State) ->
|
||||||
Name = fxml:get_attr_s(<<"name">>, Attrs),
|
Name = fxml:get_attr_s(<<"name">>, Attrs),
|
||||||
Password = fxml:get_attr_s(<<"password">>, Attrs),
|
Pass = process_password(El, LServer),
|
||||||
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,
|
|
||||||
|
|
||||||
case jid:nodeprep(Name) of
|
case jid:nodeprep(Name) of
|
||||||
error ->
|
error ->
|
||||||
stop("Invalid 'user': ~ts", [Name]);
|
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
|
case ejabberd_auth:try_register(LUser, LServer, Pass) of
|
||||||
ok ->
|
ok ->
|
||||||
process_user_els(Els, State#state{user = LUser});
|
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});
|
process_user_els(Els, State#state{user = LUser});
|
||||||
{error, Err} ->
|
{error, Err} ->
|
||||||
stop("Failed to create user '~ts': ~p", [Name, Err])
|
stop("Failed to create user '~ts': ~p", [Name, Err])
|
||||||
end
|
end
|
||||||
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) ->
|
process_user_els([#xmlel{} = El|Els], State) ->
|
||||||
case process_user_el(El, State) of
|
case process_user_el(El, State) of
|
||||||
{ok, NewState} ->
|
{ok, NewState} ->
|
||||||
|
|
Loading…
Reference in New Issue