r716 - in zope2.7/trunk/lib/python: AccessControl App OFS Products/PythonScripts

Jérémy Bobbio lunar at alioth.debian.org
Wed Mar 28 17:26:50 UTC 2007


Author: lunar
Date: 2007-03-28 16:26:49 +0000 (Wed, 28 Mar 2007)
New Revision: 716

Added:
   zope2.7/trunk/lib/python/AccessControl/requestmethod.py
Modified:
   zope2.7/trunk/lib/python/AccessControl/Owned.py
   zope2.7/trunk/lib/python/AccessControl/PermissionMapping.py
   zope2.7/trunk/lib/python/AccessControl/Role.py
   zope2.7/trunk/lib/python/AccessControl/User.py
   zope2.7/trunk/lib/python/App/ApplicationManager.py
   zope2.7/trunk/lib/python/OFS/DTMLMethod.py
   zope2.7/trunk/lib/python/Products/PythonScripts/PythonScript.py
Log:
Backport fix for CVE-2007-0240 from differences between Zope 2.8.8 and 2.8.9.


Modified: zope2.7/trunk/lib/python/AccessControl/Owned.py
===================================================================
--- zope2.7/trunk/lib/python/AccessControl/Owned.py	2007-03-21 14:43:10 UTC (rev 715)
+++ zope2.7/trunk/lib/python/AccessControl/Owned.py	2007-03-28 16:26:49 UTC (rev 716)
@@ -18,6 +18,7 @@
 import Globals, urlparse, SpecialUsers, ExtensionClass
 from AccessControl import getSecurityManager, Unauthorized
 from Acquisition import aq_get, aq_parent, aq_base
+from requestmethod import postonly
 
 UnownableOwner=[]
 def ownableFilter(self):
@@ -184,6 +185,7 @@
         self.changeOwnership(security.getUser(), recursive)
 
         RESPONSE.redirect(REQUEST['HTTP_REFERER'])
+    manage_takeOwnership = postonly(manage_takeOwnership)
 
     def manage_changeOwnershipType(self, explicit=1,
                                    RESPONSE=None, REQUEST=None):
@@ -204,6 +206,7 @@
                 del self._owner
 
         if RESPONSE is not None: RESPONSE.redirect(REQUEST['HTTP_REFERER'])
+    manage_changeOwnershipType = postonly(manage_changeOwnershipType)
 
     def _deleteOwnershipAfterAdd(self):
 

Modified: zope2.7/trunk/lib/python/AccessControl/PermissionMapping.py
===================================================================
--- zope2.7/trunk/lib/python/AccessControl/PermissionMapping.py	2007-03-21 14:43:10 UTC (rev 715)
+++ zope2.7/trunk/lib/python/AccessControl/PermissionMapping.py	2007-03-28 16:26:49 UTC (rev 716)
@@ -22,6 +22,7 @@
 from Owned import UnownableOwner
 from Globals import InitializeClass
 from cgi import escape
+from requestmethod import postonly
 
 class RoleManager:
     def manage_getPermissionMapping(self):
@@ -76,6 +77,7 @@
             return self.manage_access(
                 REQUEST,
                 manage_tabs_message='The permission mapping has been updated')
+    manage_setPermissionMapping = postonly(manage_setPermissionMapping)
 
     def _isBeingUsedAsAMethod(self, REQUEST =None, wannaBe=0):
         try:

Modified: zope2.7/trunk/lib/python/AccessControl/Role.py
===================================================================
--- zope2.7/trunk/lib/python/AccessControl/Role.py	2007-03-21 14:43:10 UTC (rev 715)
+++ zope2.7/trunk/lib/python/AccessControl/Role.py	2007-03-28 16:26:49 UTC (rev 716)
@@ -21,6 +21,7 @@
 from Permission import Permission
 from App.Common import aq_base
 from cgi import escape
+from requestmethod import postonly
 
 ListType=type([])
 
@@ -137,6 +138,7 @@
             p.setRole(role_to_manage, name in permissions)
 
         if REQUEST is not None: return self.manage_access(REQUEST)
