diff options
author | Stuart McLaren <stuart.mclaren@hp.com> | 2014-07-16 13:33:32 +0000 |
---|---|---|
committer | Nikhil Komawar <nikhilskomawar@gmail.com> | 2014-10-10 10:06:20 -0400 |
commit | c0d90a580f87dbbf71e3a5d5c1b5cf8d7c7245b2 (patch) | |
tree | 183ab7c49f9dcb22feb481aa4a5864183e14bee9 | |
parent | 8b2280466a0d84d846ccb6c7fb13e98df199bb30 (diff) | |
download | glance-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.py | 26 | ||||
-rw-r--r-- | glance/tests/functional/v1/test_copy_to_file.py | 28 | ||||
-rw-r--r-- | glance/tests/unit/v1/test_api.py | 6 |
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', |