mirror of
https://github.com/processone/ejabberd.git
synced 2024-11-24 16:23:40 +01:00
Add more tests for C2S
This commit is contained in:
parent
151668ac10
commit
a4ec064455
@ -323,24 +323,25 @@ get_subscribed(FsmRef) ->
|
|||||||
|
|
||||||
wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
|
wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
|
||||||
try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of
|
try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of
|
||||||
#stream_start{xmlns = NS_CLIENT, stream_xmlns = NS_STREAM, lang = Lang}
|
#stream_start{xmlns = NS_CLIENT, stream_xmlns = NS_STREAM,
|
||||||
|
version = Version, lang = Lang}
|
||||||
when NS_CLIENT /= ?NS_CLIENT; NS_STREAM /= ?NS_STREAM ->
|
when NS_CLIENT /= ?NS_CLIENT; NS_STREAM /= ?NS_STREAM ->
|
||||||
send_header(StateData, ?MYNAME, <<"">>, Lang),
|
send_header(StateData, ?MYNAME, Version, Lang),
|
||||||
send_element(StateData, xmpp:serr_invalid_namespace()),
|
send_element(StateData, xmpp:serr_invalid_namespace()),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
#stream_start{lang = Lang} when byte_size(Lang) > 35 ->
|
#stream_start{lang = Lang, version = Version} when byte_size(Lang) > 35 ->
|
||||||
%% As stated in BCP47, 4.4.1:
|
%% As stated in BCP47, 4.4.1:
|
||||||
%% Protocols or specifications that specify limited buffer sizes for
|
%% Protocols or specifications that specify limited buffer sizes for
|
||||||
%% language tags MUST allow for language tags of at least 35 characters.
|
%% language tags MUST allow for language tags of at least 35 characters.
|
||||||
%% Do not store long language tag to avoid possible DoS/flood attacks
|
%% Do not store long language tag to avoid possible DoS/flood attacks
|
||||||
send_header(StateData, ?MYNAME, <<"">>, ?MYLANG),
|
send_header(StateData, ?MYNAME, Version, ?MYLANG),
|
||||||
Txt = <<"Too long value of 'xml:lang' attribute">>,
|
Txt = <<"Too long value of 'xml:lang' attribute">>,
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
xmpp:serr_policy_violation(Txt, ?MYLANG)),
|
xmpp:serr_policy_violation(Txt, ?MYLANG)),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
#stream_start{to = undefined, lang = Lang} ->
|
#stream_start{to = undefined, lang = Lang, version = Version} ->
|
||||||
Txt = <<"Missing 'to' attribute">>,
|
Txt = <<"Missing 'to' attribute">>,
|
||||||
send_header(StateData, ?MYNAME, <<"">>, Lang),
|
send_header(StateData, ?MYNAME, Version, Lang),
|
||||||
send_element(StateData,
|
send_element(StateData,
|
||||||
xmpp:serr_improper_addressing(Txt, Lang)),
|
xmpp:serr_improper_addressing(Txt, Lang)),
|
||||||
{stop, normal, StateData};
|
{stop, normal, StateData};
|
||||||
@ -463,7 +464,7 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
|
|||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
_ ->
|
_ ->
|
||||||
send_header(StateData, Server, <<"">>, ?MYLANG),
|
send_header(StateData, Server, StreamVersion, ?MYLANG),
|
||||||
if not StateData#state.tls_enabled and
|
if not StateData#state.tls_enabled and
|
||||||
StateData#state.tls_required ->
|
StateData#state.tls_required ->
|
||||||
send_element(
|
send_element(
|
||||||
@ -492,7 +493,7 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
|
|||||||
end
|
end
|
||||||
catch _:{xmpp_codec, Why} ->
|
catch _:{xmpp_codec, Why} ->
|
||||||
Txt = xmpp:format_error(Why),
|
Txt = xmpp:format_error(Why),
|
||||||
send_header(StateData, ?MYNAME, <<"">>, ?MYLANG),
|
send_header(StateData, ?MYNAME, <<"1.0">>, ?MYLANG),
|
||||||
send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)),
|
send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)),
|
||||||
{stop, normal, StateData}
|
{stop, normal, StateData}
|
||||||
end;
|
end;
|
||||||
@ -517,13 +518,8 @@ wait_for_auth({xmlstreamelement, #xmlel{} = El}, StateData) ->
|
|||||||
decode_element(El, wait_for_auth, StateData);
|
decode_element(El, wait_for_auth, StateData);
|
||||||
wait_for_auth(Pkt, StateData) when ?IS_STREAM_MGMT_PACKET(Pkt) ->
|
wait_for_auth(Pkt, StateData) when ?IS_STREAM_MGMT_PACKET(Pkt) ->
|
||||||
fsm_next_state(wait_for_auth, dispatch_stream_mgmt(Pkt, StateData));
|
fsm_next_state(wait_for_auth, dispatch_stream_mgmt(Pkt, StateData));
|
||||||
wait_for_auth(#iq{type = get,
|
wait_for_auth(#iq{type = get, sub_els = [#legacy_auth{}]} = IQ, StateData) ->
|
||||||
sub_els = [#legacy_auth{username = U}]} = IQ, StateData) ->
|
Auth = #legacy_auth{username = <<>>, password = <<>>, resource = <<>>},
|
||||||
Username = case U of
|
|
||||||
undefined -> <<"">>;
|
|
||||||
_ -> U
|
|
||||||
end,
|
|
||||||
Auth = #legacy_auth{username = Username, password = <<>>, resource = <<>>},
|
|
||||||
Res = case ejabberd_auth:plain_password_required(StateData#state.server) of
|
Res = case ejabberd_auth:plain_password_required(StateData#state.server) of
|
||||||
false ->
|
false ->
|
||||||
xmpp:make_iq_result(IQ, Auth#legacy_auth{digest = <<>>});
|
xmpp:make_iq_result(IQ, Auth#legacy_auth{digest = <<>>});
|
||||||
|
@ -19,8 +19,9 @@
|
|||||||
wait_for_master/1, wait_for_slave/1,
|
wait_for_master/1, wait_for_slave/1,
|
||||||
make_iq_result/1, start_event_relay/0,
|
make_iq_result/1, start_event_relay/0,
|
||||||
stop_event_relay/1, put_event/2, get_event/1,
|
stop_event_relay/1, put_event/2, get_event/1,
|
||||||
bind/1, auth/1, open_session/1, zlib/1, starttls/1,
|
bind/1, auth/1, auth/2, open_session/1, open_session/2,
|
||||||
close_socket/1]).
|
zlib/1, starttls/1, close_socket/1, init_stream/1,
|
||||||
|
auth_legacy/2, auth_legacy/3]).
|
||||||
|
|
||||||
-include("suite.hrl").
|
-include("suite.hrl").
|
||||||
|
|
||||||
@ -154,15 +155,26 @@ init_per_testcase(stop_ejabberd, Config) ->
|
|||||||
open_session(bind(auth(connect(Config))));
|
open_session(bind(auth(connect(Config))));
|
||||||
init_per_testcase(TestCase, OrigConfig) ->
|
init_per_testcase(TestCase, OrigConfig) ->
|
||||||
subscribe_to_events(OrigConfig),
|
subscribe_to_events(OrigConfig),
|
||||||
|
TestGroup = proplists:get_value(
|
||||||
|
name, ?config(tc_group_properties, OrigConfig)),
|
||||||
Server = ?config(server, OrigConfig),
|
Server = ?config(server, OrigConfig),
|
||||||
Resource = ?config(resource, OrigConfig),
|
Resource = case TestGroup of
|
||||||
|
generic ->
|
||||||
|
randoms:get_string();
|
||||||
|
legacy_auth ->
|
||||||
|
randoms:get_string();
|
||||||
|
_ ->
|
||||||
|
?config(resource, OrigConfig)
|
||||||
|
end,
|
||||||
MasterResource = ?config(master_resource, OrigConfig),
|
MasterResource = ?config(master_resource, OrigConfig),
|
||||||
SlaveResource = ?config(slave_resource, OrigConfig),
|
SlaveResource = ?config(slave_resource, OrigConfig),
|
||||||
Test = atom_to_list(TestCase),
|
Test = atom_to_list(TestCase),
|
||||||
IsMaster = lists:suffix("_master", Test),
|
IsMaster = lists:suffix("_master", Test),
|
||||||
IsSlave = lists:suffix("_slave", Test),
|
IsSlave = lists:suffix("_slave", Test),
|
||||||
IsCarbons = lists:prefix("carbons_", Test),
|
IsCarbons = lists:prefix("carbons_", Test),
|
||||||
User = if IsMaster or IsCarbons -> <<"test_master!#$%^*()`~+-;_=[]{}|\\">>;
|
IsReplaced = lists:prefix("replaced_", Test),
|
||||||
|
User = if IsReplaced -> <<"test_single!#$%^*()`~+-;_=[]{}|\\">>;
|
||||||
|
IsMaster or IsCarbons -> <<"test_master!#$%^*()`~+-;_=[]{}|\\">>;
|
||||||
IsSlave -> <<"test_slave!#$%^*()`~+-;_=[]{}|\\">>;
|
IsSlave -> <<"test_slave!#$%^*()`~+-;_=[]{}|\\">>;
|
||||||
true -> <<"test_single!#$%^*()`~+-;_=[]{}|\\">>
|
true -> <<"test_single!#$%^*()`~+-;_=[]{}|\\">>
|
||||||
end,
|
end,
|
||||||
@ -172,11 +184,15 @@ init_per_testcase(TestCase, OrigConfig) ->
|
|||||||
end,
|
end,
|
||||||
Slave = if IsCarbons ->
|
Slave = if IsCarbons ->
|
||||||
jid:make(<<"test_master!#$%^*()`~+-;_=[]{}|\\">>, Server, SlaveResource);
|
jid:make(<<"test_master!#$%^*()`~+-;_=[]{}|\\">>, Server, SlaveResource);
|
||||||
|
IsReplaced ->
|
||||||
|
jid:make(User, Server, Resource);
|
||||||
true ->
|
true ->
|
||||||
jid:make(<<"test_slave!#$%^*()`~+-;_=[]{}|\\">>, Server, Resource)
|
jid:make(<<"test_slave!#$%^*()`~+-;_=[]{}|\\">>, Server, Resource)
|
||||||
end,
|
end,
|
||||||
Master = if IsCarbons ->
|
Master = if IsCarbons ->
|
||||||
jid:make(<<"test_master!#$%^*()`~+-;_=[]{}|\\">>, Server, MasterResource);
|
jid:make(<<"test_master!#$%^*()`~+-;_=[]{}|\\">>, Server, MasterResource);
|
||||||
|
IsReplaced ->
|
||||||
|
jid:make(User, Server, Resource);
|
||||||
true ->
|
true ->
|
||||||
jid:make(<<"test_master!#$%^*()`~+-;_=[]{}|\\">>, Server, Resource)
|
jid:make(<<"test_master!#$%^*()`~+-;_=[]{}|\\">>, Server, Resource)
|
||||||
end,
|
end,
|
||||||
@ -184,29 +200,35 @@ init_per_testcase(TestCase, OrigConfig) ->
|
|||||||
set_opt(slave, Slave,
|
set_opt(slave, Slave,
|
||||||
set_opt(master, Master,
|
set_opt(master, Master,
|
||||||
set_opt(resource, MyResource, OrigConfig)))),
|
set_opt(resource, MyResource, OrigConfig)))),
|
||||||
case TestCase of
|
case Test of
|
||||||
test_connect ->
|
"test_connect" ++ _ ->
|
||||||
Config;
|
Config;
|
||||||
test_auth ->
|
"test_legacy_auth" ++ _ ->
|
||||||
|
init_stream(set_opt(stream_version, <<"">>, Config));
|
||||||
|
"test_auth" ++ _ ->
|
||||||
connect(Config);
|
connect(Config);
|
||||||
test_starttls ->
|
"test_starttls" ++ _ ->
|
||||||
connect(Config);
|
connect(Config);
|
||||||
test_zlib ->
|
"test_zlib" ->
|
||||||
connect(Config);
|
connect(Config);
|
||||||
test_register ->
|
"test_register" ->
|
||||||
connect(Config);
|
connect(Config);
|
||||||
auth_md5 ->
|
"auth_md5" ->
|
||||||
connect(Config);
|
connect(Config);
|
||||||
auth_plain ->
|
"auth_plain" ->
|
||||||
connect(Config);
|
connect(Config);
|
||||||
test_bind ->
|
"unauthenticated_" ++ _ ->
|
||||||
|
connect(Config);
|
||||||
|
"test_bind" ->
|
||||||
auth(connect(Config));
|
auth(connect(Config));
|
||||||
sm_resume ->
|
"sm_resume" ->
|
||||||
auth(connect(Config));
|
auth(connect(Config));
|
||||||
sm_resume_failed ->
|
"sm_resume_failed" ->
|
||||||
auth(connect(Config));
|
auth(connect(Config));
|
||||||
test_open_session ->
|
"test_open_session" ->
|
||||||
bind(auth(connect(Config)));
|
bind(auth(connect(Config)));
|
||||||
|
"replaced" ++ _ ->
|
||||||
|
auth(connect(Config));
|
||||||
_ when IsMaster or IsSlave ->
|
_ when IsMaster or IsSlave ->
|
||||||
Password = ?config(password, Config),
|
Password = ?config(password, Config),
|
||||||
ejabberd_auth:try_register(User, Server, Password),
|
ejabberd_auth:try_register(User, Server, Password),
|
||||||
@ -218,30 +240,56 @@ init_per_testcase(TestCase, OrigConfig) ->
|
|||||||
end_per_testcase(_TestCase, _Config) ->
|
end_per_testcase(_TestCase, _Config) ->
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
legacy_auth_tests() ->
|
||||||
|
{legacy_auth, [parallel],
|
||||||
|
[test_legacy_auth,
|
||||||
|
test_legacy_auth_digest,
|
||||||
|
test_legacy_auth_no_resource,
|
||||||
|
test_legacy_auth_bad_jid,
|
||||||
|
test_legacy_auth_fail]}.
|
||||||
|
|
||||||
no_db_tests() ->
|
no_db_tests() ->
|
||||||
[{generic, [sequence],
|
[{generic, [parallel],
|
||||||
[test_connect,
|
[test_connect_bad_xml,
|
||||||
|
test_connect_unknown_ns,
|
||||||
|
test_connect_bad_ns_client,
|
||||||
|
test_connect_bad_ns_stream,
|
||||||
|
test_connect_bad_lang,
|
||||||
|
test_connect_bad_to,
|
||||||
|
test_connect_missing_to,
|
||||||
|
test_connect,
|
||||||
|
unauthenticated_iq,
|
||||||
|
unauthenticated_stanza,
|
||||||
test_starttls,
|
test_starttls,
|
||||||
test_zlib,
|
test_zlib,
|
||||||
test_auth,
|
test_auth,
|
||||||
|
test_auth_fail,
|
||||||
test_bind,
|
test_bind,
|
||||||
test_open_session,
|
test_open_session,
|
||||||
presence,
|
codec_failure,
|
||||||
|
unsupported_query,
|
||||||
|
bad_nonza,
|
||||||
|
invalid_from,
|
||||||
ping,
|
ping,
|
||||||
version,
|
version,
|
||||||
time,
|
time,
|
||||||
stats,
|
stats,
|
||||||
sm,
|
|
||||||
sm_resume,
|
|
||||||
sm_resume_failed,
|
|
||||||
disco]},
|
disco]},
|
||||||
|
{presence, [sequence], [presence]},
|
||||||
|
{sm, [sequence],
|
||||||
|
[sm,
|
||||||
|
sm_resume,
|
||||||
|
sm_resume_failed]},
|
||||||
{test_proxy65, [parallel],
|
{test_proxy65, [parallel],
|
||||||
[proxy65_master, proxy65_slave]}].
|
[proxy65_master, proxy65_slave]},
|
||||||
|
{replaced, [parallel],
|
||||||
|
[replaced_master, replaced_slave]}].
|
||||||
|
|
||||||
db_tests(riak) ->
|
db_tests(riak) ->
|
||||||
%% No support for mod_pubsub
|
%% No support for mod_pubsub
|
||||||
[{single_user, [sequence],
|
[{single_user, [sequence],
|
||||||
[test_register,
|
[test_register,
|
||||||
|
legacy_auth_tests(),
|
||||||
auth_plain,
|
auth_plain,
|
||||||
auth_md5,
|
auth_md5,
|
||||||
presence_broadcast,
|
presence_broadcast,
|
||||||
@ -273,6 +321,7 @@ db_tests(riak) ->
|
|||||||
db_tests(DB) when DB == mnesia; DB == redis ->
|
db_tests(DB) when DB == mnesia; DB == redis ->
|
||||||
[{single_user, [sequence],
|
[{single_user, [sequence],
|
||||||
[test_register,
|
[test_register,
|
||||||
|
legacy_auth_tests(),
|
||||||
auth_plain,
|
auth_plain,
|
||||||
auth_md5,
|
auth_md5,
|
||||||
presence_broadcast,
|
presence_broadcast,
|
||||||
@ -319,6 +368,7 @@ db_tests(_) ->
|
|||||||
%% No support for carboncopy
|
%% No support for carboncopy
|
||||||
[{single_user, [sequence],
|
[{single_user, [sequence],
|
||||||
[test_register,
|
[test_register,
|
||||||
|
legacy_auth_tests(),
|
||||||
auth_plain,
|
auth_plain,
|
||||||
auth_md5,
|
auth_md5,
|
||||||
presence_broadcast,
|
presence_broadcast,
|
||||||
@ -361,12 +411,14 @@ db_tests(_) ->
|
|||||||
ldap_tests() ->
|
ldap_tests() ->
|
||||||
[{ldap_tests, [sequence],
|
[{ldap_tests, [sequence],
|
||||||
[test_auth,
|
[test_auth,
|
||||||
|
test_auth_fail,
|
||||||
vcard_get,
|
vcard_get,
|
||||||
ldap_shared_roster_get]}].
|
ldap_shared_roster_get]}].
|
||||||
|
|
||||||
extauth_tests() ->
|
extauth_tests() ->
|
||||||
[{extauth_tests, [sequence],
|
[{extauth_tests, [sequence],
|
||||||
[test_auth,
|
[test_auth,
|
||||||
|
test_auth_fail,
|
||||||
test_unregister]}].
|
test_unregister]}].
|
||||||
|
|
||||||
groups() ->
|
groups() ->
|
||||||
@ -381,15 +433,15 @@ groups() ->
|
|||||||
{riak, [sequence], db_tests(riak)}].
|
{riak, [sequence], db_tests(riak)}].
|
||||||
|
|
||||||
all() ->
|
all() ->
|
||||||
[{group, ldap},
|
[%%{group, ldap},
|
||||||
{group, no_db},
|
{group, no_db},
|
||||||
{group, mnesia},
|
{group, mnesia},
|
||||||
{group, redis},
|
%%{group, redis},
|
||||||
{group, mysql},
|
%%{group, mysql},
|
||||||
{group, pgsql},
|
%%{group, pgsql},
|
||||||
{group, sqlite},
|
%%{group, sqlite},
|
||||||
{group, extauth},
|
%%{group, extauth},
|
||||||
{group, riak},
|
%%{group, riak},
|
||||||
stop_ejabberd].
|
stop_ejabberd].
|
||||||
|
|
||||||
stop_ejabberd(Config) ->
|
stop_ejabberd(Config) ->
|
||||||
@ -398,6 +450,48 @@ stop_ejabberd(Config) ->
|
|||||||
?recv1({xmlstreamend, <<"stream:stream">>}),
|
?recv1({xmlstreamend, <<"stream:stream">>}),
|
||||||
Config.
|
Config.
|
||||||
|
|
||||||
|
test_connect_bad_xml(Config) ->
|
||||||
|
Config0 = init_stream(set_opt(ns_client, <<"'">>, Config)),
|
||||||
|
?recv1(#stream_error{reason = 'not-well-formed'}),
|
||||||
|
?recv1({xmlstreamend, <<"stream:stream">>}),
|
||||||
|
close_socket(Config0).
|
||||||
|
|
||||||
|
test_connect_unknown_ns(Config) ->
|
||||||
|
Config0 = init_stream(set_opt(ns_client, <<"wrong">>, Config)),
|
||||||
|
?recv1(#stream_error{reason = 'not-well-formed'}),
|
||||||
|
?recv1({xmlstreamend, <<"stream:stream">>}),
|
||||||
|
close_socket(Config0).
|
||||||
|
|
||||||
|
test_connect_bad_ns_client(Config) ->
|
||||||
|
Config0 = init_stream(set_opt(ns_client, ?NS_SERVER, Config)),
|
||||||
|
?recv1(#stream_error{reason = 'invalid-namespace'}),
|
||||||
|
?recv1({xmlstreamend, <<"stream:stream">>}),
|
||||||
|
close_socket(Config0).
|
||||||
|
|
||||||
|
test_connect_bad_ns_stream(Config) ->
|
||||||
|
Config0 = init_stream(set_opt(ns_stream, <<"wrong">>, Config)),
|
||||||
|
?recv1(#stream_error{reason = 'invalid-namespace'}),
|
||||||
|
?recv1({xmlstreamend, <<"stream:stream">>}),
|
||||||
|
close_socket(Config0).
|
||||||
|
|
||||||
|
test_connect_bad_lang(Config) ->
|
||||||
|
Config0 = init_stream(set_opt(lang, lists:duplicate(36, $x), Config)),
|
||||||
|
?recv1(#stream_error{reason = 'policy-violation'}),
|
||||||
|
?recv1({xmlstreamend, <<"stream:stream">>}),
|
||||||
|
close_socket(Config0).
|
||||||
|
|
||||||
|
test_connect_bad_to(Config) ->
|
||||||
|
Config0 = init_stream(set_opt(server, <<"wrong.com">>, Config)),
|
||||||
|
?recv1(#stream_error{reason = 'host-unknown'}),
|
||||||
|
?recv1({xmlstreamend, <<"stream:stream">>}),
|
||||||
|
close_socket(Config0).
|
||||||
|
|
||||||
|
test_connect_missing_to(Config) ->
|
||||||
|
Config0 = init_stream(set_opt(server, <<"">>, Config)),
|
||||||
|
?recv1(#stream_error{reason = 'improper-addressing'}),
|
||||||
|
?recv1({xmlstreamend, <<"stream:stream">>}),
|
||||||
|
close_socket(Config0).
|
||||||
|
|
||||||
test_connect(Config) ->
|
test_connect(Config) ->
|
||||||
disconnect(connect(Config)).
|
disconnect(connect(Config)).
|
||||||
|
|
||||||
@ -462,6 +556,28 @@ try_unregister(Config) ->
|
|||||||
?recv1(#stream_error{reason = conflict}),
|
?recv1(#stream_error{reason = conflict}),
|
||||||
Config.
|
Config.
|
||||||
|
|
||||||
|
unauthenticated_stanza(Config) ->
|
||||||
|
%% Unauthenticated stanza should be silently dropped.
|
||||||
|
send(Config, #message{to = server_jid(Config)}),
|
||||||
|
disconnect(Config).
|
||||||
|
|
||||||
|
unauthenticated_iq(Config) ->
|
||||||
|
#iq{type = error} =
|
||||||
|
send_recv(Config, #iq{type = get, sub_els = [#disco_info{}]}),
|
||||||
|
disconnect(Config).
|
||||||
|
|
||||||
|
bad_nonza(Config) ->
|
||||||
|
%% Unsupported and invalid nonza should be silently dropped.
|
||||||
|
send(Config, #caps{}),
|
||||||
|
send(Config, #stanza_error{type = wrong}),
|
||||||
|
disconnect(Config).
|
||||||
|
|
||||||
|
invalid_from(Config) ->
|
||||||
|
send(Config, #message{from = jid:make(randoms:get_string())}),
|
||||||
|
?recv1(#stream_error{reason = 'invalid-from'}),
|
||||||
|
?recv1({xmlstreamend, <<"stream:stream">>}),
|
||||||
|
close_socket(Config).
|
||||||
|
|
||||||
auth_md5(Config) ->
|
auth_md5(Config) ->
|
||||||
Mechs = ?config(mechs, Config),
|
Mechs = ?config(mechs, Config),
|
||||||
case lists:member(<<"DIGEST-MD5">>, Mechs) of
|
case lists:member(<<"DIGEST-MD5">>, Mechs) of
|
||||||
@ -482,14 +598,37 @@ auth_plain(Config) ->
|
|||||||
{skipped, 'PLAIN_not_available'}
|
{skipped, 'PLAIN_not_available'}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
test_legacy_auth(Config) ->
|
||||||
|
disconnect(auth_legacy(Config, _Digest = false)).
|
||||||
|
|
||||||
|
test_legacy_auth_digest(Config) ->
|
||||||
|
ServerJID = server_jid(Config),
|
||||||
|
disconnect(auth_legacy(Config, _Digest = true)).
|
||||||
|
|
||||||
|
test_legacy_auth_no_resource(Config0) ->
|
||||||
|
Config = set_opt(resource, <<"">>, Config0),
|
||||||
|
disconnect(auth_legacy(Config, _Digest = false, _ShouldFail = true)).
|
||||||
|
|
||||||
|
test_legacy_auth_bad_jid(Config0) ->
|
||||||
|
Config = set_opt(user, <<"@">>, Config0),
|
||||||
|
disconnect(auth_legacy(Config, _Digest = false, _ShouldFail = true)).
|
||||||
|
|
||||||
|
test_legacy_auth_fail(Config0) ->
|
||||||
|
Config = set_opt(user, <<"wrong">>, Config0),
|
||||||
|
disconnect(auth_legacy(Config, _Digest = false, _ShouldFail = true)).
|
||||||
|
|
||||||
test_auth(Config) ->
|
test_auth(Config) ->
|
||||||
disconnect(auth(Config)).
|
disconnect(auth(Config)).
|
||||||
|
|
||||||
|
test_auth_fail(Config0) ->
|
||||||
|
Config = set_opt(user, <<"wrong">>, Config0),
|
||||||
|
disconnect(auth(Config, _ShouldFail = true)).
|
||||||
|
|
||||||
test_bind(Config) ->
|
test_bind(Config) ->
|
||||||
disconnect(bind(Config)).
|
disconnect(bind(Config)).
|
||||||
|
|
||||||
test_open_session(Config) ->
|
test_open_session(Config) ->
|
||||||
disconnect(open_session(Config)).
|
disconnect(open_session(Config, true)).
|
||||||
|
|
||||||
roster_get(Config) ->
|
roster_get(Config) ->
|
||||||
#iq{type = result, sub_els = [#roster_query{items = []}]} =
|
#iq{type = result, sub_els = [#roster_query{items = []}]} =
|
||||||
@ -519,6 +658,21 @@ roster_ver(Config) ->
|
|||||||
sub_els = [#roster_query{ver = Ver2}]}),
|
sub_els = [#roster_query{ver = Ver2}]}),
|
||||||
disconnect(Config).
|
disconnect(Config).
|
||||||
|
|
||||||
|
codec_failure(Config) ->
|
||||||
|
#iq{type = error} = send_recv(Config, #iq{type = wrong}),
|
||||||
|
disconnect(Config).
|
||||||
|
|
||||||
|
unsupported_query(Config) ->
|
||||||
|
ServerJID = server_jid(Config),
|
||||||
|
#iq{type = error} = send_recv(Config, #iq{type = get, to = ServerJID}),
|
||||||
|
#iq{type = error} = send_recv(Config, #iq{type = get, to = ServerJID,
|
||||||
|
sub_els = [#caps{}]}),
|
||||||
|
#iq{type = error} = send_recv(Config, #iq{type = get, to = ServerJID,
|
||||||
|
sub_els = [#roster_query{},
|
||||||
|
#disco_info{},
|
||||||
|
#privacy_query{}]}),
|
||||||
|
disconnect(Config).
|
||||||
|
|
||||||
presence(Config) ->
|
presence(Config) ->
|
||||||
send(Config, #presence{}),
|
send(Config, #presence{}),
|
||||||
JID = my_jid(Config),
|
JID = my_jid(Config),
|
||||||
@ -604,6 +758,18 @@ disco(Config) ->
|
|||||||
end, Items),
|
end, Items),
|
||||||
disconnect(Config).
|
disconnect(Config).
|
||||||
|
|
||||||
|
replaced_master(Config0) ->
|
||||||
|
Config = bind(Config0),
|
||||||
|
wait_for_slave(Config),
|
||||||
|
?recv1(#stream_error{reason = conflict}),
|
||||||
|
?recv1({xmlstreamend, <<"stream:stream">>}),
|
||||||
|
close_socket(Config).
|
||||||
|
|
||||||
|
replaced_slave(Config0) ->
|
||||||
|
wait_for_master(Config0),
|
||||||
|
Config = bind(Config0),
|
||||||
|
disconnect(Config).
|
||||||
|
|
||||||
sm(Config) ->
|
sm(Config) ->
|
||||||
Server = ?config(server, Config),
|
Server = ?config(server, Config),
|
||||||
ServerJID = jid:make(<<"">>, Server, <<"">>),
|
ServerJID = jid:make(<<"">>, Server, <<"">>),
|
||||||
|
150
test/suite.erl
150
test/suite.erl
@ -32,7 +32,7 @@ init_config(Config) ->
|
|||||||
{ok, CfgContentTpl} = file:read_file(ConfigPathTpl),
|
{ok, CfgContentTpl} = file:read_file(ConfigPathTpl),
|
||||||
CfgContent = process_config_tpl(CfgContentTpl, [
|
CfgContent = process_config_tpl(CfgContentTpl, [
|
||||||
{c2s_port, 5222},
|
{c2s_port, 5222},
|
||||||
{loglevel, 4},
|
{loglevel, 5},
|
||||||
{s2s_port, 5269},
|
{s2s_port, 5269},
|
||||||
{web_port, 5280},
|
{web_port, 5280},
|
||||||
{mysql_server, <<"localhost">>},
|
{mysql_server, <<"localhost">>},
|
||||||
@ -64,6 +64,12 @@ init_config(Config) ->
|
|||||||
{slave_nick, <<"slave_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
|
{slave_nick, <<"slave_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
|
||||||
{room_subject, <<"hello, world!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
|
{room_subject, <<"hello, world!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
|
||||||
{certfile, CertFile},
|
{certfile, CertFile},
|
||||||
|
{ns_client, ?NS_CLIENT},
|
||||||
|
{ns_stream, ?NS_STREAM},
|
||||||
|
{stream_version, <<"1.0">>},
|
||||||
|
{stream_id, <<"">>},
|
||||||
|
{mechs, []},
|
||||||
|
{lang, <<"en">>},
|
||||||
{base_dir, BaseDir},
|
{base_dir, BaseDir},
|
||||||
{resource, <<"resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
|
{resource, <<"resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
|
||||||
{master_resource, <<"master_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
|
{master_resource, <<"master_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
|
||||||
@ -118,20 +124,36 @@ process_config_tpl(Content, [{Name, DefaultValue} | Rest]) ->
|
|||||||
NewContent = binary:replace(Content, <<"@@",(atom_to_binary(Name, latin1))/binary, "@@">>, Val),
|
NewContent = binary:replace(Content, <<"@@",(atom_to_binary(Name, latin1))/binary, "@@">>, Val),
|
||||||
process_config_tpl(NewContent, Rest).
|
process_config_tpl(NewContent, Rest).
|
||||||
|
|
||||||
|
stream_header(Config) ->
|
||||||
|
NSStream = ?config(ns_stream, Config),
|
||||||
|
NSClient = ?config(ns_client, Config),
|
||||||
|
Lang = ?config(lang, Config),
|
||||||
|
To = case ?config(server, Config) of
|
||||||
|
<<"">> -> <<"">>;
|
||||||
|
Server -> <<"to='", Server/binary, "'">>
|
||||||
|
end,
|
||||||
|
Version = ?config(stream_version, Config),
|
||||||
|
io_lib:format("<?xml version='1.0'?><stream:stream "
|
||||||
|
"xmlns:stream='~s' xmlns='~s' ~s "
|
||||||
|
"version='~s' xml:lang='~s'>",
|
||||||
|
[NSStream, NSClient, To, Version, Lang]).
|
||||||
|
|
||||||
connect(Config) ->
|
connect(Config) ->
|
||||||
|
process_stream_features(init_stream(Config)).
|
||||||
|
|
||||||
|
init_stream(Config) ->
|
||||||
|
Version = ?config(stream_version, Config),
|
||||||
{ok, Sock} = ejabberd_socket:connect(
|
{ok, Sock} = ejabberd_socket:connect(
|
||||||
?config(server_host, Config),
|
?config(server_host, Config),
|
||||||
?config(server_port, Config),
|
?config(server_port, Config),
|
||||||
[binary, {packet, 0}, {active, false}]),
|
[binary, {packet, 0}, {active, false}]),
|
||||||
init_stream(set_opt(socket, Sock, Config)).
|
NewConfig = set_opt(socket, Sock, Config),
|
||||||
|
ok = send_text(NewConfig, stream_header(NewConfig)),
|
||||||
|
#stream_start{id = ID, xmlns = ?NS_CLIENT,
|
||||||
|
version = Version} = recv(),
|
||||||
|
set_opt(stream_id, ID, NewConfig).
|
||||||
|
|
||||||
init_stream(Config) ->
|
process_stream_features(Config) ->
|
||||||
ok = send_text(Config, io_lib:format(?STREAM_HEADER,
|
|
||||||
[?config(server, Config)])),
|
|
||||||
{xmlstreamstart, <<"stream:stream">>, Attrs} = recv(),
|
|
||||||
<<"jabber:client">> = fxml:get_attr_s(<<"xmlns">>, Attrs),
|
|
||||||
<<"1.0">> = fxml:get_attr_s(<<"version">>, Attrs),
|
|
||||||
#stream_features{sub_els = Fs} = recv(),
|
#stream_features{sub_els = Fs} = recv(),
|
||||||
Mechs = lists:flatmap(
|
Mechs = lists:flatmap(
|
||||||
fun(#sasl_mechanisms{list = Ms}) ->
|
fun(#sasl_mechanisms{list = Ms}) ->
|
||||||
@ -169,24 +191,27 @@ starttls(Config) ->
|
|||||||
?config(socket, Config),
|
?config(socket, Config),
|
||||||
[{certfile, ?config(certfile, Config)},
|
[{certfile, ?config(certfile, Config)},
|
||||||
connect]),
|
connect]),
|
||||||
init_stream(set_opt(socket, TLSSocket, Config)).
|
process_stream_features(init_stream(set_opt(socket, TLSSocket, Config))).
|
||||||
|
|
||||||
zlib(Config) ->
|
zlib(Config) ->
|
||||||
send(Config, #compress{methods = [<<"zlib">>]}),
|
send(Config, #compress{methods = [<<"zlib">>]}),
|
||||||
#compressed{} = recv(),
|
#compressed{} = recv(),
|
||||||
ZlibSocket = ejabberd_socket:compress(?config(socket, Config)),
|
ZlibSocket = ejabberd_socket:compress(?config(socket, Config)),
|
||||||
init_stream(set_opt(socket, ZlibSocket, Config)).
|
process_stream_features(init_stream(set_opt(socket, ZlibSocket, Config))).
|
||||||
|
|
||||||
auth(Config) ->
|
auth(Config) ->
|
||||||
|
auth(Config, false).
|
||||||
|
|
||||||
|
auth(Config, ShouldFail) ->
|
||||||
Mechs = ?config(mechs, Config),
|
Mechs = ?config(mechs, Config),
|
||||||
HaveMD5 = lists:member(<<"DIGEST-MD5">>, Mechs),
|
HaveMD5 = lists:member(<<"DIGEST-MD5">>, Mechs),
|
||||||
HavePLAIN = lists:member(<<"PLAIN">>, Mechs),
|
HavePLAIN = lists:member(<<"PLAIN">>, Mechs),
|
||||||
if HavePLAIN ->
|
if HavePLAIN ->
|
||||||
auth_SASL(<<"PLAIN">>, Config);
|
auth_SASL(<<"PLAIN">>, Config, ShouldFail);
|
||||||
HaveMD5 ->
|
HaveMD5 ->
|
||||||
auth_SASL(<<"DIGEST-MD5">>, Config);
|
auth_SASL(<<"DIGEST-MD5">>, Config, ShouldFail);
|
||||||
true ->
|
true ->
|
||||||
ct:fail(no_sasl_mechanisms_available)
|
auth_legacy(Config, false, ShouldFail)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
bind(Config) ->
|
bind(Config) ->
|
||||||
@ -198,29 +223,83 @@ bind(Config) ->
|
|||||||
Config.
|
Config.
|
||||||
|
|
||||||
open_session(Config) ->
|
open_session(Config) ->
|
||||||
#iq{type = result, sub_els = []} =
|
open_session(Config, false).
|
||||||
send_recv(Config, #iq{type = set, sub_els = [#xmpp_session{}]}),
|
|
||||||
|
open_session(Config, Force) ->
|
||||||
|
if Force ->
|
||||||
|
#iq{type = result, sub_els = []} =
|
||||||
|
send_recv(Config, #iq{type = set, sub_els = [#xmpp_session{}]});
|
||||||
|
true ->
|
||||||
|
ok
|
||||||
|
end,
|
||||||
Config.
|
Config.
|
||||||
|
|
||||||
|
auth_legacy(Config, IsDigest) ->
|
||||||
|
auth_legacy(Config, IsDigest, false).
|
||||||
|
|
||||||
|
auth_legacy(Config, IsDigest, ShouldFail) ->
|
||||||
|
ServerJID = server_jid(Config),
|
||||||
|
U = ?config(user, Config),
|
||||||
|
R = ?config(resource, Config),
|
||||||
|
P = ?config(password, Config),
|
||||||
|
#iq{type = result,
|
||||||
|
from = ServerJID,
|
||||||
|
sub_els = [#legacy_auth{username = <<"">>,
|
||||||
|
password = <<"">>,
|
||||||
|
resource = <<"">>} = Auth]} =
|
||||||
|
send_recv(Config,
|
||||||
|
#iq{to = ServerJID, type = get,
|
||||||
|
sub_els = [#legacy_auth{}]}),
|
||||||
|
Res = case Auth#legacy_auth.digest of
|
||||||
|
<<"">> when IsDigest ->
|
||||||
|
StreamID = ?config(stream_id, Config),
|
||||||
|
D = p1_sha:sha(<<StreamID/binary, P/binary>>),
|
||||||
|
send_recv(Config, #iq{to = ServerJID, type = set,
|
||||||
|
sub_els = [#legacy_auth{username = U,
|
||||||
|
resource = R,
|
||||||
|
digest = D}]});
|
||||||
|
_ when not IsDigest ->
|
||||||
|
send_recv(Config, #iq{to = ServerJID, type = set,
|
||||||
|
sub_els = [#legacy_auth{username = U,
|
||||||
|
resource = R,
|
||||||
|
password = P}]})
|
||||||
|
end,
|
||||||
|
case Res of
|
||||||
|
#iq{from = ServerJID, type = result, sub_els = []} ->
|
||||||
|
if ShouldFail ->
|
||||||
|
ct:fail(legacy_auth_should_have_failed);
|
||||||
|
true ->
|
||||||
|
Config
|
||||||
|
end;
|
||||||
|
#iq{from = ServerJID, type = error} ->
|
||||||
|
if ShouldFail ->
|
||||||
|
Config;
|
||||||
|
true ->
|
||||||
|
ct:fail(legacy_auth_failed)
|
||||||
|
end
|
||||||
|
end.
|
||||||
|
|
||||||
auth_SASL(Mech, Config) ->
|
auth_SASL(Mech, Config) ->
|
||||||
|
auth_SASL(Mech, Config, false).
|
||||||
|
|
||||||
|
auth_SASL(Mech, Config, ShouldFail) ->
|
||||||
{Response, SASL} = sasl_new(Mech,
|
{Response, SASL} = sasl_new(Mech,
|
||||||
?config(user, Config),
|
?config(user, Config),
|
||||||
?config(server, Config),
|
?config(server, Config),
|
||||||
?config(password, Config)),
|
?config(password, Config)),
|
||||||
send(Config, #sasl_auth{mechanism = Mech, text = Response}),
|
send(Config, #sasl_auth{mechanism = Mech, text = Response}),
|
||||||
wait_auth_SASL_result(set_opt(sasl, SASL, Config)).
|
wait_auth_SASL_result(set_opt(sasl, SASL, Config), ShouldFail).
|
||||||
|
|
||||||
wait_auth_SASL_result(Config) ->
|
wait_auth_SASL_result(Config, ShouldFail) ->
|
||||||
case recv() of
|
case recv() of
|
||||||
|
#sasl_success{} when ShouldFail ->
|
||||||
|
ct:fail(sasl_auth_should_have_failed);
|
||||||
#sasl_success{} ->
|
#sasl_success{} ->
|
||||||
ejabberd_socket:reset_stream(?config(socket, Config)),
|
ejabberd_socket:reset_stream(?config(socket, Config)),
|
||||||
send_text(Config,
|
send_text(Config, stream_header(Config)),
|
||||||
io_lib:format(?STREAM_HEADER,
|
#stream_start{xmlns = ?NS_CLIENT, version = <<"1.0">>} = recv(),
|
||||||
[?config(server, Config)])),
|
|
||||||
{xmlstreamstart, <<"stream:stream">>, Attrs} = recv(),
|
|
||||||
<<"jabber:client">> = fxml:get_attr_s(<<"xmlns">>, Attrs),
|
|
||||||
<<"1.0">> = fxml:get_attr_s(<<"version">>, Attrs),
|
|
||||||
#stream_features{sub_els = Fs} = recv(),
|
#stream_features{sub_els = Fs} = recv(),
|
||||||
|
#xmpp_session{optional = true} = lists:keyfind(xmpp_session, 1, Fs),
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun(#feature_sm{}, ConfigAcc) ->
|
fun(#feature_sm{}, ConfigAcc) ->
|
||||||
set_opt(sm, true, ConfigAcc);
|
set_opt(sm, true, ConfigAcc);
|
||||||
@ -232,7 +311,9 @@ wait_auth_SASL_result(Config) ->
|
|||||||
#sasl_challenge{text = ClientIn} ->
|
#sasl_challenge{text = ClientIn} ->
|
||||||
{Response, SASL} = (?config(sasl, Config))(ClientIn),
|
{Response, SASL} = (?config(sasl, Config))(ClientIn),
|
||||||
send(Config, #sasl_response{text = Response}),
|
send(Config, #sasl_response{text = Response}),
|
||||||
wait_auth_SASL_result(set_opt(sasl, SASL, Config));
|
wait_auth_SASL_result(set_opt(sasl, SASL, Config), ShouldFail);
|
||||||
|
#sasl_failure{} when ShouldFail ->
|
||||||
|
Config;
|
||||||
#sasl_failure{} ->
|
#sasl_failure{} ->
|
||||||
ct:fail(sasl_auth_failed)
|
ct:fail(sasl_auth_failed)
|
||||||
end.
|
end.
|
||||||
@ -252,18 +333,23 @@ match_failure(Received, Matches) ->
|
|||||||
recv() ->
|
recv() ->
|
||||||
receive
|
receive
|
||||||
{'$gen_event', {xmlstreamelement, El}} ->
|
{'$gen_event', {xmlstreamelement, El}} ->
|
||||||
try
|
decode(El);
|
||||||
Pkt = xmpp:decode(El),
|
{'$gen_event', {xmlstreamstart, Name, Attrs}} ->
|
||||||
ct:pal("recv: ~p ->~n~s", [El, xmpp_codec:pp(Pkt)]),
|
decode(#xmlel{name = Name, attrs = Attrs});
|
||||||
Pkt
|
|
||||||
catch _:{xmpp_codec, Why} ->
|
|
||||||
ct:fail("recv failed: ~p->~n~s",
|
|
||||||
[El, xmpp:format_error(Why)])
|
|
||||||
end;
|
|
||||||
{'$gen_event', Event} ->
|
{'$gen_event', Event} ->
|
||||||
Event
|
Event
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
decode(El) ->
|
||||||
|
try
|
||||||
|
Pkt = xmpp:decode(El),
|
||||||
|
ct:pal("recv: ~p ->~n~s", [El, xmpp_codec:pp(Pkt)]),
|
||||||
|
Pkt
|
||||||
|
catch _:{xmpp_codec, Why} ->
|
||||||
|
ct:fail("recv failed: ~p->~n~s",
|
||||||
|
[El, xmpp:format_error(Why)])
|
||||||
|
end.
|
||||||
|
|
||||||
fix_ns(#xmlel{name = Tag, attrs = Attrs} = El)
|
fix_ns(#xmlel{name = Tag, attrs = Attrs} = El)
|
||||||
when Tag == <<"stream:features">>; Tag == <<"stream:error">> ->
|
when Tag == <<"stream:features">>; Tag == <<"stream:error">> ->
|
||||||
NewAttrs = [{<<"xmlns">>, <<"http://etherx.jabber.org/streams">>}
|
NewAttrs = [{<<"xmlns">>, <<"http://etherx.jabber.org/streams">>}
|
||||||
|
@ -5,12 +5,6 @@
|
|||||||
-include("mod_proxy65.hrl").
|
-include("mod_proxy65.hrl").
|
||||||
-include("xmpp_codec.hrl").
|
-include("xmpp_codec.hrl").
|
||||||
|
|
||||||
-define(STREAM_HEADER,
|
|
||||||
<<"<?xml version='1.0'?><stream:stream "
|
|
||||||
"xmlns:stream='http://etherx.jabber.org/stream"
|
|
||||||
"s' xmlns='jabber:client' to='~s' version='1.0"
|
|
||||||
"'>">>).
|
|
||||||
|
|
||||||
-define(STREAM_TRAILER, <<"</stream:stream>">>).
|
-define(STREAM_TRAILER, <<"</stream:stream>">>).
|
||||||
|
|
||||||
-define(PUBSUB(Node), <<(?NS_PUBSUB)/binary, "#", Node>>).
|
-define(PUBSUB(Node), <<(?NS_PUBSUB)/binary, "#", Node>>).
|
||||||
|
Loading…
Reference in New Issue
Block a user