Fix volume image metadata endpoints returning None

This commit fixes the following volume image metadata
endpoints returning None following policy enforcement
failure:

  * ``os-set_image_metadata``
  * ``os-unset_image_metadata``

The endpoints will now correctly raise a 403 Forbidden
instead.

The kwarg `fatal=False` was dropped from
`context.authorize` for these APIs because the kwarg
is only useful when adding additional information to
the response body (if the user is authorized).

This commit:

  * makes the fix for the two endpoints above
  * adds unit tests for validating the new, correct
    behavior (as a side note, policy overriding
    in tests can be more easily accomplished via
    adoption of something like [0])

Also note that since the default policy rule
for these endpoints is "admin_or_owner" Tempest
doesn't validate this behavior by default.

[0] e599b13e49/nova/tests/unit/policy_fixture.py (L30)

Change-Id: Icc286d529609165e5f14cb506342660d7bc2ae9f
Closes-Bug: #1737609
This commit is contained in:
Felipe Monteiro 2017-12-14 02:24:29 +00:00
parent 526c1a7372
commit b5f6c2864f
3 changed files with 56 additions and 2 deletions

View File

@ -85,7 +85,7 @@ class VolumeImageMetadataController(wsgi.Controller):
@wsgi.action("os-set_image_metadata") @wsgi.action("os-set_image_metadata")
def create(self, req, id, body): def create(self, req, id, body):
context = req.environ['cinder.context'] context = req.environ['cinder.context']
if context.authorize(policy.IMAGE_METADATA_POLICY, fatal=False): if context.authorize(policy.IMAGE_METADATA_POLICY):
try: try:
metadata = body['os-set_image_metadata']['metadata'] metadata = body['os-set_image_metadata']['metadata']
except (KeyError, TypeError): except (KeyError, TypeError):
@ -128,7 +128,7 @@ class VolumeImageMetadataController(wsgi.Controller):
def delete(self, req, id, body): def delete(self, req, id, body):
"""Deletes an existing image metadata.""" """Deletes an existing image metadata."""
context = req.environ['cinder.context'] context = req.environ['cinder.context']
if context.authorize(policy.IMAGE_METADATA_POLICY, fatal=False): if context.authorize(policy.IMAGE_METADATA_POLICY):
try: try:
key = body['os-unset_image_metadata']['key'] key = body['os-unset_image_metadata']['key']
except (KeyError, TypeError): except (KeyError, TypeError):

View File

@ -14,6 +14,7 @@
import uuid import uuid
from oslo_policy import policy as oslo_policy
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from oslo_utils import timeutils from oslo_utils import timeutils
from six.moves import http_client from six.moves import http_client
@ -25,6 +26,9 @@ from cinder import db
from cinder import exception from cinder import exception
from cinder import objects from cinder import objects
from cinder.objects import fields from cinder.objects import fields
from cinder.policies import base as base_policy
from cinder.policies import volume_metadata as metadata_policy
from cinder import policy
from cinder import test from cinder import test
from cinder.tests.unit.api import fakes from cinder.tests.unit.api import fakes
from cinder.tests.unit import fake_constants as fake from cinder.tests.unit import fake_constants as fake
@ -216,6 +220,26 @@ class VolumeImageMetadataTest(test.TestCase):
self.assertEqual(fake_image_metadata, self.assertEqual(fake_image_metadata,
jsonutils.loads(res.body)["metadata"]) jsonutils.loads(res.body)["metadata"])
def test_create_image_metadata_policy_not_authorized(self):
rules = {
metadata_policy.IMAGE_METADATA_POLICY: base_policy.RULE_ADMIN_API
}
policy.set_rules(oslo_policy.Rules.from_dict(rules))
self.addCleanup(policy.reset)
req = fakes.HTTPRequest.blank('/v2/%s/volumes/%s/action' % (
fake.PROJECT_ID, fake.VOLUME_ID), use_admin_context=False)
req.method = 'POST'
req.content_type = "application/json"
body = {"os-set_image_metadata": {
"metadata": {"image_name": "fake"}}
}
req.body = jsonutils.dump_as_bytes(body)
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.create, req, fake.VOLUME_ID, None)
def test_create_with_keys_case_insensitive(self): def test_create_with_keys_case_insensitive(self):
# If the keys in uppercase_and_lowercase, should return the one # If the keys in uppercase_and_lowercase, should return the one
# which server added # which server added
@ -320,6 +344,26 @@ class VolumeImageMetadataTest(test.TestCase):
fake_auth_context=self.user_ctxt)) fake_auth_context=self.user_ctxt))
self.assertEqual(http_client.OK, res.status_int) self.assertEqual(http_client.OK, res.status_int)
def test_delete_image_metadata_policy_not_authorized(self):
rules = {
metadata_policy.IMAGE_METADATA_POLICY: base_policy.RULE_ADMIN_API
}
policy.set_rules(oslo_policy.Rules.from_dict(rules))
self.addCleanup(policy.reset)
req = fakes.HTTPRequest.blank('/v2/%s/volumes/%s/action' % (
fake.PROJECT_ID, fake.VOLUME_ID), use_admin_context=False)
req.method = 'POST'
req.content_type = "application/json"
body = {"os-unset_image_metadata": {
"metadata": {"image_name": "fake"}}
}
req.body = jsonutils.dump_as_bytes(body)
self.assertRaises(exception.PolicyNotAuthorized,
self.controller.delete, req, fake.VOLUME_ID, None)
def test_delete_meta_not_found(self): def test_delete_meta_not_found(self):
data = {"os-unset_image_metadata": { data = {"os-unset_image_metadata": {
"key": "invalid_id"} "key": "invalid_id"}

View File

@ -0,0 +1,10 @@
---
fixes:
- |
Fix the following volume image metadata endpoints returning None following
policy enforcement failure:
* ``os-set_image_metadata``
* ``os-unset_image_metadata``
The endpoints will now correctly raise a 403 Forbidden instead.