Fix server tags policy to be admin_or_owner

server tags API policy is default to admin_or_owner[1] but API
is allowed for everyone.

We can see the test trying with other project context can access the API
- https://review.opendev.org/#/c/717425

This is because API does not pass the server project_id in policy target[2]
and if no target is passed then, policy.py add the default targets which is
nothing but context.project_id (allow for everyone who try to access).

This commit fix this policy by passing the server's project_id in policy
target.

Closes-bug: #1871287
Partial implement blueprint policy-defaults-refresh

[1] cd16ae25c8/nova/policies/server_tags.py (L27)
[2] cd16ae25c8/nova/api/openstack/compute/server_tags.py (L88)

Change-Id: I0718fd16d91b5d208a62f6ced1cb45c1738ab96c
This commit is contained in:
Ghanshyam Mann 2020-04-06 23:52:40 -05:00
parent f1c519eb19
commit 9f5948bef8
2 changed files with 17 additions and 14 deletions

View File

@ -65,15 +65,14 @@ class ServerTagsController(wsgi.Controller):
@wsgi.expected_errors(404)
def show(self, req, server_id, id):
context = req.environ["nova.context"]
context.can(st_policies.POLICY_ROOT % 'show')
im = _get_instance_mapping(context, server_id)
context.can(st_policies.POLICY_ROOT % 'show',
target={'project_id': im.project_id})
try:
im = objects.InstanceMapping.get_by_instance_uuid(context,
server_id)
with nova_context.target_cell(context, im.cell_mapping) as cctxt:
exists = objects.Tag.exists(cctxt, server_id, id)
except (exception.InstanceNotFound,
exception.InstanceMappingNotFound) as e:
except (exception.InstanceNotFound) as e:
raise webob.exc.HTTPNotFound(explanation=e.format_message())
if not exists:
@ -85,15 +84,14 @@ class ServerTagsController(wsgi.Controller):
@wsgi.expected_errors(404)
def index(self, req, server_id):
context = req.environ["nova.context"]
context.can(st_policies.POLICY_ROOT % 'index')
im = _get_instance_mapping(context, server_id)
context.can(st_policies.POLICY_ROOT % 'index',
target={'project_id': im.project_id})
try:
im = objects.InstanceMapping.get_by_instance_uuid(context,
server_id)
with nova_context.target_cell(context, im.cell_mapping) as cctxt:
tags = objects.TagList.get_by_resource_id(cctxt, server_id)
except (exception.InstanceNotFound,
exception.InstanceMappingNotFound) as e:
except (exception.InstanceNotFound) as e:
raise webob.exc.HTTPNotFound(explanation=e.format_message())
return {'tags': _get_tags_names(tags)}
@ -103,8 +101,9 @@ class ServerTagsController(wsgi.Controller):
@validation.schema(schema.update)
def update(self, req, server_id, id, body):
context = req.environ["nova.context"]
context.can(st_policies.POLICY_ROOT % 'update')
im = _get_instance_mapping(context, server_id)
context.can(st_policies.POLICY_ROOT % 'update',
target={'project_id': im.project_id})
with nova_context.target_cell(context, im.cell_mapping) as cctxt:
instance = self._check_instance_in_valid_state(
@ -155,8 +154,9 @@ class ServerTagsController(wsgi.Controller):
@validation.schema(schema.update_all)
def update_all(self, req, server_id, body):
context = req.environ["nova.context"]
context.can(st_policies.POLICY_ROOT % 'update_all')
im = _get_instance_mapping(context, server_id)
context.can(st_policies.POLICY_ROOT % 'update_all',
target={'project_id': im.project_id})
with nova_context.target_cell(context, im.cell_mapping) as cctxt:
instance = self._check_instance_in_valid_state(
@ -179,8 +179,9 @@ class ServerTagsController(wsgi.Controller):
@wsgi.expected_errors((404, 409))
def delete(self, req, server_id, id):
context = req.environ["nova.context"]
context.can(st_policies.POLICY_ROOT % 'delete')
im = _get_instance_mapping(context, server_id)
context.can(st_policies.POLICY_ROOT % 'delete',
target={'project_id': im.project_id})
with nova_context.target_cell(context, im.cell_mapping) as cctxt:
instance = self._check_instance_in_valid_state(
@ -203,8 +204,9 @@ class ServerTagsController(wsgi.Controller):
@wsgi.expected_errors((404, 409))
def delete_all(self, req, server_id):
context = req.environ["nova.context"]
context.can(st_policies.POLICY_ROOT % 'delete_all')
im = _get_instance_mapping(context, server_id)
context.can(st_policies.POLICY_ROOT % 'delete_all',
target={'project_id': im.project_id})
with nova_context.target_cell(context, im.cell_mapping) as cctxt:
instance = self._check_instance_in_valid_state(

View File

@ -51,6 +51,7 @@ class ServerTagsTest(test.TestCase):
super(ServerTagsTest, self).setUp()
self.controller = server_tags.ServerTagsController()
inst_map = objects.InstanceMapping(
project_id=fakes.FAKE_PROJECT_ID,
cell_mapping=objects.CellMappingList.get_all(
context.get_admin_context())[1])
self.stub_out('nova.objects.InstanceMapping.get_by_instance_uuid',