Exemple #1
0
 def test_check_non_existent_action(self):
     action = "example:idonotexist"
     result_1 = policy.check(self.context, action, self.target)
     self.assertFalse(result_1)
     result_2 = policy.check(self.context, action, self.target,
                             might_not_exist=True)
     self.assertTrue(result_2)
Exemple #2
0
    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 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)
        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:
            # 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)

        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 _get_items_by_filter_and_order_and_page(self, request,kwargs,original_fields=None,fields_to_add=None,do_authz=False, parent_id=None):
        """
        get resource items by filters,order,and page

        """
        sorting_helper = self._get_sorting_helper(request)#convert sort
        pagination_helper = self._get_pagination_helper(request) #convert paging
        sorting_helper.update_args(kwargs) #add sort to kwargs
        sorting_helper.update_fields(original_fields, fields_to_add)
        pagination_helper.update_args(kwargs) #add page to kwargs
        pagination_helper.update_fields(original_fields, fields_to_add)
        if parent_id:
            kwargs[self._parent_id_name] = parent_id
        obj_getter = getattr(self._plugin, self._plugin_handlers[self.LIST])

        obj_list = obj_getter(request.context, **kwargs)
        obj_list = sorting_helper.sort(obj_list)
        obj_list = pagination_helper.paginate(obj_list)
        # Check authz
        if do_authz and obj_list:
            # FIXME(salvatore-orlando): obj_getter might return references to
            # other resources. Must check authZ on them too.
            # Omit items from list that should not be visible
            obj_list = [obj for obj in obj_list
                        if policy.check(request.context,
                                        self._plugin_handlers[self.SHOW],
                                        obj,
                                        plugin=self._plugin)]
        return obj_list,pagination_helper
Exemple #4
0
 def _items(self, request, do_authz=False, parent_id=None):
     """Retrieves and formats a list of elements of the requested entity."""
     # NOTE(salvatore-orlando): The following ensures that fields which
     # are needed for authZ policy validation are not stripped away by the
     # plugin before returning.
     original_fields, fields_to_add = self._do_field_list(
         api_common.list_args(request, 'fields'))
     filters = api_common.get_filters(
         request, self._attr_info,
         ['fields', 'sort_key', 'sort_dir',
          'limit', 'marker', 'page_reverse'],
         is_filter_validation_supported=self._filter_validation)
     kwargs = {'filters': filters,
               'fields': original_fields}
     sorting_helper = self._get_sorting_helper(request)
     pagination_helper = self._get_pagination_helper(request)
     sorting_helper.update_args(kwargs)
     sorting_helper.update_fields(original_fields, fields_to_add)
     pagination_helper.update_args(kwargs)
     pagination_helper.update_fields(original_fields, fields_to_add)
     if parent_id:
         kwargs[self._parent_id_name] = parent_id
     obj_getter = getattr(self._plugin, self._plugin_handlers[self.LIST])
     obj_list = obj_getter(request.context, **kwargs)
     obj_list = sorting_helper.sort(obj_list)
     obj_list = pagination_helper.paginate(obj_list)
     # Check authz
     if do_authz:
         # FIXME(salvatore-orlando): obj_getter might return references to
         # other resources. Must check authZ on them too.
         # Omit items from list that should not be visible
         tmp_list = []
         for obj in obj_list:
             self._set_parent_id_into_ext_resources_request(
                 request, obj, parent_id, is_get=True)
             if policy.check(
                     request.context, self._plugin_handlers[self.SHOW],
                     obj, plugin=self._plugin, pluralized=self._collection):
                 tmp_list.append(obj)
         obj_list = tmp_list
     # Use the first element in the list for discriminating which attributes
     # should be filtered out because of authZ policies
     # fields_to_add contains a list of attributes added for request policy
     # checks but that were not required by the user. They should be
     # therefore stripped
     fields_to_strip = fields_to_add or []
     if obj_list:
         fields_to_strip += self._exclude_attributes_by_policy(
             request.context, obj_list[0])
     collection = {self._collection:
                   [self._filter_attributes(obj,
                       fields_to_strip=fields_to_strip)
                    for obj in obj_list]}
     pagination_links = pagination_helper.get_links(obj_list)
     if pagination_links:
         collection[self._collection + "_links"] = pagination_links
     # Synchronize usage trackers, if needed
     resource_registry.resync_resource(
         request.context, self._resource, request.context.tenant_id)
     return collection
