[Zope3-checkins] SVN: Zope3/trunk/src/zope/security/ Add two
convenience functions: canWrite and canAccess. While the
tests for this package are not doc tests,
I included doctest-like comments in the tests. Since these functions
are primarily conveniences for app code,
I imported them in the package __init__.
Gary Poster
gary at zope.com
Mon Jan 24 22:23:41 EST 2005
Log message for revision 28952:
Add two convenience functions: canWrite and canAccess. While the tests for this package are not doc tests, I included doctest-like comments in the tests. Since these functions are primarily conveniences for app code, I imported them in the package __init__.
Changed:
U Zope3/trunk/src/zope/security/__init__.py
U Zope3/trunk/src/zope/security/checker.py
U Zope3/trunk/src/zope/security/tests/test_checker.py
-=-
Modified: Zope3/trunk/src/zope/security/__init__.py
===================================================================
--- Zope3/trunk/src/zope/security/__init__.py 2005-01-25 03:19:31 UTC (rev 28951)
+++ Zope3/trunk/src/zope/security/__init__.py 2005-01-25 03:23:41 UTC (rev 28952)
@@ -22,3 +22,4 @@
import zope.proxy
from zope.security.management import checkPermission
+from zope.security.checker import canWrite, canAccess
Modified: Zope3/trunk/src/zope/security/checker.py
===================================================================
--- Zope3/trunk/src/zope/security/checker.py 2005-01-25 03:19:31 UTC (rev 28951)
+++ Zope3/trunk/src/zope/security/checker.py 2005-01-25 03:23:41 UTC (rev 28952)
@@ -84,7 +84,40 @@
directlyProvides(ProxyFactory, ISecurityProxyFactory)
+def canWrite(obj, name):
+ """Check whether the interaction may write an attribute named name on obj.
+
+ Convenience method. Rather than using checkPermission in high level code,
+ use canWrite and canAccess to avoid binding code to permissions.
+ """
+ obj = ProxyFactory(obj)
+ checker = getChecker(obj)
+ try:
+ checker.check_setattr(obj, name)
+ except Unauthorized:
+ return False
+ # if it is Forbidden (or anything else), let it be raised: it probably
+ # indicates a programming or configuration error
+ return True
+def canAccess(obj, name):
+ """Check whether the interaction may access an attribute named name on obj.
+
+ Convenience method. Rather than using checkPermission in high level code,
+ use canWrite and canAccess to avoid binding code to permissions.
+ """
+ # access attributes and methods, including, in the current checker
+ # implementation, special names like __getitem__
+ obj = ProxyFactory(obj)
+ checker = getChecker(obj)
+ try:
+ checker.check_getattr(obj, name)
+ except Unauthorized:
+ return False
+ # if it is Forbidden (or anything else), let it be raised: it probably
+ # indicates a programming or configuration error
+ return True
+
class Checker(object):
implements(INameBasedChecker)
@@ -92,7 +125,7 @@
"""Create a checker
A dictionary must be provided for computing permissions for
- names. The disctionary get will be called with attribute names
+ names. The dictionary get 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
forbidden. If CheckerPublic is returned, then access will be
Modified: Zope3/trunk/src/zope/security/tests/test_checker.py
===================================================================
--- Zope3/trunk/src/zope/security/tests/test_checker.py 2005-01-25 03:19:31 UTC (rev 28951)
+++ Zope3/trunk/src/zope/security/tests/test_checker.py 2005-01-25 03:23:41 UTC (rev 28952)
@@ -28,6 +28,7 @@
from zope.security.proxy import removeSecurityProxy
from zope.security.proxy import getChecker
from zope.security.checker import defineChecker, ProxyFactory
+from zope.security.checker import canWrite, canAccess
from zope.security.proxy import Proxy
import types, pickle
@@ -365,8 +366,67 @@
proxy1 = ProxyFactory(obj, checker)
proxy2 = ProxyFactory(proxy1, checker)
self.assert_(proxy1 is proxy2)
+
+ def test_canWrite_canAccess(self):
+ # the canWrite and canAccess functions are conveniences. Often code
+ # wants to check if a certain option is open to a user before
+ # presenting it. If the code relies on a certain permission, the
+ # Zope 3 goal of keeping knowledge of security assertions out of the
+ # code and only in the zcml assertions is broken. Instead, ask if the
+ # current user canAccess or canWrite some pertinent aspect of the
+ # object. canAccess is used for both read access on an attribute
+ # and call access to methods.
+
+ # For example, consider this humble pair of class and object.
+ class SomeClass(object):
+ pass
+ obj = SomeClass()
+
+ # We will establish a checker for the class. This is the standard
+ # name-based checker, and works by specifying two dicts, one for read
+ # and one for write. Each item in the dictionary should be an
+ # attribute name and the permission required to read or write it.
+
+ # For these tests, the SecurityPolicy defined at the top of this file
+ # is in place. It is a stub. Normally, the security policy would
+ # have knowledge of interactions and participants, and would determine
+ # on the basis of the particpants and the object if a certain permission
+ # were authorized. This stub simply says that the 'test_allowed'
+ # permission is authorized and nothing else is, for any object you pass
+ # it.
+
+ # Therefore, according to the checker created here, the current
+ # 'interaction' (as stubbed out in the security policy) will be allowed
+ # to access and write foo, and access bar. The interaction is
+ # unauthorized for accessing baz and writing bar. Any other access or
+ # write is not merely unauthorized but forbidden--including write access
+ # for baz.
+ checker = Checker(
+ {'foo':'test_allowed',
+ 'bar':'test_allowed',
+ 'baz':'you_will_not_have_this_permission'},
+ {'foo':'test_allowed',
+ 'bar':'you_will_not_have_this_permission'})
+ defineChecker(SomeClass, checker)
+
+ # so, our hapless interaction may write and access foo...
+ self.assert_(canWrite(obj, 'foo'))
+ self.assert_(canAccess(obj, 'foo'))
+
+ # ...may access, but not write, bar...
+ self.assert_(not canWrite(obj, 'bar'))
+ self.assert_(canAccess(obj, 'bar'))
+
+ # ...and may access baz.
+ self.assert_(not canAccess(obj, 'baz'))
+
+ # there are no security assertions for writing baz or accessing
+ # anything else, so these actually raise Forbidden. The rationale
+ # behind exposing the Forbidden exception is primarily that it is
+ # usually indicative of programming or configuration errors.
+ self.assertRaises(Forbidden, canWrite, obj, 'baz')
+ self.assertRaises(Forbidden, canAccess, obj, 'shazam')
-
class TestCheckerPublic(TestCase):
def test_that_pickling_CheckerPublic_retains_identity(self):
More information about the Zope3-Checkins
mailing list