Start with tests for sasl2

This commit is contained in:
Pawel Chmielowski
2026-03-16 10:43:41 +01:00
parent 00e61dd816
commit 975dcc1128
4 changed files with 102 additions and 1 deletions
+3
View File
@@ -11,6 +11,7 @@
{<<"fast_xml">>,{pkg,<<"fast_xml">>,<<"1.1.57">>},0},
{<<"fast_yaml">>,{pkg,<<"fast_yaml">>,<<"1.0.39">>},0},
{<<"idna">>,{pkg,<<"idna">>,<<"6.1.1">>},0},
{<<"jiffy">>,{pkg,<<"jiffy">>,<<"1.1.2">>},1},
{<<"jose">>,{pkg,<<"jose">>,<<"1.11.12">>},0},
{<<"luerl">>,{pkg,<<"luerl">>,<<"1.2.3">>},0},
{<<"mqtree">>,{pkg,<<"mqtree">>,<<"1.0.19">>},0},
@@ -40,6 +41,7 @@
{<<"fast_xml">>, <<"31EFC0F9BCEDA92069704F7A25830407DA5DC3DAD1272B810D6F2E13E73CC11A">>},
{<<"fast_yaml">>, <<"2E71168091949BAB0E5F583B340A99072B4D22D93EB86624E7850A12B1517BE4">>},
{<<"idna">>, <<"8A63070E9F7D0C62EB9D9FCB360A7DE382448200FBBD1B106CC96D3D8099DF8D">>},
{<<"jiffy">>, <<"A9B6C9A7EC268E7CF493D028F0A4C9144F59CCB878B1AFE42841597800840A1B">>},
{<<"jose">>, <<"06E62B467B61D3726CBC19E9B5489F7549C37993DE846DFB3EE8259F9ED208B3">>},
{<<"luerl">>, <<"DF25F41944E57A7C4D9EF09D238BC3E850276C46039CFC12B8BB42ECCF36FCB1">>},
{<<"mqtree">>, <<"D769C25F898810725FC7DB0DBFFE5F72098647048B1BE2E6D772F1C2F31D8476">>},
@@ -68,6 +70,7 @@
{<<"fast_xml">>, <<"EEC34E90ADACAFE467D5DDAB635A014DED73B98B4061554B2D1972173D929C39">>},
{<<"fast_yaml">>, <<"24C7B9AB9E2B9269D64E45F4A2A1280966ADB17D31E63365CFD3EE277FB0A78D">>},
{<<"idna">>, <<"92376EB7894412ED19AC475E4A86F7B413C1B9FBB5BD16DCCD57934157944CEA">>},
{<<"jiffy">>, <<"BB61BC42A720BBD33CB09A410E48BB79A61012C74CB8B3E75F26D988485CF381">>},
{<<"jose">>, <<"31E92B653E9210B696765CDD885437457DE1ADD2A9011D92F8CF63E4641BAB7B">>},
{<<"luerl">>, <<"1B4B9D0CA5D7D280D1D2787A6A5EE9F5A212641B62BFF91556BAA53805DF3AED">>},
{<<"mqtree">>, <<"C81065715C49A1882812F80A5AE2D842E80DD3F2D130530DF35990248BF8CE3C">>},
+25 -1
View File
@@ -37,7 +37,7 @@
bind/1, auth/1, auth/2, open_session/1, open_session/2,
zlib/1, starttls/1, starttls/2, close_socket/1, init_stream/1,
auth_legacy/2, auth_legacy/3, tcp_connect/1, send_text/2,
set_roster/3, del_roster/1]).
set_roster/3, del_roster/1, connect_sasl2/2, auth_SASL2/3, auth_fast_token/4]).
-include("suite.hrl").
suite() ->
@@ -331,6 +331,9 @@ init_per_testcase(TestCase, OrigConfig) ->
connect(Config);
"auth_plain" ->
connect(Config);
"auth_sasl2" ->
Jid = jid:encode(jid:make(User, Server)),
connect_sasl2(starttls(connect_sasl2(Config, Jid)), Jid);
"auth_external" ++ _ ->
connect(Config);
"unauthenticated_" ++ _ ->
@@ -433,6 +436,7 @@ db_tests(DB) when DB == mnesia; DB == redis ->
[test_register,
legacy_auth_tests(),
auth_plain,
auth_sasl2,
auth_md5,
presence_broadcast,
last,
@@ -851,6 +855,26 @@ auth_plain(Config) ->
{skipped, 'PLAIN_not_available'}
end.
auth_sasl2(Config) ->
Mechs = ?config(mechs, Config),
case lists:member(<<"DIGEST-MD5">>, Mechs) of
true ->
Config2 = disconnect(auth_SASL2(<<"DIGEST-MD5">>, Config, false)),
case ?config(fast_token, Config2) of
<<>> -> disconnect(Config);
Token ->
User = ?config(user, Config),
Jid = jid:encode(jid:make(User, ?config(server, Config))),
Hash = crypto:mac(hmac, sha256, Token, <<"Initiator">>),
CalcToken = (<<User/binary, 0, Hash/binary>>),
Config3 = connect_sasl2(starttls(connect_sasl2(Config2, Jid)), Jid),
disconnect(auth_fast_token(<<"HT-SHA-256-NONE">>, CalcToken, Config3, false))
end;
false ->
disconnect(Config),
{skipped, 'PLAIN_not_available'}
end.
auth_external(Config0) ->
Config = connect(starttls(Config0)),
disconnect(auth_SASL(<<"EXTERNAL">>, Config)).
+1
View File
@@ -156,6 +156,7 @@ Welcome to this XMPP server."
get_url: GET_URL
max_size: 10000
vcard: VCARD
mod_auth_fast: []
registration_timeout: infinity
s2s_use_starttls: false
ca_file: CAFILE
+73
View File
@@ -273,6 +273,15 @@ connect(Config) ->
component -> NewConfig
end.
connect_sasl2(Config, Jid) ->
Config2 = set_opt(stream_from, Jid, Config),
NewConfig = init_stream(Config2),
case ?config(type, NewConfig) of
client -> process_stream_features(NewConfig);
server -> process_stream_features(NewConfig);
component -> NewConfig
end.
tcp_connect(Config) ->
case ?config(receiver, Config) of
undefined ->
@@ -550,6 +559,70 @@ wait_auth_SASL_result(Config, ShouldFail) ->
ct:fail(sasl_auth_failed)
end.
auth_fast_token(Mech, Token, Config, ShouldFail) ->
Pkt = #sasl2_authenticate{mechanism = Mech, initial_response = Token,
sub_els = [#bind2_bind{tag = <<"TestRunner">>}],
user_agent = #sasl2_user_agent{id = <<"9A62C3A9-FE59-43B7-80F3-9E8EE25DE6C5">>,
software = <<"TestRunner">>, device = <<"tester">>}},
send(Config, Pkt),
wait_auth_SASL2_result(Config, ShouldFail).
auth_SASL2(Mech, Config, ShouldFail) ->
Creds = {?config(user, Config),
?config(server, Config),
?config(password, Config)},
{Response, SASL} = sasl_new(Mech, Creds),
Pkt = #sasl2_authenticate{mechanism = Mech, initial_response = Response,
sub_els = [#bind2_bind{tag = <<"TestRunner">>}, #fast_request_token{mech = <<"HT-SHA-256-NONE">>}],
user_agent = #sasl2_user_agent{id = <<"9A62C3A9-FE59-43B7-80F3-9E8EE25DE6C5">>,
software = <<"TestRunner">>, device = <<"tester">>}},
send(Config, Pkt),
wait_auth_SASL2_result(set_opt(sasl, SASL, Config), ShouldFail).
wait_auth_SASL2_result(Config, ShouldFail) ->
receive
#sasl2_success{} when ShouldFail ->
ct:fail(sasl_auth_should_have_failed);
#sasl2_success{jid = JID} = Pkt ->
case {xmpp:get_subtag(Pkt, #bind2_bound{}), xmpp:get_subtag(Pkt, #fast_token{})} of
{false, _} ->
ct:fail(sasl2_bound_missing);
{_, Token} ->
{User, S, Resource} = jid:tolower(JID),
RawToken = case Token of
#fast_token{token = T} -> T;
_ -> <<>>
end,
Config2 = set_opt(user, User,
set_opt(resource, Resource,
set_opt(fast_token, RawToken, Config))),
receive #stream_features{sub_els = Fs} ->
lists:foldl(
fun(#feature_sm{}, ConfigAcc) ->
set_opt(sm, true, ConfigAcc);
(#feature_csi{}, ConfigAcc) ->
set_opt(csi, true, ConfigAcc);
(#rosterver_feature{}, ConfigAcc) ->
set_opt(rosterver, true, ConfigAcc);
(#feature_pre_approval{}, ConfigAcc) ->
set_opt(pre_approval, true, ConfigAcc);
(#compression{methods = Ms}, ConfigAcc) ->
set_opt(compression, Ms, ConfigAcc);
(_, ConfigAcc) ->
ConfigAcc
end, Config2, Fs)
end
end;
#sasl2_challenge{text = ClientIn} ->
{Response, SASL} = (?config(sasl, Config))(ClientIn),
send(Config, #sasl2_response{text = Response}),
wait_auth_SASL2_result(set_opt(sasl, SASL, Config), ShouldFail);
#sasl2_failure{} when ShouldFail ->
Config;
#sasl2_failure{} ->
ct:fail(sasl_auth_failed)
end.
re_register(Config) ->
User = ?config(user, Config),
Server = ?config(server, Config),