Exemple #5
0
    def _exclude_attributes_by_policy(self, context, resource, data):
        """Identifies attributes to exclude according to authZ policies.

        Return a list of attribute names which should be stripped from the
        response returned to the user because the user is not authorized
        to see them.
        """
        attributes_to_exclude = []
        for attr_name in data.keys():
            attr_data = attribute_population._attributes_for_resource(
                resource).get(attr_name)
            if attr_data and attr_data['is_visible']:
                if policy.check(
                    context,
                    # NOTE(kevinbenton): this used to reference a
                    # _plugin_handlers dict, why?
                    'get_%s:%s' % (resource, attr_name),
                    data,
                    might_not_exist=True,
                    pluralized=attribute_population._plural(resource)):
                    # this attribute is visible, check next one
                    continue
            # if the code reaches this point then either the policy check
            # failed or the attribute was not visible in the first place
            attributes_to_exclude.append(attr_name)
        return attributes_to_exclude
Exemple #6
0
 def _items(self, request, do_authz=False, parent_id=None):
     """Retrieves and formats a list of elements of the requested entity."""
     # NOTE(salvatore-orlando): The following ensures that fields which
     # are needed for authZ policy validation are not stripped away by the
     # plugin before returning.
     original_fields, fields_to_add = self._do_field_list(
         api_common.list_args(request, 'fields'))
     filters = api_common.get_filters(request, self._attr_info, [
         'fields', 'sort_key', 'sort_dir', 'limit', 'marker', 'page_reverse'
     ])
     kwargs = {'filters': filters, 'fields': original_fields}
     sorting_helper = self._get_sorting_helper(request)
     pagination_helper = self._get_pagination_helper(request)
     sorting_helper.update_args(kwargs)
     sorting_helper.update_fields(original_fields, fields_to_add)
     pagination_helper.update_args(kwargs)
     pagination_helper.update_fields(original_fields, fields_to_add)
     if parent_id:
         kwargs[self._parent_id_name] = parent_id
     obj_getter = getattr(self._plugin, self._plugin_handlers[self.LIST])
     obj_list = obj_getter(request.context, **kwargs)
     obj_list = sorting_helper.sort(obj_list)
     obj_list = pagination_helper.paginate(obj_list)
     # Check authz
     if do_authz:
         # FIXME(salvatore-orlando): obj_getter might return references to
         # other resources. Must check authZ on them too.
         # Omit items from list that should not be visible
         obj_list = [
             obj for obj in obj_list
             if policy.check(request.context,
                             self._plugin_handlers[self.SHOW],
                             obj,
                             plugin=self._plugin,
                             pluralized=self._collection)
         ]
     # Use the first element in the list for discriminating which attributes
     # should be filtered out because of authZ policies
     # fields_to_add contains a list of attributes added for request policy
     # checks but that were not required by the user. They should be
     # therefore stripped
     fields_to_strip = fields_to_add or []
     if obj_list:
         fields_to_strip += self._exclude_attributes_by_policy(
             request.context, obj_list[0])
     collection = {
         self._collection: [
             self._filter_attributes(obj, fields_to_strip=fields_to_strip)
             for obj in obj_list
         ]
     }
     pagination_links = pagination_helper.get_links(obj_list)
     if pagination_links:
         collection[self._collection + "_links"] = pagination_links
     # Synchronize usage trackers, if needed
     resource_registry.resync_resource(request.context, self._resource,
                                       request.context.tenant_id)
     return collection
