summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStuart McLaren <stuart.mclaren@hp.com>2014-07-16 13:33:32 +0000
committerNikhil Komawar <nikhilskomawar@gmail.com>2014-10-10 10:06:20 -0400
commitc0d90a580f87dbbf71e3a5d5c1b5cf8d7c7245b2 (patch)
tree183ab7c49f9dcb22feb481aa4a5864183e14bee9
parent8b2280466a0d84d846ccb6c7fb13e98df199bb30 (diff)
downloadglance-c0d90a580f87dbbf71e3a5d5c1b5cf8d7c7245b2.tar.gz
Prevent setting swift+config locations
Forbid setting 'swift+config' locations in a similar manner to 'file' for security reasons; knowledge of the reference name should not be exploitable. Setting swift+config had been prevented when swift was the default store, this patch changes to forbid setting no matter which store is the default. As with change id I75af34145521f533dcd6f5fd7690f5a68f3b44b3 this is v1 only for now. Change-Id: I62c4980bd5c2f3dd77fc40cd007bc1067eca63a4 Closes-bug: 1334196
-rw-r--r--glance/api/v1/images.py26
-rw-r--r--glance/tests/functional/v1/test_copy_to_file.py28
-rw-r--r--glance/tests/unit/v1/test_api.py6
3 files changed, 41 insertions, 19 deletions
diff --git a/glance/api/v1/images.py b/glance/api/v1/images.py
index 15ec91201..3b460272f 100644
--- a/glance/api/v1/images.py
+++ b/glance/api/v1/images.py
@@ -417,17 +417,20 @@ class Controller(controller.BaseController):
"""
External sources (as specified via the location or copy-from headers)
are supported only over non-local store types, i.e. S3, Swift, HTTP.
- Note the absence of file:// for security reasons, see LP bug #942118.
+ Note the absence of 'file://' for security reasons, see LP bug #942118.
+ 'swift+config://' is also absent for security reasons, see LP bug
+ #1334196.
If the above constraint is violated, we reject with 400 "Bad Request".
"""
if source:
pieces = urlparse.urlparse(source)
schemes = [scheme for scheme in store.get_known_schemes()
- if scheme != 'file']
+ if scheme != 'file' and scheme != 'swift+config']
for scheme in schemes:
if pieces.scheme == scheme:
return source
- msg = "External sourcing not supported for store %s" % source
+ msg = ("External sourcing not supported for "
+ "store '%s'" % pieces.scheme)
LOG.debug(msg)
raise HTTPBadRequest(explanation=msg,
request=req,
@@ -743,18 +746,17 @@ class Controller(controller.BaseController):
self.pool.spawn_n(self._upload_and_activate, req, image_meta)
else:
if location:
- try:
- store.validate_location(location, context=req.context)
- except store.BadStoreUri as bse:
- raise HTTPBadRequest(explanation=bse.msg,
- request=req)
-
self._validate_image_for_activation(req, image_id, image_meta)
image_size_meta = image_meta.get('size')
if image_size_meta:
- image_size_store = store.get_size_from_backend(
- location,
- context=req.context)
+ try:
+ image_size_store = store.get_size_from_backend(
+ location, req.context)
+ except (store.BadStoreUri, store.UnknownScheme) as e:
+ LOG.debug(utils.exception_to_str(e))
+ raise HTTPBadRequest(explanation=e.msg,
+ request=req,
+ content_type="text/plain")
# NOTE(zhiyan): A returned size of zero usually means
# the driver encountered an error. In this case the
# size provided by the client will be used as-is.
diff --git a/glance/tests/functional/v1/test_copy_to_file.py b/glance/tests/functional/v1/test_copy_to_file.py
index ae2c32051..15bb7081c 100644
--- a/glance/tests/functional/v1/test_copy_to_file.py
+++ b/glance/tests/functional/v1/test_copy_to_file.py
@@ -250,7 +250,33 @@ class TestCopyToFile(functional.FunctionalTest):
response, content = http.request(path, 'POST', headers=headers)
self.assertEqual(response.status, 400, content)
- expected = 'External sourcing not supported for store ' + copy_from
+ expected = 'External sourcing not supported for store \'file\''
+ msg = 'expected "%s" in "%s"' % (expected, content)
+ self.assertTrue(expected in content, msg)
+
+ self.stop_servers()
+
+ @skip_if_disabled
+ def test_copy_from_swift_config(self):
+ """
+ Ensure we can't copy from swift+config
+ """
+ self.cleanup()
+
+ self.start_servers(**self.__dict__.copy())
+
+ # POST /images with public image copied from file (to file)
+ headers = {'X-Image-Meta-Name': 'copied',
+ 'X-Image-Meta-disk_format': 'raw',
+ 'X-Image-Meta-container_format': 'ovf',
+ 'X-Image-Meta-Is-Public': 'True',
+ 'X-Glance-API-Copy-From': 'swift+config://xxx'}
+ path = "http://%s:%d/v1/images" % ("127.0.0.1", self.api_port)
+ http = httplib2.Http()
+ response, content = http.request(path, 'POST', headers=headers)
+ self.assertEqual(response.status, 400, content)
+
+ expected = 'External sourcing not supported for store \'swift+config\''
msg = 'expected "%s" in "%s"' % (expected, content)
self.assertTrue(expected in content, msg)
diff --git a/glance/tests/unit/v1/test_api.py b/glance/tests/unit/v1/test_api.py
index 8d2d68951..fa7f220e6 100644
--- a/glance/tests/unit/v1/test_api.py
+++ b/glance/tests/unit/v1/test_api.py
@@ -91,7 +91,6 @@ class TestGlanceAPI(base.IsolatedUnitTest):
'metadata': {}, 'status': 'active'}],
'properties': {}}]
self.context = glance.context.RequestContext(is_admin=True)
- store.validate_location = mock.Mock()
db_api.get_engine()
self.destroy_fixtures()
self.create_fixtures()
@@ -1009,11 +1008,6 @@ class TestGlanceAPI(base.IsolatedUnitTest):
def test_add_location_with_invalid_location(self):
"""Tests creates an image from location and conflict image size"""
-
- mock_validate_location = mock.Mock()
- store.validate_location = mock_validate_location
- mock_validate_location.side_effect = store.BadStoreUri()
-
fixture_headers = {'x-image-meta-store': 'file',
'x-image-meta-disk-format': 'vhd',
'x-image-meta-location': 'http://a/b/c.tar.gz',