From 5ec63984103ab6a26611254f3eb3c62e65488cd2 Mon Sep 17 00:00:00 2001 From: Askaholic Date: Sat, 23 Dec 2023 17:19:58 -0500 Subject: [PATCH 1/3] Refactor test names --- tests/integration_tests/test_login.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/integration_tests/test_login.py b/tests/integration_tests/test_login.py index ee1e7c77b..ade081f7d 100644 --- a/tests/integration_tests/test_login.py +++ b/tests/integration_tests/test_login.py @@ -11,7 +11,7 @@ ) -async def test_server_invalid_login(lobby_server): +async def test_server_login_invalid(lobby_server): proto = await connect_client(lobby_server) # Try a user that doesn't exist await perform_login(proto, ("Cat", "epic")) @@ -53,7 +53,7 @@ async def test_server_ban_revoked_or_expired(lobby_server, user): assert msg["login"] == user -async def test_server_valid_login(lobby_server): +async def test_server_login_valid(lobby_server): proto = await connect_client(lobby_server) await perform_login(proto, ("Rhiza", "puff_the_magic_dragon")) msg = await proto.read_message() @@ -98,7 +98,7 @@ async def test_server_valid_login(lobby_server): } -async def test_server_valid_login_admin(lobby_server): +async def test_server_login_valid_admin(lobby_server): proto = await connect_client(lobby_server) await perform_login(proto, ("test", "test_password")) msg = await proto.read_message() @@ -143,7 +143,7 @@ async def test_server_valid_login_admin(lobby_server): } -async def test_server_valid_login_moderator(lobby_server): +async def test_server_login_valid_moderator(lobby_server): proto = await connect_client(lobby_server) await perform_login(proto, ("moderator", "moderator")) msg = await proto.read_message() @@ -202,7 +202,7 @@ async def test_policy_server_contacted(lobby_server, policy_server, player_servi policy_server.verify.assert_called_once() -async def test_server_double_login(lobby_server): +async def test_server_login_double(lobby_server): proto = await connect_client(lobby_server) await perform_login(proto, ("test", "test_password")) msg = await proto.read_message() @@ -222,7 +222,7 @@ async def test_server_double_login(lobby_server): } -async def test_server_valid_login_with_token(lobby_server, jwk_priv_key, jwk_kid): +async def test_server_login_token_valid(lobby_server, jwk_priv_key, jwk_kid): proto = await connect_client(lobby_server) await proto.send_message({ "command": "auth", @@ -285,7 +285,7 @@ async def test_server_valid_login_with_token(lobby_server, jwk_priv_key, jwk_kid } -async def test_server_login_bad_id_in_token(lobby_server, jwk_priv_key, jwk_kid): +async def test_server_login_token_bad_id(lobby_server, jwk_priv_key, jwk_kid): proto = await connect_client(lobby_server) await proto.send_message({ "command": "auth", @@ -311,7 +311,7 @@ async def test_server_login_bad_id_in_token(lobby_server, jwk_priv_key, jwk_kid) } -async def test_server_login_expired_token(lobby_server, jwk_priv_key, jwk_kid): +async def test_server_login_token_expired(lobby_server, jwk_priv_key, jwk_kid): proto = await connect_client(lobby_server) await proto.send_message({ "command": "auth", @@ -333,7 +333,7 @@ async def test_server_login_expired_token(lobby_server, jwk_priv_key, jwk_kid): } -async def test_server_login_malformed_token(lobby_server, jwk_priv_key, jwk_kid): +async def test_server_login_token_malformed(lobby_server, jwk_priv_key, jwk_kid): """This scenario could only happen if the hydra signed a token that was missing critical data""" proto = await connect_client(lobby_server) @@ -355,7 +355,11 @@ async def test_server_login_malformed_token(lobby_server, jwk_priv_key, jwk_kid) } -async def test_server_login_lobby_scope_missing(lobby_server, jwk_priv_key, jwk_kid): +async def test_server_login_token_lobby_scope_missing( + lobby_server, + jwk_priv_key, + jwk_kid, +): """This scenario could only happen if the hydra signed a token that was missing critical data""" proto = await connect_client(lobby_server) From bcb8f2a3f57da39b269d195437b265494e483fde Mon Sep 17 00:00:00 2001 From: Askaholic Date: Sat, 23 Dec 2023 17:21:19 -0500 Subject: [PATCH 2/3] Add appeal email to ban message --- server/exceptions.py | 4 +++- tests/integration_tests/test_login.py | 6 +++++- tests/integration_tests/test_server.py | 6 +++++- tests/unit_tests/test_lobbyconnection.py | 5 ++++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/server/exceptions.py b/server/exceptions.py index 5c5a103d6..48095d2a4 100644 --- a/server/exceptions.py +++ b/server/exceptions.py @@ -34,7 +34,9 @@ def __init__(self, ban_expiry, ban_reason, *args, **kwargs): def message(self): return ( f"You are banned from FAF {self._ban_duration_text()}.
" - f"Reason:
{self.ban_reason}" + f"Reason:
{self.ban_reason}

