summaryrefslogtreecommitdiffstats
path: root/nova
diff options
context:
space:
mode:
Diffstat (limited to 'nova')
-rw-r--r--nova/image/glance.py23
-rw-r--r--nova/tests/image/test_glance.py44
2 files changed, 66 insertions, 1 deletions
diff --git a/nova/image/glance.py b/nova/image/glance.py
index 9a915d02d..539e7e537 100644
--- a/nova/image/glance.py
+++ b/nova/image/glance.py
@@ -286,10 +286,28 @@ class GlanceImageService(object):
"""Delete the given image.
:raises: ImageNotFound if the image does not exist.
+ :raises: NotAuthorized if the user is not an owner.
"""
# NOTE(vish): show is to check if image is available
- self.show(context, image_id)
+ image_meta = self.show(context, image_id)
+
+ if FLAGS.use_deprecated_auth:
+ # NOTE(parthi): only allow image deletions if the user
+ # is a member of the project owning the image, in case of
+ # setup without keystone
+ # TODO Currently this access control breaks if
+ # 1. Image is not owned by a project
+ # 2. Deleting user is not bound a project
+ properties = image_meta['properties']
+ if (context.project_id and ('project_id' in properties)
+ and (context.project_id != properties['project_id'])):
+ raise exception.NotAuthorized(_("Not the image owner"))
+
+ if (context.project_id and ('owner_id' in properties)
+ and (context.project_id != properties['owner_id'])):
+ raise exception.NotAuthorized(_("Not the image owner"))
+
try:
result = self._get_client(context).delete_image(image_id)
except glance_exception.NotFound:
@@ -329,6 +347,9 @@ class GlanceImageService(object):
properties = image_meta['properties']
+ if context.project_id and ('owner_id' in properties):
+ return str(properties['owner_id']) == str(context.project_id)
+
if context.project_id and ('project_id' in properties):
return str(properties['project_id']) == str(context.project_id)
diff --git a/nova/tests/image/test_glance.py b/nova/tests/image/test_glance.py
index c592b4888..aaf7a5d06 100644
--- a/nova/tests/image/test_glance.py
+++ b/nova/tests/image/test_glance.py
@@ -272,6 +272,24 @@ class TestGlanceImageService(test.TestCase):
self.assertDictMatch(meta, expected)
i = i + 1
+ def test_index_private_image(self):
+ fixture = self._make_fixture(name='test image')
+ fixture['is_public'] = False
+ properties = {'owner_id': 'proj1'}
+ fixture['properties'] = properties
+
+ image_id = self.service.create(self.context, fixture)['id']
+
+ proj = self.context.project_id
+ self.context.project_id = 'proj1'
+
+ image_metas = self.service.index(self.context)
+
+ self.context.project_id = proj
+
+ expected = [{'id': 'DONTCARE', 'name': 'test image'}]
+ self.assertDictListMatch(image_metas, expected)
+
def test_detail_marker(self):
fixtures = []
ids = []
@@ -380,6 +398,32 @@ class TestGlanceImageService(test.TestCase):
num_images = len(self.service.index(self.context))
self.assertEquals(1, num_images)
+ def test_delete_not_by_owner(self):
+ # this test is only relevant for deprecated auth mode
+ self.flags(use_deprecated_auth=True)
+
+ fixture = self._make_fixture(name='test image')
+ properties = {'project_id': 'proj1'}
+ fixture['properties'] = properties
+
+ num_images = len(self.service.index(self.context))
+ self.assertEquals(0, num_images)
+
+ image_id = self.service.create(self.context, fixture)['id']
+ num_images = len(self.service.index(self.context))
+ self.assertEquals(1, num_images)
+
+ proj_id = self.context.project_id
+ self.context.project_id = 'proj2'
+
+ self.assertRaises(exception.NotAuthorized, self.service.delete,
+ self.context, image_id)
+
+ self.context.project_id = proj_id
+
+ num_images = len(self.service.index(self.context))
+ self.assertEquals(1, num_images)
+
def test_show_passes_through_to_client(self):
fixture = self._make_fixture(name='image1', is_public=True)
image_id = self.service.create(self.context, fixture)['id']