User login and refresh on auth_session (phase 2). Refs EventHub/EventHubBack#26
This commit is contained in:
+190
-166
@@ -1,167 +1,191 @@
|
||||
-module(auth_test).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-define(JWT_SECRET, <<"test-user-secret-key-32-byt!">>).
|
||||
-define(ADMIN_JWT_SECRET, <<"test-admin-secret-key-32-b">>).
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% EUnit фикстуры – запуск и остановка моков
|
||||
%% ------------------------------------------------------------------
|
||||
setup() ->
|
||||
ok = meck:new(logic_auth, [non_strict]),
|
||||
application:set_env(eventhub, jwt_secret, ?JWT_SECRET),
|
||||
application:set_env(eventhub, admin_jwt_secret, ?ADMIN_JWT_SECRET),
|
||||
{ok, _} = application:ensure_all_started(jose),
|
||||
ok.
|
||||
|
||||
cleanup(_) ->
|
||||
application:unset_env(eventhub, jwt_secret),
|
||||
application:unset_env(eventhub, admin_jwt_secret),
|
||||
application:stop(jose),
|
||||
meck:unload(logic_auth).
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тесты генерации токенов
|
||||
%% ------------------------------------------------------------------
|
||||
generate_user_token_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Generate user token returns a binary",
|
||||
fun() ->
|
||||
Token = eventhub_auth:generate_user_token(<<"user123">>, <<"user">>),
|
||||
?assert(is_binary(Token)),
|
||||
?assert(size(Token) > 0)
|
||||
end},
|
||||
{"Generated user token can be verified",
|
||||
fun() ->
|
||||
Token = eventhub_auth:generate_user_token(<<"user123">>, <<"user">>),
|
||||
{ok, UserId, Role} = eventhub_auth:verify_user_token(Token),
|
||||
?assertEqual(<<"user123">>, UserId),
|
||||
?assertEqual(<<"user">>, Role)
|
||||
end},
|
||||
{"Generate admin token with superadmin role",
|
||||
fun() ->
|
||||
Token = eventhub_auth:generate_admin_token(<<"admin1">>, <<"superadmin">>),
|
||||
{ok, UserId, Role} = eventhub_auth:verify_admin_token(Token),
|
||||
?assertEqual(<<"admin1">>, UserId),
|
||||
?assertEqual(<<"superadmin">>, Role)
|
||||
end}
|
||||
]}.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тесты верификации токенов (граничные случаи)
|
||||
%% ------------------------------------------------------------------
|
||||
verify_token_errors_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Invalid token signature returns error",
|
||||
fun() ->
|
||||
FakeToken = <<"not.a.valid.token">>,
|
||||
?assertEqual({error, invalid_token}, eventhub_auth:verify_user_token(FakeToken)),
|
||||
?assertEqual({error, invalid_token}, eventhub_auth:verify_admin_token(FakeToken))
|
||||
end},
|
||||
{"User token rejected by admin verifier (different secret)",
|
||||
fun() ->
|
||||
Token = eventhub_auth:generate_user_token(<<"x">>, <<"user">>),
|
||||
% Разные секреты → подпись недействительна для admin JWK
|
||||
?assertEqual({error, invalid_signature}, eventhub_auth:verify_admin_token(Token))
|
||||
end},
|
||||
{"Admin token rejected by user verifier (different secret)",
|
||||
fun() ->
|
||||
Token = eventhub_auth:generate_admin_token(<<"x">>, <<"admin">>),
|
||||
?assertEqual({error, invalid_signature}, eventhub_auth:verify_user_token(Token))
|
||||
end}
|
||||
]}.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тесты для authenticate_user_request/3
|
||||
%% ------------------------------------------------------------------
|
||||
authenticate_user_request_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Successful user login returns token and user data",
|
||||
fun() ->
|
||||
UserMap = #{id => <<"user1">>, email => <<"u@test.com">>, role => <<"user">>},
|
||||
ok = meck:expect(logic_auth, authenticate_user, fun(_Email, _Password) -> {ok, UserMap} end),
|
||||
Req = undefined,
|
||||
{ok, Token, ReturnedUser} = eventhub_auth:authenticate_user_request(Req, <<"u@test.com">>, <<"pass">>),
|
||||
?assert(is_binary(Token)),
|
||||
?assertEqual(UserMap, ReturnedUser),
|
||||
{ok, UserId, Role} = eventhub_auth:verify_user_token(Token),
|
||||
?assertEqual(<<"user1">>, UserId),
|
||||
?assertEqual(<<"user">>, Role)
|
||||
end},
|
||||
{"User login failure propagates error from logic_auth",
|
||||
fun() ->
|
||||
ok = meck:expect(logic_auth, authenticate_user, fun(_Email, _Password) -> {error, bad_credentials} end),
|
||||
Req = undefined,
|
||||
?assertEqual({error, bad_credentials}, eventhub_auth:authenticate_user_request(Req, <<"bad">>, <<"pwd">>))
|
||||
end}
|
||||
]}.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тесты для authenticate_admin_request/3
|
||||
%% ------------------------------------------------------------------
|
||||
authenticate_admin_request_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Successful admin login returns admin token",
|
||||
fun() ->
|
||||
AdminMap = #{id => <<"adm1">>, email => <<"admin@test.com">>, role => <<"superadmin">>},
|
||||
ok = meck:expect(logic_auth, authenticate_admin, fun(_Email, _Password) -> {ok, AdminMap} end),
|
||||
Req = undefined,
|
||||
{ok, Token, ReturnedUser} = eventhub_auth:authenticate_admin_request(Req, <<"admin@test.com">>, <<"pass">>),
|
||||
?assert(is_binary(Token)),
|
||||
?assertEqual(AdminMap, ReturnedUser),
|
||||
{ok, UserId, Role} = eventhub_auth:verify_admin_token(Token),
|
||||
?assertEqual(<<"adm1">>, UserId),
|
||||
?assertEqual(<<"superadmin">>, Role)
|
||||
end},
|
||||
{"Non-admin role is rejected with insufficient_permissions",
|
||||
fun() ->
|
||||
UserMap = #{id => <<"simpleuser">>, email => <<"u@test.com">>, role => <<"user">>},
|
||||
ok = meck:expect(logic_auth, authenticate_admin, fun(_Email, _Password) -> {ok, UserMap} end),
|
||||
Req = undefined,
|
||||
?assertEqual({error, insufficient_permissions},
|
||||
eventhub_auth:authenticate_admin_request(Req, <<"u@test.com">>, <<"pwd">>))
|
||||
end},
|
||||
{"Moderator role is accepted as admin",
|
||||
fun() ->
|
||||
ModMap = #{id => <<"moder1">>, email => <<"mod@test.com">>, role => <<"moderator">>},
|
||||
ok = meck:expect(logic_auth, authenticate_admin, fun(_Email, _Password) -> {ok, ModMap} end),
|
||||
Req = undefined,
|
||||
{ok, Token, _} = eventhub_auth:authenticate_admin_request(Req, <<"mod@test.com">>, <<"pwd">>),
|
||||
{ok, _, Role} = eventhub_auth:verify_admin_token(Token),
|
||||
?assertEqual(<<"moderator">>, Role)
|
||||
end}
|
||||
]}.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тест generate_refresh_token/1 (legacy opaque, user flow)
|
||||
%% ------------------------------------------------------------------
|
||||
generate_refresh_token_test() ->
|
||||
{_, _} = eventhub_auth:generate_refresh_token(<<"anyuser">>).
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тесты refresh JWT (admin)
|
||||
%% ------------------------------------------------------------------
|
||||
admin_refresh_jwt_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Generate and verify admin refresh JWT",
|
||||
fun() ->
|
||||
Sid = <<"sess123">>, Fid = <<"fam456">>, Jti = <<"jti789">>,
|
||||
{Token, _} = eventhub_auth:generate_admin_refresh_token(
|
||||
Sid, Fid, Jti, <<"admin1">>, <<"admin">>
|
||||
),
|
||||
?assert(is_binary(Token)),
|
||||
{ok, Claims} = eventhub_auth:verify_admin_refresh_token(Token),
|
||||
?assertEqual(Sid, maps:get(<<"sid">>, Claims)),
|
||||
?assertEqual(Fid, maps:get(<<"fid">>, Claims)),
|
||||
?assertEqual(Jti, maps:get(<<"jti">>, Claims)),
|
||||
?assertEqual(<<"admin1">>, maps:get(<<"sub">>, Claims))
|
||||
end},
|
||||
{"User refresh JWT rejected by admin verifier",
|
||||
fun() ->
|
||||
{Token, _} = eventhub_auth:generate_admin_refresh_token(
|
||||
<<"s">>, <<"f">>, <<"j">>, <<"u">>, <<"admin">>
|
||||
),
|
||||
?assertMatch({error, invalid_signature},
|
||||
eventhub_auth:verify_user_token(Token))
|
||||
end}
|
||||
-module(auth_test).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-define(JWT_SECRET, <<"test-user-secret-key-32-byt!">>).
|
||||
-define(ADMIN_JWT_SECRET, <<"test-admin-secret-key-32-b">>).
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% EUnit фикстуры – запуск и остановка моков
|
||||
%% ------------------------------------------------------------------
|
||||
setup() ->
|
||||
ok = meck:new(logic_auth, [non_strict]),
|
||||
application:set_env(eventhub, jwt_secret, ?JWT_SECRET),
|
||||
application:set_env(eventhub, admin_jwt_secret, ?ADMIN_JWT_SECRET),
|
||||
{ok, _} = application:ensure_all_started(jose),
|
||||
ok.
|
||||
|
||||
cleanup(_) ->
|
||||
application:unset_env(eventhub, jwt_secret),
|
||||
application:unset_env(eventhub, admin_jwt_secret),
|
||||
application:stop(jose),
|
||||
meck:unload(logic_auth).
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тесты генерации токенов
|
||||
%% ------------------------------------------------------------------
|
||||
generate_user_token_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Generate user token returns a binary",
|
||||
fun() ->
|
||||
Token = eventhub_auth:generate_user_token(<<"user123">>, <<"user">>),
|
||||
?assert(is_binary(Token)),
|
||||
?assert(size(Token) > 0)
|
||||
end},
|
||||
{"Generated user token can be verified",
|
||||
fun() ->
|
||||
Token = eventhub_auth:generate_user_token(<<"user123">>, <<"user">>),
|
||||
{ok, UserId, Role} = eventhub_auth:verify_user_token(Token),
|
||||
?assertEqual(<<"user123">>, UserId),
|
||||
?assertEqual(<<"user">>, Role)
|
||||
end},
|
||||
{"Generate admin token with superadmin role",
|
||||
fun() ->
|
||||
Token = eventhub_auth:generate_admin_token(<<"admin1">>, <<"superadmin">>),
|
||||
{ok, UserId, Role} = eventhub_auth:verify_admin_token(Token),
|
||||
?assertEqual(<<"admin1">>, UserId),
|
||||
?assertEqual(<<"superadmin">>, Role)
|
||||
end}
|
||||
]}.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тесты верификации токенов (граничные случаи)
|
||||
%% ------------------------------------------------------------------
|
||||
verify_token_errors_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Invalid token signature returns error",
|
||||
fun() ->
|
||||
FakeToken = <<"not.a.valid.token">>,
|
||||
?assertEqual({error, invalid_token}, eventhub_auth:verify_user_token(FakeToken)),
|
||||
?assertEqual({error, invalid_token}, eventhub_auth:verify_admin_token(FakeToken))
|
||||
end},
|
||||
{"User token rejected by admin verifier (different secret)",
|
||||
fun() ->
|
||||
Token = eventhub_auth:generate_user_token(<<"x">>, <<"user">>),
|
||||
% Разные секреты → подпись недействительна для admin JWK
|
||||
?assertEqual({error, invalid_signature}, eventhub_auth:verify_admin_token(Token))
|
||||
end},
|
||||
{"Admin token rejected by user verifier (different secret)",
|
||||
fun() ->
|
||||
Token = eventhub_auth:generate_admin_token(<<"x">>, <<"admin">>),
|
||||
?assertEqual({error, invalid_signature}, eventhub_auth:verify_user_token(Token))
|
||||
end}
|
||||
]}.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тесты для authenticate_user_request/3
|
||||
%% ------------------------------------------------------------------
|
||||
authenticate_user_request_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Successful user login returns token and user data",
|
||||
fun() ->
|
||||
UserMap = #{id => <<"user1">>, email => <<"u@test.com">>, role => <<"user">>},
|
||||
ok = meck:expect(logic_auth, authenticate_user, fun(_Email, _Password) -> {ok, UserMap} end),
|
||||
Req = undefined,
|
||||
{ok, Token, ReturnedUser} = eventhub_auth:authenticate_user_request(Req, <<"u@test.com">>, <<"pass">>),
|
||||
?assert(is_binary(Token)),
|
||||
?assertEqual(UserMap, ReturnedUser),
|
||||
{ok, UserId, Role} = eventhub_auth:verify_user_token(Token),
|
||||
?assertEqual(<<"user1">>, UserId),
|
||||
?assertEqual(<<"user">>, Role)
|
||||
end},
|
||||
{"User login failure propagates error from logic_auth",
|
||||
fun() ->
|
||||
ok = meck:expect(logic_auth, authenticate_user, fun(_Email, _Password) -> {error, bad_credentials} end),
|
||||
Req = undefined,
|
||||
?assertEqual({error, bad_credentials}, eventhub_auth:authenticate_user_request(Req, <<"bad">>, <<"pwd">>))
|
||||
end}
|
||||
]}.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тесты для authenticate_admin_request/3
|
||||
%% ------------------------------------------------------------------
|
||||
authenticate_admin_request_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Successful admin login returns admin token",
|
||||
fun() ->
|
||||
AdminMap = #{id => <<"adm1">>, email => <<"admin@test.com">>, role => <<"superadmin">>},
|
||||
ok = meck:expect(logic_auth, authenticate_admin, fun(_Email, _Password) -> {ok, AdminMap} end),
|
||||
Req = undefined,
|
||||
{ok, Token, ReturnedUser} = eventhub_auth:authenticate_admin_request(Req, <<"admin@test.com">>, <<"pass">>),
|
||||
?assert(is_binary(Token)),
|
||||
?assertEqual(AdminMap, ReturnedUser),
|
||||
{ok, UserId, Role} = eventhub_auth:verify_admin_token(Token),
|
||||
?assertEqual(<<"adm1">>, UserId),
|
||||
?assertEqual(<<"superadmin">>, Role)
|
||||
end},
|
||||
{"Non-admin role is rejected with insufficient_permissions",
|
||||
fun() ->
|
||||
UserMap = #{id => <<"simpleuser">>, email => <<"u@test.com">>, role => <<"user">>},
|
||||
ok = meck:expect(logic_auth, authenticate_admin, fun(_Email, _Password) -> {ok, UserMap} end),
|
||||
Req = undefined,
|
||||
?assertEqual({error, insufficient_permissions},
|
||||
eventhub_auth:authenticate_admin_request(Req, <<"u@test.com">>, <<"pwd">>))
|
||||
end},
|
||||
{"Moderator role is accepted as admin",
|
||||
fun() ->
|
||||
ModMap = #{id => <<"moder1">>, email => <<"mod@test.com">>, role => <<"moderator">>},
|
||||
ok = meck:expect(logic_auth, authenticate_admin, fun(_Email, _Password) -> {ok, ModMap} end),
|
||||
Req = undefined,
|
||||
{ok, Token, _} = eventhub_auth:authenticate_admin_request(Req, <<"mod@test.com">>, <<"pwd">>),
|
||||
{ok, _, Role} = eventhub_auth:verify_admin_token(Token),
|
||||
?assertEqual(<<"moderator">>, Role)
|
||||
end}
|
||||
]}.
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тест generate_refresh_token/1 (legacy opaque, user flow)
|
||||
%% ------------------------------------------------------------------
|
||||
generate_refresh_token_test() ->
|
||||
{_, _} = eventhub_auth:generate_refresh_token(<<"anyuser">>).
|
||||
|
||||
%% ------------------------------------------------------------------
|
||||
%% Тесты refresh JWT (admin)
|
||||
%% ------------------------------------------------------------------
|
||||
admin_refresh_jwt_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Generate and verify admin refresh JWT",
|
||||
fun() ->
|
||||
Sid = <<"sess123">>, Fid = <<"fam456">>, Jti = <<"jti789">>,
|
||||
{Token, _} = eventhub_auth:generate_admin_refresh_token(
|
||||
Sid, Fid, Jti, <<"admin1">>, <<"admin">>
|
||||
),
|
||||
?assert(is_binary(Token)),
|
||||
{ok, Claims} = eventhub_auth:verify_admin_refresh_token(Token),
|
||||
?assertEqual(Sid, maps:get(<<"sid">>, Claims)),
|
||||
?assertEqual(Fid, maps:get(<<"fid">>, Claims)),
|
||||
?assertEqual(Jti, maps:get(<<"jti">>, Claims)),
|
||||
?assertEqual(<<"admin1">>, maps:get(<<"sub">>, Claims))
|
||||
end},
|
||||
{"Admin refresh JWT rejected by user verifier",
|
||||
fun() ->
|
||||
{Token, _} = eventhub_auth:generate_admin_refresh_token(
|
||||
<<"s">>, <<"f">>, <<"j">>, <<"a">>, <<"admin">>
|
||||
),
|
||||
?assertMatch({error, invalid_signature},
|
||||
eventhub_auth:verify_user_refresh_token(Token))
|
||||
end}
|
||||
]}.
|
||||
|
||||
user_refresh_jwt_test_() ->
|
||||
{setup, fun setup/0, fun cleanup/1, [
|
||||
{"Generate and verify user refresh JWT",
|
||||
fun() ->
|
||||
Sid = <<"sess123">>, Fid = <<"fam456">>, Jti = <<"jti789">>,
|
||||
{Token, _} = eventhub_auth:generate_user_refresh_token(
|
||||
Sid, Fid, Jti, <<"user1">>, <<"web">>
|
||||
),
|
||||
?assert(is_binary(Token)),
|
||||
{ok, Claims} = eventhub_auth:verify_user_refresh_token(Token),
|
||||
?assertEqual(Sid, maps:get(<<"sid">>, Claims)),
|
||||
?assertEqual(<<"user">>, maps:get(<<"aud">>, Claims)),
|
||||
?assertEqual(<<"web">>, maps:get(<<"client">>, Claims))
|
||||
end},
|
||||
{"User refresh JWT rejected by admin verifier",
|
||||
fun() ->
|
||||
{Token, _} = eventhub_auth:generate_user_refresh_token(
|
||||
<<"s">>, <<"f">>, <<"j">>, <<"u">>, <<"web">>
|
||||
),
|
||||
?assertMatch({error, invalid_signature},
|
||||
eventhub_auth:verify_admin_refresh_token(Token))
|
||||
end}
|
||||
]}.
|
||||
@@ -1,69 +1,114 @@
|
||||
-module(logic_auth_session_tests).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-include("records.hrl").
|
||||
|
||||
-define(ADMIN_JWT_SECRET, <<"test-admin-secret-key-32-b">>).
|
||||
|
||||
setup() ->
|
||||
ok = meck:new(core_admin, [non_strict]),
|
||||
mnesia:start(),
|
||||
catch ets:new(eventhub_counters, [named_table, public, set, {write_concurrency, true}]),
|
||||
mnesia:create_table(auth_session, [
|
||||
{attributes, record_info(fields, auth_session)},
|
||||
{ram_copies, [node()]}
|
||||
]),
|
||||
mnesia:add_table_index(auth_session, #auth_session.family_id),
|
||||
mnesia:add_table_index(auth_session, #auth_session.subject_id),
|
||||
application:set_env(eventhub, admin_jwt_secret, ?ADMIN_JWT_SECRET),
|
||||
{ok, _} = application:ensure_all_started(jose),
|
||||
ok.
|
||||
|
||||
cleanup(_) ->
|
||||
application:unset_env(eventhub, admin_jwt_secret),
|
||||
application:stop(jose),
|
||||
meck:unload(core_admin),
|
||||
catch mnesia:delete_table(auth_session),
|
||||
catch ets:delete(eventhub_counters),
|
||||
mnesia:stop(),
|
||||
ok.
|
||||
|
||||
logic_auth_session_test_() ->
|
||||
{foreach, fun setup/0, fun cleanup/1, [
|
||||
{"Issue and refresh admin tokens", fun test_issue_and_refresh/0},
|
||||
{"Refresh reuse revokes family", fun test_reuse_revokes/0}
|
||||
]}.
|
||||
|
||||
test_issue_and_refresh() ->
|
||||
AdminId = <<"adm1">>,
|
||||
Admin = #admin{
|
||||
id = AdminId, email = <<"a@test.com">>, role = superadmin,
|
||||
password_hash = <<>>, status = active, nickname = <<>>,
|
||||
avatar_url = default, timezone = <<"UTC">>, language = <<"ru">>,
|
||||
phone = <<>>, preferences = #{}, last_login = undefined,
|
||||
created_at = undefined, updated_at = undefined
|
||||
},
|
||||
ok = meck:expect(core_admin, get_by_id, fun(Id) ->
|
||||
?assertEqual(AdminId, Id), {ok, Admin}
|
||||
end),
|
||||
{ok, Access1, Refresh1} = logic_auth_session:issue_admin_tokens(AdminId, <<"superadmin">>),
|
||||
?assert(is_binary(Access1)),
|
||||
{ok, _, _} = eventhub_auth:verify_admin_token(Access1),
|
||||
{ok, Access2, Refresh2} = logic_auth_session:refresh_admin(Refresh1),
|
||||
?assert(is_binary(Access2)),
|
||||
?assertNotEqual(Refresh1, Refresh2),
|
||||
{ok, _, _} = eventhub_auth:verify_admin_token(Access2).
|
||||
|
||||
test_reuse_revokes() ->
|
||||
AdminId = <<"adm1">>,
|
||||
Admin = #admin{
|
||||
id = AdminId, email = <<"a@test.com">>, role = admin,
|
||||
password_hash = <<>>, status = active, nickname = <<>>,
|
||||
avatar_url = default, timezone = <<"UTC">>, language = <<"ru">>,
|
||||
phone = <<>>, preferences = #{}, last_login = undefined,
|
||||
created_at = undefined, updated_at = undefined
|
||||
},
|
||||
ok = meck:expect(core_admin, get_by_id, fun(_) -> {ok, Admin} end),
|
||||
{ok, _, Refresh1} = logic_auth_session:issue_admin_tokens(AdminId, <<"admin">>),
|
||||
{ok, _, Refresh2} = logic_auth_session:refresh_admin(Refresh1),
|
||||
?assertMatch({error, reuse_detected}, logic_auth_session:refresh_admin(Refresh1)),
|
||||
?assertMatch({error, revoked}, logic_auth_session:refresh_admin(Refresh2)).
|
||||
-module(logic_auth_session_tests).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
-include("records.hrl").
|
||||
|
||||
-define(ADMIN_JWT_SECRET, <<"test-admin-secret-key-32-b">>).
|
||||
-define(USER_JWT_SECRET, <<"test-user-secret-key-32-by">>).
|
||||
|
||||
setup() ->
|
||||
ok = meck:new(core_admin, [non_strict]),
|
||||
ok = meck:new(core_user, [non_strict]),
|
||||
mnesia:start(),
|
||||
catch ets:new(eventhub_counters, [named_table, public, set, {write_concurrency, true}]),
|
||||
mnesia:create_table(auth_session, [
|
||||
{attributes, record_info(fields, auth_session)},
|
||||
{ram_copies, [node()]}
|
||||
]),
|
||||
mnesia:add_table_index(auth_session, #auth_session.family_id),
|
||||
mnesia:add_table_index(auth_session, #auth_session.subject_id),
|
||||
application:set_env(eventhub, admin_jwt_secret, ?ADMIN_JWT_SECRET),
|
||||
application:set_env(eventhub, jwt_secret, ?USER_JWT_SECRET),
|
||||
{ok, _} = application:ensure_all_started(jose),
|
||||
ok.
|
||||
|
||||
cleanup(_) ->
|
||||
application:unset_env(eventhub, admin_jwt_secret),
|
||||
application:unset_env(eventhub, jwt_secret),
|
||||
application:stop(jose),
|
||||
meck:unload(core_admin),
|
||||
meck:unload(core_user),
|
||||
catch mnesia:delete_table(auth_session),
|
||||
catch ets:delete(eventhub_counters),
|
||||
mnesia:stop(),
|
||||
ok.
|
||||
|
||||
logic_auth_session_test_() ->
|
||||
{foreach, fun setup/0, fun cleanup/1, [
|
||||
{"Issue and refresh admin tokens", fun test_issue_and_refresh_admin/0},
|
||||
{"Refresh admin reuse revokes family", fun test_admin_reuse_revokes/0},
|
||||
{"Issue and refresh user tokens", fun test_issue_and_refresh_user/0},
|
||||
{"Refresh user reuse revokes family", fun test_user_reuse_revokes/0}
|
||||
]}.
|
||||
|
||||
test_issue_and_refresh_admin() ->
|
||||
AdminId = <<"adm1">>,
|
||||
Admin = #admin{
|
||||
id = AdminId, email = <<"a@test.com">>, role = superadmin,
|
||||
password_hash = <<>>, status = active, nickname = <<>>,
|
||||
avatar_url = default, timezone = <<"UTC">>, language = <<"ru">>,
|
||||
phone = <<>>, preferences = #{}, last_login = undefined,
|
||||
created_at = undefined, updated_at = undefined
|
||||
},
|
||||
ok = meck:expect(core_admin, get_by_id, fun(Id) ->
|
||||
?assertEqual(AdminId, Id), {ok, Admin}
|
||||
end),
|
||||
{ok, Access1, Refresh1} = logic_auth_session:issue_admin_tokens(AdminId, <<"superadmin">>),
|
||||
?assert(is_binary(Access1)),
|
||||
{ok, _, _} = eventhub_auth:verify_admin_token(Access1),
|
||||
{ok, Access2, Refresh2} = logic_auth_session:refresh_admin(Refresh1),
|
||||
?assert(is_binary(Access2)),
|
||||
?assertNotEqual(Refresh1, Refresh2),
|
||||
{ok, _, _} = eventhub_auth:verify_admin_token(Access2).
|
||||
|
||||
test_admin_reuse_revokes() ->
|
||||
AdminId = <<"adm1">>,
|
||||
Admin = #admin{
|
||||
id = AdminId, email = <<"a@test.com">>, role = admin,
|
||||
password_hash = <<>>, status = active, nickname = <<>>,
|
||||
avatar_url = default, timezone = <<"UTC">>, language = <<"ru">>,
|
||||
phone = <<>>, preferences = #{}, last_login = undefined,
|
||||
created_at = undefined, updated_at = undefined
|
||||
},
|
||||
ok = meck:expect(core_admin, get_by_id, fun(_) -> {ok, Admin} end),
|
||||
{ok, _, Refresh1} = logic_auth_session:issue_admin_tokens(AdminId, <<"admin">>),
|
||||
{ok, _, Refresh2} = logic_auth_session:refresh_admin(Refresh1),
|
||||
?assertMatch({error, reuse_detected}, logic_auth_session:refresh_admin(Refresh1)),
|
||||
?assertMatch({error, revoked}, logic_auth_session:refresh_admin(Refresh2)).
|
||||
|
||||
test_issue_and_refresh_user() ->
|
||||
UserId = <<"usr1">>,
|
||||
User = #user{
|
||||
id = UserId, email = <<"u@test.com">>, role = user,
|
||||
password_hash = <<>>, status = active, nickname = <<>>,
|
||||
avatar_url = default, timezone = <<"UTC">>, language = <<"ru">>,
|
||||
phone = <<>>, preferences = #{}, last_login = undefined,
|
||||
created_at = undefined, updated_at = undefined
|
||||
},
|
||||
ok = meck:expect(core_user, get_by_id, fun(Id) ->
|
||||
?assertEqual(UserId, Id), {ok, User}
|
||||
end),
|
||||
{ok, Access1, Refresh1} = logic_auth_session:issue_user_tokens(UserId, <<"user">>),
|
||||
?assert(is_binary(Access1)),
|
||||
{ok, _, _} = eventhub_auth:verify_user_token(Access1),
|
||||
{ok, Claims} = eventhub_auth:verify_user_refresh_token(Refresh1),
|
||||
?assertEqual(<<"user">>, maps:get(<<"aud">>, Claims)),
|
||||
?assertEqual(<<"web">>, maps:get(<<"client">>, Claims)),
|
||||
{ok, Access2, Refresh2} = logic_auth_session:refresh_user(Refresh1),
|
||||
?assert(is_binary(Access2)),
|
||||
?assertNotEqual(Refresh1, Refresh2),
|
||||
{ok, _, _} = eventhub_auth:verify_user_token(Access2).
|
||||
|
||||
test_user_reuse_revokes() ->
|
||||
UserId = <<"usr1">>,
|
||||
User = #user{
|
||||
id = UserId, email = <<"u@test.com">>, role = user,
|
||||
password_hash = <<>>, status = active, nickname = <<>>,
|
||||
avatar_url = default, timezone = <<"UTC">>, language = <<"ru">>,
|
||||
phone = <<>>, preferences = #{}, last_login = undefined,
|
||||
created_at = undefined, updated_at = undefined
|
||||
},
|
||||
ok = meck:expect(core_user, get_by_id, fun(_) -> {ok, User} end),
|
||||
{ok, _, Refresh1} = logic_auth_session:issue_user_tokens(UserId, <<"user">>),
|
||||
{ok, _, Refresh2} = logic_auth_session:refresh_user(Refresh1),
|
||||
?assertMatch({error, reuse_detected}, logic_auth_session:refresh_user(Refresh1)),
|
||||
?assertMatch({error, revoked}, logic_auth_session:refresh_user(Refresh2)).
|
||||
|
||||
Reference in New Issue
Block a user