Unable to connect to vncwebsocket endpoint via API-TOKEN

pandada8

Active Member
Jun 25, 2018
13
2
43
28
I used to have some code interactive with vncwebsocket via the following procedure. It's used to connect VM serial directly to the user terminal.

1. generate a PVEVNC ticket via /api2/json/nodes/{node}/qemu/{vmid}/termproxy
2. Submit Ticket and user to wss://<host>:8006/api2/json/nodes/{node}/qemu/{vmid}/vncwebsocket

When switching to API Token. I found that you can still generate PVEVNC Ticket from step1, but Unable to connect the websocket endpoint.
During further diagnosing, I find the following log from pvedaemon:

Code:
authentication failure; rhost=127.0.0.1 user=root@pam!<redacted> msg=value 'root@pam!<redacted>' does not look like a valid user name
command '/usr/bin/termproxy 5900 --path /vms/10020 --perm VM.Console -- /usr/sbin/qm terminal 10020 -escape 0 -iface serial0' failed: exit code 1

what's the correct way using vncwebsocket endpoint via api token ?

A small reproduce script is attached below.

Python:
"""
Install dependency by pip install proxmoxer websocket-client
"""
import proxmoxer
import websocket
import ssl
import sys
from urllib.parse import urlencode

endpoint = '<replace>'
vmid = 10020
serial='<replace>'
node = '<replace>'
opts = {"cert_reqs": ssl.CERT_NONE, "check_hostname": False}

p = proxmoxer.ProxmoxAPI(endpoint, user='<replace>', token_name="<replace>", token_value="<replace>", verify_ssl=False)
# p = proxmoxer.ProxmoxAPI(endpoint, user='<replace>', password='<replace>', verify_ssl=False)
data = p.nodes(node).qemu(vmid).termproxy.post(serial=serial)
query = {'vncticket': data['ticket'], 'port': data['port']}
extra_opts = {}
handshake = ''
if hasattr(p._backend.auth, 'token_name'):
    extra_opts['header'] = {'Authorization': f'PVEAPIToken={p._backend.auth.username}!{p._backend.auth.token_name}={p._backend.auth.token_value}'}
    # handshake = f'{p._backend.auth.username}:{data["ticket"]}\n'
    handshake = f'{p._backend.auth.username}!{p._backend.auth.token_name}:{data["ticket"]}\n'
else:
    extra_opts['cookie'] = '; '.join(['='.join(i) for i in p._backend.auth.get_cookies().items()])
    handshake = f'{p._backend.auth.username}:{data["ticket"]}\n'
ws = websocket.create_connection(f"wss://{endpoint}/api2/json/nodes/{node}/qemu/{vmid}/vncwebsocket?{urlencode(query)}", sslopt=opts, **extra_opts)
ws.send(handshake)
print(ws.recv())
# should be 'OK'
ws.close()
 
hi! i manages to create a termproxy websocket session successfully. i hope it can help you and the others in the future (to be honest it took me one entire hellish week to finally get it to work).
disclaimer 1: i tried to use tokens and it didn't work. i tried whatever i could think of.
disclaimer 2: i used aoihttp instead of websocket and websockets modules, so that i can monitor and debug the traffic using burp suit. you should remove the lines related to proxy. lines: 11, 12, 22, 23, 56 and 64.

Python:
import os
import ssl
import warnings
import asyncio
from dotenv import load_dotenv
from proxmoxer import ProxmoxAPI
import aiohttp
from time import sleep


os.environ['HTTP_PROXY'] = 'http://localhost:8080'
os.environ['HTTPS_PROXY'] = 'http://localhost:8080'

load_dotenv(dotenv_path='.env')
vmid = '310'

warnings.filterwarnings(action="ignore")
node_name: str = os.environ['PROXMOX_NODE']
proxmox_host: str = os.environ['PROXMOX_SERVER']
proxmox_user: str = os.environ['PROXMOX_USERNAME']
proxmox_password = os.environ['PROXMOX_PASSWORD']
proxy_host: str = os.environ['PROXY_HOST']  # Replace with your proxy host
proxy_port: int = int(os.environ['PROXY_PORT'])  # Replace with your proxy port

proxmox = ProxmoxAPI(
    host=proxmox_host,
    user=proxmox_user,
    password=proxmox_password,
    verify_ssl=False,
)

termproxy = proxmox.nodes(node_name).lxc(vmid).termproxy.post()

ticket: str = termproxy.get('ticket')
port: str = termproxy.get('port')

proxmox.nodes.get()
cookie, _ = proxmox.get_tokens()


async def connect_websocket():
    headers = {
        'Authorization': f'PVEAPIToken={proxmox_user}',
        'Sec-WebSocket-Protocol': 'bianry',
        'Pragma': 'no-cache',
        'Cache-Control': 'no-cache',
        'Cookie': f'PVEAuthCookie={cookie}'
    }

    ssl_defaults = ssl.get_default_verify_paths()
    ssl_context = ssl.create_default_context(cafile=ssl_defaults.cafile)
    ssl_context.check_hostname = False
    ssl_context.verify_mode = ssl.CERT_NONE

    websocket_url = f'wss://{proxmox_host}:8006/api2/json/nodes/{node_name}/lxc/{vmid}/vncwebsocket'
    proxy_server = f"http://{proxy_host}:{proxy_port}"
    query_params = {'port': port, 'vncticket': ticket}

    async with aiohttp.ClientSession() as session:
        async with session.ws_connect(
            f'{websocket_url}',
            headers=headers,
            ssl=ssl_context,
            proxy=proxy_server,
            params=query_params,
        ) as websocket:
            try:
                # Send initial message after the connection is established
                await websocket.send_str(f'{proxmox_user}:{ticket}\n')
                # Read and print incoming messages
                response = await websocket.receive()
                print(f"Received response: {response.data}")

                # based on the monitored traffic (burp suite) the following should be sent to server:
                await websocket.send_str('1:86:24:')
                   
                # now do whatever you want!!
            except aiohttp.ClientError as e:
                print(f"WebSocket connection error: {e}")
            except asyncio.CancelledError:
                print("WebSocket connection cancelled.")

loop = asyncio.get_event_loop()
loop.run_until_complete(connect_websocket())
 
Last edited:

About

The Proxmox community has been around for many years and offers help and support for Proxmox VE, Proxmox Backup Server, and Proxmox Mail Gateway.
We think our community is one of the best thanks to people like you!

Get your subscription!

The Proxmox team works very hard to make sure you are running the best software and getting stable updates and security enhancements, as well as quick enterprise support. Tens of thousands of happy customers have a Proxmox subscription. Get yours easily in our online shop.

Buy now!