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)