From e8a77b6e1baa7158003d015512d4c101ff5cadae Mon Sep 17 00:00:00 2001 From: ShaoHe Feng Date: Thu, 11 Jun 2015 03:21:32 +0800 Subject: [PATCH] enhancement for the common policy enforce Now the magnum.common.policy just support an "enforce" method to wsgi policy check. And this "enforce" method should be inline the body of wsgi method. Such as: from magnum.common import policy class BaysController(rest.RestController): .... @wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=204) def delete(self, bay_ident): ... doc string ... policy.enforce(pecan.request.context, "bay:create") .... common stuff .... This inline style is ugly. Now this patch is improving it. This patch uses a decorator for policy check. With this decorator we can do the policy check as follow: from magnum.common import policy class BaysController(rest.RestController): .... @policy.enforce_wsgi("bay", "delete") @wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=204) def delete(self, bay_ident): ... Here: This decorator MUST appear first (the outermost decorator) on an API method for it to work correctly. The decorator use functools.wraps to decorator the wsgi function. A common decorator(without functools.wraps) replaces the original function with an new one, that means it will lose the information about the original function, it would be a serious problem for pcen wsgi. That's why we have functools.wraps. This takes a function used in a decorator and adds the functionality of copying over the function name, docstring, arguments list, etc. ref: http://stackoverflow.com/questions/308999/what-does-functools-wraps-do Co-Authored-By: yuntongjin Change-Id: I9a7baf9559ff924ca4e261db2961b9d3c8763325 Partial-implements: blueprint policy-enforce --- magnum/common/policy.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/magnum/common/policy.py b/magnum/common/policy.py index f19e11e299..7258002377 100644 --- a/magnum/common/policy.py +++ b/magnum/common/policy.py @@ -15,8 +15,10 @@ """Policy Engine For magnum.""" +import functools from oslo_config import cfg from oslo_policy import policy +import pecan _ENFORCER = None @@ -88,3 +90,30 @@ def enforce(context, action=None, target=None, 'user_id': context.user_id} return enforcer.enforce(action, target, credentials, do_raise=do_raise, exc=exc, *args, **kwargs) + + +# NOTE(Shaohe Feng): This decorator MUST appear first (the outermost +# decorator) on an API method for it to work correctly +def enforce_wsgi(api_name, act=None): + """This is a decorator to simplify wsgi action policy rule check. + :param api_name: The collection name to be evaluate. + :param act: The function name of wsgi action. + + example: + from magnum.common import policy + class BaysController(rest.RestController): + .... + @policy.enforce_wsgi("bay", "delete") + @wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=204) + def delete(self, bay_ident): + ... + """ + def wraper(fn): + action = "%s:%s" % (api_name, (act or fn.func_name)) + + @functools.wraps(fn) + def handle(self, *args, **kwargs): + enforce(pecan.request.context, action, None) + return fn(self, *args, **kwargs) + return handle + return wraper