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)