Exemple #7
0
 def _test_check_system_admin_allowed_action(self, enforce_new_defaults):
     action = "example:only_system_admin_allowed"
     cfg.CONF.set_override('enforce_new_defaults',
                           enforce_new_defaults,
                           group='oslo_policy')
     project_admin_ctx = context.Context(
         user="******",
         project_id="fake",
         roles=['admin', 'member', 'reader'])
     system_admin_ctx = context.Context(user="******",
                                        project_id="fake",
                                        roles=['admin', 'member', 'reader'],
                                        system_scope='all')
     self.assertTrue(policy.check(system_admin_ctx, action, self.target))
     if enforce_new_defaults:
         self.assertFalse(
             policy.check(project_admin_ctx, action, self.target))
     else:
         self.assertTrue(
             policy.check(project_admin_ctx, action, self.target))
Exemple #8
0
 def test_check_invalid_scope(self):
     cfg.CONF.set_override('enforce_new_defaults',
                           True,
                           group='oslo_policy')
     cfg.CONF.set_override('enforce_scope', True, group='oslo_policy')
     action = "get_example:only_project_user_allowed"
     target = {'project_id': 'some-project'}
     system_admin_ctx = context.Context(user="******",
                                        roles=['admin', 'member', 'reader'],
                                        system_scope='all')
     self.assertFalse(policy.check(system_admin_ctx, action, target))
Exemple #9
0
 def _items(self, request, do_authz=False, parent_id=None):
     """Retrieves and formats a list of elements of the requested entity."""
     # NOTE(salvatore-orlando): The following ensures that fields which
     # are needed for authZ policy validation are not stripped away by the
     # plugin before returning.
     original_fields, fields_to_add = self._do_field_list(api_common.list_args(request, "fields"))
     filters = api_common.get_filters(
         request, self._attr_info, ["fields", "sort_key", "sort_dir", "limit", "marker", "page_reverse"]
     )
     kwargs = {"filters": filters, "fields": original_fields}
     sorting_helper = self._get_sorting_helper(request)
     pagination_helper = self._get_pagination_helper(request)
     sorting_helper.update_args(kwargs)
     sorting_helper.update_fields(original_fields, fields_to_add)
     pagination_helper.update_args(kwargs)
     pagination_helper.update_fields(original_fields, fields_to_add)
     if parent_id:
         kwargs[self._parent_id_name] = parent_id
     obj_getter = getattr(self._plugin, self._plugin_handlers[self.LIST])
     obj_list = obj_getter(request.context, **kwargs)
     obj_list = sorting_helper.sort(obj_list)
     obj_list = pagination_helper.paginate(obj_list)
     # Check authz
     if do_authz:
         # FIXME(salvatore-orlando): obj_getter might return references to
         # other resources. Must check authZ on them too.
         # Omit items from list that should not be visible
         obj_list = [
             obj
             for obj in obj_list
             if policy.check(request.context, self._plugin_handlers[self.SHOW], obj, plugin=self._plugin)
         ]
     # Use the first element in the list for discriminating which attributes
     # should be filtered out because of authZ policies
     # fields_to_add contains a list of attributes added for request policy
     # checks but that were not required by the user. They should be
     # therefore stripped
     fields_to_strip = fields_to_add or []
     if obj_list:
         fields_to_strip += self._exclude_attributes_by_policy(request.context, obj_list[0])
     collection = {
         self._collection: [
             self._filter_attributes(request.context, obj, fields_to_strip=fields_to_strip) for obj in obj_list
         ]
     }
     pagination_links = pagination_helper.get_links(obj_list)
     if pagination_links:
         collection[self._collection + "_links"] = pagination_links
     return collection
Exemple #10
0
    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))
