[Zope-Checkins] CVS: Zope/lib/python/AccessControl/securitySuite - testSecurity.py:1.6

Andreas Jung andreas@zope.com
Wed, 3 Oct 2001 10:52:56 -0400


Update of /cvs-repository/Zope/lib/python/AccessControl/securitySuite
In directory cvs.zope.org:/tmp/cvs-serv28361

Modified Files:
	testSecurity.py 
Log Message:
refactored test classes


=== Zope/lib/python/AccessControl/securitySuite/testSecurity.py 1.5 => 1.6 ===
 
+##############################################################################
+# 
+# Zope Public License (ZPL) Version 1.0
+# -------------------------------------
+# 
+# Copyright (c) Digital Creations.  All rights reserved.
+# 
+# This license has been certified as Open Source(tm).
+# 
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+# 
+# 1. Redistributions in source code must retain the above copyright
+#    notice, this list of conditions, and the following disclaimer.
+# 
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions, and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+# 
+# 3. Digital Creations requests that attribution be given to Zope
+#    in any manner possible. Zope includes a "Powered by Zope"
+#    button that is installed by default. While it is not a license
+#    violation to remove this button, it is requested that the
+#    attribution remain. A significant investment has been put
+#    into Zope, and this effort will continue if the Zope community
+#    continues to grow. This is one way to assure that growth.
+# 
+# 4. All advertising materials and documentation mentioning
+#    features derived from or use of this software must display
+#    the following acknowledgement:
+# 
+#      "This product includes software developed by Digital Creations
+#      for use in the Z Object Publishing Environment
+#      (http://www.zope.org/)."
+# 
+#    In the event that the product being advertised includes an
+#    intact Zope distribution (with copyright and license included)
+#    then this clause is waived.
+# 
+# 5. Names associated with Zope or Digital Creations must not be used to
+#    endorse or promote products derived from this software without
+#    prior written permission from Digital Creations.
+# 
+# 6. Modified redistributions of any form whatsoever must retain
+#    the following acknowledgment:
+# 
+#      "This product includes software developed by Digital Creations
+#      for use in the Z Object Publishing Environment
+#      (http://www.zope.org/)."
+# 
+#    Intact (re-)distributions of any official Zope release do not
+#    require an external acknowledgement.
+# 
+# 7. Modifications are encouraged but must be packaged separately as
+#    patches to official Zope releases.  Distributions that do not
+#    clearly separate the patches from the original work must be clearly
+#    labeled as unofficial distributions.  Modifications which do not
+#    carry the name Zope may be packaged in any form, as long as they
+#    conform to all of the clauses above.
+# 
+# 
+# Disclaimer
+# 
+#   THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
+#   EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+#   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+#   PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
+#   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+#   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+#   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+#   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+#   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+#   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+#   OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+#   SUCH DAMAGE.
+# 
+# 
+# This software consists of contributions made by Digital Creations and
+# many individuals on behalf of Digital Creations.  Specific
+# attributions are listed in the accompanying credits file.
+# 
+##############################################################################
+
 import os, sys
 execfile(os.path.join(sys.path[0],'framework.py'))
 
@@ -12,23 +97,56 @@
 from AccessControl.User import nobody
 import Globals
 
+
+# let's define some permissions first
+
 MAGIC_PERMISSION1 = 'Magic Permission 1'
 MAGIC_PERMISSION2 = 'Magic Permission 2'
 
 
+##############################################################################
+# ResultObject class
+##############################################################################
+
+class ResultObject:
+    """ result object used for keeping results from the 
+        ZPublisher.Zope() calls 
+    """
+
+    def __str__(self,expected=-1):
+        s  = '\n'
+        s+= '-'*78
+        s+= "\nRequest: %s" % self.request
+        s+= "\nUser: %s" % self.user
+        s+= "\nExpected: %s" % expected + "  got: %s %s" % (self.code,self.return_text)
+        s+= "\nOutput:"
+        s+= self.output
+        s+= "\n"
+
+        return s
+    
+    __repr__ = __str__
+
+    def __call__(self,expected=-1):
+        return self.__str__(expected)
+        
+
+##############################################################################
+# TestObject class
+##############################################################################
+
 class TestObject(SimpleItem):
     """ test object """
 
     security = ClassSecurityInfo()
     __allow_access_to_unprotected_subobjects__ = 0
 