+    manage_role = postonly(manage_role)
 
     manage_acquiredForm=DTMLFile('dtml/acquiredEdit', globals(),
                                  management_view='Security',
@@ -155,6 +157,7 @@
             else:                   p.setRoles(tuple(roles))
 
         if REQUEST is not None: return self.manage_access(REQUEST)
+    manage_acquiredPermissions = postonly(manage_acquiredPermissions)
 
     manage_permissionForm=DTMLFile('dtml/permissionEdit', globals(),
                                    management_view='Security',
@@ -182,6 +185,7 @@
         raise ValueError, (
             "The permission <em>%s</em> is invalid." %
                 escape(permission_to_manage))
+    manage_permission = postonly(manage_permission)
 
     _normal_manage_access=DTMLFile('dtml/access', globals())
 
@@ -224,6 +228,7 @@
             title  ='Success!',
             message='Your changes have been saved',
             action ='manage_access')
+    manage_changePermissions = postonly(manage_changePermissions)
 
 
     def permissionsOfRole(self, role):
@@ -353,6 +358,7 @@
         if REQUEST is not None:
             stat='Your changes have been saved.'
             return self.manage_listLocalRoles(self, REQUEST, stat=stat)
+    manage_addLocalRoles = postonly(manage_addLocalRoles)
 
     def manage_setLocalRoles(self, userid, roles, REQUEST=None):
         """Set local roles for a user."""
@@ -364,6 +370,7 @@
         if REQUEST is not None:
             stat='Your changes have been saved.'
             return self.manage_listLocalRoles(self, REQUEST, stat=stat)
+    manage_setLocalRoles = postonly(manage_setLocalRoles)
 
     def manage_delLocalRoles(self, userids, REQUEST=None):
         """Remove all local roles for a user."""
@@ -375,6 +382,7 @@
         if REQUEST is not None:
             stat='Your changes have been saved.'
             return self.manage_listLocalRoles(self, REQUEST, stat=stat)
+    manage_delLocalRoles = postonly(manage_delLocalRoles)
 
 
 
@@ -468,6 +476,7 @@
         self.__ac_roles__=tuple(data)
         if REQUEST is not None:
             return self.manage_access(REQUEST)
+    _addRole = postonly(_addRole)
 
 
     def _delRoles(self, roles, REQUEST=None):
@@ -483,6 +492,7 @@
         self.__ac_roles__=tuple(data)
         if REQUEST is not None:
             return self.manage_access(REQUEST)
+    _delRoles = postonly(_delRoles)
 
 
     def _has_user_defined_role(self, role):

Modified: zope2.7/trunk/lib/python/AccessControl/User.py
===================================================================
--- zope2.7/trunk/lib/python/AccessControl/User.py	2007-03-21 14:43:10 UTC (rev 715)
+++ zope2.7/trunk/lib/python/AccessControl/User.py	2007-03-28 16:26:49 UTC (rev 716)
@@ -22,6 +22,7 @@
 from OFS.SimpleItem import Item
 from base64 import decodestring
 from App.ImageFile import ImageFile
+from requestmethod import postonly
 from Role import RoleManager, DEFAULTMAXLISTUSERS
 from PermissionRole import _what_not_even_god_should_do, rolesForPermissionOn
 import AuthEncoding
@@ -527,28 +528,33 @@
     # Authors of custom user folders don't need to do anything special to
     # support these - they will just call the appropriate '_' methods that
     # user folder subclasses already implement.
-    def userFolderAddUser(self, name, password, roles, domains, **kw):
+    def userFolderAddUser(self, name, password, roles, domains,
+                          REQUEST=None, **kw):
         """API method for creating a new user object. Note that not all
            user folder implementations support dynamic creation of user
            objects."""
         if hasattr(self, '_doAddUser'):
             return self._doAddUser(name, password, roles, domains, **kw)
         raise NotImplementedError
+    userFolderAddUser = postonly(userFolderAddUser)
 
-    def userFolderEditUser(self, name, password, roles, domains, **kw):
+    def userFolderEditUser(self, name, password, roles, domains,
+                           REQUEST=None, **kw):
         """API method for changing user object attributes. Note that not
            all user folder implementations support changing of user object
            attributes."""
         if hasattr(self, '_doChangeUser'):
             return self._doChangeUser(name, password, roles, domains, **kw)
         raise NotImplementedError
+    userFolderEditUser = postonly(userFolderEditUser)
 
-    def userFolderDelUsers(self, names):
+    def userFolderDelUsers(self, names, REQUEST=None):
         """API method for deleting one or more user objects. Note that not
            all user folder implementations support deletion of user objects."""
         if hasattr(self, '_doDelUsers'):
             return self._doDelUsers(names)
         raise NotImplementedError
+    userFolderDelUsers = postonly(userFolderDelUsers)
 
 
     # -----------------------------------
@@ -819,6 +825,7 @@
             if REQUEST is not None:
                 return self.manage_userFolderProperties(
                     REQUEST, manage_tabs_message='Saved changes.')
+    manage_setUserFolderProperties = postonly(manage_setUserFolderProperties)
 
     def _isPasswordEncrypted(self, pw):
         return AuthEncoding.is_encrypted(pw)
@@ -874,6 +881,7 @@
                    action ='manage_main')
         self._doAddUser(name, password, roles, domains)
         if REQUEST: return self._mainUser(self, REQUEST)
