1: -module(graphql_account_SUITE). 2: 3: -include_lib("eunit/include/eunit.hrl"). 4: -include_lib("common_test/include/ct.hrl"). 5: 6: -compile([export_all, nowarn_export_all]). 7: 8: -import(common_helper, [unprep/1]). 9: -import(distributed_helper, [mim/0, require_rpc_nodes/1, rpc/4]). 10: -import(graphql_helper, [execute_command/4, execute_user_command/5, get_listener_port/1, 11: get_listener_config/1, get_ok_value/2, get_err_msg/1, 12: execute_domain_admin_command/4, get_unauthorized/1, 13: get_coercion_err_msg/1]). 14: 15: -define(NOT_EXISTING_JID, <<"unknown987@unknown">>). 16: -define(NOT_EXISTING_NAME, <<"unknown987@", (domain_helper:domain())/binary>>). 17: -define(EMPTY_NAME_JID, <<"@", (domain_helper:domain())/binary>>). 18: 19: suite() -> 20: require_rpc_nodes([mim]) ++ escalus:suite(). 21: 22: all() -> 23: [{group, user_account}, 24: {group, admin_account_http}, 25: {group, admin_account_cli}, 26: {group, domain_admin_account}]. 27: 28: groups() -> 29: [{user_account, [parallel], user_account_tests()}, 30: {admin_account_http, [], admin_account_tests() ++ admin_account_http_tests()}, 31: {admin_account_cli, [], admin_account_tests() ++ admin_account_cli_tests()}, 32: {domain_admin_account, [], domain_admin_tests()}]. 33: 34: user_account_tests() -> 35: [user_unregister, 36: user_change_password]. 37: 38: admin_account_tests() -> 39: [admin_list_users, 40: admin_list_users_unknown_domain, 41: admin_count_users, 42: admin_count_users_unknown_domain, 43: admin_check_password, 44: admin_check_password_non_existing_user, 45: admin_check_password_hash, 46: admin_check_password_hash_non_existing_user, 47: admin_check_plain_password_hash_md5, 48: admin_check_plain_password_hash_sha, 49: admin_check_user, 50: admin_check_non_existing_user, 51: admin_register_user, 52: admin_register_random_user, 53: admin_register_user_non_existing_domain, 54: admin_register_user_limit_error, 55: admin_remove_non_existing_user, 56: admin_remove_existing_user, 57: admin_ban_user, 58: admin_ban_non_existing_user, 59: admin_change_user_password, 60: admin_change_non_existing_user_password]. 61: 62: admin_account_http_tests() -> 63: [admin_import_users_http]. 64: 65: admin_account_cli_tests() -> 66: [admin_import_users_cli]. 67: 68: domain_admin_tests() -> 69: [admin_list_users, 70: domain_admin_list_users_no_permission, 71: admin_count_users, 72: domain_admin_count_users_no_permission, 73: admin_check_password, 74: domain_admin_check_password_no_permission, 75: admin_check_password_hash, 76: domain_admin_check_password_hash_no_permission, 77: domain_admin_check_plain_password_hash_no_permission, 78: admin_check_user, 79: domain_admin_check_user_no_permission, 80: admin_register_user, 81: domain_admin_register_user_no_permission, 82: admin_register_random_user, 83: domain_admin_register_random_user_no_permission, 84: admin_register_user_limit_error, 85: admin_remove_existing_user, 86: domain_admin_remove_user_no_permission, 87: admin_ban_user, 88: domain_admin_ban_user_no_permission, 89: admin_change_user_password, 90: domain_admin_change_user_password_no_permission]. 91: 92: init_per_suite(Config) -> 93: Config1 = [{ctl_auth_mods, mongoose_helper:auth_modules()} | Config], 94: Config2 = escalus:init_per_suite(Config1), 95: Config3 = ejabberd_node_utils:init(mim(), Config2), 96: dynamic_modules:save_modules(domain_helper:host_type(), Config3). 97: 98: end_per_suite(Config) -> 99: file:delete(filename:join(?config(mim_data_dir, Config), "users.csv.tmp")), 100: dynamic_modules:restore_modules(Config), 101: escalus:end_per_suite(Config). 102: 103: init_per_group(admin_account_http, Config) -> 104: graphql_helper:init_admin_handler(init_users(Config)); 105: init_per_group(admin_account_cli, Config) -> 106: graphql_helper:init_admin_cli(init_users(Config)); 107: init_per_group(domain_admin_account, Config) -> 108: graphql_helper:init_domain_admin_handler(domain_admin_init_users(Config)); 109: init_per_group(user_account, Config) -> 110: graphql_helper:init_user(Config). 111: 112: end_per_group(user_account, _Config) -> 113: graphql_helper:clean(), 114: escalus_fresh:clean(); 115: end_per_group(domain_admin_account, Config) -> 116: graphql_helper:clean(), 117: domain_admin_clean_users(Config); 118: end_per_group(_GroupName, Config) -> 119: graphql_helper:clean(), 120: clean_users(Config). 121: 122: init_users(Config) -> 123: escalus:create_users(Config, escalus:get_users([alice])). 124: 125: domain_admin_init_users(Config) -> 126: escalus:create_users(Config, escalus:get_users([alice, alice_bis])). 127: 128: clean_users(Config) -> 129: escalus_fresh:clean(), 130: escalus:delete_users(Config, escalus:get_users([alice])). 131: 132: domain_admin_clean_users(Config) -> 133: escalus_fresh:clean(), 134: escalus:delete_users(Config, escalus:get_users([alice, alice_bis])). 135: 136: init_per_testcase(admin_register_user = C, Config) -> 137: Config1 = [{user, {<<"gql_admin_registration_test">>, domain_helper:domain()}} | Config], 138: escalus:init_per_testcase(C, Config1); 139: init_per_testcase(C, Config) when C =:= admin_check_plain_password_hash_md5; 140: C =:= admin_check_plain_password_hash_sha -> 141: {_, AuthMods} = lists:keyfind(ctl_auth_mods, 1, Config), 142: case lists:member(ejabberd_auth_ldap, AuthMods) of 143: true -> 144: {skip, not_fully_supported_with_ldap}; 145: false -> 146: AuthOpts = mongoose_helper:auth_opts_with_password_format(plain), 147: Config1 = mongoose_helper:backup_and_set_config_option( 148: Config, {auth, domain_helper:host_type()}, AuthOpts), 149: Config2 = escalus:create_users(Config1, escalus:get_users([carol])), 150: escalus:init_per_testcase(C, Config2) 151: end; 152: init_per_testcase(admin_register_user_limit_error = C, Config) -> 153: Domain = domain_helper:domain(), 154: {ok, HostType} = rpc(mim(), mongoose_domain_api, get_domain_host_type, [Domain]), 155: OptKey = [{auth, HostType}, max_users_per_domain], 156: Config1 = mongoose_helper:backup_and_set_config_option(Config, OptKey, 3), 157: Config2 = [{bob, <<"bob">>}, {kate, <<"kate">>}, {john, <<"john">>} | Config1], 158: escalus:init_per_testcase(C, Config2); 159: init_per_testcase(domain_admin_check_plain_password_hash_no_permission = C, Config) -> 160: {_, AuthMods} = lists:keyfind(ctl_auth_mods, 1, Config), 161: case lists:member(ejabberd_auth_ldap, AuthMods) of 162: true -> 163: {skip, not_fully_supported_with_ldap}; 164: false -> 165: AuthOpts = mongoose_helper:auth_opts_with_password_format(plain), 166: Config1 = mongoose_helper:backup_and_set_config_option( 167: Config, {auth, domain_helper:host_type()}, AuthOpts), 168: Config2 = escalus:create_users(Config1, escalus:get_users([alice_bis])), 169: escalus:init_per_testcase(C, Config2) 170: end; 171: init_per_testcase(domain_admin_register_user = C, Config) -> 172: Config1 = [{user, {<<"gql_domain_admin_registration_test">>, domain_helper:domain()}} | Config], 173: escalus:init_per_testcase(C, Config1); 174: init_per_testcase(CaseName, Config) -> 175: escalus:init_per_testcase(CaseName, Config). 176: 177: end_per_testcase(admin_register_user = C, Config) -> 178: {Username, Domain} = proplists:get_value(user, Config), 179: rpc(mim(), mongoose_account_api, unregister_user, [Username, Domain]), 180: escalus:end_per_testcase(C, Config); 181: end_per_testcase(C, Config) when C =:= admin_check_plain_password_hash_md5; 182: C =:= admin_check_plain_password_hash_sha -> 183: mongoose_helper:restore_config(Config), 184: escalus:delete_users(Config, escalus:get_users([carol])); 185: end_per_testcase(admin_register_user_limit_error = C, Config) -> 186: Domain = domain_helper:domain(), 187: rpc(mim(), mongoose_account_api, unregister_user, [proplists:get_value(bob, Config), Domain]), 188: rpc(mim(), mongoose_account_api, unregister_user, [proplists:get_value(kate, Config), Domain]), 189: rpc(mim(), mongoose_account_api, unregister_user, [proplists:get_value(john, Config), Domain]), 190: mongoose_helper:restore_config(Config), 191: escalus:end_per_testcase(C, Config); 192: end_per_testcase(domain_admin_check_plain_password_hash_no_permission, Config) -> 193: mongoose_helper:restore_config(Config), 194: escalus:delete_users(Config, escalus:get_users([carol, alice_bis])); 195: end_per_testcase(domain_admin_register_user = C, Config) -> 196: {Username, Domain} = proplists:get_value(user, Config), 197: rpc(mim(), mongoose_account_api, unregister_user, [Username, Domain]), 198: escalus:end_per_testcase(C, Config); 199: end_per_testcase(CaseName, Config) 200: when CaseName == admin_import_users_http; CaseName == admin_import_users_cli -> 201: Domain = domain_helper:domain(), 202: rpc(mim(), mongoose_account_api, unregister_user, [<<"john">>, Domain]), 203: escalus:end_per_testcase(CaseName, Config); 204: end_per_testcase(CaseName, Config) -> 205: escalus:end_per_testcase(CaseName, Config). 206: 207: user_unregister(Config) -> 208: escalus:fresh_story_with_config(Config, [{alice, 1}], fun user_unregister_story/2). 209: 210: user_unregister_story(Config, Alice) -> 211: Resp = user_unregister(Alice, Config), 212: Path = [data, account, unregister], 213: ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp), <<"successfully unregistered">>)), 214: % Ensure the user is removed 215: AllUsers = rpc(mim(), mongoose_account_api, list_users, [domain_helper:domain()]), 216: {_, AllUsersList} = AllUsers, 217: LAliceJID = jid:to_binary(jid:from_binary(escalus_client:short_jid(Alice))), 218: ?assertNot(lists:member(LAliceJID, AllUsersList)). 219: 220: user_change_password(Config) -> 221: escalus:fresh_story_with_config(Config, [{alice, 1}], fun user_change_password_story/2). 222: 223: user_change_password_story(Config, Alice) -> 224: % Set an empty password 225: Resp1 = user_change_password(Alice, <<>>, Config), 226: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp1), <<"Empty password">>)), 227: % Set a correct password 228: Resp2 = user_change_password(Alice, <<"kaczka">>, Config), 229: Path = [data, account, changePassword], 230: ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp2), <<"Password changed">>)). 231: 232: admin_list_users(Config) -> 233: Domain = domain_helper:domain(), 234: Username = jid:nameprep(escalus_users:get_username(Config, alice)), 235: JID = <<Username/binary, "@", Domain/binary>>, 236: Resp1 = list_users(Domain, Config), 237: Users = get_ok_value([data, account, listUsers], Resp1), 238: ?assert(lists:member(JID, Users)), 239: Resp2 = list_users(unprep(Domain), Config), 240: ?assertEqual(Users, get_ok_value([data, account, listUsers], Resp2)). 241: 242: admin_list_users_unknown_domain(Config) -> 243: Resp = list_users(<<"unknown-domain">>, Config), 244: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp), <<"Domain does not exist">>)). 245: 246: admin_count_users(Config) -> 247: % A domain with at least one user 248: Domain = domain_helper:domain(), 249: Resp1 = count_users(Domain, Config), 250: Count = get_ok_value([data, account, countUsers], Resp1), 251: ?assert(0 < Count), 252: Resp2 = count_users(unprep(Domain), Config), 253: ?assertEqual(Count, get_ok_value([data, account, countUsers], Resp2)). 254: 255: admin_count_users_unknown_domain(Config) -> 256: Resp = count_users(<<"unknown-domain">>, Config), 257: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp), <<"Domain does not exist">>)). 258: 259: admin_check_password(Config) -> 260: Password = lists:last(escalus_users:get_usp(Config, alice)), 261: BinJID = escalus_users:get_jid(Config, alice), 262: Path = [data, account, checkPassword], 263: % A correct password 264: Resp1 = check_password(BinJID, Password, Config), 265: ?assertMatch(#{<<"correct">> := true, <<"message">> := _}, get_ok_value(Path, Resp1)), 266: % An incorrect password 267: Resp2 = check_password(BinJID, <<"incorrect_pw">>, Config), 268: ?assertMatch(#{<<"correct">> := false, <<"message">> := _}, get_ok_value(Path, Resp2)). 269: 270: admin_check_password_non_existing_user(Config) -> 271: Password = lists:last(escalus_users:get_usp(Config, alice)), 272: % Non-existing user, non-existing domain 273: Resp = check_password(?NOT_EXISTING_JID, Password, Config), 274: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp), <<"not exist">>)), 275: % Non-existing user, existing domain 276: Resp2 = check_password(?NOT_EXISTING_NAME, Password, Config), 277: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp2), <<"not exist">>)), 278: % Empty username 279: Resp3 = check_password(?EMPTY_NAME_JID, Password, Config), 280: get_coercion_err_msg(Resp3). 281: 282: admin_check_password_hash(Config) -> 283: UserSCRAM = escalus_users:get_jid(Config, alice), 284: EmptyHash = list_to_binary(get_md5(<<>>)), 285: Method = <<"md5">>, 286: % SCRAM password user 287: Resp1 = check_password_hash(UserSCRAM, EmptyHash, Method, Config), 288: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp1), <<"SCRAM password">>)). 289: 290: admin_check_password_hash_non_existing_user(Config) -> 291: EmptyHash = list_to_binary(get_md5(<<>>)), 292: Method = <<"md5">>, 293: % Non-existing user, non-existing domain 294: Resp = check_password_hash(?NOT_EXISTING_JID, EmptyHash, Method, Config), 295: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp), <<"not exist">>)), 296: % Non-existing user, existing domain 297: Resp2 = check_password_hash(?NOT_EXISTING_NAME, EmptyHash, Method, Config), 298: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp2), <<"not exist">>)), 299: % Empty username 300: Resp3 = check_password_hash(?EMPTY_NAME_JID, EmptyHash, Method, Config), 301: get_coercion_err_msg(Resp3). 302: 303: admin_check_plain_password_hash_md5(Config) -> 304: admin_check_password_hash(Config, <<"md5">>, fun get_md5/1). 305: 306: admin_check_plain_password_hash_sha(Config) -> 307: admin_check_password_hash(Config, <<"sha">>, fun get_sha/1). 308: 309: admin_check_password_hash(Config, Method, HashFun) -> 310: UserJID = escalus_users:get_jid(Config, carol), 311: Password = lists:last(escalus_users:get_usp(Config, carol)), 312: Hash = list_to_binary(HashFun(Password)), 313: WrongHash = list_to_binary(HashFun(<<"wrong password">>)), 314: Path = [data, account, checkPasswordHash], 315: % A correct hash 316: Resp = check_password_hash(UserJID, Hash, Method, Config), 317: ?assertMatch(#{<<"correct">> := true, <<"message">> := _}, get_ok_value(Path, Resp)), 318: % An incorrect hash 319: Resp2 = check_password_hash(UserJID, WrongHash, Method, Config), 320: ?assertMatch(#{<<"correct">> := false, <<"message">> := _}, get_ok_value(Path, Resp2)), 321: % A not-supported hash method 322: Resp3 = check_password_hash(UserJID, Hash, <<"a">>, Config), 323: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp3), <<"not supported">>)). 324: 325: admin_check_user(Config) -> 326: BinJID = escalus_users:get_jid(Config, alice), 327: Path = [data, account, checkUser], 328: Resp = check_user(BinJID, Config), 329: ?assertMatch(#{<<"exist">> := true, <<"message">> := _}, get_ok_value(Path, Resp)). 330: 331: admin_check_non_existing_user(Config) -> 332: Path = [data, account, checkUser], 333: % Non-existing user, non-existing domain 334: Resp = check_user(?NOT_EXISTING_JID, Config), 335: ?assertMatch(#{<<"exist">> := false, <<"message">> := _}, get_ok_value(Path, Resp)), 336: % Non-existing user, existing domain 337: Resp2 = check_user(?NOT_EXISTING_NAME, Config), 338: ?assertMatch(#{<<"exist">> := false, <<"message">> := _}, get_ok_value(Path, Resp2)), 339: % Empty username 340: Resp3 = check_user(?EMPTY_NAME_JID, Config), 341: get_coercion_err_msg(Resp3). 342: 343: admin_register_user(Config) -> 344: Password = <<"my_password">>, 345: {Username, Domain} = proplists:get_value(user, Config), 346: Path = [data, account, registerUser, message], 347: % Register a new user 348: Resp1 = register_user(Domain, Username, Password, Config), 349: ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp1), <<"successfully registered">>)), 350: % Try to register a user with existing name 351: Resp2 = register_user(Domain, Username, Password, Config), 352: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp2), <<"already registered">>)), 353: % Try again, this time with a name that is not stringprepped 354: Resp3 = register_user(unprep(Domain), unprep(Username), Password, Config), 355: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp3), <<"already registered">>)), 356: % Try to register a user without any name 357: Resp4 = register_user(Domain, <<>>, Password, Config), 358: ?assertMatch({_, _}, binary:match(get_coercion_err_msg(Resp4), <<"empty_user_name">>)), 359: % Try to register a user with an invalid name 360: Resp5 = register_user(Domain, <<"@invalid">>, Password, Config), 361: ?assertMatch({_, _}, binary:match(get_coercion_err_msg(Resp5), <<"failed_to_parse_user_name">>)). 362: 363: admin_register_random_user(Config) -> 364: Password = <<"my_password">>, 365: Domain = domain_helper:domain(), 366: Path = [data, account, registerUser], 367: % Register a new user 368: Resp1 = register_random_user(Domain, Password, Config), 369: #{<<"message">> := Msg, <<"jid">> := JID} = get_ok_value(Path, Resp1), 370: {Username, Server} = jid:to_lus(jid:from_binary(JID)), 371: 372: ?assertNotEqual(nomatch, binary:match(Msg, <<"successfully registered">>)), 373: {ok, _} = rpc(mim(), mongoose_account_api, unregister_user, [Username, Server]). 374: 375: admin_register_user_non_existing_domain(Config) -> 376: % Try to register a user with a non-existing domain 377: Resp = register_user(<<"unknown">>, <<"alice">>, <<"test_password">>, Config), 378: ?assertMatch({_, _}, binary:match(get_err_msg(Resp), <<"not_allowed">>)). 379: 380: admin_register_user_limit_error(Config) -> 381: Password = <<"password">>, 382: Domain = domain_helper:domain(), 383: Path = [data, account, registerUser, message], 384: Resp1 = register_user(Domain, proplists:get_value(bob, Config), Password, Config), 385: ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp1), <<"successfully registered">>)), 386: Resp2 = register_user(Domain, proplists:get_value(kate, Config), Password, Config), 387: ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp2), <<"successfully registered">>)), 388: %% One user was registered in the init_per_group, and two more were registered in this test case 389: %% There are three registered users at this moment 390: %% The next (fourth) registration should exceed the limit of three 391: JohnNick = proplists:get_value(john, Config), 392: Resp3 = register_user(Domain, JohnNick, Password, Config), 393: ?assertMatch({_, _}, binary:match(get_err_msg(Resp3), <<"limit has been exceeded">>)), 394: %% Make sure the fourth account wasn't created 395: CheckUserPath = [data, account, checkUser], 396: Resp4 = check_user(<<JohnNick/binary, "@", Domain/binary>>, Config), 397: ?assertMatch(#{<<"exist">> := false, <<"message">> := _}, get_ok_value(CheckUserPath, Resp4)). 398: 399: admin_remove_non_existing_user(Config) -> 400: % Non-existing user, non-existing domain 401: Resp = remove_user(?NOT_EXISTING_JID, Config), 402: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp), <<"not exist">>)), 403: % Non-existing user, existing domain 404: Resp2 = remove_user(?NOT_EXISTING_NAME, Config), 405: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp2), <<"not exist">>)), 406: % Empty username 407: Resp3 = remove_user(?EMPTY_NAME_JID, Config), 408: get_coercion_err_msg(Resp3). 409: 410: admin_remove_existing_user(Config) -> 411: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 412: Path = [data, account, removeUser, message], 413: BinJID = escalus_client:full_jid(Alice), 414: Resp4 = remove_user(BinJID, Config), 415: ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp4), 416: <<"successfully unregister">>)) 417: end). 418: 419: admin_ban_user(Config) -> 420: Path = [data, account, banUser, message], 421: Reason = <<"annoying">>, 422: % Ban an existing user 423: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 424: BinJID = escalus_client:full_jid(Alice), 425: Resp1 = ban_user(BinJID, Reason, Config), 426: ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp1), <<"successfully banned">>)) 427: end). 428: 429: admin_ban_non_existing_user(Config) -> 430: Reason = <<"annoying">>, 431: % Non-existing name, non-existing domain 432: Resp = ban_user(?NOT_EXISTING_JID, Reason, Config), 433: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp), <<"not exist">>)), 434: % Non-existing name, existing domain 435: Resp2 = ban_user(?NOT_EXISTING_NAME, Reason, Config), 436: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp2), <<"not exist">>)), 437: % Empty username 438: Resp3 = ban_user(?EMPTY_NAME_JID, Reason, Config), 439: get_coercion_err_msg(Resp3). 440: 441: admin_change_user_password(Config) -> 442: Path = [data, account, changeUserPassword, message], 443: NewPassword = <<"new password">>, 444: escalus:fresh_story(Config, [{alice, 1}], fun(Alice) -> 445: BinJID = escalus_client:full_jid(Alice), 446: % Set an empty password 447: Resp1 = change_user_password(BinJID, <<>>, Config), 448: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp1), <<"Empty password">>)), 449: % Set non-empty password 450: Resp2 = change_user_password(BinJID, NewPassword, Config), 451: ?assertNotEqual(nomatch, binary:match(get_ok_value(Path, Resp2), <<"Password changed">>)) 452: end). 453: 454: admin_change_non_existing_user_password(Config) -> 455: NewPassword = <<"new password">>, 456: % Non-existing name, non-existing domain 457: Resp = change_user_password(?NOT_EXISTING_JID, NewPassword, Config), 458: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp), <<"does not exist">>)), 459: % Non-existing name, existing domain 460: Resp2 = change_user_password(?NOT_EXISTING_NAME, NewPassword, Config), 461: ?assertNotEqual(nomatch, binary:match(get_err_msg(Resp2), <<"does not exist">>)), 462: % Empty username 463: Resp3 = ban_user(?EMPTY_NAME_JID, NewPassword, Config), 464: get_coercion_err_msg(Resp3). 465: 466: admin_import_users_cli(Config) -> 467: escalus:fresh_story(Config, [{alice, 1}], fun(_Alice) -> 468: % Non-existing file 469: Resp = import_users(<<"nonexisting.csv">>, Config), 470: ?assertEqual(<<"File not found">>, get_err_msg(Resp)), 471: % Summary 472: Path = filename:join(?config(mim_data_dir, Config), "users.csv"), 473: Path2 = replace_hosts_in_file(Path), 474: Resp2 = import_users(list_to_binary(Path2), Config), 475: Domain = domain_helper:domain(), 476: ?assertEqual(#{<<"status">> => <<"Completed">>, 477: <<"created">> => [<<"john@", Domain/binary>>], 478: <<"emptyPassword">> => [<<"elise@", Domain/binary>>], 479: <<"existing">> => [<<"alice@", Domain/binary>>], 480: <<"invalidJID">> => [<<",", Domain/binary, ",password">>], 481: <<"invalidRecord">> => [<<"elise,elise,", Domain/binary, ",esile">>], 482: <<"notAllowed">> => null}, 483: get_ok_value([data, account, importUsers], Resp2)) 484: end). 485: 486: admin_import_users_http(Config) -> 487: escalus:fresh_story(Config, [{alice, 1}], fun(_Alice) -> 488: % Summary 489: Path = filename:join(?config(mim_data_dir, Config), "users.csv"), 490: Path2 = replace_hosts_in_file(Path), 491: Resp2 = import_users(list_to_binary(Path2), Config), 492: ?assertEqual(#{<<"status">> => <<"ImportUsers scheduled">>, 493: <<"created">> => null, 494: <<"emptyPassword">> => null, 495: <<"existing">> => null, 496: <<"invalidJID">> => null, 497: <<"invalidRecord">> => null, 498: <<"notAllowed">> => null}, 499: get_ok_value([data, account, importUsers], Resp2)), 500: Domain = domain_helper:domain(), 501: JID = mongoose_helper:make_jid(<<"john">>, Domain), 502: mongoose_helper:wait_until(fun() -> 503: rpc(mim(), mongoose_account_api, check_account, [JID]) 504: end, 505: {ok, io_lib:format("User ~s exists", [<<"john@", Domain/binary>>])}, 506: #{time_left => timer:seconds(20), 507: sleep_time => 1000, 508: name => verify_account_created}) 509: end). 510: 511: replace_hosts_in_file(Path) -> 512: {ok, Content} = file:read_file(Path), 513: Content2 = binary:replace(Content, <<"$host$">>, domain_helper:domain(), [global]), 514: Path2 = Path ++ ".tmp", 515: ok = file:write_file(Path2, Content2), 516: Path2. 517: 518: domain_admin_list_users_no_permission(Config) -> 519: % An unknown domain 520: Resp1 = list_users(<<"unknown-domain">>, Config), 521: get_unauthorized(Resp1), 522: % An external domain 523: Resp2 = list_users(domain_helper:secondary_domain(), Config), 524: get_unauthorized(Resp2). 525: 526: domain_admin_count_users_no_permission(Config) -> 527: % An unknown domain 528: Resp1 = count_users(<<"unknown-domain">>, Config), 529: get_unauthorized(Resp1), 530: % An external domain 531: Resp2 = count_users(domain_helper:secondary_domain(), Config), 532: get_unauthorized(Resp2). 533: 534: domain_admin_check_password_no_permission(Config) -> 535: Password = lists:last(escalus_users:get_usp(Config, alice)), 536: PasswordOutside = lists:last(escalus_users:get_usp(Config, alice_bis)), 537: BinOutsideJID = escalus_users:get_jid(Config, alice_bis), 538: % An external domain user 539: Resp3 = check_password(BinOutsideJID, PasswordOutside, Config), 540: get_unauthorized(Resp3), 541: % A non-existing user 542: Resp4 = check_password(?NOT_EXISTING_JID, Password, Config), 543: get_unauthorized(Resp4). 544: 545: domain_admin_check_password_hash_no_permission(Config) -> 546: ExternalUserSCRAM = escalus_users:get_jid(Config, alice_bis), 547: EmptyHash = list_to_binary(get_md5(<<>>)), 548: Method = <<"md5">>, 549: % An external domain user 550: Resp1 = check_password_hash(ExternalUserSCRAM, EmptyHash, Method, Config), 551: get_unauthorized(Resp1), 552: % A non-existing user 553: Resp2 = check_password_hash(?NOT_EXISTING_JID, EmptyHash, Method, Config), 554: get_unauthorized(Resp2). 555: 556: domain_admin_check_plain_password_hash_no_permission(Config) -> 557: Method = <<"md5">>, 558: ExternalUserJID = escalus_users:get_jid(Config, alice_bis), 559: ExternalPassword = lists:last(escalus_users:get_usp(Config, alice_bis)), 560: ExternalHash = list_to_binary(get_md5(ExternalPassword)), 561: get_unauthorized(check_password_hash(ExternalUserJID, ExternalHash, Method, Config)). 562: 563: domain_admin_check_user_no_permission(Config) -> 564: ExternalBinJID = escalus_users:get_jid(Config, alice_bis), 565: % An external domain user 566: Resp1 = check_user(ExternalBinJID, Config), 567: get_unauthorized(Resp1), 568: % A non-existing user 569: Resp2 = check_user(?NOT_EXISTING_JID, Config), 570: get_unauthorized(Resp2). 571: 572: domain_admin_register_user_no_permission(Config) -> 573: Password = <<"my_password">>, 574: Domain = <<"unknown-domain">>, 575: get_unauthorized(register_user(Domain, external_user, Password, Config)). 576: 577: domain_admin_register_random_user_no_permission(Config) -> 578: Password = <<"my_password">>, 579: Domain = domain_helper:secondary_domain(), 580: Resp = register_random_user(Domain, Password, Config), 581: get_unauthorized(Resp). 582: 583: domain_admin_remove_user_no_permission(Config) -> 584: get_unauthorized(remove_user(?NOT_EXISTING_JID, Config)), 585: escalus:fresh_story(Config, [{alice_bis, 1}], fun(AliceBis) -> 586: BinJID = escalus_client:full_jid(AliceBis), 587: get_unauthorized(remove_user(BinJID, Config)) 588: end). 589: 590: domain_admin_ban_user_no_permission(Config) -> 591: Reason = <<"annoying">>, 592: % Ban not existing user 593: Resp1 = ban_user(?NOT_EXISTING_JID, Reason, Config), 594: get_unauthorized(Resp1), 595: % Ban an external domain user 596: escalus:fresh_story(Config, [{alice_bis, 1}], fun(AliceBis) -> 597: BinJID = escalus_client:full_jid(AliceBis), 598: Resp2 = ban_user(BinJID, Reason, Config), 599: get_unauthorized(Resp2) 600: end). 601: 602: domain_admin_change_user_password_no_permission(Config) -> 603: NewPassword = <<"new password">>, 604: % Change password of not existing user 605: Resp1 = change_user_password(?NOT_EXISTING_JID, NewPassword, Config), 606: get_unauthorized(Resp1), 607: % Change external domain user password 608: escalus:fresh_story(Config, [{alice_bis, 1}], fun(AliceBis) -> 609: BinJID = escalus_client:full_jid(AliceBis), 610: Resp2 = change_user_password(BinJID, NewPassword, Config), 611: get_unauthorized(Resp2) 612: end). 613: 614: %% Helpers 615: 616: get_md5(AccountPass) -> 617: lists:flatten([io_lib:format("~.16B", [X]) 618: || X <- binary_to_list(crypto:hash(md5, AccountPass))]). 619: 620: get_sha(AccountPass) -> 621: lists:flatten([io_lib:format("~.16B", [X]) 622: || X <- binary_to_list(crypto:hash(sha, AccountPass))]). 623: 624: %% Commands 625: 626: user_unregister(User, Config) -> 627: execute_user_command(<<"account">>, <<"unregister">>, User, #{}, Config). 628: 629: user_change_password(User, Password, Config) -> 630: Vars = #{<<"newPassword">> => Password}, 631: execute_user_command(<<"account">>, <<"changePassword">>, User, Vars, Config). 632: 633: list_users(Domain, Config) -> 634: Vars = #{<<"domain">> => Domain}, 635: execute_command(<<"account">>, <<"listUsers">>, Vars, Config). 636: 637: count_users(Domain, Config) -> 638: Vars = #{<<"domain">> => Domain}, 639: execute_command(<<"account">>, <<"countUsers">>, Vars, Config). 640: 641: check_password(User, Password, Config) -> 642: Vars = #{<<"user">> => User, <<"password">> => Password}, 643: execute_command(<<"account">>, <<"checkPassword">>, Vars, Config). 644: 645: check_password_hash(User, PasswordHash, HashMethod, Config) -> 646: Vars = #{<<"user">> => User, <<"passwordHash">> => PasswordHash, <<"hashMethod">> => HashMethod}, 647: execute_command(<<"account">>, <<"checkPasswordHash">>, Vars, Config). 648: 649: check_user(User, Config) -> 650: Vars = #{<<"user">> => User}, 651: execute_command(<<"account">>, <<"checkUser">>, Vars, Config). 652: 653: register_user(Domain, Username, Password, Config) -> 654: Vars = #{<<"domain">> => Domain, <<"username">> => Username, <<"password">> => Password}, 655: execute_command(<<"account">>, <<"registerUser">>, Vars, Config). 656: 657: register_random_user(Domain, Password, Config) -> 658: Vars = #{<<"domain">> => Domain, <<"password">> => Password}, 659: execute_command(<<"account">>, <<"registerUser">>, Vars, Config). 660: 661: remove_user(User, Config) -> 662: Vars = #{<<"user">> => User}, 663: execute_command(<<"account">>, <<"removeUser">>, Vars, Config). 664: 665: ban_user(JID, Reason, Config) -> 666: Vars = #{<<"user">> => JID, <<"reason">> => Reason}, 667: execute_command(<<"account">>, <<"banUser">>, Vars, Config). 668: 669: change_user_password(JID, NewPassword, Config) -> 670: Vars = #{<<"user">> => JID, <<"newPassword">> => NewPassword}, 671: execute_command(<<"account">>, <<"changeUserPassword">>, Vars, Config). 672: 673: import_users(Filename, Config) -> 674: Vars = #{<<"filename">> => Filename}, 675: execute_command(<<"account">>, <<"importUsers">>, Vars, Config).