-    attr1 = 1
-    attr2 = 2
+    public_attr     = 1
+    _protected_attr = 2
 
     def __init__(self,id):
         self.id = id
 
-
     security.declarePrivate("private_func")
     def private_func(self):
         """ private func """
@@ -63,6 +181,10 @@
 Globals.InitializeClass(TestObject)
 
 
+##############################################################################
+# Testfolder class
+##############################################################################
+
 class TestFolder(Folder):
     """ test class """
 
@@ -79,6 +201,10 @@
 Globals.InitializeClass(TestFolder)
 
 
+##############################################################################
+# User Class
+##############################################################################
+
 class User:
 
     def __init__(self,username,password,roles):
@@ -104,7 +230,17 @@
 )
 
 
-class SecurityTests(unittest.TestCase) :
+##############################################################################
+# Security tests
+##############################################################################
+
+class SecurityBase(unittest.TestCase) :
+
+    status_regex = re.compile("Status: ([0-9]{1,4}) (.*)",re.I)\
+
+    ################################################################
+    # set up the test hierachy of objects
+    ################################################################
 
     def setUp(self):
         """ my setup """
@@ -129,21 +265,28 @@
 
         # setup Folder hierarchy
 
-        test = TestFolder('test')
-        f1   = TestFolder('f1')
-        f2   = TestFolder('f2')
-        f3   = TestFolder('f3')
-        obj  = TestObject('obj3')
+        test     = TestFolder('test')
+        f1       = TestFolder('f1')
+        f2       = TestFolder('f2')
+        f3       = TestFolder('f3')
+        obj      = TestObject('obj3')
+        anonobj  = TestObject('anonobj')
+        anonobj.__roles__ = ('Anonymous',)
 
         self.root._setObject('test',test)
         self.root.test._setObject('f1',f1)
         self.root.test._setObject('f2',f2)
+        self.root.test.f1._setObject('anonobj',anonobj)
         self.root.test.f2._setObject('f3',f3)
         self.root.test.f2.f3._setObject('obj3',obj)
         
         get_transaction().commit()
 
 
+    ################################################################
+    # print the object hierachy
+    ################################################################
+
     def _testHierarchy(self):
         """ print all test objects, permissions and roles """
         self._PrintTestEnvironment(root=self.root.test)
@@ -169,29 +312,9 @@
             self._PrintTestEnvironment(folder)
 
 
-    def testAttributeAccess(self):
-        """ check access to attributes """
-
-        obj = self.root.test.f2.f3.obj3
-        print obj.attr1
-        print obj.attr2
-
-        obj.attr1 = 'sux'
-        obj.attr2 = 'sux'
-
-
-    def testNobody(self):
-        """ check permissions for nobody user """
-
-
-        self._checkPermission(nobody,'f1',   'View',1) 
-        self._checkPermission(nobody,'f2',   'View',1) 
-        self._checkPermission(nobody,'f2.f3','View',1) 
-        self._checkPermission(nobody,'f1',   MAGIC_PERMISSION1, None) 
-        self._checkPermission(nobody,'f2',   MAGIC_PERMISSION1, None) 
-        self._checkPermission(nobody,'f2.f3',MAGIC_PERMISSION1, None) 
-
-
+    ################################################################
+    # Check functions for permissions, roles and friends
+    ################################################################
 
     def _checkPermission(self, user, hier, perm, expected):
         """ low level permission check """
@@ -203,10 +326,28 @@
 
         if res != expected:        
             raise AssertionError, \