+    _addUser = postonly(_addUser)
 
 
     def _changeUser(self,name,password,confirm,roles,domains,REQUEST=None):
@@ -912,6 +920,7 @@
                    action ='manage_main')
         self._doChangeUser(name, password, roles, domains)
         if REQUEST: return self._mainUser(self, REQUEST)
+    _changeUser = postonly(_changeUser)
 
     def _delUsers(self,names,REQUEST=None):
         if not names:
@@ -921,6 +930,7 @@
                    action ='manage_main')
         self._doDelUsers(names)
         if REQUEST: return self._mainUser(self, REQUEST)
+    _delUsers = postonly(_delUsers)
 
     def manage_users(self,submit=None,REQUEST=None,RESPONSE=None):
         """This method handles operations on users for the web based forms

Added: zope2.7/trunk/lib/python/AccessControl/requestmethod.py
===================================================================
--- zope2.7/trunk/lib/python/AccessControl/requestmethod.py	2007-03-21 14:43:10 UTC (rev 715)
+++ zope2.7/trunk/lib/python/AccessControl/requestmethod.py	2007-03-28 16:26:49 UTC (rev 716)
@@ -0,0 +1,71 @@
+#############################################################################
+#
+# Copyright (c) 2007 Zope Corporation and Contributors. All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE
+#
+##############################################################################
+
+import inspect
+from zExceptions import Forbidden
+from ZPublisher.HTTPRequest import HTTPRequest
+
+def _buildFacade(spec, docstring):
+    """Build a facade function, matching the decorated method in signature.
+    
+    Note that defaults are replaced by None, and _curried will reconstruct
+    these to preserve mutable defaults.
+    
+    """
+    args = inspect.formatargspec(formatvalue=lambda v: '=None', *spec)
+    callargs = inspect.formatargspec(formatvalue=lambda v: '', *spec)
+    return 'def _facade%s:\n    """%s"""\n    return _curried%s' % (
+        args, docstring, callargs)
+
+def postonly(callable):
+    """Only allow callable when request method is POST."""
+    spec = inspect.getargspec(callable)
+    args, defaults = spec[0], spec[3]
+    try:
+        r_index = args.index('REQUEST')
+    except ValueError:
+        raise ValueError('No REQUEST parameter in callable signature')
+    
+    arglen = len(args)
+    if defaults is not None:
+        defaults = zip(args[arglen - len(defaults):], defaults)
+        arglen -= len(defaults)
+            
+    def _curried(*args, **kw):
+        request = None
+        
+        if len(args) > r_index:
+            request = args[r_index]
+        
+        if isinstance(request, HTTPRequest):
+            if request.get('REQUEST_METHOD', 'GET').upper() != 'POST':
+                raise Forbidden('Request must be POST')
+        
+        # Reconstruct keyword arguments
+        if defaults is not None:
+            args, kwparams = args[:arglen], args[arglen:]
+            for positional, (key, default) in zip(kwparams, defaults):
+                if positional is None:
+                    kw[key] = default
+                else:
+                    kw[key] = positional
+
+        return callable(*args, **kw)
+    
+    
+    # Build a facade, with a reference to our locally-scoped _curried
+    facade_globs = dict(_curried=_curried)
+    exec _buildFacade(spec, callable.__doc__) in facade_globs
+    return facade_globs['_facade']
+
+__all__ = ('postonly',)

Modified: zope2.7/trunk/lib/python/App/ApplicationManager.py
===================================================================
--- zope2.7/trunk/lib/python/App/ApplicationManager.py	2007-03-21 14:43:10 UTC (rev 715)
+++ zope2.7/trunk/lib/python/App/ApplicationManager.py	2007-03-28 16:26:49 UTC (rev 716)
@@ -33,6 +33,7 @@
 from cgi import escape
 import zLOG
 import Lifetime
+from AccessControl.requestmethod import postonly
 
 try: import thread
 except: get_ident=lambda: 0
@@ -402,8 +403,9 @@
             </head>
             <body>Zope is restarting</body></html>
             """ % escape(URL1, 1)
