1: -module(auth_internal_SUITE). 2: 3: -compile([export_all, nowarn_export_all]). 4: -include_lib("eunit/include/eunit.hrl"). 5: -include("scram.hrl"). 6: 7: all() -> 8: [passwords_as_records_are_still_supported, 9: passwords_in_plain_can_be_converted_to_scram]. 10: 11: init_per_suite(C) -> 12: application:ensure_all_started(jid), 13: ok = mnesia:create_schema([node()]), 14: ok = mnesia:start(), 15: mongoose_config:set_opt({auth, host_type()}, #{methods => [internal], 16: internal => #{}, 17: password => #{format => scram, 18: scram_iterations => 10}}), 19: mongoose_domain_core:start([{domain(), host_type()}], []), 20: ejabberd_auth_internal:start(host_type()), 21: C. 22: 23: end_per_suite(_C) -> 24: ejabberd_auth_internal:stop(host_type()), 25: mongoose_domain_core:stop(), 26: mongoose_config:unset_opt({auth, host_type()}), 27: mnesia:stop(), 28: mnesia:delete_schema([node()]). 29: 30: passwords_as_records_are_still_supported(_C) -> 31: %% given in mnesia there is a user with password in old scram format 32: {U, S, P} = gen_user(), 33: OldScramFormat = old_password_to_scram(P, 340), 34: UserRecord = {passwd, {U, S}, OldScramFormat}, 35: mnesia:dirty_write(UserRecord), 36: %% when we read the password via ejabberd_auth_internal:get_password/3 37: NewScramMap = ejabberd_auth_internal:get_password(host_type(), U, S), 38: %% then new map with sha key is returned 39: ?assertMatch(#{iteration_count := _, 40: sha := #{salt := _, 41: server_key := _, 42: stored_key := _}}, NewScramMap), 43: %% even though in db there is old record stored 44: OldScram = mnesia:dirty_read({passwd, {U, S}}), 45: ?assertMatch([{passwd, _, {scram, _, _, _, _}}], OldScram). 46: 47: passwords_in_plain_can_be_converted_to_scram(_C) -> 48: %% Given there in mnesia there are users 49: %% with plain text password 50: {U, S, P} = gen_user(), 51: UserRecord = {passwd, {U, S}, P}, 52: mnesia:dirty_write(UserRecord), 53: %% and password in the old record format 54: {U2, S2, P2} = gen_user(), 55: OldScramFormat = old_password_to_scram(P2, 340), 56: UserRecord2 = {passwd, {U2, S2}, OldScramFormat}, 57: mnesia:dirty_write(UserRecord2), 58: %% when the migration function is run 59: ejabberd_auth_internal:scram_passwords(), 60: AfterMigrationPlain = mnesia:dirty_read({passwd, {U, S}}), 61: %% then plain text passwords are converted to new map with sha and sha256 62: ?assertMatch([{passwd, _, 63: #{iteration_count := _, 64: sha := #{salt := _, 65: server_key := _, 66: stored_key := _}, 67: sha224 := #{salt := _, 68: server_key := _, 69: stored_key := _}, 70: sha256 := #{salt := _, 71: server_key := _, 72: stored_key := _}, 73: sha384 := #{salt := _, 74: server_key := _, 75: stored_key := _}, 76: sha512 := #{salt := _, 77: server_key := _, 78: stored_key := _}}}], AfterMigrationPlain), 79: %% and the old scram format remains the same 80: AfterMigrationScram = mnesia:dirty_read({passwd, {U2, S2}}), 81: ?assertMatch([{passwd, _, 82: #{iteration_count := _, 83: sha := #{salt := _, 84: server_key := _, 85: stored_key := _}}}], AfterMigrationScram). 86: 87: gen_user() -> 88: {base64:encode(crypto:strong_rand_bytes(5)), 89: domain(), 90: base64:encode(crypto:strong_rand_bytes(6))}. 91: 92: old_password_to_scram(Password, IterationCount) -> 93: Salt = crypto:strong_rand_bytes(16), 94: SaltedPassword = fast_scram:salted_password(sha, jid:resourceprep(Password), Salt, IterationCount), 95: ClientKey = fast_scram:client_key(sha, SaltedPassword), 96: StoredKey = fast_scram:stored_key(sha, ClientKey), 97: ServerKey = fast_scram:server_key(sha, SaltedPassword), 98: #scram{storedkey = base64:encode(StoredKey), 99: serverkey = base64:encode(ServerKey), 100: salt = base64:encode(Salt), 101: iterationcount = IterationCount}. 102: 103: domain() -> 104: <<"server">>. 105: 106: host_type() -> 107: <<"test host type">>.