" + "If you would like to appeal this ban, please send an email to: " + "moderation@faforever.com" ) def _ban_duration_text(self): diff --git a/tests/integration_tests/test_login.py b/tests/integration_tests/test_login.py index ade081f7d..f7b9cbc91 100644 --- a/tests/integration_tests/test_login.py +++ b/tests/integration_tests/test_login.py @@ -39,7 +39,11 @@ async def test_server_ban(lobby_server, user): assert msg == { "command": "notice", "style": "error", - "text": "You are banned from FAF forever.
Reason:
Test permanent ban" + "text": ( + "You are banned from FAF forever.
Reason:
Test permanent ban" + "

If you would like to appeal this ban, please send an " + "email to: moderation@faforever.com" + ) } diff --git a/tests/integration_tests/test_server.py b/tests/integration_tests/test_server.py index a1199e2d9..3f2fe7a7b 100644 --- a/tests/integration_tests/test_server.py +++ b/tests/integration_tests/test_server.py @@ -793,7 +793,11 @@ async def test_server_ban_prevents_hosting(lobby_server, database, command): assert msg == { "command": "notice", "style": "error", - "text": "You are banned from FAF forever.
Reason:
Test live ban" + "text": ( + "You are banned from FAF forever.
Reason:
Test live ban
" + "
If you would like to appeal this ban, please send an email " + "to: moderation@faforever.com" + ) } diff --git a/tests/unit_tests/test_lobbyconnection.py b/tests/unit_tests/test_lobbyconnection.py index 61af68d68..48e812ecc 100644 --- a/tests/unit_tests/test_lobbyconnection.py +++ b/tests/unit_tests/test_lobbyconnection.py @@ -1076,8 +1076,11 @@ async def test_abort_connection_if_banned( lobbyconnection.player.id = 203 with pytest.raises(BanError) as banned_error: await lobbyconnection.abort_connection_if_banned() - assert banned_error.value.message() == \ + assert banned_error.value.message() == ( "You are banned from FAF forever.
Reason:
Test permanent ban" + "

If you would like to appeal this ban, please send an email " + "to: moderation@faforever.com" + ) # test user who is banned for another 46 hours lobbyconnection.player.id = 204 From 2f24f69995614479474dce3212bbb64d732308b6 Mon Sep 17 00:00:00 2001 From: Askaholic Date: Sat, 23 Dec 2023 17:21:33 -0500 Subject: [PATCH 3/3] Check bans on token login --- server/lobbyconnection.py | 25 +++++++++++++++++-- tests/integration_tests/test_login.py | 35 +++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index c536c758d..e69613c89 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -516,16 +516,37 @@ async def command_auth(self, message): async with self._db.acquire() as conn: result = await conn.execute( - select(t_login.c.login) + select( + t_login.c.login, + lobby_ban.c.reason, + lobby_ban.c.expires_at + ) + .select_from(t_login.outerjoin(lobby_ban)) .where(t_login.c.id == player_id) + .order_by(lobby_ban.c.expires_at.desc()) ) row = result.fetchone() if not row: - self._logger.warning("User id not found in database possible fraudulent token: %s", player_id) + self._logger.warning( + "User id %s not found in database! Possible fraudulent " + "token: %s", + player_id, + token + ) raise AuthenticationError("Cannot find user id", auth_method) username = row.login + ban_reason = row.reason + ban_expiry = row.expires_at + + now = datetime.utcnow() + if ban_reason is not None and now < ban_expiry: + self._logger.debug( + "Rejected login from banned user: %s, %s, %s", + player_id, username, self.session + ) + raise BanError(ban_expiry, ban_reason) # DEPRECATED: IRC passwords are handled outside of the lobby server. # This message remains here for backwards compatibility, but the data diff --git a/tests/integration_tests/test_login.py b/tests/integration_tests/test_login.py index f7b9cbc91..179d71214 100644 --- a/tests/integration_tests/test_login.py +++ b/tests/integration_tests/test_login.py @@ -47,6 +47,41 @@ async def test_server_ban(lobby_server, user): } +@pytest.mark.parametrize("user", [ + ("Dostya", 2), + ("ban_long_time", 203) +]) +async def test_server_ban_token(lobby_server, user, jwk_priv_key, jwk_kid): + user_name, user_id = user + proto = await connect_client(lobby_server) + await proto.send_message({ + "command": "auth", + "version": "1.0.0-dev", + "user_agent": "faf-client", + "token": jwt.encode({ + "sub": user_id, + "user_name": user_name, + "scp": ["lobby"], + "exp": int(time() + 1000), + "authorities": [], + "non_locked": True, + "jti": "", + "client_id": "" + }, jwk_priv_key, algorithm="RS256", headers={"kid": jwk_kid}), + "unique_id": "some_id" + }) + msg = await proto.read_message() + assert msg == { + "command": "notice", + "style": "error", + "text": ( + "You are banned from FAF forever.
Reason:
Test permanent ban" + "

If you would like to appeal this ban, please send an " + "email to: moderation@faforever.com" + ) + } + + @pytest.mark.parametrize("user", ["ban_revoked", "ban_expired"]) async def test_server_ban_revoked_or_expired(lobby_server, user): proto = await connect_client(lobby_server)