Exemple #11
0
    def _items(self, request, do_authz=False, parent_id=None):
        """Retrieves and formats a list of elements of the requested entity."""
        # NOTE(salvatore-orlando): The following ensures that fields which
        # are needed for authZ policy validation are not stripped away by the
        # plugin before returning.
        original_fields, fields_to_add = self._do_field_list(
            api_common.list_args(request, 'fields'))
        filters = api_common.get_filters(request, self._attr_info, [
            'fields', 'sort_key', 'sort_dir', 'limit', 'marker', 'page_reverse'
        ])
        kwargs = {'filters': filters, 'fields': original_fields}
        sorting_helper = self._get_sorting_helper(request)
        pagination_helper = self._get_pagination_helper(request)
        sorting_helper.update_args(kwargs)
        sorting_helper.update_fields(original_fields, fields_to_add)
        pagination_helper.update_args(kwargs)
        pagination_helper.update_fields(original_fields, fields_to_add)
        if parent_id:
            kwargs[self._parent_id_name] = parent_id
        obj_getter = getattr(self._plugin, self._plugin_handlers[self.LIST])
        obj_list = obj_getter(request.context, **kwargs)
        obj_list = sorting_helper.sort(obj_list)
        obj_list = pagination_helper.paginate(obj_list)
        # Check authz
        if do_authz:
            # FIXME(salvatore-orlando): obj_getter might return references to
            # other resources. Must check authZ on them too.
            # Omit items from list that should not be visible
            obj_list = [
                obj for obj in obj_list
                if policy.check(request.context,
                                self._plugin_handlers[self.SHOW],
                                obj,
                                plugin=self._plugin)
            ]
        collection = {
            self._collection: [
                self._view(request.context, obj, fields_to_strip=fields_to_add)
                for obj in obj_list
            ]
        }
        pagination_links = pagination_helper.get_links(obj_list)
        if pagination_links:
            collection[self._collection + "_links"] = pagination_links

        return collection
Exemple #12
0
    def _items(self, request, do_authz=False, parent_id=None):
        """Retrieves and formats a list of elements of the requested entity."""
        # NOTE(salvatore-orlando): The following ensures that fields which
        # are needed for authZ policy validation are not stripped away by the
        # plugin before returning.
        original_fields, fields_to_add = self._do_field_list(
            api_common.list_args(request, 'fields'))
        filters = api_common.get_filters(request, self._attr_info,
                                         ['fields', 'sort_key', 'sort_dir',
                                          'limit', 'marker', 'page_reverse'])
        kwargs = {'filters': filters,
                  'fields': original_fields}
        sorting_helper = self._get_sorting_helper(request)
        pagination_helper = self._get_pagination_helper(request)
        sorting_helper.update_args(kwargs)
        sorting_helper.update_fields(original_fields, fields_to_add)
        pagination_helper.update_args(kwargs)
        pagination_helper.update_fields(original_fields, fields_to_add)
        if parent_id:
            kwargs[self._parent_id_name] = parent_id
        obj_getter = getattr(self._plugin, self._plugin_handlers[self.LIST])
        obj_list = obj_getter(request.context, **kwargs)
        obj_list = sorting_helper.sort(obj_list)
        obj_list = pagination_helper.paginate(obj_list)
        # Check authz
        if do_authz:
            # FIXME(salvatore-orlando): obj_getter might return references to
            # other resources. Must check authZ on them too.
            # Omit items from list that should not be visible
            obj_list = [obj for obj in obj_list
                        if policy.check(request.context,
                                        self._plugin_handlers[self.SHOW],
                                        obj,
                                        plugin=self._plugin)]
        collection = {self._collection:
                      [self._view(request.context, obj,
                                  fields_to_strip=fields_to_add)
                       for obj in obj_list]}
        pagination_links = pagination_helper.get_links(obj_list)
        if pagination_links:
            collection[self._collection + "_links"] = pagination_links

        return collection
Exemple #13
0
    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))
