Source code for score.auth._ruleset

from collections import OrderedDict
import logging
import warnings

log = logging.getLogger('score.auth')


[docs]class RuleSet: """ Stores :term:`rules <rule>` and handles :term:`operations <operation>` for classes. """ def __init__(self): self.rules = {}
[docs] def rule(self, operation, *args): """ Decorator for adding a :term:`rule` to this RuleSet. The function can be used in two different ways: Either it directly annotates a function … .. code-block:: python @ruleset.rule def sing(ctx): return ctx.actor.name == 'Stephen Hawking' … or it defines an operation and a list of argument types, which must match the types of the arguments of the call to :meth:`.RuleSet.permits`: .. code-block:: python @ruleset.rule('rewrite', Song) def rewrite_song(ctx, song): return True # songs may be rewritten at any time """ if callable(operation): if operation.__name__ not in self.rules: self.rules[operation.__name__] = OrderedDict() self.rules[operation.__name__][tuple()] = operation return operation def capturer(func): if operation not in self.rules: self.rules[operation] = OrderedDict() self.rules[operation][args] = func return func return capturer
[docs] def permits(self, ctx, operation, *args, raise_=False): """ Checks if given *operation* is allowed on given *args* in given *context*. """ for rule_args, rule_test in self.rules.get(operation, {}).items(): if len(args) != len(rule_args): continue for i, arg in enumerate(args): if not isinstance(args[i], rule_args[i]): break else: result = rule_test(ctx, *args) if not result and raise_: raise NotAuthorized(operation, args) log.debug({'operation': operation, 'args': args, 'result': result}) return result warnings.warn('No rules defined for operation "%s(%s)"' % (operation, ','.join(map(str, map(type, args))))) if raise_: raise NotAuthorized(operation, args) return False
class NotAuthorized(Exception): """ Thrown when the authorization for an operation failed. """ def __init__(self, operation, args): super().__init__('Context does not permit %s(%s)' % (operation, ','.join(map(str, map(type, args)))))