-                self._perm_error(s,perm,res,expected)
+                self._perm_debug (s,perm,res,expected)
 
 
-    def _perm_error(self, obj , perm, res, expected):
+    def _checkRoles(self,hier,expected_roles=()):
+        """ check roles for an object """
+        
+        s = "self.root.test.%s.__roles__" % hier
+        roles = eval(s)
+
+        if roles==None or len(roles)==0: 
+            roles=(None,)
+    
+        for r in roles:
+            if not r in expected_roles:
+                raise AssertionError, self._roles_debug(hier,roles,expected_roles)
+            
+
+    ################################################################
+    # Debugging helpers when raising AssertionError
+    ################################################################
+
+    def _perm_debug(self, obj , perm, res, expected):
         s = '' 
         s+=' Object: %s' % obj
         s+=', Permission: %s' % perm 
@@ -216,6 +357,72 @@
         return s
         
 
+    def _roles_debug(self,hier,expected_roles,got_roles):
+
+        s = ''
+        s+='Object: %s' % hier
+        s+=", has roles: %s " % got_roles        
+        s+=", expected roles: %s" % expected_roles
+
+        return s
+ 
+    def _request(self,*args,**kw):
+        """ perform a Zope request """
+
+        io =cStringIO.StringIO()
+        kw['fp']=io
+        ZPublisher.Zope(*args,**kw)
+        outp = io.getvalue()
+        mo = self.status_regex.search(outp)
+
+        code,txt = mo.groups()
+
+        res = ResultObject()
+        res.request     = args
+        res.user        = kw.get('u','')
+        res.code        = int(code)
+        res.return_text = txt
+        res.output      = outp
+
+        return res
+
+
+class SecurityTests(SecurityBase):
+
+
+    def testAttributeAccess(self):
+        """ check access to attributes """
+
+        obj = self.root.test.f2.f3.obj3
+
+        try:    
+            x = obj.public_attr
+            obj.public_attr = 'blabla'
+        except: raise AssertionError,'this should work !'    
+
+        try:    
+            x = obj._protected_attr
+            raise AssertionError,'this should not work !'    
+        except AssertionError: 
+                raise
+            
+        try:    
+            obj._protected_attr = "blalbla"
+            raise AssertionError,'this should not work !'    
+        except AssertionError: 
+                raise
+
+
+    def testNobody(self):
+        """ check permissions for nobody user """
+
+        self._checkPermission(nobody,'f1',   'View',1) 
+        self._checkPermission(nobody,'f2',   'View',1) 
+        self._checkPermission(nobody,'f2.f3','View',1) 
+        self._checkPermission(nobody,'f1',   MAGIC_PERMISSION1, None) 
+        self._checkPermission(nobody,'f2',   MAGIC_PERMISSION1, None) 
+        self._checkPermission(nobody,'f2.f3',MAGIC_PERMISSION1, None) 
+
 
     def testPermissionAccess(self):
         """ check permission based access """
@@ -226,26 +433,20 @@
         self._checkRoles('f2.f3.obj3.private_func',    ('Manager',))    
 
 
-    def _checkRoles(self,hier,expected_roles=()):
-        
-        s = "self.root.test.%s.__roles__" % hier
-        roles = eval(s)
+    def testZPublisherAccess(self):
+        """ test access through ZPublisher """
 
-        if roles==None or len(roles)==0: 
-            roles=(None,)
-    
-        self._debug(s,expected_roles,roles)
+        _r = [ ('/test/f1/',None,200),
+               ('/test/f1/anonobj','manager:123',200),
+              ]
+
+        for path,auth,expected in _r:
+            if auth:
+                res = self._request(path,u=auth)
+            else:
+                res = self._request(path)
 
-        for r in roles:
-            assert r in expected_roles, (roles,expected_roles)
-            
+            assert res.code==expected, (path,auth,expected,res)
 
-    def _debug(self,hier,expected_roles,got_roles):
-        print '-'*78
-        print 'Object:',hier
-        print "has roles:",got_roles        
-        print "expected roles:", expected_roles
-        
         
 framework()
-