mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-11 12:46:49 +00:00
fix: add an authorization matrix test and close the endpoints it finds
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.
This commit is contained in:
parent
b1ab1d47fa
commit
4d34d9d07c
11 changed files with 314 additions and 46 deletions
|
|
@ -1,6 +1,7 @@
|
|||
from virtsecrets.views import secrets
|
||||
|
||||
from django.urls import include, path
|
||||
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
|
||||
|
|
@ -8,6 +9,22 @@ 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(
|
||||
|
|
@ -77,3 +94,5 @@ urlpatterns = [
|
|||
),
|
||||
),
|
||||
]
|
||||
|
||||
superuser_only_patterns(urlpatterns)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue