diff options
Diffstat (limited to 'nova')
| -rw-r--r-- | nova/image/glance.py | 23 | ||||
| -rw-r--r-- | nova/tests/image/test_glance.py | 44 |
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'] |
