gluon/gluon/api/hooks/policy_enforcement.py

119 lines
3.6 KiB
Python

# Copyright 2016 Nokia
# 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.
import json
import webob
from oslo_config import cfg
from oslo_policy import policy as oslo_policy
# from oslo_utils import excutils
from pecan import hooks
from pecan.routing import lookup_controller
from gluon import constants as gluon_constants
from gluon.particleGenerator.ApiGenerator import API_OBJECT_CLASSES
from gluon import policy
# from gluon._i18n import _
class PolicyHook(hooks.PecanHook):
priority = 100
def before(self, state):
if cfg.CONF.api.auth_strategy == 'noauth':
return
if state.request.method not in ('GET', 'POST', 'PUT', 'DELETE'):
return
method = generateMethod(state)
path_info = state.request.path_info
if not path_info:
return
resource = state.request.context.get('resource')
if not resource:
return
service = path_info.split("/")[2]
action = "%s:%s_%s" % (service, method, resource)
gluon_context = state.request.context.get('gluon_context')
policy.init()
target = generateTarget(state, service, resource)
try:
policy.enforce(
gluon_context, action, target)
except oslo_policy.PolicyNotAuthorized as e:
raise webob.exc.HTTPForbidden(str(e))
def after(self, state):
# This method could be used for implementing access control
# at the attribute level.
return
# The policy enforce function requires target parameter
# oslo_policy doc descripbes target param as: "As much information about the
# object being operated on as possible"
# For delete and get, prefetch data from database and put tenant_id into target
# For post and put, get all user inputs from request body and put into target
def generateTarget(state, service, resource):
target = {}
method = state.request.method
if method in ('GET', 'DELETE') and state.arguments.args:
api_object_class = API_OBJECT_CLASSES[service][resource]
key = state.arguments.args[0]
obj = api_object_class.get_from_db(key)
tenant_id = obj.tenant_id
target['tenant_id'] = tenant_id
if method in ('POST', 'PUT'):
request_body = json.loads(state.request.body)
target = request_body
return target
# method could be 'get' or 'list' for the http get method
# If there is a key specified, method is 'get'
# If there is no key specified, method is 'list
def generateMethod(state):
method = state.request.method
if method == 'GET' and not state.arguments.args:
method = 'list'
else:
method = gluon_constants.ACTION_MAP[state.request.method]
return method
def findContrller(state):
path = state.request.path_info
pathList = path.split('/')[1:]
controller = state.app.root
resource = state.request.context.get('resource')
if pathList:
for item in pathList:
controller = getattr(controller, item)
if resource == item:
return controller
else:
return controller