Merge "use payloads for RBAC_POLICY events"
This commit is contained in:
commit
88a0a75080
@ -175,10 +175,14 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
@registry.receives(resources.RBAC_POLICY, [events.BEFORE_CREATE,
|
||||
events.BEFORE_UPDATE,
|
||||
events.BEFORE_DELETE])
|
||||
@db_api.retry_if_session_inactive()
|
||||
def validate_network_rbac_policy_change(self, resource, event, trigger,
|
||||
context, object_type, policy,
|
||||
**kwargs):
|
||||
payload=None):
|
||||
return self._validate_network_rbac_policy_change(
|
||||
resource, event, trigger, payload.context, payload)
|
||||
|
||||
@db_api.retry_if_session_inactive()
|
||||
def _validate_network_rbac_policy_change(self, resource, event, trigger,
|
||||
context, payload):
|
||||
"""Validates network RBAC policy changes.
|
||||
|
||||
On creation, verify that the creator is an admin or that it owns the
|
||||
@ -187,6 +191,10 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
On update and delete, make sure the tenant losing access does not have
|
||||
resources that depend on that access.
|
||||
"""
|
||||
object_type = payload.metadata.get('object_type')
|
||||
policy = (payload.request_body if event == events.BEFORE_CREATE
|
||||
else payload.latest_state)
|
||||
|
||||
if object_type != 'network' or policy['action'] != 'access_as_shared':
|
||||
# we only care about shared network policies
|
||||
return
|
||||
@ -206,7 +214,7 @@ class NeutronDbPluginV2(db_base_plugin_common.DbBasePluginCommon,
|
||||
if self_sharing:
|
||||
return
|
||||
if event == events.BEFORE_UPDATE:
|
||||
new_tenant = kwargs['policy_update']['target_tenant']
|
||||
new_tenant = payload.request_body['target_tenant']
|
||||
if policy['target_tenant'] != new_tenant:
|
||||
tenant_to_check = policy['target_tenant']
|
||||
|
||||
|
@ -151,8 +151,12 @@ class External_net_db_mixin(object):
|
||||
return nets[0]['id'] if nets else None
|
||||
|
||||
@registry.receives(resources.RBAC_POLICY, [events.BEFORE_CREATE])
|
||||
def _process_ext_policy_create(self, resource, event, trigger, context,
|
||||
object_type, policy, **kwargs):
|
||||
def _process_ext_policy_create(self, resource, event, trigger,
|
||||
payload=None):
|
||||
object_type = payload.metadata.get('object_type')
|
||||
policy = payload.request_body
|
||||
context = payload.context
|
||||
|
||||
if (object_type != 'network' or
|
||||
policy['action'] != 'access_as_external'):
|
||||
return
|
||||
@ -168,8 +172,12 @@ class External_net_db_mixin(object):
|
||||
allow_all=False)
|
||||
|
||||
@registry.receives(resources.RBAC_POLICY, [events.AFTER_DELETE])
|
||||
def _process_ext_policy_delete(self, resource, event, trigger, context,
|
||||
object_type, policy, **kwargs):
|
||||
def _process_ext_policy_delete(self, resource, event, trigger,
|
||||
payload=None):
|
||||
object_type = payload.metadata.get('object_type')
|
||||
policy = payload.latest_state
|
||||
context = payload.context
|
||||
|
||||
if (object_type != 'network' or
|
||||
policy['action'] != 'access_as_external'):
|
||||
return
|
||||
@ -185,14 +193,17 @@ class External_net_db_mixin(object):
|
||||
@registry.receives(resources.RBAC_POLICY, (events.BEFORE_UPDATE,
|
||||
events.BEFORE_DELETE))
|
||||
def _validate_ext_not_in_use_by_tenant(self, resource, event, trigger,
|
||||
context, object_type, policy,
|
||||
**kwargs):
|
||||
payload=None):
|
||||
object_type = payload.metadata.get('object_type')
|
||||
policy = payload.latest_state
|
||||
context = payload.context
|
||||
|
||||
if (object_type != 'network' or
|
||||
policy['action'] != 'access_as_external'):
|
||||
return
|
||||
new_project = None
|
||||
if event == events.BEFORE_UPDATE:
|
||||
new_project = kwargs['policy_update']['target_tenant']
|
||||
new_project = payload.request_body['target_tenant']
|
||||
if new_project == policy['target_tenant']:
|
||||
# nothing to validate if the tenant didn't change
|
||||
return
|
||||
|
@ -37,9 +37,10 @@ class RbacPluginMixin(object):
|
||||
def create_rbac_policy(self, context, rbac_policy):
|
||||
e = rbac_policy['rbac_policy']
|
||||
try:
|
||||
registry.notify(resources.RBAC_POLICY, events.BEFORE_CREATE, self,
|
||||
context=context, object_type=e['object_type'],
|
||||
policy=e)
|
||||
registry.publish(resources.RBAC_POLICY, events.BEFORE_CREATE, self,
|
||||
payload=events.DBEventPayload(
|
||||
context, request_body=e,
|
||||
metadata={'object_type': e['object_type']}))
|
||||
except c_exc.CallbackFailure as e:
|
||||
raise n_exc.InvalidInput(error_message=e)
|
||||
rbac_class = (
|
||||
@ -68,9 +69,11 @@ class RbacPluginMixin(object):
|
||||
entry = self._get_rbac_policy(context, id)
|
||||
object_type = entry.db_model.object_type
|
||||
try:
|
||||
registry.notify(resources.RBAC_POLICY, events.BEFORE_UPDATE, self,
|
||||
context=context, policy=entry,
|
||||
object_type=object_type, policy_update=pol)
|
||||
registry.publish(resources.RBAC_POLICY, events.BEFORE_UPDATE, self,
|
||||
payload=events.DBEventPayload(
|
||||
context, request_body=pol,
|
||||
states=(entry,), resource_id=id,
|
||||
metadata={'object_type': object_type}))
|
||||
except c_exc.CallbackFailure as ex:
|
||||
raise ext_rbac.RbacPolicyInUse(object_id=entry.object_id,
|
||||
details=ex)
|
||||
@ -83,9 +86,10 @@ class RbacPluginMixin(object):
|
||||
entry = self._get_rbac_policy(context, id)
|
||||
object_type = entry.db_model.object_type
|
||||
try:
|
||||
registry.notify(resources.RBAC_POLICY, events.BEFORE_DELETE, self,
|
||||
context=context, object_type=object_type,
|
||||
policy=entry)
|
||||
registry.publish(resources.RBAC_POLICY, events.BEFORE_DELETE, self,
|
||||
payload=events.DBEventPayload(
|
||||
context, states=(entry,), resource_id=id,
|
||||
metadata={'object_type': object_type}))
|
||||
except c_exc.CallbackFailure as ex:
|
||||
raise ext_rbac.RbacPolicyInUse(object_id=entry.object_id,
|
||||
details=ex)
|
||||
@ -93,9 +97,10 @@ class RbacPluginMixin(object):
|
||||
# object_id link to network
|
||||
entry_dict = entry.to_dict()
|
||||
entry.delete()
|
||||
registry.notify(resources.RBAC_POLICY, events.AFTER_DELETE, self,
|
||||
context=context, object_type=object_type,
|
||||
policy=entry_dict)
|
||||
registry.publish(resources.RBAC_POLICY, events.AFTER_DELETE, self,
|
||||
payload=events.DBEventPayload(
|
||||
context, states=(entry_dict,), resource_id=id,
|
||||
metadata={'object_type': object_type}))
|
||||
self.object_type_cache.pop(id, None)
|
||||
|
||||
def _get_rbac_policy(self, context, id):
|
||||
|
@ -165,12 +165,15 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
raise_policy_in_use()
|
||||
|
||||
@classmethod
|
||||
def validate_rbac_policy_delete(cls, resource, event, trigger, context,
|
||||
object_type, policy, **kwargs):
|
||||
def validate_rbac_policy_delete(cls, resource, event, trigger,
|
||||
payload=None):
|
||||
"""Callback to handle RBAC_POLICY, BEFORE_DELETE callback.
|
||||
|
||||
:raises: RbacPolicyInUse -- in case the policy is in use.
|
||||
"""
|
||||
context = payload.context
|
||||
policy = payload.latest_state
|
||||
|
||||
if policy['action'] != models.ACCESS_SHARED:
|
||||
return
|
||||
target_tenant = policy['target_tenant']
|
||||
@ -183,29 +186,36 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
target_tenant=target_tenant)
|
||||
|
||||
@classmethod
|
||||
def validate_rbac_policy_update(cls, resource, event, trigger, context,
|
||||
object_type, policy, **kwargs):
|
||||
def validate_rbac_policy_update(cls, resource, event, trigger,
|
||||
payload=None):
|
||||
"""Callback to handle RBAC_POLICY, BEFORE_UPDATE callback.
|
||||
|
||||
:raises: RbacPolicyInUse -- in case the update is forbidden.
|
||||
"""
|
||||
policy = payload.latest_state
|
||||
|
||||
prev_tenant = policy['target_tenant']
|
||||
new_tenant = kwargs['policy_update']['target_tenant']
|
||||
new_tenant = payload.request_body['target_tenant']
|
||||
if prev_tenant == new_tenant:
|
||||
return
|
||||
if new_tenant != '*':
|
||||
return cls.validate_rbac_policy_delete(
|
||||
resource, event, trigger, context, object_type, policy)
|
||||
resource, event, trigger, payload=payload)
|
||||
|
||||
@classmethod
|
||||
def validate_rbac_policy_change(cls, resource, event, trigger, context,
|
||||
object_type, policy, **kwargs):
|
||||
"""Callback to validate RBAC_POLICY changes.
|
||||
def validate_rbac_policy_change(cls, resource, event, trigger,
|
||||
payload=None):
|
||||
"""Callback to validate changes.
|
||||
|
||||
This is the dispatching function for create, update and delete
|
||||
callbacks. On creation and update, verify that the creator is an admin
|
||||
or owns the resource being shared.
|
||||
"""
|
||||
object_type = payload.metadata.get('object_type')
|
||||
context = payload.context
|
||||
policy = (payload.request_body if event == events.BEFORE_CREATE
|
||||
else payload.latest_state)
|
||||
|
||||
# TODO(hdaniel): As this code was shamelessly stolen from
|
||||
# NeutronDbPluginV2.validate_network_rbac_policy_change(), those pieces
|
||||
# should be synced and contain the same bugs, until Network RBAC logic
|
||||
@ -223,8 +233,8 @@ class RbacNeutronDbObjectMixin(rbac_db_mixin.RbacPluginMixin,
|
||||
callback_map = {events.BEFORE_UPDATE: cls.validate_rbac_policy_update,
|
||||
events.BEFORE_DELETE: cls.validate_rbac_policy_delete}
|
||||
if event in callback_map:
|
||||
return callback_map[event](resource, event, trigger, context,
|
||||
object_type, policy, **kwargs)
|
||||
return callback_map[event](resource, event, trigger,
|
||||
payload=payload)
|
||||
|
||||
def attach_rbac(self, obj_id, project_id, target_tenant='*'):
|
||||
obj_type = self.rbac_db_cls.db_model.object_type
|
||||
|
@ -208,15 +208,17 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
'tenant_id': net_owner,
|
||||
'project_id': net_owner}}
|
||||
policy = self._make_networkrbac(net, net_owner)['rbac_policy']
|
||||
kwargs = {}
|
||||
|
||||
with mock.patch.object(db_plugin_v2, '_get_network') as get_net,\
|
||||
mock.patch.object(db_plugin_v2,
|
||||
'ensure_no_tenant_ports_on_network') as ensure:
|
||||
get_net.return_value = net['network']
|
||||
payload = events.DBEventPayload(
|
||||
self.context, states=(policy,),
|
||||
metadata={'object_type': 'network'})
|
||||
self.plugin.validate_network_rbac_policy_change(
|
||||
None, events.BEFORE_DELETE, None,
|
||||
self.context, 'network', policy, **kwargs)
|
||||
payload=payload)
|
||||
self.assertEqual(0, ensure.call_count)
|
||||
|
||||
def test_update_self_share_networkrbac(self):
|
||||
@ -228,15 +230,18 @@ class NetworkRbacTestcase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
'tenant_id': net_owner,
|
||||
'project_id': net_owner}}
|
||||
policy = self._make_networkrbac(net, net_owner)['rbac_policy']
|
||||
kwargs = {'policy_update': {'target_tenant': 'new-target-tenant'}}
|
||||
|
||||
with mock.patch.object(db_plugin_v2, '_get_network') as get_net,\
|
||||
mock.patch.object(db_plugin_v2,
|
||||
'ensure_no_tenant_ports_on_network') as ensure:
|
||||
get_net.return_value = net['network']
|
||||
payload = events.DBEventPayload(
|
||||
self.context, states=(policy,),
|
||||
request_body={'target_tenant': 'new-target-tenant'},
|
||||
metadata={'object_type': 'network'})
|
||||
self.plugin.validate_network_rbac_policy_change(
|
||||
None, events.BEFORE_UPDATE, None,
|
||||
self.context, 'network', policy, **kwargs)
|
||||
payload=payload)
|
||||
self.assertEqual(0, ensure.call_count)
|
||||
|
||||
def _create_rbac_obj(self, _class):
|
||||
|
@ -129,8 +129,14 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
context, object_type, policy,
|
||||
event_list):
|
||||
for event in event_list:
|
||||
payload = events.DBEventPayload(
|
||||
context, states=(policy,),
|
||||
metadata={'object_type': object_type})
|
||||
if event == events.BEFORE_CREATE:
|
||||
payload.states = []
|
||||
payload.request_body = policy
|
||||
self._test_class.validate_rbac_policy_change(
|
||||
resource, event, trigger, context, object_type, policy)
|
||||
resource, event, trigger, payload=payload)
|
||||
|
||||
@mock.patch.object(_test_class, 'validate_rbac_policy_update')
|
||||
def test_validate_rbac_policy_change_handles_only_object_type(
|
||||
@ -175,11 +181,15 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
@mock.patch.object(_test_class, '_validate_rbac_policy_delete')
|
||||
def _test_validate_rbac_policy_delete_handles_policy(
|
||||
self, policy, mock_validate_delete):
|
||||
payload = events.DBEventPayload(
|
||||
n_context.get_admin_context(),
|
||||
states=(policy,),
|
||||
metadata={
|
||||
'object_type':
|
||||
self._test_class.rbac_db_cls.db_model.object_type})
|
||||
self._test_class.validate_rbac_policy_delete(
|
||||
resource=mock.Mock(), event=events.BEFORE_DELETE,
|
||||
trigger='dummy_trigger', context=n_context.get_admin_context(),
|
||||
object_type=self._test_class.rbac_db_cls.db_model.object_type,
|
||||
policy=policy)
|
||||
trigger='dummy_trigger', payload=payload)
|
||||
mock_validate_delete.assert_not_called()
|
||||
|
||||
def test_validate_rbac_policy_delete_handles_shared_action(self):
|
||||
@ -211,15 +221,19 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
'_get_db_obj_rbac_entries') as target_tenants_mock:
|
||||
filter_mock = target_tenants_mock.return_value.filter
|
||||
filter_mock.return_value.count.return_value = 0
|
||||
payload = events.DBEventPayload(
|
||||
context,
|
||||
states=(policy,),
|
||||
metadata={
|
||||
'object_type':
|
||||
self._test_class.rbac_db_cls.db_model.object_type})
|
||||
self.assertRaises(
|
||||
ext_rbac.RbacPolicyInUse,
|
||||
self._test_class.validate_rbac_policy_delete,
|
||||
resource=None,
|
||||
event=events.BEFORE_DELETE,
|
||||
trigger='dummy_trigger',
|
||||
context=context,
|
||||
object_type=self._test_class.rbac_db_cls.db_model.object_type,
|
||||
policy=policy)
|
||||
payload=payload)
|
||||
|
||||
def test_validate_rbac_policy_delete_not_bound_tenant_success(self):
|
||||
context = mock.Mock()
|
||||
@ -252,6 +266,12 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
'tenant_id': 'object_owner_tenant_id',
|
||||
'object_id': 'fake_obj_id'}
|
||||
context = mock.Mock()
|
||||
payload = events.DBEventPayload(
|
||||
context,
|
||||
states=(policy,),
|
||||
metadata={
|
||||
'object_type':
|
||||
self._test_class.rbac_db_cls.db_model.object_type})
|
||||
with mock.patch.object(obj_db_api, 'get_object'):
|
||||
self.assertRaises(
|
||||
ext_rbac.RbacPolicyInUse,
|
||||
@ -259,9 +279,7 @@ class RbacNeutronDbObjectTestCase(test_rbac.RBACBaseObjectIfaceTestCase,
|
||||
resource=mock.Mock(),
|
||||
event=events.BEFORE_DELETE,
|
||||
trigger='dummy_trigger',
|
||||
context=context,
|
||||
object_type=self._test_class.rbac_db_cls.db_model.object_type,
|
||||
policy=policy)
|
||||
payload=payload)
|
||||
|
||||
@mock.patch.object(_test_class, 'attach_rbac')
|
||||
@mock.patch.object(obj_db_api, 'get_object',
|
||||
|
Loading…
Reference in New Issue
Block a user