Skip to content

Commit

Permalink
Add authentication, closes #2
Browse files Browse the repository at this point in the history
  • Loading branch information
Core-i99 committed Jul 3, 2024
1 parent 1c34738 commit 0f31714
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 39 deletions.
23 changes: 15 additions & 8 deletions .github/workflows/Build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,19 @@ jobs:
with:
name: Build
path: dist/*

# upload to pipy if release
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
if: github.event_name == 'release' && github.event.action == 'published'

- name: Zip package
if: github.event_name == 'release'
run: |
cd dist
zip -r server99-websockify-token-plugin-release.zip .
mv server99-websockify-token-plugin-release.zip ../
- name: Upload to release
if: github.event_name == 'release'
uses: svenstaro/[email protected]
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}

repo_token: ${{ secrets.TOKEN }}
file: server99-websockify-token-plugin-release.zip
tag: ${{ github.ref }}
file_glob: true
28 changes: 15 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,34 +1,36 @@
# Info
Websockify token plugin for Libvirt domains, token is the Libvirt domain uuid.
This plugin lookups the domain xml using the Libvirt api and gets the vnc port.
Websockify token plugin for Server99
The format of the websockify token is DOMAIN_UUID:JWT_TOKEN
This plugin sends a request to the Server99 API to validate the authentication token and get the vnc port of the domain.

# Usage
See the [websockify wiki](https://github.com/novnc/websockify/wiki/Token-based-target-selection)
- Use `pip install websockify-LibvirtDomain` to install the package
- Start websockify with the `--token-plugin websockify_LibvirtDomain.LibvirtDomain` option
- The `--token-source` option in Websockify can be used to specify a Libvirt Uri, without this option specified the uri is `qemu:///system`
- Use `pip install /path/to/server99_websockify_token_plugin-X.X.tar.gz` to install the package
- Start websockify with the `--token-plugin server99-websockify-token-plugin.Server99Token` option
- The `--token-source` option is used to specify the Server99 API address
- The `--token-source` option is optional and defaults to `http://localhost:80`

# Example Usage
Runs a Websockify deamon for noVNC using this plugin
- Run a server on port 6080: `websockify --web=/usr/share/novnc/ 6080 --token-plugin websockify_LibvirtDomain.LibvirtDomain`
- Run a server on port 6080 with a custom libvirt uri: `websockify --web=/usr/share/novnc/ 6080 --token-plugin websockify_LibvirtDomain.LibvirtDomain --token-source 'LibvirtUri'`
- Use your browser to navigate to the Websockify server with the `token` argument being the domain uuid: `http://some-ip:6080/vnc.html?token=some-uuid`
- Run a server on port 6080: `websockify --web=/usr/share/novnc/ 6080 --token-plugin server99-websockify-token-plugin.Server99Token`
- Run a server on port 6080 with a custom uri: `websockify --web=/usr/share/novnc/ 6080 --token-plugin server99-websockify-token-plugin.Server99Token --token-source http://127.0.0.1:8000`
- Use your browser to navigate to the Websockify server with the `token` argument: `http://127.0.0.1:6080/vnc.html?token=domain_uuid:jwt_token`

## Run as a service
- Create a file at `/etc/systemd/system/websockify-libvirtdomain.service` with the contents
- Create a file at `/etc/systemd/system/websockify-server99.service` with the contents
```
[Unit]
Description=Websockify LibvirtDomain
Description=Websockify Server99 Service
After=multi-user.target
[Service]
Type=simple
Restart=always
ExecStart=websockify --web=/usr/share/novnc/ 6080 --token-plugin websockify_LibvirtDomain.LibvirtDomain
ExecStart=websockify --web=/usr/share/novnc/ 6080 --token-plugin server99-websockify-token-plugin.Server99Token
[Install]
WantedBy=multi-user.target
```
- Reload systemctl `systemctl daemon-reload`
- Enable the service (run the service on device startup) `systemctl enable websockify-libvirtdomain.service`
- Start the service `systemctl start websockify-libvirtdomain.service`
- Enable the service (run the service on device startup) `systemctl enable websockify-server99.service`
- Start the service `systemctl start websockify-server99.service`
10 changes: 5 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"

[project]
name = "websockify_LibvirtDomain"
version = "1.0"
name = "server99-websockify-token-plugin"
version = "2.0"
authors = [
{ name="Stijn Rombouts", email="[email protected]" },
]
description = "Websockify token plugin for Libvirt domains"
description = "Websockify token plugin for Server99"
readme = "README.md"
requires-python = ">=3.7"

[project.urls]
"Homepage" = "https://github.com/macOS-KVM/websockify-LibvirtDomain"
"Bug Tracker" = "https://github.com/macOS-KVM/websockify-LibvirtDomain/issues"
"Homepage" = "https://github.com/99-industries/server99-websockify-token-plugin"
"Bug Tracker" = "https://github.com/99-industries/server99-websockify-token-plugin/issues"
33 changes: 20 additions & 13 deletions src/websockify_LibvirtDomain/__init__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
import libvirt
from xml.etree import ElementTree as ET
import requests

class LibvirtDomain(object):
class Server99Token(object):
def __init__(self, src):
if src == None:
libvirturi = "qemu:///system"
else:
libvirturi = src
self.conn = libvirt.open(libvirturi)
# src is the address of the server99 backend
# For development, it should be http://localhost:5000
if src is None:
src = "http://localhost:80"
self.src = src

def lookup(self, token):
dom = self.conn.lookupByUUIDString(token)
xml = dom.XMLDesc(0)
root = ET.fromstring(xml)
graphicselem = root.find("devices/graphics")
port = graphicselem.get("port")
return ("localhost", port)
# The token is the UUID of the domain and the jwt token
# Token format DOMAIN_UUID:JWT_TOKEN
domain_uuid, jwt_token = token.split(":")

# Get the vnc_port from the server99 backend
# The server99 backend will check if the user has access to the domain
# If the user has access, it will return the vnc_port
backend_response = requests.get(f"{self.src}/api/vm-manager/{domain_uuid}/vnc_port", headers={"Authorization": f"Bearer {jwt_token}"})
if backend_response.status_code != 200:
raise Exception("Unauthorized access to the domain")
else:
vnc_port = backend_response.text
return ("localhost", vnc_port)

0 comments on commit 0f31714

Please sign in to comment.