Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/processone/ejabberd.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>2016-09-21 10:45:11 +0300
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>2016-09-21 10:45:11 +0300
commitceda0737666760e5fa93bed0a9ab160778d29358 (patch)
treee56129704f4818a4496ef092e9331254441c163c
parenta4ec06445593728af35149a2a111527f8515e43c (diff)
Add tests for external component
-rw-r--r--src/ejabberd_c2s.erl2
-rw-r--r--src/ejabberd_service.erl29
-rw-r--r--test/ejabberd_SUITE.erl82
-rw-r--r--test/ejabberd_SUITE_data/ejabberd.yml5
-rw-r--r--test/suite.erl83
5 files changed, 154 insertions, 47 deletions
diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
index e98a9eb8f..7dc9960e6 100644
--- a/src/ejabberd_c2s.erl
+++ b/src/ejabberd_c2s.erl
@@ -494,7 +494,7 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
catch _:{xmpp_codec, Why} ->
Txt = xmpp:format_error(Why),
send_header(StateData, ?MYNAME, <<"1.0">>, ?MYLANG),
- send_element(StateData, xmpp:serr_not_well_formed(Txt, ?MYLANG)),
+ send_element(StateData, xmpp:serr_invalid_xml(Txt, ?MYLANG)),
{stop, normal, StateData}
end;
wait_for_stream(timeout, StateData) ->
diff --git a/src/ejabberd_service.erl b/src/ejabberd_service.erl
index 002d74949..f4338593d 100644
--- a/src/ejabberd_service.erl
+++ b/src/ejabberd_service.erl
@@ -125,7 +125,12 @@ init([{SockMod, Socket}, Opts]) ->
wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
try xmpp:decode(#xmlel{name = Name, attrs = Attrs}) of
- #stream_start{xmlns = ?NS_COMPONENT, to = To} when is_record(To, jid) ->
+ #stream_start{xmlns = NS_COMPONENT, stream_xmlns = NS_STREAM}
+ when NS_COMPONENT /= ?NS_COMPONENT; NS_STREAM /= ?NS_STREAM ->
+ send_header(StateData, ?MYNAME),
+ send_element(StateData, xmpp:serr_invalid_namespace()),
+ {stop, normal, StateData};
+ #stream_start{to = To} when is_record(To, jid) ->
Host = To#jid.lserver,
send_header(StateData, Host),
HostOpts = case dict:is_key(Host, StateData#state.host_opts) of
@@ -141,13 +146,9 @@ wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
end,
{next_state, wait_for_handshake,
StateData#state{host = Host, host_opts = HostOpts}};
- #stream_start{xmlns = ?NS_COMPONENT} ->
- send_header(StateData, ?MYNAME),
- send_element(StateData, xmpp:serr_improper_addressing()),
- {stop, normal, StateData};
#stream_start{} ->
send_header(StateData, ?MYNAME),
- send_element(StateData, xmpp:serr_invalid_namespace()),
+ send_element(StateData, xmpp:serr_improper_addressing()),
{stop, normal, StateData}
catch _:{xmpp_codec, Why} ->
Txt = xmpp:format_error(Why),
@@ -203,7 +204,8 @@ stream_established(El, StateData) when ?is_stanza(El) ->
To = xmpp:get_to(El),
Lang = xmpp:get_lang(El),
if From == undefined orelse To == undefined ->
- send_error(StateData, El, xmpp:err_jid_malformed());
+ Txt = <<"Missing 'from' or 'to' attribute">>,
+ send_error(StateData, El, xmpp:err_jid_malformed(Txt, Lang));
true ->
FromJID = case StateData#state.check_from of
false ->
@@ -214,19 +216,16 @@ stream_established(El, StateData) when ?is_stanza(El) ->
From;
_ ->
%% The default is the standard behaviour in XEP-0114
- case From of
- #jid{lserver = Server} ->
- case dict:is_key(Server, StateData#state.host_opts) of
- true -> From;
- false -> error
- end;
- _ -> error
+ Server = From#jid.lserver,
+ case dict:is_key(Server, StateData#state.host_opts) of
+ true -> From;
+ false -> error
end
end,
if FromJID /= error ->
ejabberd_router:route(FromJID, To, El);
true ->
- Txt = <<"Incorrect value of 'from' or 'to' attribute">>,
+ Txt = <<"Improper domain part of 'from' attribute">>,
send_error(StateData, El, xmpp:err_not_allowed(Txt, Lang))
end
end,
diff --git a/test/ejabberd_SUITE.erl b/test/ejabberd_SUITE.erl
index 0af81dd33..dbcd9a905 100644
--- a/test/ejabberd_SUITE.erl
+++ b/test/ejabberd_SUITE.erl
@@ -125,6 +125,15 @@ do_init_per_group(riak, Config) ->
Err ->
{skip, {riak_not_available, Err}}
end;
+do_init_per_group(component, Config) ->
+ Server = ?config(server, Config),
+ Port = ?config(component_port, Config),
+ set_opt(xmlns, ?NS_COMPONENT,
+ set_opt(server, <<"component.", Server/binary>>,
+ set_opt(type, component,
+ set_opt(server_port, Port,
+ set_opt(stream_version, <<"">>,
+ set_opt(lang, <<"">>, Config))))));
do_init_per_group(_GroupName, Config) ->
Pid = start_event_relay(),
set_opt(event_relay, Pid, Config).
@@ -147,6 +156,8 @@ end_per_group(extauth, _Config) ->
ok;
end_per_group(riak, _Config) ->
ok;
+end_per_group(component, _Config) ->
+ ok;
end_per_group(_GroupName, Config) ->
stop_event_relay(Config),
ok.
@@ -252,7 +263,7 @@ no_db_tests() ->
[{generic, [parallel],
[test_connect_bad_xml,
test_connect_unknown_ns,
- test_connect_bad_ns_client,
+ test_connect_bad_xmlns,
test_connect_bad_ns_stream,
test_connect_bad_lang,
test_connect_bad_to,
@@ -421,10 +432,27 @@ extauth_tests() ->
test_auth_fail,
test_unregister]}].
+component_tests() ->
+ [{component_tests, [sequence],
+ [test_connect_bad_xml,
+ test_connect_unknown_ns,
+ test_connect_bad_xmlns,
+ test_connect_bad_ns_stream,
+ test_connect_missing_to,
+ test_connect,
+ test_auth,
+ test_auth_fail,
+ component_missing_address,
+ component_invalid_from,
+ component_send,
+ bad_nonza,
+ codec_failure]}].
+
groups() ->
[{ldap, [sequence], ldap_tests()},
{extauth, [sequence], extauth_tests()},
{no_db, [sequence], no_db_tests()},
+ {component, [sequence], component_tests()},
{mnesia, [sequence], db_tests(mnesia)},
{redis, [sequence], db_tests(redis)},
{mysql, [sequence], db_tests(mysql)},
@@ -433,7 +461,8 @@ groups() ->
{riak, [sequence], db_tests(riak)}].
all() ->
- [%%{group, ldap},
+ [{group, component},
+ %%{group, ldap},
{group, no_db},
{group, mnesia},
%%{group, redis},
@@ -451,19 +480,19 @@ stop_ejabberd(Config) ->
Config.
test_connect_bad_xml(Config) ->
- Config0 = init_stream(set_opt(ns_client, <<"'">>, Config)),
+ Config0 = init_stream(set_opt(xmlns, <<"'">>, 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'}),
+ Config0 = init_stream(set_opt(xmlns, <<"wrong">>, Config)),
+ ?recv1(#stream_error{reason = 'invalid-xml'}),
?recv1({xmlstreamend, <<"stream:stream">>}),
close_socket(Config0).
-test_connect_bad_ns_client(Config) ->
- Config0 = init_stream(set_opt(ns_client, ?NS_SERVER, Config)),
+test_connect_bad_xmlns(Config) ->
+ Config0 = init_stream(set_opt(xmlns, ?NS_SERVER, Config)),
?recv1(#stream_error{reason = 'invalid-namespace'}),
?recv1({xmlstreamend, <<"stream:stream">>}),
close_socket(Config0).
@@ -495,6 +524,12 @@ test_connect_missing_to(Config) ->
test_connect(Config) ->
disconnect(connect(Config)).
+test_component_connect(Config) ->
+ disconnect(component_connect(Config)).
+
+component_connect(Config) ->
+ init_stream(Config).
+
test_starttls(Config) ->
case ?config(starttls, Config) of
true ->
@@ -578,6 +613,25 @@ invalid_from(Config) ->
?recv1({xmlstreamend, <<"stream:stream">>}),
close_socket(Config).
+component_missing_address(Config) ->
+ Server = server_jid(Config),
+ #iq{type = error} = send_recv(Config, #iq{type = get, from = Server}),
+ #iq{type = error} = send_recv(Config, #iq{type = get, to = Server}),
+ disconnect(Config).
+
+component_invalid_from(Config) ->
+ From = jid:make(randoms:get_string()),
+ To = jid:make(randoms:get_string()),
+ #iq{type = error} =
+ send_recv(Config, #iq{type = get, from = From, to = To}),
+ disconnect(Config).
+
+component_send(Config) ->
+ JID = my_jid(Config),
+ send(Config, #message{from = JID, to = JID}),
+ #message{from = JID, to = JID} = recv(),
+ disconnect(Config).
+
auth_md5(Config) ->
Mechs = ?config(mechs, Config),
case lists:member(<<"DIGEST-MD5">>, Mechs) of
@@ -621,7 +675,8 @@ test_auth(Config) ->
disconnect(auth(Config)).
test_auth_fail(Config0) ->
- Config = set_opt(user, <<"wrong">>, Config0),
+ Config = set_opt(user, <<"wrong">>,
+ set_opt(password, <<"wrong">>, Config0)),
disconnect(auth(Config, _ShouldFail = true)).
test_bind(Config) ->
@@ -659,7 +714,9 @@ roster_ver(Config) ->
disconnect(Config).
codec_failure(Config) ->
- #iq{type = error} = send_recv(Config, #iq{type = wrong}),
+ JID = my_jid(Config),
+ #iq{type = error} =
+ send_recv(Config, #iq{type = wrong, from = JID, to = JID}),
disconnect(Config).
unsupported_query(Config) ->
@@ -829,13 +886,14 @@ private(Config) ->
<<>>)},
Storage = #bookmark_storage{conference = [Conference]},
StorageXMLOut = xmpp_codec:encode(Storage),
+ WrongEl = #xmlel{name = <<"wrong">>},
#iq{type = error} =
- send_recv(Config, #iq{type = get, sub_els = [#private{}],
- to = server_jid(Config)}),
+ send_recv(Config, #iq{type = get,
+ sub_els = [#private{xml_els = [WrongEl]}]}),
#iq{type = result, sub_els = []} =
send_recv(
Config, #iq{type = set,
- sub_els = [#private{xml_els = [StorageXMLOut]}]}),
+ sub_els = [#private{xml_els = [WrongEl, StorageXMLOut]}]}),
#iq{type = result,
sub_els = [#private{xml_els = [StorageXMLIn]}]} =
send_recv(
diff --git a/test/ejabberd_SUITE_data/ejabberd.yml b/test/ejabberd_SUITE_data/ejabberd.yml
index b2a0cd5ac..99af18bbf 100644
--- a/test/ejabberd_SUITE_data/ejabberd.yml
+++ b/test/ejabberd_SUITE_data/ejabberd.yml
@@ -428,6 +428,11 @@ listen:
port: @@web_port@@
module: ejabberd_http
captcha: true
+ -
+ port: @@component_port@@
+ module: ejabberd_service
+ password: >-
+ @@password@@
loglevel: @@loglevel@@
max_fsm_queue: 1000
modules:
diff --git a/test/suite.erl b/test/suite.erl
index 93141d846..f78b7bd1a 100644
--- a/test/suite.erl
+++ b/test/suite.erl
@@ -30,11 +30,14 @@ init_config(Config) ->
{ok, CWD} = file:get_cwd(),
{ok, _} = file:copy(CertFile, filename:join([CWD, "cert.pem"])),
{ok, CfgContentTpl} = file:read_file(ConfigPathTpl),
+ Password = <<"password!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>,
CfgContent = process_config_tpl(CfgContentTpl, [
{c2s_port, 5222},
{loglevel, 5},
{s2s_port, 5269},
+ {component_port, 5270},
{web_port, 5280},
+ {password, Password},
{mysql_server, <<"localhost">>},
{mysql_port, 3306},
{mysql_db, <<"ejabberd_test">>},
@@ -58,13 +61,15 @@ init_config(Config) ->
application:set_env(mnesia, dir, MnesiaDir),
[{server_port, ct:get_config(c2s_port, 5222)},
{server_host, "localhost"},
+ {component_port, ct:get_config(component_port, 5270)},
{server, ?COMMON_VHOST},
{user, <<"test_single!#$%^*()`~+-;_=[]{}|\\">>},
{master_nick, <<"master_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
{slave_nick, <<"slave_nick!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
{room_subject, <<"hello, world!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
{certfile, CertFile},
- {ns_client, ?NS_CLIENT},
+ {type, client},
+ {xmlns, ?NS_CLIENT},
{ns_stream, ?NS_STREAM},
{stream_version, <<"1.0">>},
{stream_id, <<"">>},
@@ -74,7 +79,7 @@ init_config(Config) ->
{resource, <<"resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
{master_resource, <<"master_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
{slave_resource, <<"slave_resource!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
- {password, <<"password!@#$%^&*()'\"`~<>+-/;:_=[]{}|\\">>},
+ {password, Password},
{backends, get_config_backends()}
|Config].
@@ -126,20 +131,29 @@ process_config_tpl(Content, [{Name, DefaultValue} | Rest]) ->
stream_header(Config) ->
NSStream = ?config(ns_stream, Config),
- NSClient = ?config(ns_client, Config),
- Lang = ?config(lang, Config),
+ XMLNS = ?config(xmlns, Config),
+ Lang = case ?config(lang, Config) of
+ <<"">> -> <<"">>;
+ L -> iolist_to_binary(["xml:lang='", L, "'"])
+ end,
To = case ?config(server, Config) of
<<"">> -> <<"">>;
Server -> <<"to='", Server/binary, "'">>
end,
- Version = ?config(stream_version, Config),
+ Version = case ?config(stream_version, Config) of
+ <<"">> -> <<"">>;
+ V -> <<"version='", V/binary, "'">>
+ end,
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]).
+ "xmlns:stream='~s' xmlns='~s' ~s ~s ~s>",
+ [NSStream, XMLNS, To, Version, Lang]).
connect(Config) ->
- process_stream_features(init_stream(Config)).
+ NewConfig = init_stream(Config),
+ case ?config(type, NewConfig) of
+ client -> process_stream_features(NewConfig);
+ component -> NewConfig
+ end.
init_stream(Config) ->
Version = ?config(stream_version, Config),
@@ -149,8 +163,11 @@ init_stream(Config) ->
[binary, {packet, 0}, {active, false}]),
NewConfig = set_opt(socket, Sock, Config),
ok = send_text(NewConfig, stream_header(NewConfig)),
- #stream_start{id = ID, xmlns = ?NS_CLIENT,
- version = Version} = recv(),
+ XMLNS = case ?config(type, Config) of
+ client -> ?NS_CLIENT;
+ component -> ?NS_COMPONENT
+ end,
+ #stream_start{id = ID, xmlns = XMLNS, version = Version} = recv(),
set_opt(stream_id, ID, NewConfig).
process_stream_features(Config) ->
@@ -174,7 +191,11 @@ process_stream_features(Config) ->
disconnect(Config) ->
Socket = ?config(socket, Config),
- ok = ejabberd_socket:send(Socket, ?STREAM_TRAILER),
+ try
+ ok = send_text(Config, ?STREAM_TRAILER)
+ catch exit:normal ->
+ ok
+ end,
{xmlstreamend, <<"stream:stream">>} = recv(),
ejabberd_socket:close(Socket),
Config.
@@ -203,6 +224,7 @@ auth(Config) ->
auth(Config, false).
auth(Config, ShouldFail) ->
+ Type = ?config(type, Config),
Mechs = ?config(mechs, Config),
HaveMD5 = lists:member(<<"DIGEST-MD5">>, Mechs),
HavePLAIN = lists:member(<<"PLAIN">>, Mechs),
@@ -210,16 +232,23 @@ auth(Config, ShouldFail) ->
auth_SASL(<<"PLAIN">>, Config, ShouldFail);
HaveMD5 ->
auth_SASL(<<"DIGEST-MD5">>, Config, ShouldFail);
- true ->
- auth_legacy(Config, false, ShouldFail)
+ Type == client ->
+ auth_legacy(Config, false, ShouldFail);
+ Type == component ->
+ auth_component(Config, ShouldFail)
end.
bind(Config) ->
- #iq{type = result, sub_els = [#bind{}]} =
- send_recv(
- Config,
- #iq{type = set,
- sub_els = [#bind{resource = ?config(resource, Config)}]}),
+ case ?config(type, Config) of
+ client ->
+ #iq{type = result, sub_els = [#bind{}]} =
+ send_recv(
+ Config,
+ #iq{type = set,
+ sub_els = [#bind{resource = ?config(resource, Config)}]});
+ component ->
+ ok
+ end,
Config.
open_session(Config) ->
@@ -279,6 +308,22 @@ auth_legacy(Config, IsDigest, ShouldFail) ->
end
end.
+auth_component(Config, ShouldFail) ->
+ StreamID = ?config(stream_id, Config),
+ Password = ?config(password, Config),
+ Digest = p1_sha:sha(<<StreamID/binary, Password/binary>>),
+ send(Config, #handshake{data = Digest}),
+ case recv() of
+ #handshake{} when ShouldFail ->
+ ct:fail(component_auth_should_have_failed);
+ #handshake{} ->
+ Config;
+ #stream_error{reason = 'not-authorized'} when ShouldFail ->
+ Config;
+ #stream_error{reason = 'not-authorized'} ->
+ ct:fail(component_auth_failed)
+ end.
+
auth_SASL(Mech, Config) ->
auth_SASL(Mech, Config, false).