1: %%============================================================================== 2: %% Copyright 2010 Erlang Solutions Ltd. 3: %% 4: %% Licensed under the Apache License, Version 2.0 (the "License"); 5: %% you may not use this file except in compliance with the License. 6: %% You may obtain a copy of the License at 7: %% 8: %% http://www.apache.org/licenses/LICENSE-2.0 9: %% 10: %% Unless required by applicable law or agreed to in writing, software 11: %% distributed under the License is distributed on an "AS IS" BASIS, 12: %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13: %% See the License for the specific language governing permissions and 14: %% limitations under the License. 15: %%============================================================================== 16: 17: -module(login_SUITE). 18: -compile([export_all, nowarn_export_all]). 19: 20: -include_lib("exml/include/exml.hrl"). 21: -include_lib("stdlib/include/assert.hrl"). 22: 23: -import(distributed_helper, [mim/0, 24: require_rpc_nodes/1, 25: rpc/4]). 26: 27: -import(domain_helper, [host_type/0, domain/0]). 28: 29: %%-------------------------------------------------------------------- 30: %% Suite configuration 31: %%-------------------------------------------------------------------- 32: 33: all() -> 34: [ 35: {group, login}, 36: {group, login_digest}, 37: {group, login_scram}, 38: {group, login_scram_store_plain}, 39: {group, login_specific_scram}, 40: {group, login_scram_tls}, 41: {group, messages}, 42: {group, access} 43: ]. 44: 45: groups() -> 46: [{login, [parallel], all_tests()}, 47: {login_digest, [sequence], digest_tests()}, 48: {login_scram, [parallel], scram_tests()}, 49: {login_scram_store_plain, [parallel], scram_tests()}, 50: {login_scram_tls, [parallel], scram_tests()}, 51: {login_specific_scram, [sequence], configure_specific_scram_test()}, 52: {messages, [sequence], [messages_story]}, 53: {access, [], access_tests()}]. 54: 55: scram_tests() -> 56: [scram_failed_with_non_authorized, 57: log_one, 58: log_one_scram_sha1, 59: log_one_scram_sha224, 60: log_one_scram_sha256, 61: log_one_scram_sha384, 62: log_one_scram_sha512, 63: log_one_scram_sha1_plus, 64: log_one_scram_sha224_plus, 65: log_one_scram_sha256_plus, 66: log_one_scram_sha384_plus, 67: log_one_scram_sha512_plus]. 68: 69: configure_specific_scram_test() -> 70: [configure_sha1_log_with_sha1, 71: configure_sha224_log_with_sha224, 72: configure_sha256_log_with_sha256, 73: configure_sha384_log_with_sha384, 74: configure_sha512_log_with_sha512, 75: configure_sha1_log_with_sha1_plus, 76: configure_sha224_log_with_sha224_plus, 77: configure_sha256_log_with_sha256_plus, 78: configure_sha384_log_with_sha384_plus, 79: configure_sha512_log_with_sha512_plus, 80: configure_sha1_fail_log_with_sha224, 81: configure_sha224_fail_log_with_sha256, 82: configure_sha256_fail_log_with_sha384, 83: configure_sha384_fail_log_with_sha512, 84: configure_sha512_fail_log_with_sha1, 85: configure_sha1_plus_fail_log_with_sha1, 86: configure_sha224_plus_fail_log_with_sha224, 87: configure_sha256_plus_fail_log_with_sha256, 88: configure_sha384_plus_fail_log_with_sha384, 89: configure_sha512_plus_fail_log_with_sha512]. 90: 91: all_tests() -> 92: [log_one, 93: log_non_existent_plain, 94: log_one_scram_sha1, 95: log_non_existent_scram, 96: log_bad_user_fails 97: ]. 98: 99: access_tests() -> 100: [blocked_user, 101: access_none_blocks_all_users, 102: access_none_for_other_listener_has_no_effect]. 103: 104: digest_tests() -> 105: [log_one_digest, 106: log_non_existent_digest]. 107: 108: suite() -> 109: require_rpc_nodes([mim]) ++ escalus:suite(). 110: 111: %%-------------------------------------------------------------------- 112: %% Init & teardown 113: %%-------------------------------------------------------------------- 114: 115: init_per_suite(Config) -> 116: escalus:init_per_suite(Config). 117: 118: end_per_suite(Config) -> 119: escalus_fresh:clean(), 120: escalus:end_per_suite(Config). 121: 122: init_per_group(login_digest = GroupName, ConfigIn) -> 123: Config = backup_and_set_options(GroupName, ConfigIn), 124: case mongoose_helper:supports_sasl_module(cyrsasl_digest) of 125: false -> 126: mongoose_helper:restore_config(Config), 127: {skip, "digest password type not supported"}; 128: true -> 129: escalus:create_users(Config, escalus:get_users([alice, bob])) 130: end; 131: init_per_group(GroupName, ConfigIn) 132: when GroupName == login_scram; 133: GroupName == login_scram_store_plain -> 134: Config = backup_and_set_options(GroupName, ConfigIn), 135: case are_sasl_scram_modules_supported() of 136: false -> 137: mongoose_helper:restore_config(Config), 138: {skip, "scram password type not supported"}; 139: true -> 140: Config2 = escalus:create_users(Config, escalus:get_users([alice, bob, neustradamus])), 141: assert_password_format(GroupName, Config2) 142: end; 143: init_per_group(login_scram_tls = GroupName, ConfigIn) -> 144: Config = backup_and_set_options(GroupName, ConfigIn), 145: case are_sasl_scram_modules_supported() of 146: false -> 147: mongoose_helper:restore_config(Config), 148: {skip, "scram password type not supported"}; 149: true -> 150: Config1 = configure_c2s_listener(Config), 151: Config2 = create_tls_users(Config1), 152: assert_password_format(scram, Config2) 153: end; 154: init_per_group(login_specific_scram = GroupName, ConfigIn) -> 155: Config = backup_and_set_options(GroupName, ConfigIn), 156: case are_sasl_scram_modules_supported() of 157: false -> 158: mongoose_helper:restore_config(Config), 159: {skip, "scram password type not supported"}; 160: true -> 161: escalus:create_users(Config, escalus:get_users([alice, bob, neustradamus])) 162: end; 163: init_per_group(GroupName, ConfigIn) -> 164: Config = backup_and_set_options(GroupName, ConfigIn), 165: escalus:create_users(Config, escalus:get_users([alice, bob])). 166: 167: backup_and_set_options(GroupName, Config) -> 168: mongoose_helper:backup_and_set_config_option(Config, {auth, host_type()}, auth_opts(GroupName)). 169: 170: auth_opts(login_digest) -> 171: AuthOpts = mongoose_helper:auth_opts_with_password_format(plain), 172: AuthOpts#{sasl_mechanisms => [cyrsasl_digest]}; 173: auth_opts(login_scram_store_plain) -> 174: mongoose_helper:auth_opts_with_password_format(plain); 175: auth_opts(_GroupName) -> 176: mongoose_helper:auth_opts_with_password_format(scram). 177: 178: end_per_group(login_digest, Config) -> 179: mongoose_helper:restore_config(Config), 180: escalus:delete_users(Config, escalus:get_users([alice, bob])); 181: end_per_group(GroupName, Config) when 182: GroupName == login_scram; GroupName == login_specific_scram -> 183: mongoose_helper:restore_config(Config), 184: escalus:delete_users(Config, escalus:get_users([alice, bob, neustradamus])); 185: end_per_group(login_scram_tls, Config) -> 186: mongoose_helper:restore_config(Config), 187: restore_c2s(Config), 188: delete_tls_users(Config); 189: end_per_group(_GroupName, Config) -> 190: mongoose_helper:restore_config(Config), 191: escalus:delete_users(Config, escalus:get_users([alice, bob])). 192: 193: init_per_testcase(CaseName, Config) when 194: CaseName =:= log_one_scram_sha1; CaseName =:= log_non_existent_scram -> 195: case mongoose_helper:supports_sasl_module(cyrsasl_scram_sha1) of 196: false -> 197: {skip, "scram password type not supported"}; 198: true -> 199: escalus:init_per_testcase(CaseName, Config) 200: end; 201: init_per_testcase(blocked_user = CaseName, Config) -> 202: [{_, Spec}] = escalus_users:get_users([alice]), 203: Config1 = set_acl_for_blocking(Config, Spec), 204: escalus:init_per_testcase(CaseName, Config1); 205: init_per_testcase(access_none_blocks_all_users = CaseName, Config) -> 206: Config1 = set_access_none(ct:get_config({hosts, mim, c2s_port}), Config), 207: escalus:init_per_testcase(CaseName, Config1); 208: init_per_testcase(access_none_for_other_listener_has_no_effect = CaseName, Config) -> 209: Config1 = set_access_none(ct:get_config({hosts, mim, c2s_tls_port}), Config), 210: escalus:init_per_testcase(CaseName, Config1); 211: init_per_testcase(CaseName, Config) -> 212: escalus:init_per_testcase(CaseName, Config). 213: 214: end_per_testcase(blocked_user = CaseName, Config) -> 215: unset_acl_for_blocking(Config), 216: escalus:end_per_testcase(CaseName, Config); 217: end_per_testcase(access_none_blocks_all_users = CaseName, Config) -> 218: restore_c2s(Config), 219: escalus:end_per_testcase(CaseName, Config); 220: end_per_testcase(access_none_for_other_listener_has_no_effect = CaseName, Config) -> 221: restore_c2s(Config), 222: escalus:end_per_testcase(CaseName, Config); 223: end_per_testcase(CaseName, Config) -> 224: escalus:end_per_testcase(CaseName, Config). 225: 226: set_access_none(C2SPort, Config) -> 227: [C2SListener] = 228: mongoose_helper:get_listeners(mim(), #{port => C2SPort, module => mongoose_c2s_listener}), 229: mongoose_helper:restart_listener(mim(), C2SListener#{access := none}), 230: [{c2s_listener, C2SListener} | Config]. 231: 232: %%-------------------------------------------------------------------- 233: %% Message tests 234: %%-------------------------------------------------------------------- 235: 236: scram_failed_with_non_authorized(Config) -> 237: ConnectionSteps = [start_stream, stream_features], 238: UserSpec = escalus_fresh:create_fresh_user(Config, alice), 239: {ok, Alice, _Features} = escalus_connection:start(UserSpec, ConnectionSteps), 240: Username = escalus_utils:get_username(Alice), 241: BadPayload = <<"n,,n=", Username/binary, ",r=9ZdW+o71OwOrDUx4J5+M+A==">>, 242: AuthStanza = auth_stanza(<<"SCRAM-SHA-1">>, BadPayload), 243: escalus_client:send(Alice, AuthStanza), 244: _Challenge = escalus_client:wait_for_stanza(Alice), 245: WrongProof = <<"c=biws,r=invalid_nonce,p=wrong_proof">>, 246: Response = auth_response(WrongProof), 247: escalus_client:send(Alice, Response), 248: Failure = escalus_client:wait_for_stanza(Alice), 249: ?assertMatch(#xmlel{name = <<"failure">>}, Failure), 250: ?assertMatch(#xmlel{}, exml_query:subelement(Failure, <<"not-authorized">>)). 251: 252: log_one(Config) -> 253: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 254: 255: escalus_client:send(Alice, escalus_stanza:chat_to(Alice, <<"Hi!">>)), 256: escalus:assert(is_chat_message, [<<"Hi!">>], escalus_client:wait_for_stanza(Alice)) 257: 258: end). 259: 260: log_one_scram_plus(Config) -> 261: escalus:fresh_story(Config, [{neustradamus, 1}], fun(Neustradamus) -> 262: 263: escalus_client:send(Neustradamus, escalus_stanza:chat_to(Neustradamus, <<"Hi!">>)), 264: escalus:assert(is_chat_message, [<<"Hi!">>], escalus_client:wait_for_stanza(Neustradamus)) 265: 266: end). 267: 268: log_one_digest(Config) -> 269: log_one([{escalus_auth_method, <<"DIGEST-MD5">>} | Config]). 270: 271: log_one_scram_sha1(Config) -> 272: log_one([{escalus_auth_method, <<"SCRAM-SHA-1">>} | Config]). 273: 274: log_one_scram_sha224(Config) -> 275: log_one([{escalus_auth_method, <<"SCRAM-SHA-224">>} | Config]). 276: 277: log_one_scram_sha256(Config) -> 278: log_one([{escalus_auth_method, <<"SCRAM-SHA-256">>} | Config]). 279: 280: log_one_scram_sha384(Config) -> 281: log_one([{escalus_auth_method, <<"SCRAM-SHA-384">>} | Config]). 282: 283: log_one_scram_sha512(Config) -> 284: log_one([{escalus_auth_method, <<"SCRAM-SHA-512">>} | Config]). 285: 286: log_one_scram_sha1_plus(Config) -> 287: log_one_scram_plus([{escalus_auth_method, <<"SCRAM-SHA-1-PLUS">>} | Config]). 288: 289: log_one_scram_sha224_plus(Config) -> 290: log_one_scram_plus([{escalus_auth_method, <<"SCRAM-SHA-224-PLUS">>} | Config]). 291: 292: log_one_scram_sha256_plus(Config) -> 293: log_one_scram_plus([{escalus_auth_method, <<"SCRAM-SHA-256-PLUS">>} | Config]). 294: 295: log_one_scram_sha384_plus(Config) -> 296: log_one_scram_plus([{escalus_auth_method, <<"SCRAM-SHA-384-PLUS">>} | Config]). 297: 298: log_one_scram_sha512_plus(Config) -> 299: log_one_scram_plus([{escalus_auth_method, <<"SCRAM-SHA-512-PLUS">>} | Config]). 300: 301: configure_sha1_log_with_sha1(Config) -> 302: configure_and_log_scram(Config, sha, <<"SCRAM-SHA-1">>). 303: 304: configure_sha224_log_with_sha224(Config) -> 305: configure_and_log_scram(Config, sha224, <<"SCRAM-SHA-224">>). 306: 307: configure_sha256_log_with_sha256(Config) -> 308: configure_and_log_scram(Config, sha256, <<"SCRAM-SHA-256">>). 309: 310: configure_sha384_log_with_sha384(Config) -> 311: configure_and_log_scram(Config, sha384, <<"SCRAM-SHA-384">>). 312: 313: configure_sha512_log_with_sha512(Config) -> 314: configure_and_log_scram(Config, sha512, <<"SCRAM-SHA-512">>). 315: 316: configure_sha1_log_with_sha1_plus(Config) -> 317: configure_and_log_scram_plus(Config, sha, <<"SCRAM-SHA-1-PLUS">>). 318: 319: configure_sha224_log_with_sha224_plus(Config) -> 320: configure_and_log_scram_plus(Config, sha224, <<"SCRAM-SHA-224-PLUS">>). 321: 322: configure_sha256_log_with_sha256_plus(Config) -> 323: configure_and_log_scram_plus(Config, sha256, <<"SCRAM-SHA-256-PLUS">>). 324: 325: configure_sha384_log_with_sha384_plus(Config) -> 326: configure_and_log_scram_plus(Config, sha384, <<"SCRAM-SHA-384-PLUS">>). 327: 328: configure_sha512_log_with_sha512_plus(Config) -> 329: configure_and_log_scram_plus(Config, sha512, <<"SCRAM-SHA-512-PLUS">>). 330: 331: configure_sha1_fail_log_with_sha224(Config) -> 332: configure_and_fail_log_scram(Config, sha, <<"SCRAM-SHA-224">>). 333: 334: configure_sha224_fail_log_with_sha256(Config) -> 335: configure_and_fail_log_scram(Config, sha224, <<"SCRAM-SHA-256">>). 336: 337: configure_sha256_fail_log_with_sha384(Config) -> 338: configure_and_fail_log_scram(Config, sha256, <<"SCRAM-SHA-384">>). 339: 340: configure_sha384_fail_log_with_sha512(Config) -> 341: configure_and_fail_log_scram(Config, sha384, <<"SCRAM-SHA-512">>). 342: 343: configure_sha512_fail_log_with_sha1(Config) -> 344: configure_and_fail_log_scram(Config, sha512, <<"SCRAM-SHA-1">>). 345: 346: %% 347: %% configure_sha*_plus_fail_log_with_sha* tests are succeeding due to the fact that 348: %% escalus, when configured with fast_tls and login with scram, sets channel binding 349: %% flag to 'y'. This indicates that escalus supports channel binding but the server 350: %% does not. The server did advertise the SCRAM PLUS mechanism, so this flag is 351: %% incorrect and could be the result of the man-in-the-middle attack attempting to 352: %% downgrade the authentication mechanism. Because of that, the authentication should fail. 353: %% 354: configure_sha1_plus_fail_log_with_sha1(Config) -> 355: configure_scram_plus_and_fail_log_scram(Config, sha, <<"SCRAM-SHA-1">>). 356: 357: configure_sha224_plus_fail_log_with_sha224(Config) -> 358: configure_scram_plus_and_fail_log_scram(Config, sha224, <<"SCRAM-SHA-224">>). 359: 360: configure_sha256_plus_fail_log_with_sha256(Config) -> 361: configure_scram_plus_and_fail_log_scram(Config, sha256, <<"SCRAM-SHA-256">>). 362: 363: configure_sha384_plus_fail_log_with_sha384(Config) -> 364: configure_scram_plus_and_fail_log_scram(Config, sha384, <<"SCRAM-SHA-384">>). 365: 366: configure_sha512_plus_fail_log_with_sha512(Config) -> 367: configure_scram_plus_and_fail_log_scram(Config, sha512, <<"SCRAM-SHA-512">>). 368: 369: log_non_existent_plain(Config) -> 370: {auth_failed, _, Xmlel} = log_non_existent(Config), 371: #xmlel{name = <<"failure">>} = Xmlel, 372: #xmlel{} = exml_query:subelement(Xmlel, <<"not-authorized">>). 373: 374: log_non_existent_digest(Config) -> 375: R = log_non_existent([{escalus_auth_method, <<"DIGEST-MD5">>} | Config]), 376: {expected_challenge, _, _} = R. 377: 378: log_non_existent_scram(Config) -> 379: R = log_non_existent([{escalus_auth_method, <<"SCRAM-SHA-1">>} | Config]), 380: {expected_challenge, _, _} = R. 381: 382: log_bad_user_fails(Config) -> 383: Config1 = [{escalus_auth_method, <<"SCRAM-SHA-1">>} | Config], 384: [{kate, UserSpec}] = escalus_users:get_users([kate]), 385: UserSpec1 = lists:keyreplace(username, 1, UserSpec, {username, <<" kate">>}), 386: {error, {connection_step_failed, _, R}} = escalus_client:start(Config1, UserSpec1, <<"res">>), 387: {expected_challenge, got, Xmlel} = R, 388: #xmlel{name = <<"failure">>} = Xmlel. 389: 390: log_non_existent(Config) -> 391: [{kate, UserSpec}] = escalus_users:get_users([kate]), 392: {error, {connection_step_failed, _, R}} = escalus_client:start(Config, UserSpec, <<"res">>), 393: R. 394: 395: blocked_user(_Config) -> 396: [{_, Spec}] = escalus_users:get_users([alice]), 397: try 398: {ok, _Alice, _Spec2, _Features} = escalus_connection:start(Spec), 399: ct:fail("Alice authenticated but shouldn't") 400: catch 401: error:{assertion_failed, assert, is_iq_result, Stanza, _Bin} -> 402: <<"cancel">> = exml_query:path(Stanza, [{element, <<"error">>}, {attr, <<"type">>}]) 403: end. 404: 405: access_none_blocks_all_users(Config) -> 406: blocked_user(Config). 407: 408: access_none_for_other_listener_has_no_effect(Config) -> 409: log_one(Config). 410: 411: messages_story(Config) -> 412: escalus:story(Config, [{alice, 1}, {bob, 1}], fun(Alice, Bob) -> 413: 414: % Alice sends a message to Bob 415: escalus_client:send(Alice, escalus_stanza:chat_to(Bob, <<"Hi!">>)), 416: 417: % Bob gets the message 418: escalus_assert:is_chat_message(<<"Hi!">>, escalus_client:wait_for_stanza(Bob)) 419: 420: end). 421: 422: %%-------------------------------------------------------------------- 423: %% Helpers 424: %%-------------------------------------------------------------------- 425: 426: configure_c2s_listener(Config) -> 427: C2SPort = ct:get_config({hosts, mim, c2s_port}), 428: [C2SListener = #{tls := TLSOpts}] = 429: mongoose_helper:get_listeners(mim(), #{port => C2SPort, module => mongoose_c2s_listener}), 430: %% replace starttls with tls 431: NewTLSOpts = TLSOpts#{mode := tls}, 432: mongoose_helper:restart_listener(mim(), C2SListener#{tls := NewTLSOpts}), 433: [{c2s_listener, C2SListener} | Config]. 434: 435: create_tls_users(Config) -> 436: Config1 = escalus:create_users(Config, escalus:get_users([alice, neustradamus])), 437: Users = proplists:get_value(escalus_users, Config1, []), 438: Users1 = prepare_user_for_ssl(Users, neustradamus), 439: Users2 = prepare_user_for_ssl(Users1, alice), 440: lists:keystore(escalus_users, 1, Config1, {escalus_users, Users2}). 441: 442: prepare_user_for_ssl(Users, User) -> 443: UserSpec = proplists:get_value(User, Users), 444: UserSpec1 = lists:keydelete(starttls, 1, UserSpec), 445: UserSpec2 = lists:keystore(ssl, 1, UserSpec1, {ssl, true}), 446: UserSpec3 = lists:keystore(ssl_opts, 1, UserSpec2, {ssl_opts, [{verify, verify_none}]}), 447: lists:keystore(User, 1, Users, {User, UserSpec3}). 448: 449: delete_tls_users(Config) -> 450: escalus:delete_users(Config, escalus:get_users([alice, neustradamus])). 451: 452: assert_password_format(GroupName, Config) -> 453: Users = proplists:get_value(escalus_users, Config), 454: [verify_format(GroupName, User) || User <- Users], 455: Config. 456: 457: verify_format(GroupName, {_User, Props}) -> 458: Username = escalus_utils:jid_to_lower(proplists:get_value(username, Props)), 459: Server = proplists:get_value(server, Props), 460: Password = proplists:get_value(password, Props), 461: JID = mongoose_helper:make_jid(Username, Server), 462: {SPassword, _} = rpc(mim(), ejabberd_auth, get_passterm_with_authmodule, [host_type(), JID]), 463: do_verify_format(GroupName, Password, SPassword). 464: 465: 466: do_verify_format(GroupName, _P, #{iteration_count := _IC, 467: sha := #{salt := _, stored_key := _, server_key := _}, 468: sha224 := #{salt := _, stored_key := _, server_key := _}, 469: sha256 := #{salt := _, stored_key := _, server_key := _}, 470: sha384 := #{salt := _, stored_key := _, server_key := _}, 471: sha512 := #{salt := _, stored_key := _, server_key := _}}) when 472: GroupName == login_scram orelse GroupName == scram -> 473: true; 474: do_verify_format({scram, Sha}, _Password, ScramMap = #{iteration_count := _IC}) -> 475: maps:is_key(Sha, ScramMap); 476: do_verify_format(login_scram, _Password, SPassword) -> 477: %% returned password is a tuple containing scram data 478: {_, _, _, _} = SPassword; 479: do_verify_format(_, Password, SPassword) -> 480: Password = SPassword. 481: 482: set_acl_for_blocking(Config, Spec) -> 483: User = proplists:get_value(username, Spec), 484: LUser = jid:nodeprep(User), 485: mongoose_helper:backup_and_set_config_option(Config, [{acl, host_type()}, blocked], 486: [#{user => LUser, match => current_domain}]). 487: 488: unset_acl_for_blocking(Config) -> 489: mongoose_helper:restore_config_option(Config, [{acl, host_type()}, blocked]). 490: 491: configure_and_log_scram(Config, Sha, Mech) -> 492: set_scram_sha(Config, Sha), 493: log_one([{escalus_auth_method, Mech} | Config]). 494: 495: configure_and_log_scram_plus(Config, Sha, Mech) -> 496: set_scram_sha(Config, Sha), 497: log_one_scram_plus([{escalus_auth_method, Mech} | Config]). 498: 499: configure_and_fail_log_scram(Config, Sha, Mech) -> 500: set_scram_sha(Config, Sha), 501: {expected_challenge, _, _} = fail_log_one([{escalus_auth_method, Mech} | Config]). 502: 503: configure_scram_plus_and_fail_log_scram(Config, Sha, Mech) -> 504: set_scram_sha(Config, Sha), 505: {expected_challenge, _, _} = fail_log_one_scram_plus([{escalus_auth_method, Mech} | Config]). 506: 507: set_scram_sha(Config, Sha) -> 508: NewAuthOpts = mongoose_helper:auth_opts_with_password_format({scram, [Sha]}), 509: mongoose_helper:change_config_option(Config, {auth, host_type()}, NewAuthOpts), 510: assert_password_format({scram, Sha}, Config). 511: 512: fail_log_one(Config) -> 513: [{alice, UserSpec}] = escalus_users:get_users([alice]), 514: {error, {connection_step_failed, _, R}} = escalus_client:start(Config, UserSpec, <<"res">>), 515: R. 516: 517: fail_log_one_scram_plus(Config) -> 518: [{neustradamus, UserSpec}] = escalus_users:get_users([neustradamus]), 519: {error, {connection_step_failed, _, R}} = escalus_client:start(Config, UserSpec, <<"res">>), 520: R. 521: 522: are_sasl_scram_modules_supported() -> 523: ScramModules = [cyrsasl_scram_sha1, cyrsasl_scram_sha224, cyrsasl_scram_sha256, 524: cyrsasl_scram_sha384, cyrsasl_scram_sha512], 525: IsSupported = [mongoose_helper:supports_sasl_module(Module) || Module <- ScramModules], 526: [true, true, true, true, true] == IsSupported. 527: 528: restore_c2s(Config) -> 529: C2SListener = proplists:get_value(c2s_listener, Config), 530: mongoose_helper:restart_listener(mim(), C2SListener). 531: 532: -define(NS_SASL, <<"urn:ietf:params:xml:ns:xmpp-sasl">>). 533: auth_stanza(Mech, Payload) -> 534: #xmlel{name = <<"auth">>, 535: attrs = [{<<"xmlns">>, ?NS_SASL}, 536: {<<"mechanism">>, Mech}], 537: children = [#xmlcdata{content = base64:encode(Payload)}]}. 538: 539: auth_response(Payload) -> 540: #xmlel{name = <<"response">>, 541: attrs = [{<<"xmlns">>, ?NS_SASL}], 542: children = [#xmlcdata{content = base64:encode(Payload)}]}.