Exemple #14
0
    def _exclude_attributes_by_policy(self, context, data):
        """Identifies attributes to exclude according to authZ policies.

        Return a list of attribute names which should be stripped from the
        response returned to the user because the user is not authorized
        to see them.
        """
        attributes_to_exclude = []
        for attr_name in data.keys():
            attr_data = self._attr_info.get(attr_name)
            if attr_data and attr_data["is_visible"]:
                if policy.check(
                    context, "%s:%s" % (self._plugin_handlers[self.SHOW], attr_name), data, might_not_exist=True
                ):
                    # this attribute is visible, check next one
                    continue
            # if the code reaches this point then either the policy check
            # failed or the attribute was not visible in the first place
            attributes_to_exclude.append(attr_name)
        return attributes_to_exclude
    def _exclude_attributes_by_policy(self, context, controller, resource,
                                      collection, data):
        """Identifies attributes to exclude according to authZ policies.

        Return a list of attribute names which should be stripped from the
        response returned to the user because the user is not authorized
        to see them.
        """
        attributes_to_exclude = []
        for attr_name in data.keys():
            # TODO(amotoki): All attribute maps have tenant_id and
            # it determines excluded attributes based on tenant_id.
            # We need to migrate tenant_id to project_id later
            # as attr_info is referred to in various places and we need
            # to check all logs carefully.
            if attr_name == 'project_id':
                continue
            attr_data = controller.resource_info.get(attr_name)
            if attr_data and attr_data['is_visible']:
                if policy.check(
                    context,
                    # NOTE(kevinbenton): this used to reference a
                    # _plugin_handlers dict, why?
                    'get_%s:%s' % (resource, attr_name),
                    data,
                    might_not_exist=True,
                    pluralized=collection):
                    # this attribute is visible, check next one
                    continue
            # if the code reaches this point then either the policy check
            # failed or the attribute was not visible in the first place
            attributes_to_exclude.append(attr_name)
            # TODO(amotoki): As mentioned in the above TODO,
            # we treat project_id and tenant_id equivalently.
            # This should be migrated to project_id later.
            if attr_name == 'tenant_id':
                attributes_to_exclude.append('project_id')
        if attributes_to_exclude:
            LOG.debug("Attributes excluded by policy engine: %s",
                      attributes_to_exclude)
        return attributes_to_exclude
Exemple #16
0
    def _exclude_attributes_by_policy(self, context, controller, resource,
                                      collection, data):
        """Identifies attributes to exclude according to authZ policies.

        Return a list of attribute names which should be stripped from the
        response returned to the user because the user is not authorized
        to see them.
        """
        attributes_to_exclude = []
        for attr_name in list(data):
            # TODO(amotoki): All attribute maps have tenant_id and
            # it determines excluded attributes based on tenant_id.
            # We need to migrate tenant_id to project_id later
            # as attr_info is referred to in various places and we need
            # to check all logs carefully.
            if attr_name == 'project_id':
                continue
            attr_data = controller.resource_info.get(attr_name)
            if attr_data and attr_data['is_visible']:
                if policy.check(
                        context,
                        # NOTE(kevinbenton): this used to reference a
                        # _plugin_handlers dict, why?
                        'get_%s:%s' % (resource, attr_name),
                        data,
                        might_not_exist=True,
                        pluralized=collection):
                    # this attribute is visible, check next one
                    continue
            # if the code reaches this point then either the policy check
            # failed or the attribute was not visible in the first place
            attributes_to_exclude.append(attr_name)
            # TODO(amotoki): As mentioned in the above TODO,
            # we treat project_id and tenant_id equivalently.
            # This should be migrated to project_id later.
            if attr_name == 'tenant_id':
                attributes_to_exclude.append('project_id')
        if attributes_to_exclude:
            LOG.debug("Attributes excluded by policy engine: %s",
                      attributes_to_exclude)
        return attributes_to_exclude
