def before(self, state): if state.request.method not in self.ACTION_MAP: pecan.abort(405) neutron_context = state.request.context.get('neutron_context') resource = state.request.context.get('resource') is_update = (state.request.method == 'PUT') items = state.request.resources policy.init() action = '%s_%s' % (self.ACTION_MAP[state.request.method], resource) for item in items: if is_update: obj = copy.copy(state.request.original_object) obj.update(item) obj[const.ATTRIBUTES_TO_UPDATE] = item.keys() item = obj try: policy.enforce( neutron_context, action, item, pluralized=attribute_population._plural(resource)) except oslo_policy.PolicyNotAuthorized: with excutils.save_and_reraise_exception() as ctxt: # If a tenant is modifying it's own object, it's safe to # return a 403. Otherwise, pretend that it doesn't exist # to avoid giving away information. if (is_update and neutron_context.tenant_id != obj['tenant_id']): ctxt.reraise = False msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg)
def _handle_action(request, id, **kwargs): arg_list = [request.context, id] # Ensure policy engine is initialized policy.init() # Fetch the resource and verify if the user can access it try: parent_id = kwargs.get(self._parent_id_name) resource = self._item(request, id, do_authz=True, field_list=None, parent_id=parent_id) except oslo_policy.PolicyNotAuthorized: msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) body = copy.deepcopy(kwargs.pop('body', None)) # Explicit comparison with None to distinguish from {} if body is not None: arg_list.append(body) # It is ok to raise a 403 because accessibility to the # object was checked earlier in this method policy.enforce(request.context, name, resource, pluralized=self._collection) ret_value = getattr(self._plugin, name)(*arg_list, **kwargs) # It is simply impossible to predict whether one of this # actions alters resource usage. For instance a tenant port # is created when a router interface is added. Therefore it is # important to mark as dirty resources whose counters have # been altered by this operation resource_registry.set_resources_dirty(request.context) return ret_value
def setUp(self): super(BaseTestCase, self).setUp() self.useFixture(lockutils.ExternalLockFixture()) self.useFixture(fixture.APIDefinitionFixture()) cfg.CONF.set_override('state_path', self.get_default_temp_dir().path) self.addCleanup(CONF.reset) self.useFixture(ProcessMonitorFixture()) self.useFixture(fixtures.MonkeyPatch( 'neutron_lib.exceptions.NeutronException.use_fatal_exceptions', fake_use_fatal_exceptions)) self.useFixture(fixtures.MonkeyPatch( 'oslo_config.cfg.find_config_files', lambda project=None, prog=None, extension=None: [])) self.setup_rpc_mocks() self.setup_config() self._callback_manager = registry_manager.CallbacksManager() self.useFixture(fixture.CallbackRegistryFixture( callback_manager=self._callback_manager)) # Give a private copy of the directory to each test. self.useFixture(fixture.PluginDirectoryFixture()) policy.init() self.addCleanup(policy.reset) self.addCleanup(resource_registry.unregister_all_resources) self.addCleanup(db_api.sqla_remove_all) self.addCleanup(rpc_consumer_reg.clear) self.addCleanup(rpc_producer_reg.clear)
def _update(self, request, id, body, **kwargs): body = Controller.prepare_request_body( request.context, copy.deepcopy(body), False, self._resource, self._attr_info, allow_bulk=self._allow_bulk ) action = self._plugin_handlers[self.UPDATE] # Load object to check authz # but pass only attributes in the original body and required # by the policy engine to the policy 'brain' field_list = [ name for (name, value) in six.iteritems(self._attr_info) if (value.get("required_by_policy") or value.get("primary_key") or "default" not in value) ] # Ensure policy engine is initialized policy.init() parent_id = kwargs.get(self._parent_id_name) orig_obj = self._item(request, id, field_list=field_list, parent_id=parent_id) orig_object_copy = copy.copy(orig_obj) orig_obj.update(body[self._resource]) # Make a list of attributes to be updated to inform the policy engine # which attributes are set explicitly so that it can distinguish them # from the ones that are set to their default values. orig_obj[n_const.ATTRIBUTES_TO_UPDATE] = body[self._resource].keys() try: policy.enforce(request.context, action, orig_obj, pluralized=self._collection) except oslo_policy.PolicyNotAuthorized: with excutils.save_and_reraise_exception() as ctxt: # If a tenant is modifying it's own object, it's safe to return # a 403. Otherwise, pretend that it doesn't exist to avoid # giving away information. if request.context.tenant_id != orig_obj["tenant_id"]: ctxt.reraise = False msg = _("The resource could not be found.") raise webob.exc.HTTPNotFound(msg) obj_updater = getattr(self._plugin, action) kwargs = {self._resource: body} if parent_id: kwargs[self._parent_id_name] = parent_id obj = obj_updater(request.context, id, **kwargs) # Usually an update operation does not alter resource usage, but as # there might be side effects it might be worth checking for changes # in resource usage here as well (e.g: a tenant port is created when a # router interface is added) resource_registry.set_resources_dirty(request.context) result = {self._resource: self._view(request.context, obj)} notifier_method = self._resource + ".update.end" self._notifier.info(request.context, notifier_method, result) registry.notify( self._resource, events.BEFORE_RESPONSE, self, context=request.context, data=result, method_name=notifier_method, action=action, original=orig_object_copy, ) return result
def delete(self, request, id, **kwargs): """Deletes the specified entity.""" self._notifier.info(request.context, self._resource + '.delete.start', {self._resource + '_id': id}) action = self._plugin_handlers[self.DELETE] # Check authz policy.init() parent_id = kwargs.get(self._parent_id_name) obj = self._item(request, id, parent_id=parent_id) try: policy.enforce(request.context, action, obj) except common_policy.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) obj_deleter = getattr(self._plugin, action) obj_deleter(request.context, id, **kwargs) notifier_method = self._resource + '.delete.end' self._notifier.info(request.context, notifier_method, {self._resource + '_id': id}) result = {self._resource: self._view(request.context, obj)} self._send_nova_notification(action, {}, result) self._send_dhcp_notification(request.context, result, notifier_method)
def delete(self, request, id, **kwargs): """Deletes the specified entity.""" self._notifier.info(request.context, self._resource + '.delete.start', {self._resource + '_id': id}) #通知 action = self._plugin_handlers[self.DELETE] #获取具体资源操作行为 eg delete_port # Check authz policy.init() parent_id = kwargs.get(self._parent_id_name) obj = self._item(request, id, parent_id=parent_id) try: policy.enforce(request.context, action, obj) #检查操作权限 except exceptions.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) obj_deleter = getattr(self._plugin, action) #获取具体操作方法 eg:M2lplugin类中delete_port obj_deleter(request.context, id, **kwargs) #根据参数,执行具体操作方法 notifier_method = self._resource + '.delete.end' self._notifier.info(request.context, notifier_method, {self._resource + '_id': id}) #消息格式?? result = {self._resource: self._view(request.context, obj)} self._send_nova_notification(action, {}, result) #通知nova消息,消息内容什么样的? self._send_dhcp_notification(request.context, #通知dhcp消息,消息内容什么样的? result, notifier_method)
def update(self, request, id, body=None, **kwargs): """Updates the specified entity's attributes.""" parent_id = kwargs.get(self._parent_id_name) try: payload = body.copy() except AttributeError: msg = _("Invalid format: %s") % request.body raise exceptions.BadRequest(resource='body', msg=msg) payload['id'] = id self._notifier.info(request.context, self._resource + '.update.start', payload) body = Controller.prepare_request_body(request.context, body, False, self._resource, self._attr_info, allow_bulk=self._allow_bulk) action = self._plugin_handlers[self.UPDATE] # Load object to check authz # but pass only attributes in the original body and required # by the policy engine to the policy 'brain' field_list = [name for (name, value) in self._attr_info.iteritems() if (value.get('required_by_policy') or value.get('primary_key') or 'default' not in value)] # Ensure policy engine is initialized policy.init() orig_obj = self._item(request, id, field_list=field_list, parent_id=parent_id) orig_object_copy = copy.copy(orig_obj) orig_obj.update(body[self._resource]) # Make a list of attributes to be updated to inform the policy engine # which attributes are set explicitly so that it can distinguish them # from the ones that are set to their default values. orig_obj[const.ATTRIBUTES_TO_UPDATE] = body[self._resource].keys() try: policy.enforce(request.context, action, orig_obj) except common_policy.PolicyNotAuthorized: with excutils.save_and_reraise_exception() as ctxt: # If a tenant is modifying it's own object, it's safe to return # a 403. Otherwise, pretend that it doesn't exist to avoid # giving away information. if request.context.tenant_id != orig_obj['tenant_id']: ctxt.reraise = False msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) obj_updater = getattr(self._plugin, action) kwargs = {self._resource: body} if parent_id: kwargs[self._parent_id_name] = parent_id obj = obj_updater(request.context, id, **kwargs) result = {self._resource: self._view(request.context, obj)} notifier_method = self._resource + '.update.end' self._notifier.info(request.context, notifier_method, result) self._send_dhcp_notification(request.context, result, notifier_method) self._send_nova_notification(action, orig_object_copy, result) return result
def setUp(self): super(BaseTestCase, self).setUp() self.useFixture(lockutils.ExternalLockFixture()) cfg.CONF.set_override("state_path", self.get_default_temp_dir().path) self.addCleanup(CONF.reset) self.useFixture(ProcessMonitorFixture()) self.useFixture( fixtures.MonkeyPatch( "neutron_lib.exceptions.NeutronException.use_fatal_exceptions", fake_use_fatal_exceptions ) ) self.useFixture( fixtures.MonkeyPatch( "oslo_config.cfg.find_config_files", lambda project=None, prog=None, extension=None: [] ) ) self.setup_rpc_mocks() self.setup_config() self.setup_test_registry_instance() self.setup_test_directory_instance() policy.init() self.addCleanup(policy.reset) self.addCleanup(resource_registry.unregister_all_resources) self.addCleanup(rpc_consumer_reg.clear)
def _delete(self, request, id, **kwargs): action = self._plugin_handlers[self.DELETE] # Check authz policy.init() parent_id = kwargs.get(self._parent_id_name) obj = self._item(request, id, parent_id=parent_id) try: policy.enforce(request.context, action, obj, pluralized=self._collection) except oslo_policy.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist msg = _("The resource could not be found.") raise webob.exc.HTTPNotFound(msg) obj_deleter = getattr(self._plugin, action) obj_deleter(request.context, id, **kwargs) # A delete operation usually alters resource usage, so mark affected # usage trackers as dirty resource_registry.set_resources_dirty(request.context) notifier_method = self._resource + ".delete.end" result = {self._resource: self._view(request.context, obj)} notifier_payload = {self._resource + "_id": id} notifier_payload.update(result) self._notifier.info(request.context, notifier_method, notifier_payload) registry.notify( self._resource, events.BEFORE_RESPONSE, self, context=request.context, data=result, method_name=notifier_method, action=action, original={}, )
def _test_enforce_tenant_id_raises(self, bad_rule): self.rules["admin_or_owner"] = common_policy.parse_rule(bad_rule) # Trigger a policy with rule admin_or_owner action = "create_network" target = {"tenant_id": "fake"} policy.init() self.assertRaises(exceptions.PolicyCheckError, policy.enforce, self.context, action, target)
def _delete(self, request, id, **kwargs): action = self._plugin_handlers[self.DELETE] # Check authz policy.init() parent_id = kwargs.get(self._parent_id_name) obj = self._item(request, id, parent_id=parent_id) try: policy.enforce(request.context, action, obj, pluralized=self._collection) except oslo_policy.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) obj_deleter = getattr(self._plugin, action) obj_deleter(request.context, id, **kwargs) # A delete operation usually alters resource usage, so mark affected # usage trackers as dirty resource_registry.set_resources_dirty(request.context) notifier_method = self._resource + '.delete.end' self._notifier.info(request.context, notifier_method, {self._resource + '_id': id}) result = {self._resource: self._view(request.context, obj)} self._send_nova_notification(action, {}, result) self._send_dhcp_notification(request.context, result, notifier_method)
def setUp(self): super(BaseTestCase, self).setUp() # suppress all but errors here capture_logs = bool_from_env('OS_LOG_CAPTURE') self.useFixture( fixtures.FakeLogger( name='neutron.api.extensions', format=LOG_FORMAT, level=std_logging.ERROR, nuke_handlers=capture_logs, )) self.useFixture(lockutils.ExternalLockFixture()) cfg.CONF.set_override('state_path', self.get_default_temp_dir().path) self.addCleanup(CONF.reset) self.useFixture(ProcessMonitorFixture()) self.useFixture(fixtures.MonkeyPatch( 'neutron.common.exceptions.NeutronException.use_fatal_exceptions', fake_use_fatal_exceptions)) self.setup_rpc_mocks() self.setup_config() policy.init() self.addCleanup(policy.reset)
def setUp(self): super(NeutronPolicyTestCase, self).setUp() policy.reset() policy.init() self.addCleanup(policy.reset) self.admin_only_legacy = "role:admin" self.admin_or_owner_legacy = "role:admin or tenant_id:%(tenant_id)s" # Add a Fake 'something' resource to RESOURCE_ATTRIBUTE_MAP attributes.RESOURCE_ATTRIBUTE_MAP.update(FAKE_RESOURCE) self.rules = dict((k, common_policy.parse_rule(v)) for k, v in { "context_is_admin": "role:admin", "admin_or_network_owner": "rule:context_is_admin or " "tenant_id:%(network:tenant_id)s", "admin_or_owner": ("rule:context_is_admin or " "tenant_id:%(tenant_id)s"), "admin_only": "rule:context_is_admin", "regular_user": "******", "shared": "field:networks:shared=True", "external": "field:networks:router:external=True", "default": '@', "create_network": "rule:admin_or_owner", "create_network:shared": "rule:admin_only", "update_network": '@', "update_network:shared": "rule:admin_only", "get_network": "rule:admin_or_owner or " "rule:shared or " "rule:external", "create_port:mac": "rule:admin_or_network_owner", "create_something": "rule:admin_or_owner", "create_something:attr": "rule:admin_or_owner", "create_something:attr:sub_attr_1": "rule:admin_or_owner", "create_something:attr:sub_attr_2": "rule:admin_only", "get_firewall_policy": "rule:admin_or_owner or " "rule:shared", "get_firewall_rule": "rule:admin_or_owner or " "rule:shared" }.items()) def fakepolicyinit(): common_policy.set_rules(common_policy.Rules(self.rules)) def remove_fake_resource(): del attributes.RESOURCE_ATTRIBUTE_MAP["%ss" % FAKE_RESOURCE_NAME] self.patcher = mock.patch.object(neutron.policy, 'init', new=fakepolicyinit) self.patcher.start() self.addCleanup(remove_fake_resource) self.context = context.Context('fake', 'fake', roles=['user']) plugin_klass = importutils.import_class( "neutron.db.db_base_plugin_v2.NeutronDbPluginV2") self.manager_patcher = mock.patch('neutron.manager.NeutronManager') fake_manager = self.manager_patcher.start() fake_manager_instance = fake_manager.return_value fake_manager_instance.plugin = plugin_klass()
def update(self, request, id, body=None, **kwargs): """Updates the specified entity's attributes.""" parent_id = kwargs.get(self._parent_id_name) try: payload = body.copy() except AttributeError: msg = _("Invalid format: %s") % request.body raise exceptions.BadRequest(resource='body', msg=msg) payload['id'] = id notifier_api.notify(request.context, self._publisher_id, self._resource + '.update.start', notifier_api.CONF.default_notification_level, payload) body = Controller.prepare_request_body(request.context, body, False, self._resource, self._attr_info, allow_bulk=self._allow_bulk) action = self._plugin_handlers[self.UPDATE] # Load object to check authz # but pass only attributes in the original body and required # by the policy engine to the policy 'brain' field_list = [name for (name, value) in self._attr_info.iteritems() if (value.get('required_by_policy') or value.get('primary_key') or 'default' not in value)] # Ensure policy engine is initialized policy.init() orig_obj = self._item(request, id, field_list=field_list, parent_id=parent_id) orig_object_copy = copy.copy(orig_obj) orig_obj.update(body[self._resource]) try: policy.enforce(request.context, action, orig_obj) except exceptions.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) obj_updater = getattr(self._plugin, action) kwargs = {self._resource: body} if parent_id: kwargs[self._parent_id_name] = parent_id obj = obj_updater(request.context, id, **kwargs) result = {self._resource: self._view(request.context, obj)} notifier_method = self._resource + '.update.end' notifier_api.notify(request.context, self._publisher_id, notifier_method, notifier_api.CONF.default_notification_level, result) self._send_dhcp_notification(request.context, result, notifier_method) self._nova_notifier.send_network_change( action, orig_object_copy, result) return result
def setUp(self): super(TestPaginationAndSorting, self).setUp() policy.init() self.addCleanup(policy.reset) self.plugin = directory.get_plugin() self.ctx = context.get_admin_context() self._create_networks(self.RESOURCE_COUNT) self.networks = self._get_collection()['networks']
def setUp(self): super(TestExcludeAttributePolicy, self).setUp() policy.init() self.addCleanup(policy.reset) plugin = directory.get_plugin() ctx = context.get_admin_context() self.network_id = pecan_utils.create_network(ctx, plugin)['id'] mock.patch('neutron.pecan_wsgi.controllers.resource.' 'CollectionsController.get').start()
def delete(self, request, id, **kwargs): """Deletes the specified entity.""" self._notifier.info(request.context, self._resource + '.delete.start', {self._resource + '_id': id}) action = self._plugin_handlers[self.DELETE] # Check authz policy.init() parent_id = kwargs.get(self._parent_id_name) obj = self._item(request, id, parent_id=parent_id) try: policy.enforce(request.context, action, obj) except exceptions.PolicyNotAuthorized: with excutils.save_and_reraise_exception() as ctxt: # if the tenant id is same, reraise # otherwise pretend if request.context.tenant_id != obj['tenant_id']: ctxt.reraise = False # To avoid giving away information, pretend that it # doesn't exist msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) filters = api_common.get_filters( request, self._attr_info, keeps_pre='_x_') if not kwargs: kwargs = {} if filters: kwargs['filters'] = filters obj_deleter = getattr(self._plugin, action) if kwargs: obj_deleter(request.context, id, **kwargs) else: obj_deleter(request.context, id) result = {self._resource: self._view(request.context, obj)} notifier_method = self._resource + '.delete.end' delete_notification_dict = result.copy() delete_notification_dict[self._resource + '_id'] = id data = {} for attr, attr_vals in self._attr_info.iteritems(): delete_notification = attr_vals.get('delete_notification') if delete_notification: data[attr] = obj[attr] if data: delete_notification_dict['_x_data'] = data self._notifier.info(request.context, notifier_method, delete_notification_dict) self._send_nova_notification(action, {}, result) self._send_dhcp_notification(request.context, result, notifier_method)
def before(self, state): # This hook should be run only for PUT,POST and DELETE methods and for # requests targeting a neutron resource resources = state.request.context.get('resources', []) if state.request.method not in ('POST', 'PUT', 'DELETE'): return # As this routine will likely alter the resources, do a shallow copy resources_copy = resources[:] neutron_context = state.request.context.get('neutron_context') resource = state.request.context.get('resource') # If there is no resource for this request, don't bother running authZ # policies if not resource: return collection = state.request.context.get('collection') needs_prefetch = (state.request.method == 'PUT' or state.request.method == 'DELETE') policy.init() action = '%s_%s' % (self.ACTION_MAP[state.request.method], resource) # NOTE(salv-orlando): As bulk updates are not supported, in case of PUT # requests there will be only a single item to process, and its # identifier would have been already retrieved by the lookup process; # in the case of DELETE requests there won't be any item to process in # the request body if needs_prefetch: try: item = resources_copy.pop() except IndexError: # Ops... this was a delete after all! item = {} resource_id = state.request.context.get('resource_id') obj = copy.copy(self._fetch_resource(neutron_context, resource, resource_id)) obj.update(item) obj[const.ATTRIBUTES_TO_UPDATE] = item.keys() # Put back the item in the list so that policies could be enforced resources_copy.append(obj) for item in resources_copy: try: policy.enforce( neutron_context, action, item, pluralized=collection) except oslo_policy.PolicyNotAuthorized: with excutils.save_and_reraise_exception() as ctxt: # If a tenant is modifying it's own object, it's safe to # return a 403. Otherwise, pretend that it doesn't exist # to avoid giving away information. if (needs_prefetch and neutron_context.tenant_id != item['tenant_id']): ctxt.reraise = False msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg)
def setUp(self): super(DefaultPolicyTestCase, self).setUp() policy.reset() policy.init() self.addCleanup(policy.reset) self.rules = {"default": "", "example:exist": "!"} self._set_rules("default") self.context = context.Context("fake", "fake")
def before(self, state): # This hook should be run only for PUT,POST and DELETE methods and for # requests targeting a neutron resource resources = state.request.context.get("resources", []) if state.request.method not in ("POST", "PUT", "DELETE"): return # As this routine will likely alter the resources, do a shallow copy resources_copy = resources[:] neutron_context = state.request.context.get("neutron_context") resource = state.request.context.get("resource") # If there is no resource for this request, don't bother running authZ # policies if not resource: return collection = state.request.context.get("collection") needs_prefetch = state.request.method == "PUT" or state.request.method == "DELETE" policy.init() action = "%s_%s" % (pecan_constants.ACTION_MAP[state.request.method], resource) # NOTE(salv-orlando): As bulk updates are not supported, in case of PUT # requests there will be only a single item to process, and its # identifier would have been already retrieved by the lookup process; # in the case of DELETE requests there won't be any item to process in # the request body merged_resources = [] if needs_prefetch: try: item = resources_copy.pop() except IndexError: # Ops... this was a delete after all! item = {} resource_id = state.request.context.get("resource_id") obj = copy.copy(self._fetch_resource(neutron_context, resource, resource_id)) obj.update(item) merged_resources.append(obj.copy()) obj[const.ATTRIBUTES_TO_UPDATE] = item.keys() # Put back the item in the list so that policies could be enforced resources_copy.append(obj) # TODO(salv-orlando): as other hooks might need to prefetch resources, # store them in the request context. However, this should be done in a # separate hook which is conventietly called before all other hooks state.request.context["request_resources"] = merged_resources for item in resources_copy: try: policy.enforce(neutron_context, action, item, pluralized=collection) except oslo_policy.PolicyNotAuthorized: with excutils.save_and_reraise_exception() as ctxt: # If a tenant is modifying it's own object, it's safe to # return a 403. Otherwise, pretend that it doesn't exist # to avoid giving away information. if needs_prefetch and neutron_context.tenant_id != item["tenant_id"]: ctxt.reraise = False msg = _("The resource could not be found.") raise webob.exc.HTTPNotFound(msg)
def setUp(self): fake_ext = pecan_utils.FakeExtension() fake_plugin = pecan_utils.FakePlugin() plugins = {pecan_utils.FakePlugin.PLUGIN_TYPE: fake_plugin} new_extensions = {fake_ext.get_alias(): fake_ext} super(TestShimControllers, self).setUp(service_plugins=plugins, extensions=new_extensions) policy.init() policy._ENFORCER.set_rules( oslo_policy.Rules.from_dict({"get_meh_meh": "", "get_meh_mehs": "", "get_fake_subresources": ""}), overwrite=False, ) self.addCleanup(policy.reset)
def after(self, state): neutron_context = state.request.context.get('neutron_context') resource = state.request.context.get('resource') collection = state.request.context.get('collection') controller = utils.get_controller(state) if not resource: # can't filter a resource we don't recognize return # NOTE(kevinbenton): extension listing isn't controlled by policy if resource == 'extension': return try: data = state.response.json except ValueError: return if state.request.method not in pecan_constants.ACTION_MAP: return if not data or (resource not in data and collection not in data): return policy.init() is_single = resource in data action_type = pecan_constants.ACTION_MAP[state.request.method] if action_type == 'get': action = controller.plugin_handlers[controller.SHOW] else: action = controller.plugin_handlers[action_type] key = resource if is_single else collection to_process = [data[resource]] if is_single else data[collection] # in the single case, we enforce which raises on violation # in the plural case, we just check so violating items are hidden policy_method = policy.enforce if is_single else policy.check plugin = manager.NeutronManager.get_plugin_for_resource(collection) try: resp = [self._get_filtered_item(state.request, controller, resource, collection, item) for item in to_process if (state.request.method != 'GET' or policy_method(neutron_context, action, item, plugin=plugin, pluralized=collection))] except oslo_policy.PolicyNotAuthorized: # This exception must be explicitly caught as the exception # translation hook won't be called if an error occurs in the # 'after' handler. Instead of raising an HTTPForbidden exception, # we have to set the status_code here to prevent the catch_errors # middleware from turning this into a 500. state.response.status_code = 403 return if is_single: resp = resp[0] state.response.json = {key: resp}
def setUp(self): super(DefaultPolicyTestCase, self).setUp() policy.reset() policy.init() self.addCleanup(policy.reset) self.rules = { "default": '', "example:exist": '!', } self._set_rules('default') self.context = context.Context('fake', 'fake')
def test_get_child_resource_policy_check(self): policy.reset() policy.init() policy._ENFORCER.set_rules( oslo_policy.Rules.from_dict( {'get_meh_meh_fake_duplicate': ''} ) ) url = '/v2.0/{0}/something/{1}'.format(self.collection, self.fake_collection) resp = self.app.get(url) self.assertEqual(200, resp.status_int) self.assertEqual({'fake_duplicates': [{'fake': 'something'}]}, resp.json)
def setUp(self): cfg.CONF.set_override( 'service_plugins', ['neutron.services.l3_router.l3_router_plugin.L3RouterPlugin', 'neutron.services.flavors.flavors_plugin.FlavorsPlugin']) super(TestRouterController, self).setUp() policy.init() self.addCleanup(policy.reset) plugin = directory.get_plugin() ctx = context.get_admin_context() l3_plugin = directory.get_plugin(plugin_constants.L3) network_id = pecan_utils.create_network(ctx, plugin)['id'] self.subnet = pecan_utils.create_subnet(ctx, plugin, network_id) self.router = pecan_utils.create_router(ctx, l3_plugin)
def test_proper_load_order(self): """ Verifies that loading policies by way of admin context after populating extensions and extending the resource map results in networks with router:external are visible to regular tenants. """ policy.reset() extension_manager = extensions.ExtensionManager(self.extension_path) extension_manager.extend_resources(self.api_version, attributes.RESOURCE_ATTRIBUTE_MAP) policy.init() admin_context = context.get_admin_context() tenant_context = context.Context('test_user', 'test_tenant_id', False) self.assertTrue(self._check_external_router_policy(admin_context)) self.assertTrue(self._check_external_router_policy(tenant_context))
def _delete(self, request, id, **kwargs): action = self._plugin_handlers[self.DELETE] # Check authz policy.init() parent_id = kwargs.get(self._parent_id_name) obj = self._item(request, id, parent_id=parent_id) try: policy.enforce(request.context, action, obj, pluralized=self._collection) except oslo_policy.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist if policy does not authorize SHOW with excutils.save_and_reraise_exception() as ctxt: if not policy.check(request.context, self._plugin_handlers[self.SHOW], obj, pluralized=self._collection): ctxt.reraise = False msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) obj_deleter = getattr(self._plugin, action) obj_deleter(request.context, id, **kwargs) # A delete operation usually alters resource usage, so mark affected # usage trackers as dirty resource_registry.set_resources_dirty(request.context) notifier_method = self._resource + '.delete.end' result = {self._resource: self._view(request.context, obj)} notifier_payload = {self._resource + '_id': id} notifier_payload.update(result) self._notifier.info(request.context, notifier_method, notifier_payload) registry.publish(self._resource, events.BEFORE_RESPONSE, self, payload=events.APIEventPayload( request.context, notifier_method, action, states=( {}, obj, result, ), collection_name=self._collection))
def setUp(self): super(UOSExtensionPolicyTestCase, self).setUp() policy.reset() policy.init() rules = { "associate_floatingip_router": "not role:project_observer", "get_router_details": "role:admin", "remove_router_portforwarding": "role:member" } common_policy.set_rules(common_policy.Rules( dict((k, common_policy.parse_rule(v)) for k, v in rules.items()))) self.context = context.Context('fake', 'fake', roles=['member']) self.request = FakeRequest(self.context) self.target = {} self.controller = uos.UosController()
def test_proper_load_order(self): """Test proper policy load order Verifies that loading policies by way of admin context after populating extensions and extending the resource map results in networks with router:external are visible to regular tenants. """ policy.reset() extension_manager = extensions.ExtensionManager(self.extension_path) extension_manager.extend_resources(self.api_version, attributes.RESOURCES) policy.init() admin_context = context.get_admin_context() tenant_context = context.Context('test_user', 'test_tenant_id', False) self.assertTrue(self._check_external_router_policy(admin_context)) self.assertTrue(self._check_external_router_policy(tenant_context))
def setUp(self): fake_ext = pecan_utils.FakeExtension() fake_plugin = pecan_utils.FakePlugin() plugins = {pecan_utils.FakePlugin.PLUGIN_TYPE: fake_plugin} new_extensions = {fake_ext.get_alias(): fake_ext} super(TestShimControllers, self).setUp(service_plugins=plugins, extensions=new_extensions) policy.init() policy._ENFORCER.set_rules(oslo_policy.Rules.from_dict({ 'get_meh_meh': '', 'get_meh_mehs': '' }), overwrite=False) self.addCleanup(policy.reset)
def setUp(self): super(TestDHCPAgentShimControllers, self).setUp() policy.init() policy._ENFORCER.set_rules( oslo_policy.Rules.from_dict( {'get_dhcp-agents': 'role:admin', 'get_dhcp-networks': 'role:admin', 'create_dhcp-networks': 'role:admin', 'delete_dhcp-networks': 'role:admin'}), overwrite=False) plugin = directory.get_plugin() ctx = context.get_admin_context() self.network = pecan_utils.create_network(ctx, plugin) self.agent = helpers.register_dhcp_agent() # NOTE(blogan): Not sending notifications because this test is for # testing the shim controllers plugin.agent_notifiers[n_const.AGENT_TYPE_DHCP] = None
def setUp(self): super(UOSExtensionPolicyTestCase, self).setUp() policy.reset() policy.init() rules = { "associate_floatingip_router": "not role:project_observer", "get_router_details": "role:admin", "remove_router_portforwarding": "role:member" } common_policy.set_rules( common_policy.Rules( dict((k, common_policy.parse_rule(v)) for k, v in rules.items()))) self.context = context.Context('fake', 'fake', roles=['member']) self.request = FakeRequest(self.context) self.target = {} self.controller = uos.UosController()
def setUp(self): super(TestDHCPAgentShimControllers, self).setUp() policy.init() policy._ENFORCER.set_rules( oslo_policy.Rules.from_dict( {'get_dhcp-agents': 'role:admin', 'get_dhcp-networks': 'role:admin', 'create_dhcp-networks': 'role:admin', 'delete_dhcp-networks': 'role:admin'}), overwrite=False) plugin = manager.NeutronManager.get_plugin() ctx = context.get_admin_context() self.network = pecan_utils.create_network(ctx, plugin) self.agent = helpers.register_dhcp_agent() # NOTE(blogan): Not sending notifications because this test is for # testing the shim controllers plugin.agent_notifiers[n_const.AGENT_TYPE_DHCP] = None
def _handle_action(request, id, **kwargs): arg_list = [request.context, id] # Ensure policy engine is initialized policy.init() # Fetch the resource and verify if the user can access it try: resource = self._item(request, id, True) except exceptions.PolicyNotAuthorized: msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) body = kwargs.pop('body', None) # Explicit comparison with None to distinguish from {} if body is not None: arg_list.append(body) # It is ok to raise a 403 because accessibility to the # object was checked earlier in this method policy.enforce(request.context, name, resource) return getattr(self._plugin, name)(*arg_list, **kwargs)
def _handle_action(request, id, **kwargs): arg_list = [request.context, id] # Ensure policy engine is initialized policy.init() # Fetch the resource and verify if the user can access it try: resource = self._item(request, id, True) except exceptions.PolicyNotAuthorized: msg = _("The resource could not be found.") raise webob.exc.HTTPNotFound(msg) body = kwargs.pop("body", None) # Explicit comparison with None to distinguish from {} if body is not None: arg_list.append(body) # It is ok to raise a 403 because accessibility to the # object was checked earlier in this method policy.enforce(request.context, name, resource) return getattr(self._plugin, name)(*arg_list, **kwargs)
def setUp(self): fake_ext = pecan_utils.FakeExtension() fake_plugin = pecan_utils.FakePlugin() plugins = {pecan_utils.FakePlugin.PLUGIN_TYPE: fake_plugin} new_extensions = {fake_ext.get_alias(): fake_ext} super(TestParentSubresourceController, self).setUp( service_plugins=plugins, extensions=new_extensions) policy.init() policy._ENFORCER.set_rules( oslo_policy.Rules.from_dict( {'get_fake_duplicate': '', 'get_meh_meh_fake_duplicate': ''}), overwrite=False) self.addCleanup(policy.reset) hyphen_collection = pecan_utils.FakeExtension.HYPHENATED_COLLECTION self.collection = hyphen_collection.replace('_', '-') self.fake_collection = (pecan_utils.FakeExtension. FAKE_PARENT_SUBRESOURCE_COLLECTION)
def setUp(self): fake_ext = pecan_utils.FakeExtension() fake_plugin = pecan_utils.FakePlugin() plugins = {pecan_utils.FakePlugin.PLUGIN_TYPE: fake_plugin} new_extensions = {fake_ext.get_alias(): fake_ext} super(TestParentSubresourceController, self).setUp( service_plugins=plugins, extensions=new_extensions) policy.init() policy._ENFORCER.set_rules( oslo_policy.Rules.from_dict( {'get_fake_duplicate': '', 'get_meh_meh_fake_duplicates': ''}), overwrite=False) self.addCleanup(policy.reset) hyphen_collection = pecan_utils.FakeExtension.HYPHENATED_COLLECTION self.collection = hyphen_collection.replace('_', '-') self.fake_collection = (pecan_utils.FakeExtension. FAKE_PARENT_SUBRESOURCE_COLLECTION)
def setUp(self): cfg.CONF.set_override( 'service_plugins', ['neutron.services.l3_router.l3_router_plugin.L3RouterPlugin', 'neutron.services.flavors.flavors_plugin.FlavorsPlugin']) super(TestL3AgentShimControllers, self).setUp() policy.init() policy._ENFORCER.set_rules( oslo_policy.Rules.from_dict( {'get_l3-agents': 'role:admin', 'get_l3-routers': 'role:admin'}), overwrite=False) ctx = context.get_admin_context() l3_plugin = directory.get_plugin(n_const.L3) self.router = pecan_utils.create_router(ctx, l3_plugin) self.agent = helpers.register_l3_agent() # NOTE(blogan): Not sending notifications because this test is for # testing the shim controllers l3_plugin.agent_notifiers[n_const.AGENT_TYPE_L3] = None
def test_proper_load_order(self): """Test proper policy load order Verifies that loading policies by way of admin context after populating extensions and extending the resource map results in networks with router:external are visible to regular tenants. """ policy.reset() extension_manager = extensions.ExtensionManager(self.extension_path) extension_manager.extend_resources(self.api_version, attributes.RESOURCES) # TODO(amotoki): Consider this should be part of # neutron.policy.reset (or refresh), but as of now # this is only required for unit testing. policies.reload_default_policies() policy.init() admin_context = context.get_admin_context() tenant_context = context.Context('test_user', 'test_tenant_id', False) self.assertTrue(self._check_external_router_policy(admin_context)) self.assertTrue(self._check_external_router_policy(tenant_context))
def before(self, state): # This hook should be run only for PUT,POST and DELETE methods and for # requests targeting a neutron resource # FIXME(salv-orlando): DELETE support. It does not work with the # current logic. See LP Bug #1520180 items = state.request.context.get('resources') if state.request.method not in ('POST', 'PUT') or not items: return neutron_context = state.request.context.get('neutron_context') resource = state.request.context.get('resource') collection = state.request.context.get('collection') is_update = (state.request.method == 'PUT') policy.init() action = '%s_%s' % (self.ACTION_MAP[state.request.method], resource) # NOTE(salv-orlando): As bulk updates are not supported, in case of PUT # requests there will be only a single item to process, and its # identifier would have been already retrieved by the lookup process for item in items: if is_update: resource_id = state.request.context.get('resource_id') obj = copy.copy(self._fetch_resource(neutron_context, resource, resource_id)) obj.update(item) obj[const.ATTRIBUTES_TO_UPDATE] = item.keys() item = obj try: policy.enforce( neutron_context, action, item, pluralized=collection) except oslo_policy.PolicyNotAuthorized: with excutils.save_and_reraise_exception() as ctxt: # If a tenant is modifying it's own object, it's safe to # return a 403. Otherwise, pretend that it doesn't exist # to avoid giving away information. if (is_update and neutron_context.tenant_id != obj['tenant_id']): ctxt.reraise = False msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg)
def test_policy_404(self): with self.subnet(cidr='12.0.0.0/24') as public_sub: self._set_net_external(public_sub['subnet']['network_id']) fip = self._make_floatingip(self.fmt, public_sub['subnet']['network_id']) policy.reset() policy.init() rules = {"delete_floatingip": "role:admin_only"} common_policy.set_rules( common_policy.Rules( dict((k, common_policy.parse_rule(v)) for k, v in rules.items()))) fip_id = fip['floatingip']['id'] self.context = context.Context('fake', 'fake', roles=['member']) req = self.new_delete_request('floatingips', fip_id) req.environ['neutron.context'] = self.context res = req.get_response(self._api_for_resource('floatingips')) self.assertEqual(404, res.status_int) policy.reset() policy.init() self._delete('floatingips', fip_id)
def test_modified_policy_reloads(self): def fake_find_config_file(_1, _2): return self.tempdir.join('policy') with mock.patch.object(neutron.common.utils, 'find_config_file', new=fake_find_config_file): tmpfilename = fake_find_config_file(None, None) action = "example:test" with open(tmpfilename, "w") as policyfile: policyfile.write("""{"example:test": ""}""") policy.init() policy.enforce(self.context, action, self.target) with open(tmpfilename, "w") as policyfile: policyfile.write("""{"example:test": "!"}""") # NOTE(vish): reset stored policy cache so we don't have to # sleep(1) policy._POLICY_CACHE = {} policy.init() self.assertRaises(exceptions.PolicyNotAuthorized, policy.enforce, self.context, action, self.target)
def setUp(self): super(BaseTestCase, self).setUp() self.useFixture(lockutils.ExternalLockFixture()) self.useFixture(fixture.APIDefinitionFixture()) config.register_common_config_options() cfg.CONF.set_override('state_path', self.get_default_temp_dir().path) self.addCleanup(CONF.reset) self.useFixture(ProcessMonitorFixture()) self.useFixture( fixtures.MonkeyPatch( 'neutron_lib.exceptions.NeutronException.use_fatal_exceptions', fake_use_fatal_exceptions)) self.useFixture( fixtures.MonkeyPatch( 'oslo_config.cfg.find_config_files', lambda project=None, prog=None, extension=None: [])) self.useFixture(fixture.RPCFixture()) self.setup_config() self._callback_manager = registry_manager.CallbacksManager() self.useFixture( fixture.CallbackRegistryFixture( callback_manager=self._callback_manager)) # Give a private copy of the directory to each test. self.useFixture(fixture.PluginDirectoryFixture()) policy.init(suppress_deprecation_warnings=True) self.addCleanup(policy.reset) self.addCleanup(resource_registry.unregister_all_resources) self.addCleanup(db_api.sqla_remove_all) self.addCleanup(rpc_consumer_reg.clear) self.addCleanup(rpc_producer_reg.clear) self.addCleanup(profiler.clean)
def setUp(self): # Create a controller for a fake resource. This will make the tests # independent from the evolution of the API (so if one changes the API # or the default policies there won't be any risk of breaking these # tests, or at least I hope so) super(TestPolicyEnforcementHook, self).setUp() self.mock_plugin = mock.Mock() attributes.RESOURCES.update(self.FAKE_RESOURCE) manager.NeutronManager.set_plugin_for_resource('mehs', self.mock_plugin) manager.NeutronManager.set_plugin_for_resource('admin_mehs', self.mock_plugin) fake_controller = resource.CollectionsController('mehs', 'meh') admin_fake_controller = resource.CollectionsController( 'admin_mehs', 'admin_meh') manager.NeutronManager.set_controller_for_resource( 'mehs', fake_controller) manager.NeutronManager.set_controller_for_resource( 'admin_mehs', admin_fake_controller) # Inject policies for the fake resource policy.init() policy._ENFORCER.set_rules(oslo_policy.Rules.from_dict({ 'create_meh': '', 'update_meh': 'rule:admin_only', 'delete_meh': 'rule:admin_only', 'get_meh': 'rule:admin_only or field:mehs:id=xxx', 'get_meh:restricted_attr': 'rule:admin_only', 'create_admin_meh': 'rule:admin_only', 'get_admin_meh': 'rule:admin_only' }), overwrite=False)
def setUp(self): super(PolicyTestCase, self).setUp() policy.reset() self.addCleanup(policy.reset) # NOTE(vish): preload rules to circumvent reloading from file policy.init() rules = { "true": '@', "example:allowed": '@', "example:denied": '!', "example:get_http": "http:http://www.example.com", "example:my_file": "role:compute_admin or tenant_id:%(tenant_id)s", "example:early_and_fail": "! and @", "example:early_or_success": "@ or !", "example:lowercase_admin": "role:admin or role:sysadmin", "example:uppercase_admin": "role:ADMIN or role:sysadmin", } # NOTE(vish): then overload underlying rules common_policy.set_rules(common_policy.Rules( dict((k, common_policy.parse_rule(v)) for k, v in rules.items()))) self.context = context.Context('fake', 'fake', roles=['member']) self.target = {}
def setUp(self): super(BaseTestCase, self).setUp() # suppress all but errors here capture_logs = bool_from_env('OS_LOG_CAPTURE') self.useFixture( fixtures.FakeLogger( name='neutron.api.extensions', format=LOG_FORMAT, level=std_logging.ERROR, nuke_handlers=capture_logs, )) self.useFixture(lockutils.ExternalLockFixture()) cfg.CONF.set_override('state_path', self.get_default_temp_dir().path) self.addCleanup(CONF.reset) self.useFixture(ProcessMonitorFixture()) self.useFixture( fixtures.MonkeyPatch( 'neutron.common.exceptions.NeutronException.use_fatal_exceptions', fake_use_fatal_exceptions)) self.useFixture( fixtures.MonkeyPatch( 'oslo_config.cfg.find_config_files', lambda project=None, prog=None, extension=None: [])) self.setup_rpc_mocks() self.setup_config() self.setup_test_registry_instance() policy.init() self.addCleanup(policy.reset) self.addCleanup(rpc_consumer_reg.clear)
def _delete(self, request, id, **kwargs): action = self._plugin_handlers[self.DELETE] # Check authz policy.init() parent_id = kwargs.get(self._parent_id_name) obj = self._item(request, id, parent_id=parent_id) try: policy.enforce(request.context, action, obj, pluralized=self._collection) except oslo_policy.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) obj_deleter = getattr(self._plugin, action) obj_deleter(request.context, id, **kwargs) # A delete operation usually alters resource usage, so mark affected # usage trackers as dirty resource_registry.set_resources_dirty(request.context) notifier_method = self._resource + '.delete.end' result = {self._resource: self._view(request.context, obj)} notifier_payload = {self._resource + '_id': id} notifier_payload.update(result) self._notifier.info(request.context, notifier_method, notifier_payload) registry.notify(self._resource, events.BEFORE_RESPONSE, self, context=request.context, data=result, method_name=notifier_method, action=action, original={})
def show(self, request, id, **kwargs): """Returns detailed information about the requested entity.""" try: # NOTE(salvatore-orlando): The following ensures that fields # which are needed for authZ policy validation are not stripped # away by the plugin before returning. field_list, added_fields = self._do_field_list( api_common.list_args(request, "fields")) parent_id = kwargs.get(self._parent_id_name) # Ensure policy engine is initialized policy.init() return {self._resource: self._view(request.context, self._item(request, id, do_authz=True, field_list=field_list, parent_id=parent_id), fields_to_strip=added_fields)} except oslo_policy.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg)
def delete(self, request, id, **kwargs): """Deletes the specified entity.""" self._notifier.info(request.context, self._resource + '.delete.start', {self._resource + '_id': id}) action = self._plugin_handlers[self.DELETE] # Check authz policy.init() parent_id = kwargs.get(self._parent_id_name) obj = self._item(request, id, parent_id=parent_id) try: policy.enforce(request.context, action, obj, pluralized=self._collection) except oslo_policy.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) obj_deleter = getattr(self._plugin, action) obj_deleter(request.context, id, **kwargs) # A delete operation usually alters resource usage, so mark affected # usage trackers as dirty resource_registry.set_resources_dirty(request.context) notifier_method = self._resource + '.delete.end' self._notifier.info(request.context, notifier_method, {self._resource + '_id': id}) result = {self._resource: self._view(request.context, obj)} self._send_nova_notification(action, {}, result) self._send_dhcp_notification(request.context, result, notifier_method)
def index(self, request, **kwargs): """Returns a list of the requested entity.""" parent_id = kwargs.get(self._parent_id_name) # Ensure policy engine is initialized policy.init() return self._items(request, True, parent_id)
def _create(self, request, body, **kwargs): """Creates a new instance of the requested entity.""" parent_id = kwargs.get(self._parent_id_name) body = Controller.prepare_request_body(request.context, copy.deepcopy(body), True, self._resource, self._attr_info, allow_bulk=self._allow_bulk) action = self._plugin_handlers[self.CREATE] # Check authz if self._collection in body: # Have to account for bulk create items = body[self._collection] else: items = [body] # Ensure policy engine is initialized policy.init() # Store requested resource amounts grouping them by tenant # This won't work with multiple resources. However because of the # current structure of this controller there will hardly be more than # one resource for which reservations are being made request_deltas = collections.defaultdict(int) for item in items: self._validate_network_tenant_ownership(request, item[self._resource]) policy.enforce(request.context, action, item[self._resource], pluralized=self._collection) if 'tenant_id' not in item[self._resource]: # no tenant_id - no quota check continue tenant_id = item[self._resource]['tenant_id'] request_deltas[tenant_id] += 1 # Quota enforcement reservations = [] try: for (tenant, delta) in request_deltas.items(): reservation = quota.QUOTAS.make_reservation( request.context, tenant, {self._resource: delta}, self._plugin) reservations.append(reservation) except exceptions.QuotaResourceUnknown as e: # We don't want to quota this resource LOG.debug(e) def notify(create_result): # Ensure usage trackers for all resources affected by this API # operation are marked as dirty with request.context.session.begin(): # Commit the reservation(s) for reservation in reservations: quota.QUOTAS.commit_reservation(request.context, reservation.reservation_id) resource_registry.set_resources_dirty(request.context) notifier_method = self._resource + '.create.end' self._notifier.info(request.context, notifier_method, create_result) self._send_dhcp_notification(request.context, create_result, notifier_method) return create_result def do_create(body, bulk=False, emulated=False): kwargs = {self._parent_id_name: parent_id} if parent_id else {} if bulk and not emulated: obj_creator = getattr(self._plugin, "%s_bulk" % action) else: obj_creator = getattr(self._plugin, action) try: if emulated: return self._emulate_bulk_create(obj_creator, request, body, parent_id) else: if self._collection in body: # This is weird but fixing it requires changes to the # plugin interface kwargs.update({self._collection: body}) else: kwargs.update({self._resource: body}) return obj_creator(request.context, **kwargs) except Exception: # In case of failure the plugin will always raise an # exception. Cancel the reservation with excutils.save_and_reraise_exception(): for reservation in reservations: quota.QUOTAS.cancel_reservation( request.context, reservation.reservation_id) if self._collection in body and self._native_bulk: # plugin does atomic bulk create operations objs = do_create(body, bulk=True) # Use first element of list to discriminate attributes which # should be removed because of authZ policies fields_to_strip = self._exclude_attributes_by_policy( request.context, objs[0]) return notify({ self._collection: [ self._filter_attributes(request.context, obj, fields_to_strip=fields_to_strip) for obj in objs ] }) else: if self._collection in body: # Emulate atomic bulk behavior objs = do_create(body, bulk=True, emulated=True) return notify({self._collection: objs}) else: obj = do_create(body) self._send_nova_notification(action, {}, {self._resource: obj}) return notify( {self._resource: self._view(request.context, obj)})
def update(self, request, id, body=None, **kwargs): """Updates the specified entity's attributes.""" parent_id = kwargs.get(self._parent_id_name) try: payload = body.copy() except AttributeError: msg = _("Invalid format: %s") % request.body raise exceptions.BadRequest(resource='body', msg=msg) payload['id'] = id notifier_api.notify(request.context, self._publisher_id, self._resource + '.update.start', notifier_api.CONF.default_notification_level, payload) body = Controller.prepare_request_body(request.context, body, False, self._resource, self._attr_info, allow_bulk=self._allow_bulk) action = self._plugin_handlers[self.UPDATE] # Load object to check authz # but pass only attributes in the original body and required # by the policy engine to the policy 'brain' field_list = [ name for (name, value) in self._attr_info.iteritems() if (value.get('required_by_policy') or value.get('primary_key') or 'default' not in value) ] # Ensure policy engine is initialized policy.init() orig_obj = self._item(request, id, field_list=field_list, parent_id=parent_id) orig_object_copy = copy.copy(orig_obj) orig_obj.update(body[self._resource]) # Make a list of attributes to be updated to inform the policy engine # which attributes are set explicitly so that it can distinguish them # from the ones that are set to their default values. orig_obj[const.ATTRIBUTES_TO_UPDATE] = body[self._resource].keys() try: policy.enforce(request.context, action, orig_obj) except exceptions.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) obj_updater = getattr(self._plugin, action) kwargs = {self._resource: body} if parent_id: kwargs[self._parent_id_name] = parent_id obj = obj_updater(request.context, id, **kwargs) result = {self._resource: self._view(request.context, obj)} notifier_method = self._resource + '.update.end' notifier_api.notify(request.context, self._publisher_id, notifier_method, notifier_api.CONF.default_notification_level, result) self._send_dhcp_notification(request.context, result, notifier_method) self._nova_notifier.send_network_change(action, orig_object_copy, result) return result
def setUp(self): super(RuleScopesTestCase, self).setUp() policy.init()
def _update(self, request, id, body, **kwargs): body = Controller.prepare_request_body(request.context, body, False, self._resource, self._attr_info, allow_bulk=self._allow_bulk) action = self._plugin_handlers[self.UPDATE] # Load object to check authz # but pass only attributes in the original body and required # by the policy engine to the policy 'brain' field_list = [ name for (name, value) in six.iteritems(self._attr_info) if (value.get('required_by_policy') or value.get('primary_key') or 'default' not in value) ] # Ensure policy engine is initialized policy.init() parent_id = kwargs.get(self._parent_id_name) orig_obj = self._item(request, id, field_list=field_list, parent_id=parent_id) orig_object_copy = copy.copy(orig_obj) orig_obj.update(body[self._resource]) # Make a list of attributes to be updated to inform the policy engine # which attributes are set explicitly so that it can distinguish them # from the ones that are set to their default values. orig_obj[const.ATTRIBUTES_TO_UPDATE] = body[self._resource].keys() try: policy.enforce(request.context, action, orig_obj, pluralized=self._collection) except oslo_policy.PolicyNotAuthorized: with excutils.save_and_reraise_exception() as ctxt: # If a tenant is modifying it's own object, it's safe to return # a 403. Otherwise, pretend that it doesn't exist to avoid # giving away information. if request.context.tenant_id != orig_obj['tenant_id']: ctxt.reraise = False msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) obj_updater = getattr(self._plugin, action) kwargs = {self._resource: body} if parent_id: kwargs[self._parent_id_name] = parent_id obj = obj_updater(request.context, id, **kwargs) # Usually an update operation does not alter resource usage, but as # there might be side effects it might be worth checking for changes # in resource usage here as well (e.g: a tenant port is created when a # router interface is added) resource_registry.set_resources_dirty(request.context) result = {self._resource: self._view(request.context, obj)} notifier_method = self._resource + '.update.end' self._notifier.info(request.context, notifier_method, result) self._send_dhcp_notification(request.context, result, notifier_method) self._send_nova_notification(action, orig_object_copy, result) return result
def create(self, request, body=None, **kwargs): """Creates a new instance of the requested entity.""" parent_id = kwargs.get(self._parent_id_name) notifier_api.notify(request.context, self._publisher_id, self._resource + '.create.start', notifier_api.CONF.default_notification_level, body) body = Controller.prepare_request_body(request.context, body, True, self._resource, self._attr_info, allow_bulk=self._allow_bulk) action = self._plugin_handlers[self.CREATE] # Check authz if self._collection in body: # Have to account for bulk create items = body[self._collection] deltas = {} bulk = True else: items = [body] bulk = False # Ensure policy engine is initialized policy.init() for item in items: self._validate_network_tenant_ownership(request, item[self._resource]) policy.enforce(request.context, action, item[self._resource]) try: tenant_id = item[self._resource]['tenant_id'] count = quota.QUOTAS.count(request.context, self._resource, self._plugin, self._collection, tenant_id) if bulk: delta = deltas.get(tenant_id, 0) + 1 deltas[tenant_id] = delta else: delta = 1 kwargs = {self._resource: count + delta} except exceptions.QuotaResourceUnknown as e: # We don't want to quota this resource LOG.debug(e) else: quota.QUOTAS.limit_check(request.context, item[self._resource]['tenant_id'], **kwargs) def notify(create_result): notifier_method = self._resource + '.create.end' notifier_api.notify(request.context, self._publisher_id, notifier_method, notifier_api.CONF.default_notification_level, create_result) self._send_dhcp_notification(request.context, create_result, notifier_method) return create_result kwargs = {self._parent_id_name: parent_id} if parent_id else {} if self._collection in body and self._native_bulk: # plugin does atomic bulk create operations obj_creator = getattr(self._plugin, "%s_bulk" % action) objs = obj_creator(request.context, body, **kwargs) return notify({ self._collection: [self._view(request.context, obj) for obj in objs] }) else: obj_creator = getattr(self._plugin, action) if self._collection in body: # Emulate atomic bulk behavior objs = self._emulate_bulk_create(obj_creator, request, body, parent_id) return notify({self._collection: objs}) else: kwargs.update({self._resource: body}) obj = obj_creator(request.context, **kwargs) self._nova_notifier.send_network_change( action, {}, {self._resource: obj}) return notify( {self._resource: self._view(request.context, obj)})
def setUp(self): super(NeutronPolicyTestCase, self).setUp() policy.reset() policy.init() self.addCleanup(policy.reset) self.admin_only_legacy = "role:admin" self.admin_or_owner_legacy = "role:admin or tenant_id:%(tenant_id)s" # Add a Fake 'something' resource to RESOURCE_ATTRIBUTE_MAP attributes.RESOURCE_ATTRIBUTE_MAP.update(FAKE_RESOURCE) self.rules = dict( (k, common_policy.parse_rule(v)) for k, v in { "context_is_admin": "role:admin", "admin_or_network_owner": "rule:context_is_admin or " "tenant_id:%(network:tenant_id)s", "admin_or_owner": ("rule:context_is_admin or " "tenant_id:%(tenant_id)s"), "admin_only": "rule:context_is_admin", "regular_user": "******", "shared": "field:networks:shared=True", "external": "field:networks:router:external=True", "default": '@', "create_network": "rule:admin_or_owner", "create_network:shared": "rule:admin_only", "update_network": '@', "update_network:shared": "rule:admin_only", "get_network": "rule:admin_or_owner or " "rule:shared or " "rule:external", "create_port:mac": "rule:admin_or_network_owner", "create_something": "rule:admin_or_owner", "create_something:attr": "rule:admin_or_owner", "create_something:attr:sub_attr_1": "rule:admin_or_owner", "create_something:attr:sub_attr_2": "rule:admin_only", "get_firewall_policy": "rule:admin_or_owner or " "rule:shared", "get_firewall_rule": "rule:admin_or_owner or " "rule:shared" }.items()) def fakepolicyinit(): common_policy.set_rules(common_policy.Rules(self.rules)) def remove_fake_resource(): del attributes.RESOURCE_ATTRIBUTE_MAP["%ss" % FAKE_RESOURCE_NAME] self.patcher = mock.patch.object(neutron.policy, 'init', new=fakepolicyinit) self.patcher.start() self.addCleanup(self.patcher.stop) self.addCleanup(remove_fake_resource) self.context = context.Context('fake', 'fake', roles=['user']) plugin_klass = importutils.import_class( "neutron.db.db_base_plugin_v2.NeutronDbPluginV2") self.manager_patcher = mock.patch('neutron.manager.NeutronManager') fake_manager = self.manager_patcher.start() fake_manager_instance = fake_manager.return_value fake_manager_instance.plugin = plugin_klass() self.addCleanup(self.manager_patcher.stop)
def validate_policy(context, policy_name): policy.init() policy.enforce(context, policy_name, target={'project_id': context.project_id}, plugin=None)
def _update(self, request, id, body, **kwargs): try: body = Controller.prepare_request_body(request.context, body, False, self._resource, self._attr_info, allow_bulk=self._allow_bulk) except Exception as e: LOG.warning( "An exception happened while processing the request " "body. The exception message is [%s].", e) raise e action = self._plugin_handlers[self.UPDATE] # Load object to check authz # but pass only attributes in the original body and required # by the policy engine to the policy 'brain' field_list = [ name for (name, value) in self._attr_info.items() if (value.get('required_by_policy') or value.get('primary_key') or 'default' not in value) ] # Ensure policy engine is initialized policy.init() parent_id = kwargs.get(self._parent_id_name) # If the parent_id exist, we should get orig_obj with # self._parent_id_name field. if parent_id and self._parent_id_name not in field_list: field_list.append(self._parent_id_name) orig_obj = self._item(request, id, field_list=field_list, parent_id=parent_id) orig_object_copy = copy.copy(orig_obj) orig_obj.update(body[self._resource]) # Make a list of attributes to be updated to inform the policy engine # which attributes are set explicitly so that it can distinguish them # from the ones that are set to their default values. orig_obj[constants.ATTRIBUTES_TO_UPDATE] = body[self._resource].keys() # Then get the ext_parent_id, format to ext_parent_parent_resource_id if self._parent_id_name in orig_obj: self._set_parent_id_into_ext_resources_request( request, orig_obj, parent_id) try: policy.enforce(request.context, action, orig_obj, pluralized=self._collection) except oslo_policy.PolicyNotAuthorized: # To avoid giving away information, pretend that it # doesn't exist if policy does not authorize SHOW with excutils.save_and_reraise_exception() as ctxt: if not policy.check(request.context, self._plugin_handlers[self.SHOW], orig_obj, pluralized=self._collection): ctxt.reraise = False msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg) if self._native_bulk and hasattr(self._plugin, "%s_bulk" % action): obj_updater = getattr(self._plugin, "%s_bulk" % action) else: obj_updater = getattr(self._plugin, action) kwargs = {self._resource: body} if parent_id: kwargs[self._parent_id_name] = parent_id obj = obj_updater(request.context, id, **kwargs) # Usually an update operation does not alter resource usage, but as # there might be side effects it might be worth checking for changes # in resource usage here as well (e.g: a tenant port is created when a # router interface is added) resource_registry.set_resources_dirty(request.context) result = {self._resource: self._view(request.context, obj)} notifier_method = self._resource + '.update.end' self._notifier.info(request.context, notifier_method, result) registry.publish(self._resource, events.BEFORE_RESPONSE, self, payload=events.APIEventPayload( request.context, notifier_method, action, request_body=body, states=( orig_object_copy, result, ), collection_name=self._collection)) return result
def setUp(self): super(TestResourceController, self).setUp() policy.init() self.addCleanup(policy.reset) self._gen_port()
def before(self, state): # This hook should be run only for PUT,POST and DELETE methods and for # requests targeting a neutron resource resources = state.request.context.get('resources', []) if state.request.method not in ('POST', 'PUT', 'DELETE'): return # As this routine will likely alter the resources, do a shallow copy resources_copy = resources[:] neutron_context = state.request.context.get('neutron_context') resource = state.request.context.get('resource') # If there is no resource for this request, don't bother running authZ # policies if not resource: return controller = utils.get_controller(state) if not controller or utils.is_member_action(controller): return collection = state.request.context.get('collection') needs_prefetch = (state.request.method == 'PUT' or state.request.method == 'DELETE') policy.init() action = controller.plugin_handlers[ pecan_constants.ACTION_MAP[state.request.method]] # NOTE(salv-orlando): As bulk updates are not supported, in case of PUT # requests there will be only a single item to process, and its # identifier would have been already retrieved by the lookup process; # in the case of DELETE requests there won't be any item to process in # the request body original_resources = [] if needs_prefetch: try: item = resources_copy.pop() except IndexError: # Ops... this was a delete after all! item = {} resource_id = state.request.context.get('resource_id') parent_id = state.request.context.get('parent_id') method = state.request.method resource_obj = fetch_resource(method, neutron_context, controller, collection, resource, resource_id, parent_id=parent_id) if resource_obj: original_resources.append(resource_obj) obj = copy.copy(resource_obj) obj.update(item) obj[const.ATTRIBUTES_TO_UPDATE] = item.keys() # Put back the item in the list so that policies could be # enforced resources_copy.append(obj) # TODO(salv-orlando): as other hooks might need to prefetch resources, # store them in the request context. However, this should be done in a # separate hook which is conveniently called before all other hooks state.request.context['original_resources'] = original_resources for item in resources_copy: try: policy.enforce( neutron_context, action, item, pluralized=collection) except oslo_policy.PolicyNotAuthorized: with excutils.save_and_reraise_exception() as ctxt: # If a tenant is modifying it's own object, it's safe to # return a 403. Otherwise, pretend that it doesn't exist # to avoid giving away information. orig_item_tenant_id = item.get('tenant_id') if (needs_prefetch and (neutron_context.tenant_id != orig_item_tenant_id or orig_item_tenant_id is None)): ctxt.reraise = False msg = _('The resource could not be found.') raise webob.exc.HTTPNotFound(msg)