This patch simplifies the process for validating the request body for POST and PUT requests and preparing it for dispatching to plugins. In particular it removes the need for parsing the URL to find the resource identifier, and instead leverages Pecan's routing engine to extract it. As a result the attribute population hook now simply deals with request body validation, and has been renamed accordingly. The logic for loading the current state of the object from the plugin in order to enforce authZ policy on PUT requests has been moved to the appropriate hook, PolicyEnforcementHook. The logic for managing plural/singular names for resource has also been improved, and two helper functions to retrieve a resource's attributes have been added to neutron.api.v2.attributes The logic for aborting requests with unsupported HTTP methods has also been moved to the REST controllers. It used to be in PolicyEnforcementHook, which was probably not the right thing to do. This patch also unskips a functional test concerning ownership checks, and add functional tests for verifying correct request processing. Unit tests for the newly added helper functions are also provided. Related blueprint wsgi-pecan-switch Change-Id: Ib26998b37bdeec8af7a97f77b66d421b8cd271da
57 lines
2.1 KiB
Python
57 lines
2.1 KiB
Python
# Copyright (c) 2015 Mirantis, Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
from pecan import hooks
|
|
import webob
|
|
|
|
from neutron._i18n import _
|
|
from neutron import manager
|
|
|
|
|
|
class OwnershipValidationHook(hooks.PecanHook):
|
|
|
|
priority = 125
|
|
|
|
def before(self, state):
|
|
if state.request.method != 'POST':
|
|
return
|
|
for item in state.request.context.get('resources', []):
|
|
self._validate_network_tenant_ownership(state, item)
|
|
|
|
def _validate_network_tenant_ownership(self, state, resource_item):
|
|
# TODO(salvatore-orlando): consider whether this check can be folded
|
|
# in the policy engine
|
|
neutron_context = state.request.context.get('neutron_context')
|
|
resource = state.request.context.get('resource')
|
|
if (neutron_context.is_admin or neutron_context.is_advsvc or
|
|
resource not in ('port', 'subnet')):
|
|
return
|
|
plugin = manager.NeutronManager.get_plugin()
|
|
network = plugin.get_network(neutron_context,
|
|
resource_item['network_id'])
|
|
# do not perform the check on shared networks
|
|
if network.get('shared'):
|
|
return
|
|
|
|
network_owner = network['tenant_id']
|
|
|
|
if network_owner != resource_item['tenant_id']:
|
|
msg = _("Tenant %(tenant_id)s not allowed to "
|
|
"create %(resource)s on this network")
|
|
raise webob.exc.HTTPForbidden(msg % {
|
|
"tenant_id": resource_item['tenant_id'],
|
|
"resource": resource,
|
|
})
|