Exemple #17
0
    def _exclude_attributes_by_policy(self, context, data):
        """Identifies attributes to exclude according to authZ policies.

        Return a list of attribute names which should be stripped from the
        response returned to the user because the user is not authorized
        to see them.
        """
        attributes_to_exclude = []
        for attr_name in data.keys():
            attr_data = self._attr_info.get(attr_name)
            if attr_data and attr_data['is_visible']:
                if policy.check(context,
                                '%s:%s' %
                                (self._plugin_handlers[self.SHOW], attr_name),
                                data,
                                might_not_exist=True):
                    # this attribute is visible, check next one
                    continue
            # if the code reaches this point then either the policy check
            # failed or the attribute was not visible in the first place
            attributes_to_exclude.append(attr_name)
        return attributes_to_exclude
    def _get_items_by_filter_and_order_and_page(self,
                                                request,
                                                kwargs,
                                                original_fields=None,
                                                fields_to_add=None,
                                                do_authz=False,
                                                parent_id=None):
        """
        get resource items by filters,order,and page

        """
        sorting_helper = self._get_sorting_helper(request)  #convert sort
        pagination_helper = self._get_pagination_helper(
            request)  #convert paging
        sorting_helper.update_args(kwargs)  #add sort to kwargs
        sorting_helper.update_fields(original_fields, fields_to_add)
        pagination_helper.update_args(kwargs)  #add page to kwargs
        pagination_helper.update_fields(original_fields, fields_to_add)
        if parent_id:
            kwargs[self._parent_id_name] = parent_id
        obj_getter = getattr(self._plugin, self._plugin_handlers[self.LIST])

        obj_list = obj_getter(request.context, **kwargs)
        obj_list = sorting_helper.sort(obj_list)
        obj_list = pagination_helper.paginate(obj_list)
        # Check authz
        if do_authz and obj_list:
            # FIXME(salvatore-orlando): obj_getter might return references to
            # other resources. Must check authZ on them too.
            # Omit items from list that should not be visible
            obj_list = [
                obj for obj in obj_list
                if policy.check(request.context,
                                self._plugin_handlers[self.SHOW],
                                obj,
                                plugin=self._plugin)
            ]
        return obj_list, pagination_helper
Exemple #19
0
    def _exclude_attributes_by_policy(self, context, data):
        """Identifies attributes to exclude according to authZ policies.

        Return a list of attribute names which should be stripped from the
        response returned to the user because the user is not authorized
        to see them.
        """
        LOG.info('%s(): caller(): %s', log_utils.get_fname(1),
                 log_utils.get_fname(2))
        attributes_to_exclude = []
        for attr_name in data.keys():
            # TODO(amotoki): At now, all attribute maps have tenant_id and
            # determine excluded attributes based on tenant_id.
            # We need to migrate tenant_id to project_id later
            # as attr_info is referred to in various places and we need
            # to check all logis carefully.
            if attr_name == 'project_id':
                continue
            attr_data = self._attr_info.get(attr_name)
            if attr_data and attr_data['is_visible']:
                if policy.check(context,
                                '%s:%s' %
                                (self._plugin_handlers[self.SHOW], attr_name),
                                data,
                                might_not_exist=True,
                                pluralized=self._collection):
                    # this attribute is visible, check next one
                    continue
            # if the code reaches this point then either the policy check
            # failed or the attribute was not visible in the first place
            attributes_to_exclude.append(attr_name)
            # TODO(amotoki): As mentioned in the above TODO,
            # we treat project_id and tenant_id equivalently.
            # This should be migrated to project_id in Ocata.
            if attr_name == 'tenant_id':
                attributes_to_exclude.append('project_id')

        return attributes_to_exclude
Exemple #20
0
    def _exclude_attributes_by_policy(self, context, data):
        """Identifies attributes to exclude according to authZ policies.

        Return a list of attribute names which should be stripped from the
        response returned to the user because the user is not authorized
        to see them.
        """
        attributes_to_exclude = []
        for attr_name in data.keys():
            # TODO(amotoki): At now, all attribute maps have tenant_id and
            # determine excluded attributes based on tenant_id.
            # We need to migrate tenant_id to project_id later
            # as attr_info is referred to in various places and we need
            # to check all logis carefully.
            if attr_name == 'project_id':
                continue
            attr_data = self._attr_info.get(attr_name)
            if attr_data and attr_data['is_visible']:
                if policy.check(
                        context,
                        '%s:%s' % (self._plugin_handlers[self.SHOW],
                                   attr_name),
                        data,
                        might_not_exist=True,
                        pluralized=self._collection):
                    # this attribute is visible, check next one
                    continue
            # if the code reaches this point then either the policy check
            # failed or the attribute was not visible in the first place
            attributes_to_exclude.append(attr_name)
            # TODO(amotoki): As mentioned in the above TODO,
            # we treat project_id and tenant_id equivalently.
            # This should be migrated to project_id in Ocata.
            if attr_name == 'tenant_id':
                attributes_to_exclude.append('project_id')

        return attributes_to_exclude
