mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-10 20:26:48 +00:00
fix(console): a VNC token works only in its user's session; refusals reach the Logs page
The VNC page's token travels in the websocket URL, so nginx's access log and anyone who saw the URL had it for 120 s, and it opened the console as a bearer token. novncd now also wants the session cookie of the token's user. Its refusals were a warning without a user or an address: they now name the client address (nginx sends X-Real-IP to novncd too) and leave a Logs row "VNC console refused: reason".
This commit is contained in:
parent
6e3abd11ea
commit
2e4e9c78f8
4 changed files with 75 additions and 5 deletions
|
|
@ -4,6 +4,7 @@
|
|||
# through an SSH tunnel or a local Unix socket.
|
||||
|
||||
import argparse
|
||||
import ipaddress
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
|
|
@ -22,7 +23,8 @@ django.setup()
|
|||
from websockify import ProxyRequestHandler, WebSocketProxy # noqa: E402
|
||||
|
||||
from console.sshtunnels import open_tunnel, tunnel_target # noqa: E402
|
||||
from console.tokens import ACCESS_CHECK, authorize, may_still_open # noqa: E402
|
||||
from console.tokens import ACCESS_CHECK, authorize, may_still_open, session_user_id # noqa: E402
|
||||
from logs.audit import write # noqa: E402
|
||||
from vrtManager.connection import CONN_SOCKET, CONN_SSH # noqa: E402
|
||||
from vrtManager.util import is_loopback # noqa: E402
|
||||
from webvirtcloud.settings import WS_HOST, WS_PORT # noqa: E402
|
||||
|
|
@ -77,6 +79,14 @@ def get_connection_infos(instance):
|
|||
WILDCARD = (None, "", "0.0.0.0", "::")
|
||||
|
||||
|
||||
def client_address(value):
|
||||
"""The client's address nginx sends in X-Real-IP, or None."""
|
||||
try:
|
||||
return str(ipaddress.ip_address(value))
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def end_when_refused(instance, user_id, tsock, ended):
|
||||
"""Close the session's VNC socket, which ends it, once its user may no
|
||||
longer open the console (as the serial console does)."""
|
||||
|
|
@ -102,11 +112,20 @@ class ConsoleClient:
|
|||
logging.warning("Console connection without a token in its websocket URL")
|
||||
return
|
||||
|
||||
user = None
|
||||
try:
|
||||
instance, user = authorize(token, "vnc")
|
||||
# a token read from a log or a URL is no use without its user's session
|
||||
if session_user_id(self.headers.get("Cookie")) != str(user.pk):
|
||||
raise PermissionError("The console page was opened in another session")
|
||||
connhost, connuser, conntype, console_host, console_port, console_socket = get_connection_infos(instance)
|
||||
except PermissionError as e:
|
||||
address = client_address(self.headers.get("X-Real-IP"))
|
||||
logging.warning("Console connection from %s denied: %s", address, e)
|
||||
write(user.username if user else "", "-", "", f"VNC console refused: {e}", False, address)
|
||||
return
|
||||
except Exception as e:
|
||||
logging.warning("Console connection denied: %s", e)
|
||||
logging.warning("Console connection failed: %s", e)
|
||||
return
|
||||
logging.debug(
|
||||
"Console of %s@%s (type %s): %s:%s, socket %s",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue