1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-11 04:36:48 +00:00

fix(console): socketiod refuses a request without a signed-in session

Engine.IO accepts a connection, and holds one of socketiod's 40 threads
for it, from its first request; the console token is checked only in
Socket.IO's connect(), which a client need never send. Anyone who could
reach the panel, without an account, could open 40 websockets, answer
their pings, and no serial console would open for anybody (checked: the
41st handshake got no answer until they were closed).

The daemon's WSGI app now refuses a request whose session cookie names
no signed-in user, with 403, before Engine.IO sees it; the page always
sends that cookie. A token without its session no longer connects either,
as for novncd. Checked again: 60 such websockets are each answered 403 at
once and hold nothing.

The process tests sign their client in with a session cookie, as a
browser; python-socketio sends a custom Cookie header only with its first
request, so the client gets a cookie jar instead.
This commit is contained in:
catborise 2026-11-06 19:53:15 +03:00
parent bb490101fd
commit 4f7bca9754
3 changed files with 59 additions and 14 deletions

View file

@ -15,7 +15,7 @@ from vrtManager.connection import connection_manager
from accounts.models import UserInstance
from computes.models import Compute
from console import tokens
from console.tests.test_socketiod_child import consoles, console, start_socketiod, socketio
from console.tests.test_socketiod_child import consoles, console, session_key, start_socketiod, socketio
from instances.models import Instance
from vrtManager.tests import livetest
@ -65,22 +65,22 @@ class LiveSerialConsoleTestCase(TransactionTestCase):
def admin_token(self, token):
host, uuid, _user, _type = tokens.SIGNER.unsign(token).split(":")
admin, _ = get_user_model().objects.get_or_create(username="serial-live-admin", is_superuser=True)
return tokens.sign(host, uuid, admin.id, "pty")
self.admin, _ = get_user_model().objects.get_or_create(username="serial-live-admin", is_superuser=True)
return tokens.sign(host, uuid, self.admin.id, "pty")
def test_the_console_of_a_running_vm_opens_once(self):
for args in self.hosts:
with self.subTest(host=args[0], type=args[3]):
token, dom = self.token(*args)
client, received = console(self.port, token)
client, received = console(self.port, token, session_key(self.user))
deadline = time.monotonic() + 30
while "SeaBIOS" not in "".join(received["output"]) and time.monotonic() < deadline:
time.sleep(0.2)
self.assertIn("SeaBIOS", "".join(received["output"]))
# one client per VM; a superuser takes a console left open over
with self.assertRaises(socketio.exceptions.ConnectionError):
console(self.port, token)
admin_client, admin_received = console(self.port, self.admin_token(token))
console(self.port, token, session_key(self.user))
admin_client, admin_received = console(self.port, self.admin_token(token), session_key(self.admin))
wait_for(lambda: received["taken_over"])
self.assertEqual(received["taken_over"], ["serial-live-admin"])
client.disconnect()