[Zope3-checkins] SVN: Zope3/trunk/src/zope/ Implemented Checker in
C for performance
Jim Fulton
jim at zope.com
Tue Jun 22 08:15:41 EDT 2004
Log message for revision 25933:
Implemented Checker in C for performance
-=-
Modified: Zope3/trunk/src/zope/app/tests/test_decorator.py
===================================================================
--- Zope3/trunk/src/zope/app/tests/test_decorator.py 2004-06-21 21:26:15 UTC (rev 25932)
+++ Zope3/trunk/src/zope/app/tests/test_decorator.py 2004-06-22 12:13:32 UTC (rev 25933)
@@ -108,8 +108,8 @@
>>> print selectChecker(w)
None
>>> c = w.__Security_checker__
- >>> print type(c)
- <class 'zope.security.checker.Checker'>
+ >>> c.__class__.__module__, c.__class__.__name__
+ ('zope.security.checker', 'Checker')
>>> c.check_getattr(w, 'a')
>>> check_forbidden_call(c.check_getattr, w, 'b')
@@ -135,8 +135,9 @@
>>> int(w.__Security_checker__ is None)
1
>>> w = MyDecorator2(None)
- >>> type(w.__Security_checker__)
- <class 'zope.security.checker.Checker'>
+ >>> c = w.__Security_checker__
+ >>> c.__class__.__module__, c.__class__.__name__
+ ('zope.security.checker', 'Checker')
"""
Modified: Zope3/trunk/src/zope/security/_zope_security_checker.c
===================================================================
--- Zope3/trunk/src/zope/security/_zope_security_checker.c 2004-06-21 21:26:15 UTC (rev 25932)
+++ Zope3/trunk/src/zope/security/_zope_security_checker.c 2004-06-22 12:13:32 UTC (rev 25933)
@@ -1,10 +1,397 @@
#include <Python.h>
-static PyObject *_checkers, *NoProxy;
-static PyObject *Proxy=NULL, *_defaultChecker, *Checker=NULL;
+static PyObject *_checkers, *_defaultChecker, *_always_available, *NoProxy;
+static PyObject *Proxy, *getSecurityPolicy, *queryInteraction, *CheckerPublic;
+static PyObject *ForbiddenAttribute, *Unauthorized;
+#define DECLARE_STRING(N) static PyObject *str_##N
+DECLARE_STRING(checkPermission);
+DECLARE_STRING(__Security_checker__);
+#define CLEAR(O) if (O) {PyObject *t = O; O = 0; Py_DECREF(t); }
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *getperms, *setperms;
+} Checker;
+
+/* def permission_id(self, name): */
+static PyObject *
+Checker_permission_id(Checker *self, PyObject *name)
+{
+/* return self._permission_func(name) */
+ PyObject *result;
+
+ if (self->getperms)
+ {
+ result = PyDict_GetItem(self->getperms, name);
+ if (result == NULL)
+ result = Py_None;
+ }
+ else
+ result = Py_None;
+
+ Py_INCREF(result);
+ return result;
+}
+
+/* def setattr_permission_id(self, name): */
+static PyObject *
+Checker_setattr_permission_id(Checker *self, PyObject *name)
+{
+/* return self._setattr_permission_func(name) */
+ PyObject *result;
+
+ if (self->setperms)
+ {
+ result = PyDict_GetItem(self->setperms, name);
+ if (result == NULL)
+ result = Py_None;
+ }
+ else
+ result = Py_None;
+
+ Py_INCREF(result);
+ return result;
+}
+
+static int
+checkPermission(PyObject *permission, PyObject *object, PyObject *name)
+{
+ PyObject *policy, *interaction, *r;
+ int i;
+
+/* policy = getSecurityPolicy() */
+ policy = PyObject_CallObject(getSecurityPolicy, NULL);
+ if (policy == NULL)
+ return -1;
+/* interaction = queryInteraction() */
+ interaction = PyObject_CallObject(queryInteraction, NULL);
+ if (interaction == NULL)
+ {
+ Py_DECREF(policy);
+ return -1;
+ }
+/* if policy.checkPermission(permission, object, interaction): */
+/* return */
+ r = PyObject_CallMethodObjArgs(policy, str_checkPermission,
+ permission, object, interaction, NULL);
+ Py_DECREF(policy);
+ Py_DECREF(interaction);
+ i = PyObject_IsTrue(r);
+ Py_DECREF(r);
+ if (i < 0)
+ return -1;
+ if (i)
+ return 0;
+/* else: */
+/* __traceback_supplement__ = (TracebackSupplement, object) */
+/* raise Unauthorized, name */
+ PyErr_SetObject(Unauthorized, name);
+ return -1;
+}
+
+
+/* def check(self, object, name): */
+static PyObject *
+Checker_check(Checker *self, PyObject *args)
+{
+ PyObject *object, *name, *permission=NULL;
+ int operator;
+
+ if (!PyArg_ParseTuple(args, "OO", &object, &name))
+ return NULL;
+
+/* permission = self._permission_func(name) */
+ if (self->getperms)
+ permission = PyDict_GetItem(self->getperms, name);
+
+/* if permission is not None: */
+ if (permission != NULL)
+ {
+/* if permission is CheckerPublic: */
+/* return # Public */
+ if (permission == CheckerPublic)
+ goto ok;
+
+ if (checkPermission(permission, object, name) < 0)
+ return NULL;
+ goto ok;
+ }
+
+
+ operator = (PyString_Check(name)
+ && PyString_AS_STRING(name)[0] == '_'
+ && PyString_AS_STRING(name)[1] == '_');
+
+ if (operator)
+ {
+/* elif name in _always_available: */
+/* return */
+ int ic = PySequence_Contains(_always_available, name);
+ if (ic < 0)
+ return NULL;
+ if (ic)
+ goto ok;
+
+/* if name != '__iter__' or hasattr(object, name): */
+/* __traceback_supplement__ = (TracebackSupplement, object) */
+/* raise ForbiddenAttribute, (name, object) */
+
+ if (strcmp("__iter__", PyString_AS_STRING(name)) == 0
+ && ! PyObject_HasAttr(object, name))
+ /* We want an attr error if we're asked for __iter__ and we don't
+ have it. We'll get one by allowing the access. */
+ goto ok;
+ }
+
+ args = Py_BuildValue("OO", name, object);
+ if (args != NULL)
+ {
+ PyErr_SetObject(ForbiddenAttribute, args);
+ Py_DECREF(args);
+ }
+ return NULL;
+
+ ok:
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+
+/* def check_setattr(self, object, name): */
+static PyObject *
+Checker_check_setattr(Checker *self, PyObject *args)
+{
+ PyObject *object, *name, *permission=NULL;
+
+ if (!PyArg_ParseTuple(args, "OO", &object, &name))
+ return NULL;
+
+/* permission = self._permission_func(name) */
+ if (self->setperms)
+ permission = PyDict_GetItem(self->setperms, name);
+
+/* if permission is not None: */
+ if (permission != NULL)
+ {
+/* if permission is CheckerPublic: */
+/* return # Public */
+ if (permission != CheckerPublic
+ && checkPermission(permission, object, name) < 0)
+ return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+/* __traceback_supplement__ = (TracebackSupplement, object) */
+/* raise ForbiddenAttribute, (name, object) */
+ args = Py_BuildValue("OO", name, object);
+ if (args != NULL)
+ {
+ PyErr_SetObject(ForbiddenAttribute, args);
+ Py_DECREF(args);
+ }
+ return NULL;
+}
+
+
+static PyObject *
+selectChecker(PyObject *ignored, PyObject *object);
+
+/* def proxy(self, value): */
+static PyObject *
+Checker_proxy(Checker *self, PyObject *value)
+{
+ PyObject *checker, *r;
+/* checker = getattr(value, '__Security_checker__', None) */
+ checker = PyObject_GetAttr(value, str___Security_checker__);
+/* if checker is None: */
+ if (checker == NULL)
+ {
+ PyErr_Clear();
+
+/* checker = selectChecker(value) */
+ checker = selectChecker(NULL, value);
+ if (checker == NULL)
+ return NULL;
+
+/* if checker is None: */
+/* return value */
+ if (checker == Py_None)
+ {
+ Py_DECREF(checker);
+ Py_INCREF(value);
+ return value;
+ }
+ }
+
+ r = PyObject_CallFunctionObjArgs(Proxy, value, checker, NULL);
+ Py_DECREF(checker);
+ return r;
+}
+
+/* return Proxy(value, checker) */
+
+
+static struct PyMethodDef Checker_methods[] = {
+ {"permission_id", (PyCFunction)Checker_permission_id, METH_O,
+ "permission_id(name) -- Return the permission neded to get the name"},
+ {"setattr_permission_id", (PyCFunction)Checker_setattr_permission_id,
+ METH_O,
+ "setattr_permission_id(name) -- Return the permission neded to set the name"
+ },
+ {"check_getattr", (PyCFunction)Checker_check, METH_VARARGS,
+ "check_getattr(object, name) -- Check whether a getattr is allowes"},
+ {"check_setattr", (PyCFunction)Checker_check_setattr, METH_VARARGS,
+ "check_setattr(object, name) -- Check whether a setattr is allowes"},
+ {"check", (PyCFunction)Checker_check, METH_VARARGS,
+ "check(object, opname) -- Check whether an operation is allowes"},
+ {"proxy", (PyCFunction)Checker_proxy, METH_O,
+ "proxy(object) -- Security-proxy an object"},
+
+ {NULL, NULL} /* sentinel */
+};
+
+static int
+Checker_clear(Checker *self)
+{
+ CLEAR(self->getperms);
+ CLEAR(self->setperms);
+ return 0;
+}
+
+static void
+Checker_dealloc(Checker *self)
+{
+ Checker_clear(self);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static int
+Checker_traverse(Checker *self, visitproc visit, void *arg)
+{
+ if (self->getperms != NULL && visit(self->getperms, arg) < 0)
+ return -1;
+ if (self->setperms != NULL && visit(self->setperms, arg) < 0)
+ return -1;
+
+ return 0;
+}
+
+static int
+Checker_init(Checker *self, PyObject *args, PyObject *kwds)
+{
+ PyObject *getperms, *setperms=NULL;
+ static char *kwlist[] = {"get_permissions", "set_permissions", NULL};
+
+ if (! PyArg_ParseTupleAndKeywords(args, kwds, "O!|O!:Checker", kwlist,
+ &PyDict_Type, &getperms,
+ &PyDict_Type, &setperms))
+ return -1;
+
+ Py_INCREF(getperms);
+ self->getperms = getperms;
+ Py_XINCREF(setperms);
+ self->setperms = setperms;
+
+ return 0;
+}
+
+static PyObject *
+Checker_get_get_permissions(Checker *self, void *closure)
+{
+ if (self->getperms == NULL)
+ {
+ self->getperms = PyDict_New();
+ if (self->getperms == NULL)
+ return NULL;
+ }
+
+ Py_INCREF(self->getperms);
+ return self->getperms;
+}
+
+static PyObject *
+Checker_get_set_permissions(Checker *self, void *closure)
+{
+ if (self->setperms == NULL)
+ {
+ self->setperms = PyDict_New();
+ if (self->setperms == NULL)
+ return NULL;
+ }
+
+ Py_INCREF(self->setperms);
+ return self->setperms;
+}
+
+static PyGetSetDef Checker_getset[] = {
+ {"get_permissions",
+ (getter)Checker_get_get_permissions, NULL,
+ "getattr name to permission dictionary",
+ NULL},
+ {"set_permissions",
+ (getter)Checker_get_set_permissions, NULL,
+ "setattr name to permission dictionary",
+ NULL},
+ {NULL} /* Sentinel */
+};
+
+
+static PyTypeObject CheckerType = {
+ PyObject_HEAD_INIT(NULL)
+ /* ob_size */ 0,
+ /* tp_name */ "zope.security.checker."
+ "Checker",
+ /* tp_basicsize */ sizeof(Checker),
+ /* tp_itemsize */ 0,
+ /* tp_dealloc */ (destructor)&Checker_dealloc,
+ /* tp_print */ (printfunc)0,
+ /* tp_getattr */ (getattrfunc)0,
+ /* tp_setattr */ (setattrfunc)0,
+ /* tp_compare */ (cmpfunc)0,
+ /* tp_repr */ (reprfunc)0,
+ /* tp_as_number */ 0,
+ /* tp_as_sequence */ 0,
+ /* tp_as_mapping */ 0,
+ /* tp_hash */ (hashfunc)0,
+ /* tp_call */ (ternaryfunc)0,
+ /* tp_str */ (reprfunc)0,
+ /* tp_getattro */ (getattrofunc)0,
+ /* tp_setattro */ (setattrofunc)0,
+ /* tp_as_buffer */ 0,
+ /* tp_flags */ Py_TPFLAGS_DEFAULT
+ | Py_TPFLAGS_BASETYPE
+ | Py_TPFLAGS_HAVE_GC,
+ /* tp_doc */ "Security checker",
+ /* tp_traverse */ (traverseproc)Checker_traverse,
+ /* tp_clear */ (inquiry)Checker_clear,
+ /* tp_richcompare */ (richcmpfunc)0,
+ /* tp_weaklistoffset */ (long)0,
+ /* tp_iter */ (getiterfunc)0,
+ /* tp_iternext */ (iternextfunc)0,
+ /* tp_methods */ Checker_methods,
+ /* tp_members */ 0,
+ /* tp_getset */ Checker_getset,
+ /* tp_base */ 0,
+ /* tp_dict */ 0, /* internal use */
+ /* tp_descr_get */ (descrgetfunc)0,
+ /* tp_descr_set */ (descrsetfunc)0,
+ /* tp_dictoffset */ 0,
+ /* tp_init */ (initproc)Checker_init,
+ /* tp_alloc */ (allocfunc)0,
+ /* tp_new */ (newfunc)0,
+ /* tp_free */ 0, /* Low-level free-mem routine */
+ /* tp_is_gc */ (inquiry)0, /* For PyObject_IS_GC */
+};
+
+
+
+
+
/* def selectChecker(object): */
/* """Get a checker for the given object */
/* The appropriate checker is returned or None is returned. If the */
@@ -23,28 +410,6 @@
{
PyObject *checker;
- /* Import names from checker is hasn't been done before */
- if (_defaultChecker == NULL)
- {
- checker = PyImport_ImportModule("zope.security.checker");
- if (checker == NULL)
- return NULL;
-
- Proxy = PyObject_GetAttrString(checker, "Proxy");
- if (Proxy == NULL)
- return NULL;
-
- Checker = PyObject_GetAttrString(checker, "Checker");
- if (Checker == NULL)
- return NULL;
-
- _defaultChecker = PyObject_GetAttrString(checker, "_defaultChecker");
- if (_defaultChecker == NULL)
- return NULL;
-
- Py_DECREF(checker);
- }
-
/* checker = _getChecker(type(object), _defaultChecker) */
checker = PyDict_GetItem(_checkers, (PyObject*)(object->ob_type));
@@ -76,7 +441,7 @@
/* return None */
Py_INCREF(checker);
- while (! PyObject_TypeCheck(checker, (PyTypeObject*)Checker))
+ while (! PyObject_TypeCheck(checker, &CheckerType))
{
PyObject *newchecker;
newchecker = PyObject_CallFunctionObjArgs(checker, object, NULL);
@@ -109,21 +474,67 @@
PyMODINIT_FUNC
init_zope_security_checker(void)
{
- PyObject* m;
+ PyObject* m;
- if ((_checkers = PyDict_New()) == NULL) return;
- NoProxy = PyObject_CallObject((PyObject*)&PyBaseObject_Type, NULL);
- if (NoProxy == NULL)
- return;
+ CheckerType.tp_new = PyType_GenericNew;
+ if (PyType_Ready(&CheckerType) < 0)
+ return;
- m = Py_InitModule3("_zope_security_checker", module_methods,
- "C optimizations for zope.security.checker");
+ _defaultChecker = PyObject_CallFunction((PyObject*)&CheckerType, "{}");
+ if (_defaultChecker == NULL)
+ return;
- if (m == NULL)
- return;
+#define INIT_STRING(S) \
+if((str_##S = PyString_InternFromString(#S)) == NULL) return
- Py_INCREF(_checkers);
- PyModule_AddObject(m, "_checkers", _checkers);
- Py_INCREF(NoProxy);
- PyModule_AddObject(m, "NoProxy", NoProxy);
+ INIT_STRING(checkPermission);
+ INIT_STRING(__Security_checker__);
+
+ if ((_checkers = PyDict_New()) == NULL)
+ return;
+
+ NoProxy = PyObject_CallObject((PyObject*)&PyBaseObject_Type, NULL);
+ if (NoProxy == NULL)
+ return;
+
+ if ((m = PyImport_ImportModule("zope.security._proxy")) == NULL) return;
+ if ((Proxy = PyObject_GetAttrString(m, "_Proxy")) == NULL) return;
+ Py_DECREF(m);
+
+ if ((m = PyImport_ImportModule("zope.security.management")) == NULL) return;
+ getSecurityPolicy = PyObject_GetAttrString(m, "getSecurityPolicy");
+ if (getSecurityPolicy == NULL) return;
+ queryInteraction = PyObject_GetAttrString(m, "queryInteraction");
+ if (queryInteraction == NULL) return;
+ Py_DECREF(m);
+
+ if ((m = PyImport_ImportModule("zope.exceptions")) == NULL) return;
+ ForbiddenAttribute = PyObject_GetAttrString(m, "ForbiddenAttribute");
+ if (ForbiddenAttribute == NULL) return;
+ Unauthorized = PyObject_GetAttrString(m, "Unauthorized");
+ if (Unauthorized == NULL) return;
+ Py_DECREF(m);
+
+ if ((m = PyImport_ImportModule("zope.security.checker")) == NULL) return;
+ CheckerPublic = PyObject_GetAttrString(m, "CheckerPublic");
+ if (CheckerPublic == NULL) return;
+ Py_DECREF(m);
+
+ if ((_always_available = PyList_New(0)) == NULL) return;
+
+ m = Py_InitModule3("_zope_security_checker", module_methods,
+ "C optimizations for zope.security.checker");
+
+ if (m == NULL)
+ return;
+
+#define EXPORT(N) Py_INCREF(N); PyModule_AddObject(m, #N, N)
+
+ EXPORT(_checkers);
+ EXPORT(NoProxy);
+ EXPORT(_defaultChecker);
+ EXPORT(_always_available);
+
+ Py_INCREF(&CheckerType);
+ PyModule_AddObject(m, "Checker", (PyObject *)&CheckerType);
}
Modified: Zope3/trunk/src/zope/security/checker.py
===================================================================
--- Zope3/trunk/src/zope/security/checker.py 2004-06-21 21:26:15 UTC (rev 25932)
+++ Zope3/trunk/src/zope/security/checker.py 2004-06-22 12:13:32 UTC (rev 25933)
@@ -91,11 +91,7 @@
directlyProvides(ProxyFactory, ISecurityProxyFactory)
-class TrustedCheckerBase:
- """Marker type used by zope.security.proxy.trustedRemoveSecurityProxy"""
-
-
-class Checker(TrustedCheckerBase):
+class Checker(object):
implements(INameBasedChecker)
def __init__(self, get_permissions, set_permissions=None):
@@ -184,139 +180,7 @@
return Proxy(value, checker)
-class CombinedChecker(Checker):
- """A checker that combines two other checkers in a logical-or fashion.
- The following table describes the result of a combined checker in detail.
-
- checker1 checker2 CombinedChecker(checker1, checker2)
- ------------------ ------------------ -----------------------------------
- ok anything ok (checker2 is never called)
- Unauthorized ok ok
- Unauthorized Unauthorized Unauthorized
- Unauthorized ForbiddenAttribute Unauthorized
- ForbiddenAttribute ok ok
- ForbiddenAttribute Unauthorized Unauthorized
- ForbiddenAttribute ForbiddenAttribute ForbiddenAttribute
- ------------------ ------------------ -----------------------------------
- """
- implements(IChecker)
-
- def __init__(self, checker1, checker2):
- """Create a combined checker."""
- Checker.__init__(self,
- checker1.get_permissions,
- checker1.set_permissions)
- self._checker2 = checker2
-
- def check(self, object, name):
- 'See IChecker'
- try:
- Checker.check(self, object, name)
- except ForbiddenAttribute:
- self._checker2.check(object, name)
- except Unauthorized, unauthorized_exception:
- try: self._checker2.check(object, name)
- except ForbiddenAttribute:
- raise unauthorized_exception
-
- def check_getattr(self, object, name):
- 'See IChecker'
- try:
- Checker.check_getattr(self, object, name)
- except ForbiddenAttribute:
- self._checker2.check_getattr(object, name)
- except Unauthorized, unauthorized_exception:
- try: self._checker2.check_getattr(object, name)
- except ForbiddenAttribute:
- raise unauthorized_exception
-
- def check_setattr(self, object, name):
- 'See IChecker'
- try:
- Checker.check_setattr(self, object, name)
- except ForbiddenAttribute:
- self._checker2.check_setattr(object, name)
- except Unauthorized, unauthorized_exception:
- try: self._checker2.check_setattr(object, name)
- except ForbiddenAttribute:
- raise unauthorized_exception
-
-class CheckerLoggingMixin:
- """Debugging mixin for checkers.
-
- Prints verbose debugging information about every performed check to
- sys.stderr.
-
- If verbosity is set to 1, only displays Unauthorized and Forbidden messages.
- If verbosity is set to a larger number, displays all messages.
- """
-
- verbosity = 1
-
- def check(self, object, name):
- try:
- super(CheckerLoggingMixin, self).check(object, name)
- if self.verbosity > 1:
- if name in _always_available:
- print >> sys.stderr, (
- '[CHK] + Always available: %s on %r' % (name, object))
- else:
- print >> sys.stderr, (
- '[CHK] + Granted: %s on %r' % (name, object))
- except Unauthorized:
- print >> sys.stderr, (
- '[CHK] - Unauthorized: %s on %r' % (name, object))
- raise
- except ForbiddenAttribute:
- print >> sys.stderr, (
- '[CHK] - Forbidden: %s on %r' % (name, object))
- raise
-
- def check_getattr(self, object, name):
- try:
- super(CheckerLoggingMixin, self).check(object, name)
- if self.verbosity > 1:
- if name in _always_available:
- print >> sys.stderr, (
- '[CHK] + Always available getattr: %s on %r'
- % (name, object))
- else:
- print >> sys.stderr, (
- '[CHK] + Granted getattr: %s on %r'
- % (name, object))
- except Unauthorized:
- print >> sys.stderr, (
- '[CHK] - Unauthorized getattr: %s on %r' % (name, object))
- raise
- except ForbiddenAttribute:
- print >> sys.stderr, (
- '[CHK] - Forbidden getattr: %s on %r' % (name, object))
- raise
-
- def check_setattr(self, object, name):
- try:
- super(CheckerLoggingMixin, self).check_setattr(object, name)
- if self.verbosity > 1:
- print >> sys.stderr, (
- '[CHK] + Granted setattr: %s on %r' % (name, object))
- except Unauthorized:
- print >> sys.stderr, (
- '[CHK] - Unauthorized setattr: %s on %r' % (name, object))
- raise
- except ForbiddenAttribute:
- print >> sys.stderr, (
- '[CHK] - Forbidden setattr: %s on %r' % (name, object))
- raise
-
-
-if WATCH_CHECKERS:
- class Checker(CheckerLoggingMixin, Checker):
- verbosity = WATCH_CHECKERS
- class CombinedChecker(CheckerLoggingMixin, CombinedChecker):
- verbosity = WATCH_CHECKERS
-
-
# Helper class for __traceback_supplement__
class TracebackSupplement:
@@ -504,6 +368,9 @@
#
_checkers = {}
+_defaultChecker = Checker({})
+_always_available = []
+
# Get optimized versions
try:
import zope.security._zope_security_checker
@@ -511,12 +378,150 @@
pass
else:
from zope.security._zope_security_checker import _checkers, selectChecker
- from zope.security._zope_security_checker import NoProxy
+ from zope.security._zope_security_checker import NoProxy, Checker
+ from zope.security._zope_security_checker import _defaultChecker
+ from zope.security._zope_security_checker import _always_available
+ zope.interface.classImplements(Checker, INameBasedChecker)
+
_getChecker = _checkers.get
-_defaultChecker = Checker({})
+# Marker type used by bogus zope.security.proxy.trustedRemoveSecurityProxy
+TrustedCheckerBase = Checker
+
+class CombinedChecker(Checker):
+ """A checker that combines two other checkers in a logical-or fashion.
+
+ The following table describes the result of a combined checker in detail.
+
+ checker1 checker2 CombinedChecker(checker1, checker2)
+ ------------------ ------------------ -----------------------------------
+ ok anything ok (checker2 is never called)
+ Unauthorized ok ok
+ Unauthorized Unauthorized Unauthorized
+ Unauthorized ForbiddenAttribute Unauthorized
+ ForbiddenAttribute ok ok
+ ForbiddenAttribute Unauthorized Unauthorized
+ ForbiddenAttribute ForbiddenAttribute ForbiddenAttribute
+ ------------------ ------------------ -----------------------------------
+ """
+ implements(IChecker)
+
+ def __init__(self, checker1, checker2):
+ """Create a combined checker."""
+ Checker.__init__(self,
+ checker1.get_permissions,
+ checker1.set_permissions)
+ self._checker2 = checker2
+
+ def check(self, object, name):
+ 'See IChecker'
+ try:
+ Checker.check(self, object, name)
+ except ForbiddenAttribute:
+ self._checker2.check(object, name)
+ except Unauthorized, unauthorized_exception:
+ try: self._checker2.check(object, name)
+ except ForbiddenAttribute:
+ raise unauthorized_exception
+
+ def check_getattr(self, object, name):
+ 'See IChecker'
+ try:
+ Checker.check_getattr(self, object, name)
+ except ForbiddenAttribute:
+ self._checker2.check_getattr(object, name)
+ except Unauthorized, unauthorized_exception:
+ try: self._checker2.check_getattr(object, name)
+ except ForbiddenAttribute:
+ raise unauthorized_exception
+
+ def check_setattr(self, object, name):
+ 'See IChecker'
+ try:
+ Checker.check_setattr(self, object, name)
+ except ForbiddenAttribute:
+ self._checker2.check_setattr(object, name)
+ except Unauthorized, unauthorized_exception:
+ try: self._checker2.check_setattr(object, name)
+ except ForbiddenAttribute:
+ raise unauthorized_exception
+
+class CheckerLoggingMixin:
+ """Debugging mixin for checkers.
+
+ Prints verbose debugging information about every performed check to
+ sys.stderr.
+
+ If verbosity is set to 1, only displays Unauthorized and Forbidden messages.
+ If verbosity is set to a larger number, displays all messages.
+ """
+
+ verbosity = 1
+
+ def check(self, object, name):
+ try:
+ super(CheckerLoggingMixin, self).check(object, name)
+ if self.verbosity > 1:
+ if name in _always_available:
+ print >> sys.stderr, (
+ '[CHK] + Always available: %s on %r' % (name, object))
+ else:
+ print >> sys.stderr, (
+ '[CHK] + Granted: %s on %r' % (name, object))
+ except Unauthorized:
+ print >> sys.stderr, (
+ '[CHK] - Unauthorized: %s on %r' % (name, object))
+ raise
+ except ForbiddenAttribute:
+ print >> sys.stderr, (
+ '[CHK] - Forbidden: %s on %r' % (name, object))
+ raise
+
+ def check_getattr(self, object, name):
+ try:
+ super(CheckerLoggingMixin, self).check(object, name)
+ if self.verbosity > 1:
+ if name in _always_available:
+ print >> sys.stderr, (
+ '[CHK] + Always available getattr: %s on %r'
+ % (name, object))
+ else:
+ print >> sys.stderr, (
+ '[CHK] + Granted getattr: %s on %r'
+ % (name, object))
+ except Unauthorized:
+ print >> sys.stderr, (
+ '[CHK] - Unauthorized getattr: %s on %r' % (name, object))
+ raise
+ except ForbiddenAttribute:
+ print >> sys.stderr, (
+ '[CHK] - Forbidden getattr: %s on %r' % (name, object))
+ raise
+
+ def check_setattr(self, object, name):
+ try:
+ super(CheckerLoggingMixin, self).check_setattr(object, name)
+ if self.verbosity > 1:
+ print >> sys.stderr, (
+ '[CHK] + Granted setattr: %s on %r' % (name, object))
+ except Unauthorized:
+ print >> sys.stderr, (
+ '[CHK] - Unauthorized setattr: %s on %r' % (name, object))
+ raise
+ except ForbiddenAttribute:
+ print >> sys.stderr, (
+ '[CHK] - Forbidden setattr: %s on %r' % (name, object))
+ raise
+
+
+if WATCH_CHECKERS:
+ class Checker(CheckerLoggingMixin, Checker):
+ verbosity = WATCH_CHECKERS
+ class CombinedChecker(CheckerLoggingMixin, CombinedChecker):
+ verbosity = WATCH_CHECKERS
+
def _instanceChecker(inst):
checker = _checkers.get(inst.__class__, _defaultChecker)
if checker is _defaultChecker and isinstance(inst, Exception):
@@ -536,12 +541,12 @@
# The variable '_always_available' should really be called
# '_available_by_default', as that would better reflect its meaning.
# XXX: Fix the name.
-_always_available = ['__lt__', '__le__', '__eq__',
- '__gt__', '__ge__', '__ne__',
- '__hash__', '__nonzero__',
- '__class__', '__providedBy__', '__implements__',
- '__repr__', '__conform__',
- ]
+_always_available [:] = ['__lt__', '__le__', '__eq__',
+ '__gt__', '__ge__', '__ne__',
+ '__hash__', '__nonzero__',
+ '__class__', '__providedBy__', '__implements__',
+ '__repr__', '__conform__',
+ ]
_callableChecker = NamesChecker(['__str__', '__name__', '__call__'])
_typeChecker = NamesChecker(
More information about the Zope3-Checkins
mailing list