Exemple #21
0
    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[n_const.ATTRIBUTES_TO_UPDATE] = body[self._resource].keys()
        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)

        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
Exemple #22
0
 def test_firewall_policy_insert_rule_with_admin_context(self):
     action = "insert_rule"
     target = {}
     result = policy.check(context.get_admin_context(), action, target)
     self.assertTrue(result)
Exemple #23
0
 def _check_view_auth(self, context, resource, action):
     return policy.check(context, action, resource)
 def _check_external_router_policy(self, context):
     return policy.check(context, "get_network", self._network_definition())
Exemple #25
0
    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
Exemple #26
0
 def _check_provider_view_auth(self, context, network):
     return policy.check(context, "extension:provider_network:view",
                         network)
Exemple #27
0
 def test_firewall_policy_remove_rule_without_admin_or_owner(self):
     action = "remove_rule"
     target = {"firewall_rule_id": "rule_id", "tenant_id": "tenantA"}
     user_context = context.Context('', "another_tenant", roles=['user'])
     result = policy.check(user_context, action, target)
     self.assertFalse(result)
Exemple #28
0
 def test_check_bad_action_noraise(self):
     action = "example:denied"
     result = policy.check(self.context, action, self.target)
     self.assertEqual(result, False)
Exemple #29
0
 def test_firewall_policy_insert_rule_with_owner(self):
     action = "insert_rule"
     target = {"tenant_id": "own_tenant"}
     user_context = context.Context('', "own_tenant", roles=['user'])
     result = policy.check(user_context, action, target)
     self.assertTrue(result)
Exemple #30
0
    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] = list(item)
                # 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.
                    controller = utils.get_controller(state)
                    s_action = controller.plugin_handlers[controller.SHOW]
                    if not policy.check(
                            neutron_context, s_action, item,
                            pluralized=collection):
                        ctxt.reraise = False
                msg = _('The resource could not be found.')
                raise webob.exc.HTTPNotFound(msg)
Exemple #31
0
 def test_firewall_policy_remove_rule_without_admin_or_owner(self):
     action = "remove_rule"
     target = {"firewall_rule_id": "rule_id", "tenant_id": "tenantA"}
     user_context = context.Context('', "another_tenant", roles=['user'])
     result = policy.check(user_context, action, target)
     self.assertFalse(result)
Exemple #32
0
 def test_firewall_policy_insert_rule_with_owner(self):
     action = "insert_rule"
     target = {"tenant_id": "own_tenant"}
     user_context = context.Context('', "own_tenant", roles=['user'])
     result = policy.check(user_context, action, target)
     self.assertTrue(result)
Exemple #33
0
 def test_firewall_policy_insert_rule_with_admin_context(self):
     action = "insert_rule"
     target = {}
     result = policy.check(context.get_admin_context(), action, target)
     self.assertTrue(result)
Exemple #34
0
 def test_check_bad_action_noraise(self):
     action = "example:denied"
     result = policy.check(self.context, action, self.target)
     self.assertEqual(result, False)
 def _check_provider_view_auth(self, context, network):
     return policy.check(context,
                         "extension:provider_network:view",
                         network)
    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.
                    controller = utils.get_controller(state)
                    s_action = controller.plugin_handlers[controller.SHOW]
                    if not policy.check(neutron_context, s_action, item,
                                        pluralized=collection):
                        ctxt.reraise = False
                msg = _('The resource could not be found.')
                raise webob.exc.HTTPNotFound(msg)
Exemple #37
0
 def _check_external_router_policy(self, context):
     return policy.check(context, 'get_network', self._network_definition())
Exemple #38
0
 def _check_view_auth(self, context, resource, action):
     return policy.check(context, action, resource)