mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
fix(storages): Ceph and NFS pool values are escaped, host names may be long
create_storage_ceph and create_storage_netfs wrote the pool, host, user, secret and format values into the pool XML unescaped and unchecked: the page's patterns were the only guard, and a direct POST could break or extend the XML. The values now go through util.xml_escape, as the network code does. The page's host fields stopped at 20 characters, so nfs01.storage.example.com could not be typed: they take a host name's 253; the Ceph pool and user fields lose the limit the server never had.
This commit is contained in:
parent
7f1780ad2d
commit
eb828b364d
4 changed files with 39 additions and 4 deletions
|
|
@ -120,19 +120,19 @@
|
|||
<div class="row">
|
||||
<label for="stg_rbd_ceph_user" class="col-sm-3 col-form-label">{% trans "Ceph User" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input id="stg_rbd_ceph_user" type="text" class="form-control" name="ceph_user" placeholder="libvirt" maxlength="20" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
<input id="stg_rbd_ceph_user" type="text" class="form-control" name="ceph_user" placeholder="libvirt" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label for="stg_rbd_ceph_pool" class="col-sm-3 col-form-label">{% trans "Ceph Pool" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input id="stg_rbd_ceph_pool" type="text" class="form-control" name="ceph_pool" placeholder="libvirt-pool" maxlength="20" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
<input id="stg_rbd_ceph_pool" type="text" class="form-control" name="ceph_pool" placeholder="libvirt-pool" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<label for="stg_rbd_ceph_host" class="col-sm-3 col-form-label">{% trans "Ceph Host" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input id="stg_rbd_ceph_host" type="text" class="form-control" name="ceph_host" placeholder="mon0.ceph.host" maxlength="20" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
<input id="stg_rbd_ceph_host" type="text" class="form-control" name="ceph_host" placeholder="mon0.ceph.host" maxlength="253" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
@ -185,7 +185,7 @@
|
|||
<div class="row">
|
||||
<label for="stg_netfs_netfs_host" class="col-sm-3 col-form-label">{% trans "Hostname" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input id="stg_netfs_netfs_host" type="text" class="form-control" name="netfs_host" placeholder="nfs.example.com" maxlength="20" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
<input id="stg_netfs_netfs_host" type="text" class="form-control" name="netfs_host" placeholder="nfs.example.com" maxlength="253" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
|
|||
|
|
@ -74,3 +74,6 @@ class PoolTargetTests(SimpleTestCase):
|
|||
with self.subTest(form=field.xpath("string(ancestor::form//input[@name='stg_type']/@value)"), name=field.name):
|
||||
self.assertIsNone(field.get("pattern"))
|
||||
self.assertGreaterEqual(int(field.get("maxlength", 100)), 100)
|
||||
for name in ("netfs_host", "ceph_host"): # a host name is up to 253 characters
|
||||
with self.subTest(name=name):
|
||||
self.assertGreaterEqual(int(page.xpath(f"//input[@name='{name}']/@maxlength")[0]), 253)
|
||||
|
|
|
|||
30
storages/tests/test_pool_xml.py
Normal file
30
storages/tests/test_pool_xml.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
"""The host, pool, user and format values of a new Ceph or NFS pool go into
|
||||
its XML as text, whatever characters they hold."""
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
from django.test import SimpleTestCase
|
||||
from lxml import etree
|
||||
from vrtManager.storage import wvmStorages
|
||||
|
||||
ODD = "a'b\"c<d>&e"
|
||||
|
||||
|
||||
class PoolXmlTests(SimpleTestCase):
|
||||
def defined_xml(self, create, *args):
|
||||
with patch("vrtManager.connection.connection_manager.get_connection") as get:
|
||||
getattr(wvmStorages("host", "login", "pw", 1), create)(*args)
|
||||
return etree.fromstring(get.return_value.storagePoolDefineXML.call_args.args[0])
|
||||
|
||||
def test_ceph_values_are_text(self):
|
||||
pool = self.defined_xml("create_storage_ceph", "rbd", "pool1", ODD + "pool", ODD + "host", ODD + "user", ODD + "secret")
|
||||
self.assertEqual(pool.findtext("source/name"), ODD + "pool")
|
||||
self.assertEqual(pool.find("source/host").get("name"), ODD + "host")
|
||||
self.assertEqual(pool.find("source/auth").get("username"), ODD + "user")
|
||||
self.assertEqual(pool.find("source/auth/secret").get("uuid"), ODD + "secret")
|
||||
|
||||
def test_nfs_values_are_text(self):
|
||||
pool = self.defined_xml("create_storage_netfs", "netfs", "pool1", ODD + "host", "/srv/nfs", ODD + "fmt", "/mnt/pool1")
|
||||
self.assertEqual(pool.find("source/host").get("name"), ODD + "host")
|
||||
self.assertEqual(pool.find("source/format").get("type"), ODD + "fmt")
|
||||
self.assertEqual(pool.find("source/dir").get("path"), "/srv/nfs")
|
||||
|
|
@ -66,6 +66,7 @@ class wvmStorages(wvmConnect):
|
|||
def create_storage_ceph(
|
||||
self, stg_type, name, ceph_pool, ceph_host, ceph_user, secret
|
||||
):
|
||||
ceph_pool, ceph_host, ceph_user, secret = map(util.xml_escape, (ceph_pool, ceph_host, ceph_user, secret))
|
||||
xml = f"""
|
||||
<pool type='{stg_type}'>
|
||||
<name>{name}</name>
|
||||
|
|
@ -86,6 +87,7 @@ class wvmStorages(wvmConnect):
|
|||
def create_storage_netfs(
|
||||
self, stg_type, name, netfs_host, source, source_format, target
|
||||
):
|
||||
netfs_host, source_format = util.xml_escape(netfs_host), util.xml_escape(source_format)
|
||||
xml = f"""
|
||||
<pool type='{stg_type}'>
|
||||
<name>{name}</name>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue