[Zope3-checkins] CVS: Zope3/src/zope/security - checker.py:1.22.2.1
Marius Gedminas
mgedmin@codeworks.lt
Wed, 14 May 2003 06:39:36 -0400
Update of /cvs-repository/Zope3/src/zope/security
In directory cvs.zope.org:/tmp/cvs-serv2024/src/zope/security
Modified Files:
Tag: stevea-decorators-branch
checker.py
Log Message:
Refactored WATCH_CHECKERS from base Checker code into a separate mixin class.
New class: DecoratedChecker.
Some work on the global decorator service.
=== Zope3/src/zope/security/checker.py 1.22 => 1.22.2.1 ===
--- Zope3/src/zope/security/checker.py:1.22 Sat May 3 12:38:17 2003
+++ Zope3/src/zope/security/checker.py Wed May 14 06:39:05 2003
@@ -20,7 +20,7 @@
import types
import datetime
-from zope.interface import directlyProvides, Interface
+from zope.interface import directlyProvides, implements, Interface
from zope.interface.interfaces import IInterface, IInterfaceSpecification
from zope.interface.declarations import ObjectSpecification
from zope.interface.declarations import ProvidesSpecification
@@ -34,6 +34,8 @@
from zope.exceptions \
import Unauthorized, ForbiddenAttribute, DuplicationError
+__metaclass__ = type
+
if os.environ.get('ZOPE_WATCH_CHECKERS'):
WATCH_CHECKERS = True
else:
@@ -117,64 +119,36 @@
def check_setattr(self, object, name):
'See IChecker'
- if WATCH_CHECKERS:
- print >> sys.stderr, ('Checking %r.%s:' % (object, name)),
-
- # We have the information we need already
permission = self._setattr_permission_func(name)
- if permission:
+ if permission is not None:
if permission is CheckerPublic:
- if WATCH_CHECKERS:
- print >> sys.stderr, 'Public.'
return # Public
manager = getSecurityManager()
if manager.checkPermission(permission, object):
- if WATCH_CHECKERS:
- print >> sys.stderr, 'Granted.'
return
else:
- if WATCH_CHECKERS:
- print >> sys.stderr, 'Unauthorized.'
__traceback_supplement__ = (TracebackSupplement, object)
raise Unauthorized(name=name)
- if WATCH_CHECKERS:
- print >> sys.stderr, 'Forbidden.'
-
__traceback_supplement__ = (TracebackSupplement, object)
raise ForbiddenAttribute(name)
def check(self, object, name):
'See IChecker'
- if WATCH_CHECKERS:
- print >> sys.stderr, ('Checking %r.%s:' % (object, name)),
-
- # We have the information we need already
permission = self._permission_func(name)
- if permission:
+ if permission is not None:
if permission is CheckerPublic:
- if WATCH_CHECKERS:
- print >> sys.stderr, 'Public.'
return # Public
manager = getSecurityManager()
if manager.checkPermission(permission, object):
- if WATCH_CHECKERS:
- print >> sys.stderr, 'Granted.'
return
else:
- if WATCH_CHECKERS:
- print >> sys.stderr, 'Unauthorized.'
__traceback_supplement__ = (TracebackSupplement, object)
raise Unauthorized(name=name)
elif name in _always_available:
- if WATCH_CHECKERS:
- print >> sys.stderr, 'Always available.'
return
- if WATCH_CHECKERS:
- print >> sys.stderr, 'Forbidden.'
-
__traceback_supplement__ = (TracebackSupplement, object)
raise ForbiddenAttribute(name)
@@ -190,6 +164,164 @@
return Proxy(value, checker)
+class CheckerLoggingMixin:
+ """Debugging mixin for Checker.
+
+ Prints verbose debugging information about every performed check to
+ sys.stderr.
+
+ This class relies on the class it's mixed into having permission_id
+ and setattr_permission_id methods.
+ """
+
+ def check(self, object, name):
+ print >> sys.stderr, ('Checking %r.%s:' % (object, name)),
+ try:
+ super(CheckerLoggingMixin, self).check(object, name)
+ if name in _always_available:
+ print >> sys.stderr, 'Always available.'
+ elif self.permission_id(name) is CheckerPublic:
+ print >> sys.stderr, 'Public.'
+ else:
+ print >> sys.stderr, 'Granted.'
+ except Unauthorized:
+ print >> sys.stderr, 'Unauthorized.'
+ raise
+ except ForbiddenAttribute:
+ print >> sys.stderr, 'Forbidden.'
+ raise
+
+ def check_getattr(self, object, name):
+ print >> sys.stderr, ('Checking get %r.%s:' % (object, name)),
+ try:
+ super(CheckerLoggingMixin, self).check(object, name)
+ if name in _always_available:
+ print >> sys.stderr, 'Always available.'
+ elif self.permission_id(name) is CheckerPublic:
+ print >> sys.stderr, 'Public.'
+ else:
+ print >> sys.stderr, 'Granted.'
+ except Unauthorized:
+ print >> sys.stderr, 'Unauthorized.'
+ raise
+ except ForbiddenAttribute:
+ print >> sys.stderr, 'Forbidden.'
+ raise
+
+ def check_setattr(self, object, name):
+ print >> sys.stderr, ('Checking set %r.%s:' % (object, name)),
+ try:
+ super(CheckerLoggingMixin, self).check_setattr(object, name)
+ if self.setattr_permission_id(name) is CheckerPublic:
+ print >> sys.stderr, 'Public.'
+ else:
+ print >> sys.stderr, 'Granted.'
+ except Unauthorized:
+ print >> sys.stderr, 'Unauthorized.'
+ raise
+ except ForbiddenAttribute:
+ print >> sys.stderr, 'Forbidden.'
+ raise
+
+
+class DecoratedChecker:
+ """A checker using further permissions relative to an original checker.
+ """
+
+ implements(IChecker)
+
+ def __init__(self, original_checker, permission_func,
+ setattr_permission_func=lambda name: None
+ ):
+ """Create a checker
+
+ A dictionary or a callable must be provided for computing permissions
+ for names. The callable will be called with attribute names and must
+ return a permission id, None, or the special marker, CheckerPublic. If
+ None is returned, then access to the name is decided by
+ original_checker. If CheckerPublic is returned, then access will be
+ granted without checking a permission.
+
+ An optional setattr permission function or dictionary may be
+ provided for checking set attribute access.
+ """
+ self._original_checker = original_checker
+
+ if type(permission_func) is dict:
+ permission_func = permission_func.get
+ self._permission_func = permission_func
+
+ if type(setattr_permission_func) is dict:
+ setattr_permission_func = setattr_permission_func.get
+ self._setattr_permission_func = setattr_permission_func
+
+ def permission_id(self, name):
+ permission = self._permission_func(name)
+ if permission is None:
+ permission = self._original_checker.permission_id(name)
+ return permission
+
+ def setattr_permission_id(self, name):
+ permission = self._setattr_permission_func(name)
+ if permission is None:
+ permission = self._original_checker.setattr_permission_id(name)
+ return permission
+
+ def check(self, object, name):
+ permission = self._permission_func(name)
+ if permission is not None:
+ if permission is CheckerPublic:
+ return # Public
+ manager = getSecurityManager()
+ if manager.checkPermission(permission, object):
+ return
+ else:
+ __traceback_supplement__ = (TracebackSupplement, object)
+ raise Unauthorized(name=name)
+ else:
+ # let the original checker decide
+ self._original_checker.check(object, name)
+ return
+
+ def check_getattr(self, object, name):
+ permission = self._permission_func(name)
+ if permission is not None:
+ if permission is CheckerPublic:
+ return # Public
+ manager = getSecurityManager()
+ if manager.checkPermission(permission, object):
+ return
+ else:
+ __traceback_supplement__ = (TracebackSupplement, object)
+ raise Unauthorized(name=name)
+ else:
+ # let the original checker decide
+ self._original_checker.check_getattr(object, name)
+ return
+
+ def check_setattr(self, object, name):
+ permission = self._setattr_permission_func(name)
+ if permission is not None:
+ if permission is CheckerPublic:
+ return # Public
+ manager = getSecurityManager()
+ if manager.checkPermission(permission, object):
+ return
+ else:
+ __traceback_supplement__ = (TracebackSupplement, object)
+ raise Unauthorized(name=name)
+ else:
+ # let the original checker decide
+ self._original_checker.check_setattr(object, name)
+ return
+
+
+if WATCH_CHECKERS:
+ class Checker(CheckerLoggingMixin, Checker):
+ pass
+ class DecoratedChecker(CheckerLoggingMixin, DecoratedChecker):
+ pass
+
# Helper class for __traceback_supplement__
class TracebackSupplement:
@@ -398,6 +530,7 @@
+# It should really be called _available_by_default
_always_available = ['__lt__', '__le__', '__eq__',
'__gt__', '__ge__', '__ne__',
'__hash__', '__nonzero__',