mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
Add webvirtcloud/test_authorization_matrix.py, which walks every named URL and checks that a user without any VM/compute relation only reaches an explicit allowlist, and that the global view_instances permission does not open consoles. It found: - /computes/<id>/... views without any check (compute_graph, get_compute_*, get_dom_capabilities, storages.get_volumes): the whole computes URL namespace is now wrapped with superuser_only, so a view added there later cannot be exposed by a missing decorator. - guess_mac_address (leaks dhcpd.conf host/MAC pairs), random_mac_address and guess_clone_name: superuser-only, like the buttons that use them. - check_instance: cross-tenant VM name lookup with no caller; removed. - getvvfile and get_vdi_url: reachable with only view_instances, and the .vv file contains the VNC password. Console access now follows one rule, instances.utils.can_open_console: an active superuser or an active owner of the VM. The global view_instances permission is read-only. It is used by the console page, novncd, getvvfile and get_vdi_url (getvvfile and the VDI tab are kept for virt-viewer users). The console page answers 403 instead of 500 when access is denied, with the same answer for a missing VM.
98 lines
3.5 KiB
Python
98 lines
3.5 KiB
Python
from virtsecrets.views import secrets
|
|
|
|
from admin.decorators import superuser_only
|
|
from django.urls import URLPattern, URLResolver, include, path
|
|
from interfaces.views import interface, interfaces
|
|
from networks.views import network, networks
|
|
from nwfilters.views import nwfilter, nwfilters
|
|
from storages.views import create_volume, get_volumes, storage, storages
|
|
|
|
from . import forms, views
|
|
|
|
|
|
def superuser_only_patterns(patterns):
|
|
"""
|
|
Wrap every view below these patterns with superuser_only. Everything under
|
|
/computes/ is host administration (ROADMAP S-10), so the check is applied
|
|
to the whole namespace instead of per view, and a view added here later
|
|
cannot be exposed by forgetting a decorator.
|
|
"""
|
|
for pattern in patterns:
|
|
if isinstance(pattern, URLResolver):
|
|
superuser_only_patterns(pattern.url_patterns)
|
|
elif isinstance(pattern, URLPattern):
|
|
pattern.callback = superuser_only(pattern.callback)
|
|
return patterns
|
|
|
|
|
|
urlpatterns = [
|
|
path("", views.computes, name="computes"),
|
|
path(
|
|
"add_tcp_host/",
|
|
views.compute_create,
|
|
{"FormClass": forms.TcpComputeForm},
|
|
name="add_tcp_host",
|
|
),
|
|
path(
|
|
"add_ssh_host/",
|
|
views.compute_create,
|
|
{"FormClass": forms.SshComputeForm},
|
|
name="add_ssh_host",
|
|
),
|
|
path(
|
|
"add_tls_host/",
|
|
views.compute_create,
|
|
{"FormClass": forms.TlsComputeForm},
|
|
name="add_tls_host",
|
|
),
|
|
path(
|
|
"add_socket_host/",
|
|
views.compute_create,
|
|
{"FormClass": forms.SocketComputeForm},
|
|
name="add_socket_host",
|
|
),
|
|
path(
|
|
"<int:compute_id>/",
|
|
include(
|
|
[
|
|
path("", views.overview, name="overview"),
|
|
path("update/", views.compute_update, name="compute_update"),
|
|
path("delete/", views.compute_delete, name="compute_delete"),
|
|
path("statistics", views.compute_graph, name="compute_graph"),
|
|
path("instances/", views.instances, name="instances"),
|
|
path("storages/", storages, name="storages"),
|
|
path("storage/<str:pool>/volumes/", get_volumes, name="volumes"),
|
|
path("storage/<str:pool>/", storage, name="storage"),
|
|
path(
|
|
"storage/<str:pool>/create_volume/",
|
|
create_volume,
|
|
name="create_volume",
|
|
),
|
|
path("networks/", networks, name="networks"),
|
|
path("network/<str:pool>/", network, name="network"),
|
|
path("interfaces/", interfaces, name="interfaces"),
|
|
path("interface/<str:iface>/", interface, name="interface"),
|
|
path("nwfilters/", nwfilters, name="nwfilters"),
|
|
path("nwfilter/<str:nwfltr>/", nwfilter, name="nwfilter"),
|
|
path("virtsecrets/", secrets, name="virtsecrets"),
|
|
path(
|
|
"archs/<str:arch>/machines",
|
|
views.get_compute_machine_types,
|
|
name="machines",
|
|
),
|
|
path(
|
|
"archs/<str:arch>/machines/<str:machine>/disks/<str:disk>/buses",
|
|
views.get_compute_disk_buses,
|
|
name="buses",
|
|
),
|
|
path(
|
|
"archs/<str:arch>/machines/<str:machine>/capabilities",
|
|
views.get_dom_capabilities,
|
|
name="domcaps",
|
|
),
|
|
]
|
|
),
|
|
),
|
|
]
|
|
|
|
superuser_only_patterns(urlpatterns)
|