24
1
mirror of https://github.com/processone/ejabberd.git synced 2024-06-24 22:25:47 +02:00

Add tests for external component

This commit is contained in:
Evgeniy Khramtsov 2016-09-21 10:45:11 +03:00
parent a4ec064455
commit ceda073766
5 changed files with 154 additions and 47 deletions

View File

@ -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) ->

View File

@ -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,

View File

@ -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(

View File

@ -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:

View File

@ -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).