def delete(self, request, id, body=None, **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: # 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) if body: kwargs.update({self._resource: body}) obj_deleter(request.context, id, **kwargs) notifier_method = self._resource + '.delete.end' self._notifier.info(request.context, notifier_method, {self._resource + '_id': id})
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: # 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})
def test_templatized_enforcement(self): target_mine = {'tenant_id': 'fake'} target_not_mine = {'tenant_id': 'another'} action = "example:my_file" policy.enforce(self.context, action, target_mine) self.assertRaises(exceptions.PolicyNotAuthorized, policy.enforce, self.context, action, target_not_mine)
def test_ignore_case_role_check(self): lowercase_action = "example:lowercase_admin" uppercase_action = "example:uppercase_admin" # NOTE(dprince) we mix case in the Admin role here to ensure # case is ignored admin_context = context.Context('admin', 'fake', roles=['AdMiN']) policy.enforce(admin_context, lowercase_action, self.target) policy.enforce(admin_context, uppercase_action, self.target)
def create(self, request, body=None, **kwargs): """Creates a new instance of the requested entity.""" parent_id = kwargs.get(self._parent_id_name) self._notifier.info(request.context, self._resource + '.create.start', 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] else: items = [body] # Ensure policy engine is initialized policy.init() for item in items: policy.enforce(request.context, action, item[self._resource]) def notify(create_result): notifier_method = self._resource + '.create.end' self._notifier.info(request.context, notifier_method, create_result) 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) # 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: 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) return notify( {self._resource: self._view(request.context, obj)})
def create(self, request, body=None, **kwargs): """Creates a new instance of the requested entity.""" parent_id = kwargs.get(self._parent_id_name) self._notifier.info(request.context, self._resource + '.create.start', 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] else: items = [body] # Ensure policy engine is initialized policy.init() for item in items: policy.enforce(request.context, action, item[self._resource]) def notify(create_result): notifier_method = self._resource + '.create.end' self._notifier.info(request.context, notifier_method, create_result) 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) # 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: 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) 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 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).items() 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_obj.update(body[self._resource]) attribs = attributes.ATTRIBUTES_TO_UPDATE orig_obj[attribs] = 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' self._notifier.info(request.context, notifier_method, result) return result
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).items() 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_obj.update(body[self._resource]) attribs = attributes.ATTRIBUTES_TO_UPDATE orig_obj[attribs] = 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' self._notifier.info(request.context, notifier_method, result) return result
def _item(self, request, id, do_authz=False, field_list=None, parent_id=None): """Retrieves and formats a single element of the requested entity.""" kwargs = {'fields': field_list} action = self._plugin_handlers[self.SHOW] if parent_id: kwargs[self._parent_id_name] = parent_id obj_getter = getattr(self._plugin, action) obj = obj_getter(request.context, id, **kwargs) # Check authz # FIXME(salvatore-orlando): obj_getter might return references to # other resources. Must check authZ on them too. if do_authz: policy.enforce(request.context, action, obj) return obj
def test_enforce_admin_only_subattribute(self): action = "create_something" target = {'tenant_id': 'fake', 'attr': {'sub_attr_1': 'x', 'sub_attr_2': 'y'}} result = policy.enforce(context.get_admin_context(), action, target, None) self.assertEqual(True, result)
def _test_action_on_attr(self, context, action, attr, value, exception=None): action = "%s_network" % action target = {"tenant_id": "the_owner", attr: value} if exception: self.assertRaises(exception, policy.enforce, context, action, target) else: result = policy.enforce(context, action, target) self.assertEqual(result, True)
def test_enforce_http_true(self): def fakeurlopen(url, post_data): return six.StringIO("True") with mock.patch.object(urlrequest, 'urlopen', new=fakeurlopen): action = "example:get_http" target = {} result = policy.enforce(self.context, action, target) self.assertEqual(True, result)
def test_modified_policy_reloads(self): def fake_find_config_file(_1, _2): return self.tempdir.join("policy") with mock.patch.object(tacker.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 _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 test_enforce_tenant_id_check_parent_resource(self): def fakegetnetwork(*args, **kwargs): return {"tenant_id": "fake"} action = "create_port:mac" with mock.patch.object(manager.TackerManager.get_instance().plugin, "get_network", new=fakegetnetwork): target = {"network_id": "whatever"} result = policy.enforce(self.context, action, target) self.assertTrue(result)
def test_enforce_http_true(self): def fakeurlopen(url, post_data): return six.StringIO("True") with mock.patch.object(urlrequest, "urlopen", new=fakeurlopen): action = "example:get_http" target = {} result = policy.enforce(self.context, action, target) self.assertEqual(result, True)
def _test_action_on_attr(self, context, action, attr, value, exception=None): action = "%s_network" % action target = {'tenant_id': 'the_owner', attr: value} if exception: self.assertRaises(exception, policy.enforce, context, action, target) else: result = policy.enforce(context, action, target) self.assertEqual(True, result)
def test_enforce_tenant_id_check_parent_resource(self): def fakegetnetwork(*args, **kwargs): return {'tenant_id': 'fake'} action = "create_port:mac" with mock.patch.object(manager.TackerManager.get_instance().plugin, 'get_network', new=fakegetnetwork): target = {'network_id': 'whatever'} result = policy.enforce(self.context, action, target) self.assertTrue(result)
def test_enforce_tenant_id_check_parent_resource_bw_compatibility(self): def fakegetnetwork(*args, **kwargs): return {"tenant_id": "fake"} del self.rules["admin_or_network_owner"] self.rules["admin_or_network_owner"] = common_policy.parse_rule("role:admin or tenant_id:%(network_tenant_id)s") action = "create_port:mac" with mock.patch.object(manager.TackerManager.get_instance().plugin, "get_network", new=fakegetnetwork): target = {"network_id": "whatever"} result = policy.enforce(self.context, action, target) self.assertTrue(result)
def test_modified_policy_reloads(self): def fake_find_config_file(_1, _2): return self.tempdir.join('policy') with mock.patch.object(tacker.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 test_enforce_tenant_id_check_parent_resource_bw_compatibility(self): def fakegetnetwork(*args, **kwargs): return {'tenant_id': 'fake'} del self.rules['admin_or_network_owner'] self.rules['admin_or_network_owner'] = common_policy.parse_rule( "role:admin or tenant_id:%(network_tenant_id)s") action = "create_port:mac" with mock.patch.object(manager.TackerManager.get_instance().plugin, 'get_network', new=fakegetnetwork): target = {'network_id': 'whatever'} result = policy.enforce(self.context, action, target) self.assertTrue(result)
def test_not_found_policy_calls_default(self): policy.enforce(self.context, "example:noexist", {})
def test_enforce_subattribute(self): action = "create_something" target = {'tenant_id': 'fake', 'attr': {'sub_attr_1': 'x'}} result = policy.enforce(self.context, action, target, None) self.assertEqual(result, True)
def test_early_OR_enforcement(self): action = "example:early_or_success" policy.enforce(self.context, action, self.target)
def test_enforce_firewall_policy_shared(self): action = "get_firewall_policy" target = {"shared": True, "tenant_id": "somebody_else"} result = policy.enforce(self.context, action, target) self.assertTrue(result)
def test_enforce_tenant_id_check(self): # Trigger a policy with rule admin_or_owner action = "create_network" target = {'tenant_id': 'fake'} result = policy.enforce(self.context, action, target) self.assertTrue(result)
def test_enforce_regularuser_on_read(self): action = "get_network" target = {'shared': True, 'tenant_id': 'somebody_else'} result = policy.enforce(self.context, action, target) self.assertTrue(result)
def test_enforce_admin_only_subattribute(self): action = "create_something" target = {"tenant_id": "fake", "attr": {"sub_attr_1": "x", "sub_attr_2": "y"}} result = policy.enforce(context.get_admin_context(), action, target, None) self.assertEqual(result, True)
def test_enforce_firewall_rule_shared(self): action = "get_firewall_rule" target = {'shared': True, 'tenant_id': 'somebody_else'} result = policy.enforce(self.context, action, target) self.assertTrue(result)
def _test_enforce_adminonly_attribute(self, action): admin_context = context.get_admin_context() target = {'shared': True} result = policy.enforce(admin_context, action, target) self.assertEqual(True, result)
def test_enforce_good_action(self): action = "example:allowed" result = policy.enforce(self.context, action, self.target) self.assertEqual(True, result)