+        manage_restart = postonly(manage_restart)
 
-    def manage_shutdown(self):
+    def manage_shutdown(self, REQUEST=None):
         """Shut down the application"""
         try:
             user = '"%s"' % getSecurityManager().getUser().getUserName()
@@ -418,6 +420,7 @@
         </head>
         <body>Zope is shutting down</body></html>
         """
+    manage_shutdown = postonly(manage_shutdown)
 
     def manage_pack(self, days=0, REQUEST=None):
         """Pack the database"""
@@ -430,6 +433,7 @@
             REQUEST['RESPONSE'].redirect(
                 REQUEST['URL1']+'/manage_workspace')
         return t
+    manage_pack = postonly(manage_pack)
 
     def revert_points(self): return ()
 
@@ -480,6 +484,7 @@
             db.commitVersion(v)
         if REQUEST is not None:
             REQUEST['RESPONSE'].redirect(REQUEST['URL1']+'/manage_main')
+    manage_saveVersions = postonly(manage_saveVersions)
 
     def manage_discardVersions(self, versions, REQUEST=None):
         "Discard some versions"
@@ -488,6 +493,7 @@
             db.abortVersion(v)
         if REQUEST is not None:
             REQUEST['RESPONSE'].redirect(REQUEST['URL1']+'/manage_main')
+    manage_discardVersions = postonly(manage_discardVersions)
 
     def getSOFTWARE_HOME(self):
         return getConfiguration().softwarehome

Modified: zope2.7/trunk/lib/python/OFS/DTMLMethod.py
===================================================================
--- zope2.7/trunk/lib/python/OFS/DTMLMethod.py	2007-03-21 14:43:10 UTC (rev 715)
+++ zope2.7/trunk/lib/python/OFS/DTMLMethod.py	2007-03-28 16:26:49 UTC (rev 716)
@@ -29,6 +29,7 @@
 import  Globals, sys, Acquisition
 from AccessControl import getSecurityManager
 from AccessControl.DTML import RestrictedDTML
+from AccessControl.requestmethod import postonly
 from Cache import Cacheable
 from zExceptions import Forbidden
 from zExceptions.TracebackSupplement import PathTracebackSupplement
@@ -324,6 +325,7 @@
         if REQUEST:
             message="Saved changes."
             return self.manage_proxyForm(self,REQUEST,manage_tabs_message=message)
+    manage_proxy = postonly(manage_proxy)
 
     def PrincipiaSearchSource(self):
         "Support for searching - the document's contents are searched."

Modified: zope2.7/trunk/lib/python/Products/PythonScripts/PythonScript.py
===================================================================
--- zope2.7/trunk/lib/python/Products/PythonScripts/PythonScript.py	2007-03-21 14:43:10 UTC (rev 715)
+++ zope2.7/trunk/lib/python/Products/PythonScripts/PythonScript.py	2007-03-28 16:26:49 UTC (rev 716)
@@ -33,6 +33,7 @@
 from OFS.History import Historical, html_diff
 from OFS.Cache import Cacheable
 from AccessControl.ZopeGuards import get_safe_globals, guarded_getattr
+from AccessControl.requestmethod import postonly
 from zLOG import LOG, ERROR, INFO, PROBLEM
 from zExceptions import Forbidden
 import Globals
@@ -359,6 +360,7 @@
                     title  ='Success!',
                     message='Your changes have been saved',
                     action ='manage_main')
+    manage_proxy = postonly(manage_proxy)
 
     security.declareProtected('Change Python Scripts',
       'PUT', 'manage_FTPput', 'write',




More information about the pkg-zope-commits mailing list