mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Synchronizing master changes
This commit is contained in:
parent
127342449e
commit
cd2e2b1a88
@ -8,7 +8,7 @@
|
|||||||
%%%-------------------------------------------------------------------
|
%%%-------------------------------------------------------------------
|
||||||
|
|
||||||
{deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.0.2"}}},
|
{deps, [{lager, ".*", {git, "https://github.com/basho/lager", {tag, "3.0.2"}}},
|
||||||
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.3"}}},
|
{p1_utils, ".*", {git, "https://github.com/processone/p1_utils", {tag, "1.0.4"}}},
|
||||||
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.2"}}},
|
{cache_tab, ".*", {git, "https://github.com/processone/cache_tab", {tag, "1.0.2"}}},
|
||||||
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.1"}}},
|
{fast_tls, ".*", {git, "https://github.com/processone/fast_tls", {tag, "1.0.1"}}},
|
||||||
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.3"}}},
|
{stringprep, ".*", {git, "https://github.com/processone/stringprep", {tag, "1.0.3"}}},
|
||||||
|
@ -362,8 +362,8 @@ WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW
|
|||||||
CREATE TABLE [dbo].[users] (
|
CREATE TABLE [dbo].[users] (
|
||||||
[username] [varchar] (250) NOT NULL,
|
[username] [varchar] (250) NOT NULL,
|
||||||
[password] [text] NOT NULL,
|
[password] [text] NOT NULL,
|
||||||
[serverkey] [text] NOT NULL,
|
[serverkey] [text] NOT NULL DEFAULT '',
|
||||||
[salt] [text] NOT NULL,
|
[salt] [text] NOT NULL DEFAULT '',
|
||||||
[iterationcount] [smallint] NOT NULL DEFAULT 0,
|
[iterationcount] [smallint] NOT NULL DEFAULT 0,
|
||||||
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
|
[created_at] [datetime] NOT NULL DEFAULT GETDATE(),
|
||||||
CONSTRAINT [users_PRIMARY] PRIMARY KEY CLUSTERED
|
CONSTRAINT [users_PRIMARY] PRIMARY KEY CLUSTERED
|
||||||
|
@ -19,15 +19,15 @@
|
|||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
username varchar(191) PRIMARY KEY,
|
username varchar(191) PRIMARY KEY,
|
||||||
password text NOT NULL,
|
password text NOT NULL,
|
||||||
serverkey text NOT NULL DEFAULT '',
|
serverkey varchar(64) NOT NULL DEFAULT '',
|
||||||
salt text NOT NULL DEFAULT '',
|
salt varchar(64) NOT NULL DEFAULT '',
|
||||||
iterationcount integer NOT NULL DEFAULT 0,
|
iterationcount integer NOT NULL DEFAULT 0,
|
||||||
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||||
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
) ENGINE=InnoDB CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
-- Add support for SCRAM auth to a database created before ejabberd 16.03:
|
-- Add support for SCRAM auth to a database created before ejabberd 16.03:
|
||||||
-- ALTER TABLE users ADD COLUMN serverkey text NOT NULL DEFAULT '';
|
-- ALTER TABLE users ADD COLUMN serverkey varchar(64) NOT NULL DEFAULT '';
|
||||||
-- ALTER TABLE users ADD COLUMN salt text NOT NULL DEFAULT '';
|
-- ALTER TABLE users ADD COLUMN salt varchar(64) NOT NULL DEFAULT '';
|
||||||
-- ALTER TABLE users ADD COLUMN iterationcount integer NOT NULL DEFAULT 0;
|
-- ALTER TABLE users ADD COLUMN iterationcount integer NOT NULL DEFAULT 0;
|
||||||
|
|
||||||
CREATE TABLE last (
|
CREATE TABLE last (
|
||||||
|
@ -45,9 +45,8 @@ mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) ->
|
|||||||
|
|
||||||
mech_step(#state{server = Server} = S, ClientIn) ->
|
mech_step(#state{server = Server} = S, ClientIn) ->
|
||||||
User = iolist_to_binary([randoms:get_string(),
|
User = iolist_to_binary([randoms:get_string(),
|
||||||
randoms:get_string(),
|
jlib:integer_to_binary(p1_time_compat:unique_integer([positive]))]),
|
||||||
randoms:get_string()]),
|
|
||||||
case ejabberd_auth:is_user_exists(User, Server) of
|
case ejabberd_auth:is_user_exists(User, Server) of
|
||||||
true -> mech_step(S, ClientIn);
|
true -> mech_step(S, ClientIn);
|
||||||
false -> {ok, [{username, User}, {auth_module, ejabberd_auth_anonymous}]}
|
false -> {ok, [{username, User}, {authzid, User}, {auth_module, ejabberd_auth_anonymous}]}
|
||||||
end.
|
end.
|
||||||
|
@ -56,7 +56,7 @@
|
|||||||
%% Create the anonymous table if at least one virtual host has anonymous features enabled
|
%% Create the anonymous table if at least one virtual host has anonymous features enabled
|
||||||
%% Register to login / logout events
|
%% Register to login / logout events
|
||||||
-record(anonymous, {us = {<<"">>, <<"">>} :: {binary(), binary()},
|
-record(anonymous, {us = {<<"">>, <<"">>} :: {binary(), binary()},
|
||||||
sid = {p1_time_compat:timestamp(), self()} :: ejabberd_sm:sid()}).
|
sid = ejabberd_sm:make_sid() :: ejabberd_sm:sid()}).
|
||||||
|
|
||||||
start(Host) ->
|
start(Host) ->
|
||||||
%% TODO: Check cluster mode
|
%% TODO: Check cluster mode
|
||||||
|
@ -327,7 +327,7 @@ init([{SockMod, Socket}, Opts]) ->
|
|||||||
xml_socket = XMLSocket, zlib = Zlib, tls = TLS,
|
xml_socket = XMLSocket, zlib = Zlib, tls = TLS,
|
||||||
tls_required = StartTLSRequired,
|
tls_required = StartTLSRequired,
|
||||||
tls_enabled = TLSEnabled, tls_options = TLSOpts,
|
tls_enabled = TLSEnabled, tls_options = TLSOpts,
|
||||||
sid = {p1_time_compat:timestamp(), self()}, streamid = new_id(),
|
sid = ejabberd_sm:make_sid(), streamid = new_id(),
|
||||||
access = Access, shaper = Shaper, ip = IP,
|
access = Access, shaper = Shaper, ip = IP,
|
||||||
mgmt_state = StreamMgmtState,
|
mgmt_state = StreamMgmtState,
|
||||||
mgmt_max_queue = MaxAckQueue,
|
mgmt_max_queue = MaxAckQueue,
|
||||||
@ -522,7 +522,6 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
?POLICY_VIOLATION_ERR(Lang,
|
?POLICY_VIOLATION_ERR(Lang,
|
||||||
<<"Use of STARTTLS required">>)),
|
<<"Use of STARTTLS required">>)),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
true ->
|
true ->
|
||||||
fsm_next_state(wait_for_auth,
|
fsm_next_state(wait_for_auth,
|
||||||
@ -537,34 +536,28 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
|
|||||||
[jlib:ip_to_list(IP), LogReason]),
|
[jlib:ip_to_list(IP), LogReason]),
|
||||||
send_header(StateData, Server, <<"">>, DefaultLang),
|
send_header(StateData, Server, <<"">>, DefaultLang),
|
||||||
send_element(StateData, ?POLICY_VIOLATION_ERR(Lang, ReasonT)),
|
send_element(StateData, ?POLICY_VIOLATION_ERR(Lang, ReasonT)),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
_ ->
|
_ ->
|
||||||
send_header(StateData, ?MYNAME, <<"">>, DefaultLang),
|
send_header(StateData, ?MYNAME, <<"">>, DefaultLang),
|
||||||
send_element(StateData, ?HOST_UNKNOWN_ERR),
|
send_element(StateData, ?HOST_UNKNOWN_ERR),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
send_header(StateData, ?MYNAME, <<"">>, DefaultLang),
|
send_header(StateData, ?MYNAME, <<"">>, DefaultLang),
|
||||||
send_element(StateData, ?INVALID_NS_ERR),
|
send_element(StateData, ?INVALID_NS_ERR),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
wait_for_stream(timeout, StateData) ->
|
wait_for_stream(timeout, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_stream({xmlstreamelement, _}, StateData) ->
|
wait_for_stream({xmlstreamelement, _}, StateData) ->
|
||||||
send_element(StateData, ?INVALID_XML_ERR),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_stream({xmlstreamend, _}, StateData) ->
|
wait_for_stream({xmlstreamend, _}, StateData) ->
|
||||||
send_element(StateData, ?INVALID_XML_ERR),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_stream({xmlstreamerror, _}, StateData) ->
|
wait_for_stream({xmlstreamerror, _}, StateData) ->
|
||||||
send_header(StateData, ?MYNAME, <<"1.0">>, <<"">>),
|
send_header(StateData, ?MYNAME, <<"1.0">>, <<"">>),
|
||||||
send_element(StateData, ?INVALID_XML_ERR),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_stream(closed, StateData) ->
|
wait_for_stream(closed, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -724,10 +717,9 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
|||||||
wait_for_auth(timeout, StateData) ->
|
wait_for_auth(timeout, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_auth({xmlstreamend, _Name}, StateData) ->
|
wait_for_auth({xmlstreamend, _Name}, StateData) ->
|
||||||
send_trailer(StateData), {stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_auth({xmlstreamerror, _}, StateData) ->
|
wait_for_auth({xmlstreamerror, _}, StateData) ->
|
||||||
send_element(StateData, ?INVALID_XML_ERR),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_auth(closed, StateData) ->
|
wait_for_auth(closed, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -843,7 +835,6 @@ wait_for_feature_request({xmlstreamelement, El},
|
|||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
?POLICY_VIOLATION_ERR(Lang,
|
?POLICY_VIOLATION_ERR(Lang,
|
||||||
<<"Use of STARTTLS required">>)),
|
<<"Use of STARTTLS required">>)),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
true ->
|
true ->
|
||||||
process_unauthenticated_stanza(StateData, El),
|
process_unauthenticated_stanza(StateData, El),
|
||||||
@ -854,11 +845,10 @@ wait_for_feature_request(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_feature_request({xmlstreamend, _Name},
|
wait_for_feature_request({xmlstreamend, _Name},
|
||||||
StateData) ->
|
StateData) ->
|
||||||
send_trailer(StateData), {stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_feature_request({xmlstreamerror, _},
|
wait_for_feature_request({xmlstreamerror, _},
|
||||||
StateData) ->
|
StateData) ->
|
||||||
send_element(StateData, ?INVALID_XML_ERR),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_feature_request(closed, StateData) ->
|
wait_for_feature_request(closed, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -963,11 +953,10 @@ wait_for_sasl_response(timeout, StateData) ->
|
|||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_sasl_response({xmlstreamend, _Name},
|
wait_for_sasl_response({xmlstreamend, _Name},
|
||||||
StateData) ->
|
StateData) ->
|
||||||
send_trailer(StateData), {stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_sasl_response({xmlstreamerror, _},
|
wait_for_sasl_response({xmlstreamerror, _},
|
||||||
StateData) ->
|
StateData) ->
|
||||||
send_element(StateData, ?INVALID_XML_ERR),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_sasl_response(closed, StateData) ->
|
wait_for_sasl_response(closed, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -1092,10 +1081,9 @@ wait_for_bind({xmlstreamelement, El}, StateData) ->
|
|||||||
wait_for_bind(timeout, StateData) ->
|
wait_for_bind(timeout, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_bind({xmlstreamend, _Name}, StateData) ->
|
wait_for_bind({xmlstreamend, _Name}, StateData) ->
|
||||||
send_trailer(StateData), {stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_bind({xmlstreamerror, _}, StateData) ->
|
wait_for_bind({xmlstreamerror, _}, StateData) ->
|
||||||
send_element(StateData, ?INVALID_XML_ERR),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
wait_for_bind(closed, StateData) ->
|
wait_for_bind(closed, StateData) ->
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -1168,7 +1156,6 @@ session_established({xmlstreamelement, El},
|
|||||||
case check_from(El, FromJID) of
|
case check_from(El, FromJID) of
|
||||||
'invalid-from' ->
|
'invalid-from' ->
|
||||||
send_element(StateData, ?INVALID_FROM),
|
send_element(StateData, ?INVALID_FROM),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
_NewEl ->
|
_NewEl ->
|
||||||
session_established2(El, StateData)
|
session_established2(El, StateData)
|
||||||
@ -1181,17 +1168,15 @@ session_established(timeout, StateData) ->
|
|||||||
[?MODULE, Options, session_established, StateData]),
|
[?MODULE, Options, session_established, StateData]),
|
||||||
fsm_next_state(session_established, StateData);
|
fsm_next_state(session_established, StateData);
|
||||||
session_established({xmlstreamend, _Name}, StateData) ->
|
session_established({xmlstreamend, _Name}, StateData) ->
|
||||||
send_trailer(StateData), {stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
session_established({xmlstreamerror,
|
session_established({xmlstreamerror,
|
||||||
<<"XML stanza is too big">> = E},
|
<<"XML stanza is too big">> = E},
|
||||||
StateData) ->
|
StateData) ->
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
?POLICY_VIOLATION_ERR((StateData#state.lang), E)),
|
?POLICY_VIOLATION_ERR((StateData#state.lang), E)),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
session_established({xmlstreamerror, _}, StateData) ->
|
session_established({xmlstreamerror, _}, StateData) ->
|
||||||
send_element(StateData, ?INVALID_XML_ERR),
|
send_element(StateData, ?INVALID_XML_ERR),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
session_established(closed, #state{mgmt_state = active} = StateData) ->
|
session_established(closed, #state{mgmt_state = active} = StateData) ->
|
||||||
catch (StateData#state.sockmod):close(StateData#state.socket),
|
catch (StateData#state.sockmod):close(StateData#state.socket),
|
||||||
@ -1346,7 +1331,6 @@ handle_info(kick, StateName, StateData) ->
|
|||||||
handle_info({kick, kicked_by_admin, Xmlelement}, StateName, StateData);
|
handle_info({kick, kicked_by_admin, Xmlelement}, StateName, StateData);
|
||||||
handle_info({kick, Reason, Xmlelement}, _StateName, StateData) ->
|
handle_info({kick, Reason, Xmlelement}, _StateName, StateData) ->
|
||||||
send_element(StateData, Xmlelement),
|
send_element(StateData, Xmlelement),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal,
|
{stop, normal,
|
||||||
StateData#state{authenticated = Reason}};
|
StateData#state{authenticated = Reason}};
|
||||||
handle_info({route, _From, _To, {broadcast, Data}},
|
handle_info({route, _From, _To, {broadcast, Data}},
|
||||||
@ -1359,7 +1343,6 @@ handle_info({route, _From, _To, {broadcast, Data}},
|
|||||||
{exit, Reason} ->
|
{exit, Reason} ->
|
||||||
Lang = StateData#state.lang,
|
Lang = StateData#state.lang,
|
||||||
send_element(StateData, ?SERRT_CONFLICT(Lang, Reason)),
|
send_element(StateData, ?SERRT_CONFLICT(Lang, Reason)),
|
||||||
catch send_trailer(StateData),
|
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
{privacy_list, PrivList, PrivListName} ->
|
{privacy_list, PrivList, PrivListName} ->
|
||||||
case ejabberd_hooks:run_fold(privacy_updated_list,
|
case ejabberd_hooks:run_fold(privacy_updated_list,
|
||||||
@ -1673,11 +1656,9 @@ handle_info(system_shutdown, StateName, StateData) ->
|
|||||||
wait_for_stream ->
|
wait_for_stream ->
|
||||||
send_header(StateData, ?MYNAME, <<"1.0">>, <<"en">>),
|
send_header(StateData, ?MYNAME, <<"1.0">>, <<"en">>),
|
||||||
send_element(StateData, ?SERR_SYSTEM_SHUTDOWN),
|
send_element(StateData, ?SERR_SYSTEM_SHUTDOWN),
|
||||||
send_trailer(StateData),
|
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
send_element(StateData, ?SERR_SYSTEM_SHUTDOWN),
|
send_element(StateData, ?SERR_SYSTEM_SHUTDOWN),
|
||||||
send_trailer(StateData),
|
|
||||||
ok
|
ok
|
||||||
end,
|
end,
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -1809,6 +1790,7 @@ terminate(_Reason, StateName, StateData) ->
|
|||||||
ok
|
ok
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
catch send_trailer(StateData),
|
||||||
(StateData#state.sockmod):close(StateData#state.socket),
|
(StateData#state.sockmod):close(StateData#state.socket),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
@ -2431,7 +2413,6 @@ fsm_next_state(session_established, #state{mgmt_max_queue = exceeded} =
|
|||||||
Err = ?SERRT_POLICY_VIOLATION(StateData#state.lang,
|
Err = ?SERRT_POLICY_VIOLATION(StateData#state.lang,
|
||||||
<<"Too many unacked stanzas">>),
|
<<"Too many unacked stanzas">>),
|
||||||
send_element(StateData, Err),
|
send_element(StateData, Err),
|
||||||
send_trailer(StateData),
|
|
||||||
{stop, normal, StateData#state{mgmt_resend = false}};
|
{stop, normal, StateData#state{mgmt_resend = false}};
|
||||||
fsm_next_state(session_established, #state{mgmt_state = pending} = StateData) ->
|
fsm_next_state(session_established, #state{mgmt_state = pending} = StateData) ->
|
||||||
fsm_next_state(wait_for_resume, StateData);
|
fsm_next_state(wait_for_resume, StateData);
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
-behaviour(ejabberd_config).
|
-behaviour(ejabberd_config).
|
||||||
-author('alexey@process-one.net').
|
-author('alexey@process-one.net').
|
||||||
|
|
||||||
-export([start/0, init/0, process/1,
|
-export([start/0, init/0, process/1, process2/2,
|
||||||
register_commands/3, unregister_commands/3,
|
register_commands/3, unregister_commands/3,
|
||||||
opt_type/1]).
|
opt_type/1]).
|
||||||
|
|
||||||
@ -231,6 +231,10 @@ process(Args, Version) ->
|
|||||||
Code.
|
Code.
|
||||||
|
|
||||||
%% @spec (Args::[string()], AccessCommands) -> {String::string(), Code::integer()}
|
%% @spec (Args::[string()], AccessCommands) -> {String::string(), Code::integer()}
|
||||||
|
process2(Args, AccessCommands) ->
|
||||||
|
process2(Args, AccessCommands, ?DEFAULT_VERSION).
|
||||||
|
|
||||||
|
%% @spec (Args::[string()], AccessCommands, Version) -> {String::string(), Code::integer()}
|
||||||
process2(["--auth", User, Server, Pass | Args], AccessCommands, Version) ->
|
process2(["--auth", User, Server, Pass | Args], AccessCommands, Version) ->
|
||||||
process2(Args, AccessCommands, {list_to_binary(User), list_to_binary(Server),
|
process2(Args, AccessCommands, {list_to_binary(User), list_to_binary(Server),
|
||||||
list_to_binary(Pass), true}, Version);
|
list_to_binary(Pass), true}, Version);
|
||||||
|
@ -325,7 +325,7 @@ wait_for_feature_request({xmlstreamelement, El},
|
|||||||
{s2s_tls_compression, StateData#state.server},
|
{s2s_tls_compression, StateData#state.server},
|
||||||
fun(true) -> true;
|
fun(true) -> true;
|
||||||
(false) -> false
|
(false) -> false
|
||||||
end, true) of
|
end, false) of
|
||||||
true -> lists:delete(compression_none, TLSOpts1);
|
true -> lists:delete(compression_none, TLSOpts1);
|
||||||
false -> [compression_none | TLSOpts1]
|
false -> [compression_none | TLSOpts1]
|
||||||
end,
|
end,
|
||||||
|
@ -192,7 +192,7 @@ init([From, Server, Type]) ->
|
|||||||
{s2s_tls_compression, From},
|
{s2s_tls_compression, From},
|
||||||
fun(true) -> true;
|
fun(true) -> true;
|
||||||
(false) -> false
|
(false) -> false
|
||||||
end, true) of
|
end, false) of
|
||||||
false -> [compression_none | TLSOpts4];
|
false -> [compression_none | TLSOpts4];
|
||||||
true -> TLSOpts4
|
true -> TLSOpts4
|
||||||
end,
|
end,
|
||||||
|
@ -66,7 +66,8 @@
|
|||||||
get_max_user_sessions/2,
|
get_max_user_sessions/2,
|
||||||
get_all_pids/0,
|
get_all_pids/0,
|
||||||
is_existing_resource/3,
|
is_existing_resource/3,
|
||||||
get_commands_spec/0
|
get_commands_spec/0,
|
||||||
|
make_sid/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export([init/1, handle_call/3, handle_cast/2,
|
-export([init/1, handle_call/3, handle_cast/2,
|
||||||
@ -806,6 +807,9 @@ kick_user(User, Server) ->
|
|||||||
end, Resources),
|
end, Resources),
|
||||||
length(Resources).
|
length(Resources).
|
||||||
|
|
||||||
|
make_sid() ->
|
||||||
|
{p1_time_compat:unique_timestamp(), self()}.
|
||||||
|
|
||||||
opt_type(sm_db_type) ->
|
opt_type(sm_db_type) ->
|
||||||
fun (mnesia) -> mnesia;
|
fun (mnesia) -> mnesia;
|
||||||
(internal) -> mnesia;
|
(internal) -> mnesia;
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
|
|
||||||
-export([start/2, stop/1, compile/1, get_cookie/0,
|
-export([start/2, stop/1, compile/1, get_cookie/0,
|
||||||
remove_node/1, set_password/3,
|
remove_node/1, set_password/3, check_password/3,
|
||||||
check_password_hash/4, delete_old_users/1,
|
check_password_hash/4, delete_old_users/1,
|
||||||
delete_old_users_vhost/2, ban_account/3,
|
delete_old_users_vhost/2, ban_account/3,
|
||||||
num_active_users/2, num_resources/2, resource_num/3,
|
num_active_users/2, num_resources/2, resource_num/3,
|
||||||
@ -162,7 +162,7 @@ get_commands_spec() ->
|
|||||||
result_desc = "Status code: 0 on success, 1 otherwise"},
|
result_desc = "Status code: 0 on success, 1 otherwise"},
|
||||||
#ejabberd_commands{name = check_password, tags = [accounts],
|
#ejabberd_commands{name = check_password, tags = [accounts],
|
||||||
desc = "Check if a password is correct",
|
desc = "Check if a password is correct",
|
||||||
module = ejabberd_auth, function = check_password,
|
module = ?MODULE, function = check_password,
|
||||||
args = [{user, binary}, {host, binary}, {password, binary}],
|
args = [{user, binary}, {host, binary}, {password, binary}],
|
||||||
args_example = [<<"peter">>, <<"myserver.com">>, <<"secret">>],
|
args_example = [<<"peter">>, <<"myserver.com">>, <<"secret">>],
|
||||||
args_desc = ["User name to check", "Server to check", "Password to check"],
|
args_desc = ["User name to check", "Server to check", "Password to check"],
|
||||||
@ -593,6 +593,9 @@ set_password(User, Host, Password) ->
|
|||||||
Fun = fun () -> ejabberd_auth:set_password(User, Host, Password) end,
|
Fun = fun () -> ejabberd_auth:set_password(User, Host, Password) end,
|
||||||
user_action(User, Host, Fun, ok).
|
user_action(User, Host, Fun, ok).
|
||||||
|
|
||||||
|
check_password(User, Host, Password) ->
|
||||||
|
ejabberd_auth:check_password(User, <<>>, Host, Password).
|
||||||
|
|
||||||
%% Copied some code from ejabberd_commands.erl
|
%% Copied some code from ejabberd_commands.erl
|
||||||
check_password_hash(User, Host, PasswordHash, HashMethod) ->
|
check_password_hash(User, Host, PasswordHash, HashMethod) ->
|
||||||
AccountPass = ejabberd_auth:get_password_s(User, Host),
|
AccountPass = ejabberd_auth:get_password_s(User, Host),
|
||||||
|
@ -375,7 +375,7 @@ try_set_password(User, Server, Password, IQ, SubEl,
|
|||||||
Txt = <<"Empty password">>,
|
Txt = <<"Empty password">>,
|
||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]};
|
IQ#iq{type = error, sub_el = [SubEl, ?ERRT_BAD_REQUEST(Lang, Txt)]};
|
||||||
{error, not_allowed} ->
|
{error, not_allowed} ->
|
||||||
Txt = <<"Chaning password is not allowed">>,
|
Txt = <<"Changing password is not allowed">>,
|
||||||
IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]};
|
IQ#iq{type = error, sub_el = [SubEl, ?ERRT_NOT_ALLOWED(Lang, Txt)]};
|
||||||
{error, invalid_jid} ->
|
{error, invalid_jid} ->
|
||||||
IQ#iq{type = error,
|
IQ#iq{type = error,
|
||||||
|
153
test/ejabberd_cyrsasl_test.exs
Normal file
153
test/ejabberd_cyrsasl_test.exs
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
# ----------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# ejabberd, Copyright (C) 2002-2016 ProcessOne
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or
|
||||||
|
# modify it under the terms of the GNU General Public License as
|
||||||
|
# published by the Free Software Foundation; either version 2 of the
|
||||||
|
# License, or (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License along
|
||||||
|
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
#
|
||||||
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
defmodule EjabberdCyrsaslTest do
|
||||||
|
@author "pawel@process-one.net"
|
||||||
|
|
||||||
|
use ExUnit.Case, async: true
|
||||||
|
|
||||||
|
setup_all do
|
||||||
|
:p1_sha.load_nif()
|
||||||
|
:mnesia.start
|
||||||
|
:ok = start_module(:stringprep)
|
||||||
|
:ok = start_module(:jid)
|
||||||
|
:ok = :ejabberd_config.start(["domain1"], [])
|
||||||
|
:ok = :cyrsasl.start
|
||||||
|
cyrstate = :cyrsasl.server_new("domain1", "domain1", "domain1", :ok, &get_password/1,
|
||||||
|
&check_password/3, &check_password_digest/5)
|
||||||
|
{:ok, cyrstate: cyrstate}
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Plain text (correct user and pass)", context do
|
||||||
|
step1 = :cyrsasl.server_start(context[:cyrstate], "PLAIN", <<0,"user1",0,"pass">>)
|
||||||
|
assert {:ok, _} = step1
|
||||||
|
{:ok, kv} = step1
|
||||||
|
assert kv[:authzid] == "user1", "got correct user"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Plain text (correct user wrong pass)", context do
|
||||||
|
step1 = :cyrsasl.server_start(context[:cyrstate], "PLAIN", <<0,"user1",0,"badpass">>)
|
||||||
|
assert step1 == {:error, "not-authorized", "user1"}, "got error response"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Plain text (wrong user wrong pass)", context do
|
||||||
|
step1 = :cyrsasl.server_start(context[:cyrstate], "PLAIN", <<0,"nouser1",0,"badpass">>)
|
||||||
|
assert step1 == {:error, "not-authorized", "nouser1"}, "got error response"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Anonymous", context do
|
||||||
|
setup_anonymous_mocks()
|
||||||
|
step1 = :cyrsasl.server_start(context[:cyrstate], "ANONYMOUS", "domain1")
|
||||||
|
assert {:ok, _} = step1
|
||||||
|
end
|
||||||
|
|
||||||
|
test "Digest-MD5 (correct user and pass)", context do
|
||||||
|
assert {:continue, init_str, state1} = :cyrsasl.server_start(context[:cyrstate], "DIGEST-MD5", "")
|
||||||
|
assert [_, nonce] = Regex.run(~r/nonce="(.*?)"/, init_str)
|
||||||
|
user = "user1"
|
||||||
|
domain = "domain1"
|
||||||
|
digest_uri = "xmpp/#{domain}"
|
||||||
|
pass = "pass"
|
||||||
|
cnonce = "abcd"
|
||||||
|
nc = "00000001"
|
||||||
|
response_hash = calc_digest_sha(user, domain, pass, nc, nonce, cnonce)
|
||||||
|
response = "username=\"#{user}\",realm=\"#{domain}\",nonce=\"#{nonce}\",cnonce=\"#{cnonce}\"," <>
|
||||||
|
"nc=\"#{nc}\",qop=auth,digest-uri=\"#{digest_uri}\",response=\"#{response_hash}\"," <>
|
||||||
|
"charset=utf-8,algorithm=md5-sess"
|
||||||
|
assert {:continue, calc_str, state3} = :cyrsasl.server_step(state1, response)
|
||||||
|
assert {:ok, list} = :cyrsasl.server_step(state3, "")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp calc_digest_sha(user, domain, pass, nc, nonce, cnonce) do
|
||||||
|
digest_uri = "xmpp/#{domain}"
|
||||||
|
a0 = "#{user}:#{domain}:#{pass}"
|
||||||
|
a1 = "#{str_md5(a0)}:#{nonce}:#{cnonce}"
|
||||||
|
a2 = "AUTHENTICATE:#{digest_uri}"
|
||||||
|
hex_md5("#{hex_md5(a1)}:#{nonce}:#{nc}:#{cnonce}:auth:#{hex_md5(a2)}")
|
||||||
|
end
|
||||||
|
|
||||||
|
defp str_md5(str) do
|
||||||
|
:erlang.md5(str)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp hex_md5(str) do
|
||||||
|
:p1_sha.to_hexlist(:erlang.md5(str))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp setup_anonymous_mocks() do
|
||||||
|
:meck.unload
|
||||||
|
mock(:ejabberd_auth_anonymous, :is_sasl_anonymous_enabled,
|
||||||
|
fn (host) ->
|
||||||
|
true
|
||||||
|
end)
|
||||||
|
mock(:ejabberd_auth, :is_user_exists,
|
||||||
|
fn (user, domain) ->
|
||||||
|
domain == "domain1" and get_password(user) != false
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp start_module(module) do
|
||||||
|
case apply(module, :start, []) do
|
||||||
|
:ok -> :ok
|
||||||
|
{:error, {:already_started, _}} -> :ok
|
||||||
|
other -> other
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp get_password(user) do
|
||||||
|
if user == "user1" or user == "user2" do
|
||||||
|
{"pass", :internal}
|
||||||
|
else
|
||||||
|
:false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp check_password(user, authzid, pass) do
|
||||||
|
case get_password(authzid) do
|
||||||
|
{^pass, mod} ->
|
||||||
|
{true, mod}
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp check_password_digest(user, authzid, pass, digest, digest_gen) do
|
||||||
|
case get_password(authzid) do
|
||||||
|
{spass, mod} ->
|
||||||
|
v = digest_gen.(spass)
|
||||||
|
if v == digest do
|
||||||
|
{true, mod}
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
|
_ ->
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp mock(module, function, fun) do
|
||||||
|
try do
|
||||||
|
:meck.new(module, [:non_strict])
|
||||||
|
catch
|
||||||
|
:error, {:already_started, _pid} -> :ok
|
||||||
|
end
|
||||||
|
:meck.expect(module, function, fun)
|
||||||
|
end
|
||||||
|
end
|
@ -73,13 +73,13 @@ defmodule EjabberdModAdminExtraTest do
|
|||||||
EjabberdAuthMock.create_user @user, @domain, @password
|
EjabberdAuthMock.create_user @user, @domain, @password
|
||||||
|
|
||||||
assert :ejabberd_commands.execute_command(:check_password,
|
assert :ejabberd_commands.execute_command(:check_password,
|
||||||
[@user, <<"">>, @domain, @password])
|
[@user, @domain, @password])
|
||||||
refute :ejabberd_commands.execute_command(:check_password,
|
refute :ejabberd_commands.execute_command(:check_password,
|
||||||
[@user, <<"">>, @domain, "bad_password"])
|
[@user, @domain, "bad_password"])
|
||||||
refute :ejabberd_commands.execute_command(:check_password,
|
refute :ejabberd_commands.execute_command(:check_password,
|
||||||
[@user, <<"">>, "bad_domain", @password])
|
[@user, "bad_domain", @password])
|
||||||
refute :ejabberd_commands.execute_command(:check_password,
|
refute :ejabberd_commands.execute_command(:check_password,
|
||||||
["bad_user", <<"">>, @domain, @password])
|
["bad_user", @domain, @password])
|
||||||
|
|
||||||
assert :meck.validate :ejabberd_auth
|
assert :meck.validate :ejabberd_auth
|
||||||
|
|
||||||
@ -117,9 +117,9 @@ defmodule EjabberdModAdminExtraTest do
|
|||||||
assert :ejabberd_commands.execute_command(:change_password,
|
assert :ejabberd_commands.execute_command(:change_password,
|
||||||
[@user, @domain, "new_password"])
|
[@user, @domain, "new_password"])
|
||||||
refute :ejabberd_commands.execute_command(:check_password,
|
refute :ejabberd_commands.execute_command(:check_password,
|
||||||
[@user, <<"">>, @domain, @password])
|
[@user, @domain, @password])
|
||||||
assert :ejabberd_commands.execute_command(:check_password,
|
assert :ejabberd_commands.execute_command(:check_password,
|
||||||
[@user, <<"">>, @domain, "new_password"])
|
[@user, @domain, "new_password"])
|
||||||
assert {:not_found, 'unknown_user'} ==
|
assert {:not_found, 'unknown_user'} ==
|
||||||
catch_throw :ejabberd_commands.execute_command(:change_password,
|
catch_throw :ejabberd_commands.execute_command(:change_password,
|
||||||
["bad_user", @domain,
|
["bad_user", @domain,
|
||||||
|
Loading…
Reference in New Issue
Block a user