Pass context objects directly to policy enforcement
The oslo.policy Enforcer() object knows what to do with instances of oslo.context RequestContext() if you pass it one. This makes it easier for people to perform policy enforcement since they don't need to map important authorization information from the context object into a dictionary (historically called `creds`). This practiced didn't guarantee any consistency in `creds` implementations. You also don't need to call context.to_policy_values() anymore. The oslo.policy library will do that for you under the hood and map context values into a set of policy attributes it understands. This commit updates the calls to enforcement to pass in the context object where applicable. Change-Id: Ife4ba098303088023e4341354a1e3bc9f378ce93
This commit is contained in:
parent
5640860c81
commit
72044aaa85
|
@ -1458,8 +1458,11 @@ def check_policy(policy_name):
|
|||
:policy_name: Name of the policy to check.
|
||||
:raises: HTTPForbidden if the policy forbids access.
|
||||
"""
|
||||
# NOTE(lbragstad): Mapping context attributes into a target dictionary is
|
||||
# effectively a noop from an authorization perspective because the values
|
||||
# we're comparing are coming from the same place.
|
||||
cdict = api.request.context.to_policy_values()
|
||||
policy.authorize(policy_name, cdict, cdict)
|
||||
policy.authorize(policy_name, cdict, api.request.context)
|
||||
|
||||
|
||||
def check_owner_policy(object_type, policy_name, owner, lessee=None):
|
||||
|
@ -1478,7 +1481,7 @@ def check_owner_policy(object_type, policy_name, owner, lessee=None):
|
|||
target_dict[object_type + '.owner'] = owner
|
||||
if lessee:
|
||||
target_dict[object_type + '.lessee'] = lessee
|
||||
policy.authorize(policy_name, target_dict, cdict)
|
||||
policy.authorize(policy_name, target_dict, api.request.context)
|
||||
|
||||
|
||||
def check_node_policy_and_retrieve(policy_name, node_ident,
|
||||
|
@ -1502,7 +1505,7 @@ def check_node_policy_and_retrieve(policy_name, node_ident,
|
|||
# don't expose non-existence of node unless requester
|
||||
# has generic access to policy
|
||||
cdict = api.request.context.to_policy_values()
|
||||
policy.authorize(policy_name, cdict, cdict)
|
||||
policy.authorize(policy_name, cdict, api.request.context)
|
||||
raise
|
||||
|
||||
check_owner_policy('node', policy_name,
|
||||
|
@ -1527,7 +1530,7 @@ def check_allocation_policy_and_retrieve(policy_name, allocation_ident):
|
|||
# don't expose non-existence unless requester
|
||||
# has generic access to policy
|
||||
cdict = api.request.context.to_policy_values()
|
||||
policy.authorize(policy_name, cdict, cdict)
|
||||
policy.authorize(policy_name, cdict, api.request.context)
|
||||
raise
|
||||
|
||||
check_owner_policy('allocation', policy_name, rpc_allocation['owner'])
|
||||
|
@ -1571,12 +1574,13 @@ def check_list_policy(object_type, owner=None):
|
|||
cdict = api.request.context.to_policy_values()
|
||||
try:
|
||||
policy.authorize('baremetal:%s:list_all' % object_type,
|
||||
cdict, cdict)
|
||||
cdict, api.request.context)
|
||||
except exception.HTTPForbidden:
|
||||
project_owner = cdict.get('project_id')
|
||||
if (not project_owner or (owner and owner != project_owner)):
|
||||
raise
|
||||
policy.authorize('baremetal:%s:list' % object_type, cdict, cdict)
|
||||
policy.authorize('baremetal:%s:list' % object_type,
|
||||
cdict, api.request.context)
|
||||
return project_owner
|
||||
return owner
|
||||
|
||||
|
@ -1599,14 +1603,14 @@ def check_port_policy_and_retrieve(policy_name, port_uuid):
|
|||
except exception.PortNotFound:
|
||||
# don't expose non-existence of port unless requester
|
||||
# has generic access to policy
|
||||
policy.authorize(policy_name, cdict, cdict)
|
||||
policy.authorize(policy_name, cdict, context)
|
||||
raise
|
||||
|
||||
rpc_node = objects.Node.get_by_id(context, rpc_port.node_id)
|
||||
target_dict = dict(cdict)
|
||||
target_dict['node.owner'] = rpc_node['owner']
|
||||
target_dict['node.lessee'] = rpc_node['lessee']
|
||||
policy.authorize(policy_name, target_dict, cdict)
|
||||
policy.authorize(policy_name, target_dict, context)
|
||||
|
||||
return rpc_port, rpc_node
|
||||
|
||||
|
@ -1619,12 +1623,14 @@ def check_port_list_policy():
|
|||
"""
|
||||
cdict = api.request.context.to_policy_values()
|
||||
try:
|
||||
policy.authorize('baremetal:port:list_all', cdict, cdict)
|
||||
policy.authorize('baremetal:port:list_all',
|
||||
cdict, api.request.context)
|
||||
except exception.HTTPForbidden:
|
||||
owner = cdict.get('project_id')
|
||||
if not owner:
|
||||
raise
|
||||
policy.authorize('baremetal:port:list', cdict, cdict)
|
||||
policy.authorize('baremetal:port:list',
|
||||
cdict, api.request.context)
|
||||
return owner
|
||||
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ from oslo_utils import uuidutils
|
|||
from ironic import api
|
||||
from ironic.api.controllers.v1 import node as api_node
|
||||
from ironic.api.controllers.v1 import utils
|
||||
from ironic.common import context as ironic_context
|
||||
from ironic.common import exception
|
||||
from ironic.common import policy
|
||||
from ironic.common import states
|
||||
|
@ -992,9 +993,12 @@ class TestVendorPassthru(base.TestCase):
|
|||
@mock.patch.object(api, 'request', spec_set=["context"])
|
||||
@mock.patch.object(policy, 'authorize', spec=True)
|
||||
def test_check_policy(self, mock_authorize, mock_pr):
|
||||
fake_context = ironic_context.RequestContext()
|
||||
mock_pr.context = fake_context
|
||||
expected_target = dict(fake_context.to_policy_values())
|
||||
utils.check_policy('fake-policy')
|
||||
cdict = api.request.context.to_policy_values()
|
||||
mock_authorize.assert_called_once_with('fake-policy', cdict, cdict)
|
||||
mock_authorize.assert_called_once_with('fake-policy', expected_target,
|
||||
fake_context)
|
||||
|
||||
@mock.patch.object(api, 'request', spec_set=["context"])
|
||||
@mock.patch.object(policy, 'authorize', spec=True)
|
||||
|
@ -1048,15 +1052,18 @@ class TestCheckOwnerPolicy(base.TestCase):
|
|||
def test_check_owner_policy(
|
||||
self, mock_authorize, mock_pr
|
||||
):
|
||||
fake_context = ironic_context.RequestContext()
|
||||
mock_pr.version.minor = 50
|
||||
mock_pr.context.to_policy_values.return_value = {}
|
||||
mock_pr.context = fake_context
|
||||
expected_target = dict(fake_context.to_policy_values())
|
||||
expected_target['node.owner'] = '12345'
|
||||
expected_target['node.lessee'] = '54321'
|
||||
|
||||
utils.check_owner_policy(
|
||||
'node', 'fake_policy', self.node['owner'], self.node['lessee']
|
||||
)
|
||||
mock_authorize.assert_called_once_with(
|
||||
'fake_policy',
|
||||
{'node.owner': '12345', 'node.lessee': '54321'}, {})
|
||||
'fake_policy', expected_target, fake_context)
|
||||
|
||||
@mock.patch.object(api, 'request', spec_set=["context", "version"])
|
||||
@mock.patch.object(policy, 'authorize', spec=True)
|
||||
|
@ -1091,8 +1098,13 @@ class TestCheckNodePolicyAndRetrieve(base.TestCase):
|
|||
def test_check_node_policy_and_retrieve(
|
||||
self, mock_grnws, mock_grn, mock_authorize, mock_pr
|
||||
):
|
||||
fake_context = ironic_context.RequestContext()
|
||||
expected_target = dict(fake_context.to_policy_values())
|
||||
expected_target['node.owner'] = '12345'
|
||||
expected_target['node.lessee'] = '54321'
|
||||
mock_pr.context = fake_context
|
||||
|
||||
mock_pr.version.minor = 50
|
||||
mock_pr.context.to_policy_values.return_value = {}
|
||||
mock_grn.return_value = self.node
|
||||
|
||||
rpc_node = utils.check_node_policy_and_retrieve(
|
||||
|
@ -1101,8 +1113,7 @@ class TestCheckNodePolicyAndRetrieve(base.TestCase):
|
|||
mock_grn.assert_called_once_with(self.valid_node_uuid)
|
||||
mock_grnws.assert_not_called()
|
||||
mock_authorize.assert_called_once_with(
|
||||
'fake_policy',
|
||||
{'node.owner': '12345', 'node.lessee': '54321'}, {})
|
||||
'fake_policy', expected_target, fake_context)
|
||||
self.assertEqual(self.node, rpc_node)
|
||||
|
||||
@mock.patch.object(api, 'request', spec_set=["context", "version"])
|
||||
|
@ -1112,8 +1123,12 @@ class TestCheckNodePolicyAndRetrieve(base.TestCase):
|
|||
def test_check_node_policy_and_retrieve_with_suffix(
|
||||
self, mock_grnws, mock_grn, mock_authorize, mock_pr
|
||||
):
|
||||
fake_context = ironic_context.RequestContext()
|
||||
expected_target = fake_context.to_policy_values()
|
||||
expected_target['node.owner'] = '12345'
|
||||
expected_target['node.lessee'] = '54321'
|
||||
mock_pr.context = fake_context
|
||||
mock_pr.version.minor = 50
|
||||
mock_pr.context.to_policy_values.return_value = {}
|
||||
mock_grnws.return_value = self.node
|
||||
|
||||
rpc_node = utils.check_node_policy_and_retrieve(
|
||||
|
@ -1122,8 +1137,7 @@ class TestCheckNodePolicyAndRetrieve(base.TestCase):
|
|||
mock_grn.assert_not_called()
|
||||
mock_grnws.assert_called_once_with(self.valid_node_uuid)
|
||||
mock_authorize.assert_called_once_with(
|
||||
'fake_policy',
|
||||
{'node.owner': '12345', 'node.lessee': '54321'}, {})
|
||||
'fake_policy', expected_target, fake_context)
|
||||
self.assertEqual(self.node, rpc_node)
|
||||
|
||||
@mock.patch.object(api, 'request', spec_set=["context"])
|
||||
|
@ -1193,8 +1207,11 @@ class TestCheckAllocationPolicyAndRetrieve(base.TestCase):
|
|||
def test_check_node_policy_and_retrieve(
|
||||
self, mock_graws, mock_authorize, mock_pr
|
||||
):
|
||||
fake_context = ironic_context.RequestContext()
|
||||
expected_target = dict(fake_context.to_policy_values())
|
||||
expected_target['allocation.owner'] = '12345'
|
||||
mock_pr.version.minor = 60
|
||||
mock_pr.context.to_policy_values.return_value = {}
|
||||
mock_pr.context = fake_context
|
||||
mock_graws.return_value = self.allocation
|
||||
|
||||
rpc_allocation = utils.check_allocation_policy_and_retrieve(
|
||||
|
@ -1202,7 +1219,7 @@ class TestCheckAllocationPolicyAndRetrieve(base.TestCase):
|
|||
)
|
||||
mock_graws.assert_called_once_with(self.valid_allocation_uuid)
|
||||
mock_authorize.assert_called_once_with(
|
||||
'fake_policy', {'allocation.owner': '12345'}, {})
|
||||
'fake_policy', expected_target, fake_context)
|
||||
self.assertEqual(self.allocation, rpc_allocation)
|
||||
|
||||
@mock.patch.object(api, 'request', spec_set=["context"])
|
||||
|
@ -1444,8 +1461,12 @@ class TestCheckPortPolicyAndRetrieve(base.TestCase):
|
|||
def test_check_port_policy_and_retrieve(
|
||||
self, mock_ngbi, mock_pgbu, mock_authorize, mock_pr
|
||||
):
|
||||
fake_context = ironic_context.RequestContext()
|
||||
expected_target = fake_context.to_policy_values()
|
||||
expected_target['node.owner'] = '12345'
|
||||
expected_target['node.lessee'] = '54321'
|
||||
mock_pr.context = fake_context
|
||||
mock_pr.version.minor = 50
|
||||
mock_pr.context.to_policy_values.return_value = {}
|
||||
mock_pgbu.return_value = self.port
|
||||
mock_ngbi.return_value = self.node
|
||||
|
||||
|
@ -1456,9 +1477,7 @@ class TestCheckPortPolicyAndRetrieve(base.TestCase):
|
|||
self.valid_port_uuid)
|
||||
mock_ngbi.assert_called_once_with(mock_pr.context, 42)
|
||||
mock_authorize.assert_called_once_with(
|
||||
'fake_policy',
|
||||
{'node.owner': '12345', 'node.lessee': '54321'},
|
||||
{})
|
||||
'fake_policy', expected_target, fake_context)
|
||||
self.assertEqual(self.port, rpc_port)
|
||||
self.assertEqual(self.node, rpc_node)
|
||||
|
||||
|
|
Loading…
Reference in New Issue