mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
fix(console): a VM with a QEMU websocket port opens through novncd
A VM defined with QEMU's own VNC websocket (graphics websocket='...', which the panel never sets) made the console page connect to that port on the panel's host name: the port is on the compute, so the console did not open unless the panel ran on that compute, and then it bypassed novncd and the panel's console token. Such a VM has its ordinary VNC port too, and novncd now reaches it there like any other VM.
This commit is contained in:
parent
3bd9fe63e5
commit
554e3a7995
5 changed files with 6 additions and 31 deletions
|
|
@ -66,8 +66,7 @@
|
|||
|
||||
bindSendKeys(() => UI.rfb);
|
||||
|
||||
// novncd behind the panel's own address (nginx's /novncd/); a VM with a
|
||||
// QEMU websocket port is reached on that port of the panel's host name
|
||||
// novncd behind the panel's own address (nginx's /novncd/)
|
||||
let fullPath = 'novncd/';
|
||||
const token = '{{ token|escapejs }}';
|
||||
if (token) {
|
||||
|
|
@ -87,7 +86,7 @@
|
|||
const https = window.location.protocol === 'https:';
|
||||
const mandatory = {
|
||||
host: window.location.hostname,
|
||||
port: Number('{{ console_websocket_port|default_if_none:""|escapejs }}' || window.location.port || (https ? 443 : 80)),
|
||||
port: Number(window.location.port || (https ? 443 : 80)),
|
||||
path: fullPath,
|
||||
encrypt: https,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -149,10 +149,9 @@
|
|||
bindSendKeys(() => rfb);
|
||||
|
||||
// novncd behind the panel's own address (nginx's /novncd/), never a host
|
||||
// from the link: the page sends it a console token. A VM with a QEMU
|
||||
// websocket port is reached on that port of the panel's host name.
|
||||
// from the link: the page sends it a console token
|
||||
const host = window.location.hostname;
|
||||
let port = '{{ console_websocket_port|default_if_none:""|escapejs }}' || window.location.port;
|
||||
let port = window.location.port;
|
||||
|
||||
{% if perms.instances.passwordless_console and console_passwd %}
|
||||
const password = '{{ console_passwd|escapejs }}';
|
||||
|
|
|
|||
|
|
@ -75,7 +75,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
def test_console_superuser_vnc_lite(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_conn.get_console_websocket_port.return_value = None
|
||||
mock_conn.get_console_passwd.return_value = "vncsecret"
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
|
|
@ -96,7 +95,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
def test_console_superuser_vnc_full(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_conn.get_console_websocket_port.return_value = 5900
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
self.client.force_login(self.admin_user)
|
||||
|
|
@ -105,12 +103,12 @@ class ConsoleViewsTestCase(TestCase):
|
|||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTemplateUsed(response, "console-vnc-full.html")
|
||||
self.assertEqual(response.context["console_websocket_port"], 5900)
|
||||
# a VM with a QEMU websocket port goes through novncd too, on its VNC port
|
||||
self.assertContains(response, "port: Number(window.location.port")
|
||||
|
||||
@patch("console.views.wvmInstance")
|
||||
def test_the_lite_console_switches_scaling_from_its_menu(self, mock_wvm):
|
||||
mock_wvm.return_value.get_console_type.return_value = "vnc"
|
||||
mock_wvm.return_value.get_console_websocket_port.return_value = None
|
||||
self.client.force_login(self.admin_user)
|
||||
for query, pressed in (("", "false"), ("&scale=true", "true")):
|
||||
with self.subTest(query=query):
|
||||
|
|
@ -126,7 +124,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
# Only VNC is supported; a VM defined elsewhere may use another type.
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "rdp"
|
||||
mock_conn.get_console_websocket_port.return_value = None
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
self.client.force_login(self.admin_user)
|
||||
|
|
@ -173,7 +170,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
def test_console_user_assigned_instance_access(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_conn.get_console_websocket_port.return_value = None
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
self.client.force_login(self.alice)
|
||||
|
|
@ -189,7 +185,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
# (letters and digits only: escapejs keeps them as they are in the lite view)
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_conn.get_console_websocket_port.return_value = None
|
||||
mock_conn.get_console_passwd.return_value = "vncpw7f3a"
|
||||
mock_wvm.return_value = mock_conn
|
||||
permission = Permission.objects.get(codename="passwordless_console")
|
||||
|
|
@ -217,7 +212,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
def test_console_lite_uses_the_signed_token(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_conn.get_console_websocket_port.return_value = None
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
self.client.force_login(self.admin_user)
|
||||
|
|
@ -241,7 +235,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
def test_the_lite_console_connects_only_to_the_servers_proxy(self, mock_wvm):
|
||||
# a link naming another host would send it the signed console token
|
||||
mock_wvm.return_value.get_console_type.return_value = "vnc"
|
||||
mock_wvm.return_value.get_console_websocket_port.return_value = None
|
||||
self.client.force_login(self.alice)
|
||||
response = self.client.get(self.url + "?host=attacker.example&port=443&path=x")
|
||||
self.assertNotContains(response, "attacker.example")
|
||||
|
|
@ -253,7 +246,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
def test_the_page_sets_no_token_cookie(self, mock_wvm):
|
||||
# one cookie for every tab would name the last console opened
|
||||
mock_wvm.return_value.get_console_type.return_value = "vnc"
|
||||
mock_wvm.return_value.get_console_websocket_port.return_value = None
|
||||
self.client.force_login(self.admin_user)
|
||||
response = self.client.get(self.url)
|
||||
self.assertNotIn("token", response.cookies)
|
||||
|
|
@ -264,7 +256,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
# is for superusers and VM owners only.
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_conn.get_console_websocket_port.return_value = None
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
perm = Permission.objects.get(codename="view_instances")
|
||||
|
|
@ -291,7 +282,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
# nginx proxies /novncd/ on the panel's own scheme, host and port: no
|
||||
# console address to configure, HTTPS gives wss
|
||||
mock_wvm.return_value.get_console_type.return_value = "vnc"
|
||||
mock_wvm.return_value.get_console_websocket_port.return_value = None
|
||||
self.client.force_login(self.admin_user)
|
||||
lite = self.client.get(self.url + "?view=lite")
|
||||
self.assertContains(lite, "const host = window.location.hostname;")
|
||||
|
|
@ -304,7 +294,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
def test_console_xss_protection_query_parameters(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_conn.get_console_websocket_port.return_value = None
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
self.client.force_login(self.admin_user)
|
||||
|
|
@ -329,7 +318,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
def test_console_password_escapejs_escaping(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_conn.get_console_websocket_port.return_value = None
|
||||
mock_conn.get_console_passwd.return_value = "O'Brian<script>&123"
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
|
|
@ -362,7 +350,6 @@ class ConsoleViewsTestCase(TestCase):
|
|||
def test_console_full_resize_syntax_validity(self, mock_wvm):
|
||||
mock_conn = MagicMock()
|
||||
mock_conn.get_console_type.return_value = "vnc"
|
||||
mock_conn.get_console_websocket_port.return_value = None
|
||||
mock_wvm.return_value = mock_conn
|
||||
|
||||
self.client.force_login(self.admin_user)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ def console(request, compute_id, uuid):
|
|||
uuid=instance.uuid,
|
||||
)
|
||||
console_type = conn.get_console_type()
|
||||
console_websocket_port = conn.get_console_websocket_port()
|
||||
console_passwd = conn.get_console_passwd()
|
||||
running = conn.instance.isActive()
|
||||
# novncd reaches a console that listens on its host's loopback only
|
||||
|
|
@ -63,7 +62,6 @@ def console(request, compute_id, uuid):
|
|||
except (libvirtError, ValueError, IndexError, Instance.DoesNotExist):
|
||||
running = unreachable = False
|
||||
console_type = None
|
||||
console_websocket_port = None
|
||||
console_passwd = None
|
||||
|
||||
if console_type and not running: # a shut-off VM has no console to connect to
|
||||
|
|
|
|||
|
|
@ -1368,14 +1368,6 @@ class wvmInstance(wvmConnect):
|
|||
)
|
||||
return port
|
||||
|
||||
def get_console_websocket_port(self):
|
||||
console_type = self.get_console_type()
|
||||
websocket_port = util.get_xml_path(
|
||||
self._XMLDesc(0),
|
||||
"/domain/devices/graphics[@type='%s']/@websocket" % console_type,
|
||||
)
|
||||
return websocket_port
|
||||
|
||||
def get_console_passwd(self, config=False):
|
||||
return util.get_xml_path(
|
||||
self._XMLDesc(PERSISTENT_XML if config else VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@passwd"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue