[CMF-checkins] SVN: CMF/branches/2.1/ Forward port fixes from 1.6 branch r73950:73969 and r74140:74202 (POST only fixes and fix for skin lookup

Alec Mitchell apm13 at columbia.edu
Sat Apr 21 00:54:51 EDT 2007


Log message for revision 74276:
  Forward port fixes from 1.6 branch r73950:73969 and r74140:74202 (POST only fixes and fix for skin lookup
  

Changed:
  U   CMF/branches/2.1/CHANGES.txt
  U   CMF/branches/2.1/CMFCore/MembershipTool.py
  U   CMF/branches/2.1/CMFCore/RegistrationTool.py
  U   CMF/branches/2.1/CMFCore/SkinsTool.py
  U   CMF/branches/2.1/CMFCore/WorkflowTool.py
  U   CMF/branches/2.1/CMFCore/dtml/selectWorkflows.dtml
  U   CMF/branches/2.1/CMFCore/utils.py
  U   CMF/branches/2.1/CMFDefault/RegistrationTool.py
  U   CMF/branches/2.1/CMFDefault/skins/zpt_control/change_password.py
  U   CMF/branches/2.1/CMFDefault/skins/zpt_control/folder_localrole_edit.py
  U   CMF/branches/2.1/CMFDefault/skins/zpt_control/members_add_control.py
  U   CMF/branches/2.1/CMFDefault/skins/zpt_control/members_delete_control.py
  U   CMF/branches/2.1/DCWorkflow/States.py
  U   CMF/branches/2.1/DCWorkflow/WorkflowUIMixin.py

-=-
Modified: CMF/branches/2.1/CHANGES.txt
===================================================================
--- CMF/branches/2.1/CHANGES.txt	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CHANGES.txt	2007-04-21 04:54:50 UTC (rev 74276)
@@ -2,6 +2,13 @@
 
   Bug Fixes
 
+    - Use the property API to get the member specific skin, because
+      direct attribute access won't work with PAS based membership.
+      (http://dev.plone.org/plone/ticket/5904)
+
+    - Add POST-only protections to security critical methods (see
+      http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2007-0240).
+
     - Added forward-compatibility fix for running tests under the
       testrunner shipped with Zope 2.11.
 

Modified: CMF/branches/2.1/CMFCore/MembershipTool.py
===================================================================
--- CMF/branches/2.1/CMFCore/MembershipTool.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFCore/MembershipTool.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -52,6 +52,7 @@
 from utils import _dtmldir
 from utils import _getAuthenticatedUser
 from utils import UniqueObject
+from utils import postonly
 
 
 logger = logging.getLogger('CMFCore.MembershipTool')
@@ -96,7 +97,7 @@
     manage_mapRoles = DTMLFile('membershipRolemapping', _dtmldir )
 
     security.declareProtected(SetOwnPassword, 'setPassword')
-    def setPassword(self, password, domains=None):
+    def setPassword(self, password, domains=None, REQUEST=None):
         '''Allows the authenticated member to set his/her own password.
         '''
         registration = queryUtility(IRegistrationTool)
@@ -109,6 +110,7 @@
             member.setSecurityProfile(password=password, domains=domains)
         else:
             raise BadRequest('Not logged in.')
+    setPassword = postonly(setPassword)
 
     security.declarePublic('getAuthenticatedMember')
     def getAuthenticatedMember(self):
@@ -173,7 +175,7 @@
         return roles
 
     security.declareProtected(ManagePortal, 'setRoleMapping')
-    def setRoleMapping(self, portal_role, userfolder_role):
+    def setRoleMapping(self, portal_role, userfolder_role, REQUEST=None):
         """
         set the mapping of roles between roles understood by
         the portal and roles coming from outside user sources
@@ -189,6 +191,7 @@
                title  ='Mapping updated',
                message='The Role mappings have been updated',
                action ='manage_mapRoles')
+    setRoleMapping = postonly(setRoleMapping)
 
     security.declareProtected(ManagePortal, 'getMappedRole')
     def getMappedRole(self, portal_role):
@@ -289,7 +292,7 @@
     createMemberarea = createMemberArea
 
     security.declareProtected(ManageUsers, 'deleteMemberArea')
-    def deleteMemberArea(self, member_id):
+    def deleteMemberArea(self, member_id, REQUEST=None):
         """ Delete member area of member specified by member_id.
         """
         members = self.getMembersFolder()
@@ -300,6 +303,7 @@
             return 1
         else:
             return 0
+    deleteMemberArea = postonly(deleteMemberArea)
 
     security.declarePublic('isAnonymousUser')
     def isAnonymousUser(self):
@@ -429,7 +433,8 @@
         return tuple(local_roles)
 
     security.declareProtected(View, 'setLocalRoles')
-    def setLocalRoles(self, obj, member_ids, member_role, reindex=1):
+    def setLocalRoles(self, obj, member_ids, member_role, reindex=1,
+                      REQUEST=None):
         """ Add local roles on an item.
         """
         if ( _checkPermission(ChangeLocalRoles, obj)
@@ -446,9 +451,11 @@
             # reindexObjectSecurity, which is in CMFCatalogAware and
             # thus PortalContent and PortalFolder.
             obj.reindexObjectSecurity()
+    setLocalRoles = postonly(setLocalRoles)
 
     security.declareProtected(View, 'deleteLocalRoles')
-    def deleteLocalRoles(self, obj, member_ids, reindex=1, recursive=0):
+    def deleteLocalRoles(self, obj, member_ids, reindex=1, recursive=0,
+                         REQUEST=None):
         """ Delete local roles of specified members.
         """
         if _checkPermission(ChangeLocalRoles, obj):
@@ -464,6 +471,7 @@
         if reindex:
             # reindexObjectSecurity is always recursive
             obj.reindexObjectSecurity()
+    deleteLocalRoles = postonly(deleteLocalRoles)
 
     security.declarePrivate('addMember')
     def addMember(self, id, password, roles, domains, properties=None):
@@ -487,7 +495,7 @@
 
     security.declareProtected(ManageUsers, 'deleteMembers')
     def deleteMembers(self, member_ids, delete_memberareas=1,
-                      delete_localroles=1):
+                      delete_localroles=1, REQUEST=None):
         """ Delete members specified by member_ids.
         """
 
@@ -526,6 +534,7 @@
                                    reindex=1, recursive=1 )
 
         return tuple(member_ids)
+    deleteMembers = postonly(deleteMembers)
 
     security.declarePublic('getHomeFolder')
     def getHomeFolder(self, id=None, verifyPermission=0):

Modified: CMF/branches/2.1/CMFCore/RegistrationTool.py
===================================================================
--- CMF/branches/2.1/CMFCore/RegistrationTool.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFCore/RegistrationTool.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -39,6 +39,7 @@
 from utils import _limitGrantedRoles
 from utils import Message as _
 from utils import UniqueObject
+from utils import postonly
 
 
 class RegistrationTool(UniqueObject, SimpleItem, ActionProviderBase):
@@ -133,7 +134,7 @@
 
     security.declareProtected(AddPortalMember, 'addMember')
     def addMember(self, id, password, roles=('Member',), domains='',
-                  properties=None):
+                  properties=None, REQUEST=None):
         '''Creates a PortalMember and returns it. The properties argument
         can be a mapping with additional member properties. Raises an
         exception if the given id already exists, the password does not
@@ -165,6 +166,7 @@
         member = membership.getMemberById(id)
         self.afterAdd(member, id, password, properties)
         return member
+    addMember = postonly(addMember)
 
     security.declareProtected(AddPortalMember, 'isMemberIdAllowed')
     def isMemberIdAllowed(self, id):

Modified: CMF/branches/2.1/CMFCore/SkinsTool.py
===================================================================
--- CMF/branches/2.1/CMFCore/SkinsTool.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFCore/SkinsTool.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -312,8 +312,8 @@
         mtool = getUtility(IMembershipTool)
         utool = getUtility(IURLTool)
         member = mtool.getAuthenticatedMember()
-        if hasattr(aq_base(member), 'portal_skin'):
-            mskin = member.portal_skin
+        if hasattr(aq_base(member), 'getProperty'):
+            mskin = member.getProperty('portal_skin', None)
             if mskin:
                 req = self.REQUEST
                 cookie = req.cookies.get(self.request_varname, None)

Modified: CMF/branches/2.1/CMFCore/WorkflowTool.py
===================================================================
--- CMF/branches/2.1/CMFCore/WorkflowTool.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFCore/WorkflowTool.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -41,6 +41,7 @@
 from utils import Message as _
 from utils import registerToolInterface
 from utils import UniqueObject
+from utils import postonly
 from WorkflowCore import ObjectDeleted
 from WorkflowCore import ObjectMoved
 from WorkflowCore import WorkflowException
@@ -155,6 +156,7 @@
         if REQUEST is not None:
             return self.manage_selectWorkflows(REQUEST,
                             manage_tabs_message='Changed.')
+    manage_changeWorkflows = postonly(manage_changeWorkflows)
 
     #
     #   'IActionProvider' interface methods
@@ -362,7 +364,7 @@
     #   'IConfigurableWorkflowTool' interface methods
     #
     security.declareProtected(ManagePortal, 'setDefaultChain')
-    def setDefaultChain(self, default_chain):
+    def setDefaultChain(self, default_chain, REQUEST=None):
         """ Set the default chain for this tool.
         """
         default_chain = default_chain.replace(',', ' ')
@@ -374,9 +376,11 @@
                 ids.append(wf_id)
 
         self._default_chain = tuple(ids)
+    setDefaultChain = postonly(setDefaultChain)
 
     security.declareProtected(ManagePortal, 'setChainForPortalTypes')
-    def setChainForPortalTypes(self, pt_names, chain, verify=True):
+    def setChainForPortalTypes(self, pt_names, chain, verify=True,
+                               REQUEST=None):
         """ Set a chain for specific portal types.
         """
         cbt = self._chains_by_type
@@ -398,6 +402,7 @@
             if verify and not (type_id in ti_ids):
                 continue
             cbt[type_id] = tuple(chain)
+    setChainForPortalTypes = postonly(setChainForPortalTypes)
 
     security.declarePrivate('getDefaultChain')
     def getDefaultChain(self):
@@ -455,6 +460,7 @@
                                                '%d object(s) updated.' % count)
         else:
             return count
+    updateRoleMappings = postonly(updateRoleMappings)
 
     security.declarePrivate('getWorkflowById')
     def getWorkflowById(self, wf_id):

Modified: CMF/branches/2.1/CMFCore/dtml/selectWorkflows.dtml
===================================================================
--- CMF/branches/2.1/CMFCore/dtml/selectWorkflows.dtml	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFCore/dtml/selectWorkflows.dtml	2007-04-21 04:54:50 UTC (rev 74276)
@@ -50,7 +50,7 @@
 Click the button below to update the security settings of all
 workflow-aware objects in this portal.
 
-<form action="updateRoleMappings" method="GET">
+<form action="updateRoleMappings" method="POST">
 <input type="submit" name="submit" value="Update security settings" />
 </form>
 </p>

Modified: CMF/branches/2.1/CMFCore/utils.py
===================================================================
--- CMF/branches/2.1/CMFCore/utils.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFCore/utils.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -929,3 +929,14 @@
 
 security.declarePublic('Message')
 Message = MessageFactory('cmf_default')
+
+# postonly decorator is only available in Zope 2.8.9, 2.9.7, 2.10.3 and 2.11,
+# or in Hotfix_20070320.
+try:
+    from AccessControl.requestmethod import postonly
+except ImportError:
+    try:
+        from Products.Hotfix_20070320 import postonly
+    except ImportError:
+        def postonly(callable):
+            return callable

Modified: CMF/branches/2.1/CMFDefault/RegistrationTool.py
===================================================================
--- CMF/branches/2.1/CMFDefault/RegistrationTool.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFDefault/RegistrationTool.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -28,6 +28,7 @@
 from Products.CMFCore.RegistrationTool import RegistrationTool as BaseTool
 from Products.CMFCore.utils import _checkPermission
 from Products.CMFCore.utils import registerToolInterface
+from Products.CMFCore.utils import postonly
 
 from permissions import ManagePortal
 from utils import checkEmailAddress
@@ -194,6 +195,7 @@
                   , password=None
                   , roles=None
                   , domains=None
+                  , REQUEST = None
                   ):
         """ Edit a user's properties and security settings
 
@@ -207,6 +209,7 @@
         member.setSecurityProfile(password,roles,domains)
 
         return member
+    editMember = postonly(editMember)
 
 InitializeClass(RegistrationTool)
 registerToolInterface('portal_registration', IRegistrationTool)

Modified: CMF/branches/2.1/CMFDefault/skins/zpt_control/change_password.py
===================================================================
--- CMF/branches/2.1/CMFDefault/skins/zpt_control/change_password.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFDefault/skins/zpt_control/change_password.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -12,7 +12,7 @@
     return context.setStatus(False, result)
 
 member = mtool.getAuthenticatedMember()
-mtool.setPassword(password, domains)
+mtool.setPassword(password, domains, REQUEST=context.REQUEST)
 if member.getProperty('last_login_time') == DateTime('1999/01/01'):
     member.setProperties(last_login_time='2000/01/01')
 

Modified: CMF/branches/2.1/CMFDefault/skins/zpt_control/folder_localrole_edit.py
===================================================================
--- CMF/branches/2.1/CMFDefault/skins/zpt_control/folder_localrole_edit.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFDefault/skins/zpt_control/folder_localrole_edit.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -9,10 +9,12 @@
 if change_type == 'add':
     mtool.setLocalRoles(obj=context,
                         member_ids=context.REQUEST.get('member_ids', ()),
-                        member_role=context.REQUEST.get('member_role', ''))
+                        member_role=context.REQUEST.get('member_role', ''),
+                        REQUEST=context.REQUEST)
 else:
     mtool.deleteLocalRoles(obj=context,
-                           member_ids=context.REQUEST.get('member_ids', ()))
+                           member_ids=context.REQUEST.get('member_ids', ()),
+                           REQUEST=context.REQUEST)
 
 context.setStatus(True, _(u'Local Roles changed.'))
 context.setRedirect(context, 'object/localroles')

Modified: CMF/branches/2.1/CMFDefault/skins/zpt_control/members_add_control.py
===================================================================
--- CMF/branches/2.1/CMFDefault/skins/zpt_control/members_add_control.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFDefault/skins/zpt_control/members_add_control.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -12,7 +12,8 @@
 try:
     rtool.addMember( id=member_id, password=password,
                      properties={'username': member_id,
-                                 'email': member_email} )
+                                 'email': member_email},
+                     REQUEST=context.REQUEST)
 except ValueError, errmsg:
     return context.setStatus(False, errmsg)
 else:

Modified: CMF/branches/2.1/CMFDefault/skins/zpt_control/members_delete_control.py
===================================================================
--- CMF/branches/2.1/CMFDefault/skins/zpt_control/members_delete_control.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/CMFDefault/skins/zpt_control/members_delete_control.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -6,7 +6,7 @@
 
 mtool = getToolByInterfaceName('Products.CMFCore.interfaces.IMembershipTool')
 
-mtool.deleteMembers(ids)
+mtool.deleteMembers(ids, REQUEST=context.REQUEST)
 
 if len(ids) == 1:
     return context.setStatus(True, _(u'Selected member deleted.'))

Modified: CMF/branches/2.1/DCWorkflow/States.py
===================================================================
--- CMF/branches/2.1/DCWorkflow/States.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/DCWorkflow/States.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -27,6 +27,7 @@
 from ContainerTab import ContainerTab
 from permissions import ManagePortal
 from utils import _dtmldir
+from Products.CMFCore.utils import postonly
 
 
 class StateDefinition(SimpleItem):
@@ -213,8 +214,9 @@
                 roles = tuple(roles)
             pr[p] = roles
         return self.manage_permissions(REQUEST, 'Permissions changed.')
+    setPermissions = postonly(setPermissions)
 
-    def setPermission(self, permission, acquired, roles):
+    def setPermission(self, permission, acquired, roles, REQUEST=None):
         """Set a permission for this State."""
         pr = self.permission_roles
         if pr is None:
@@ -224,6 +226,7 @@
         else:
             roles = tuple(roles)
         pr[permission] = roles
+    setPermission = postonly(setPermission)
 
     manage_groups = PageTemplateFile('state_groups.pt', _dtmldir)
 
@@ -247,6 +250,7 @@
             RESPONSE.redirect(
                 "%s/manage_groups?manage_tabs_message=Groups+changed."
                 % self.absolute_url())
+    setGroups = postonly(setGroups)
 
 InitializeClass(StateDefinition)
 

Modified: CMF/branches/2.1/DCWorkflow/WorkflowUIMixin.py
===================================================================
--- CMF/branches/2.1/DCWorkflow/WorkflowUIMixin.py	2007-04-21 04:36:04 UTC (rev 74275)
+++ CMF/branches/2.1/DCWorkflow/WorkflowUIMixin.py	2007-04-21 04:54:50 UTC (rev 74276)
@@ -27,6 +27,7 @@
 from permissions import ManagePortal
 from Guard import Guard
 from utils import _dtmldir
+from Products.CMFCore.utils import postonly
 
 try:
     #
@@ -66,6 +67,7 @@
         if REQUEST is not None:
             return self.manage_properties(
                 REQUEST, manage_tabs_message='Properties changed.')
+    setProperties = postonly(setProperties)
 
     _permissions_form = DTMLFile('workflow_permissions', _dtmldir)
 
@@ -90,6 +92,7 @@
         if REQUEST is not None:
             return self.manage_permissions(
                 REQUEST, manage_tabs_message='Permission added.')
+    addManagedPermission = postonly(addManagedPermission)
 
     security.declareProtected(ManagePortal, 'delManagedPermissions')
     def delManagedPermissions(self, ps, REQUEST=None):
@@ -103,6 +106,7 @@
         if REQUEST is not None:
             return self.manage_permissions(
                 REQUEST, manage_tabs_message='Permission(s) removed.')
+    delManagedPermissions = postonly(delManagedPermissions)
 
     security.declareProtected(ManagePortal, 'getPossiblePermissions')
     def getPossiblePermissions(self):
@@ -132,7 +136,7 @@
             return [g['id'] for g in groups]
 
     security.declareProtected(ManagePortal, 'addGroup')
-    def addGroup(self, group, RESPONSE=None):
+    def addGroup(self, group, RESPONSE=None, REQUEST=None):
         """Adds a group by name.
         """
         if group not in self.getAvailableGroups():
@@ -142,9 +146,10 @@
             RESPONSE.redirect(
                 "%s/manage_groups?manage_tabs_message=Added+group."
                 % self.absolute_url())
+    addGroup = postonly(addGroup)
 
     security.declareProtected(ManagePortal, 'delGroups')
-    def delGroups(self, groups, RESPONSE=None):
+    def delGroups(self, groups, RESPONSE=None, REQUEST=None):
         """Removes groups by name.
         """
         self.groups = tuple([g for g in self.groups if g not in groups])
@@ -152,6 +157,7 @@
             RESPONSE.redirect(
                 "%s/manage_groups?manage_tabs_message=Groups+removed."
                 % self.absolute_url())
+    delGroups = postonly(delGroups)
 
     security.declareProtected(ManagePortal, 'getAvailableRoles')
     def getAvailableRoles(self):
@@ -179,7 +185,7 @@
         return self.valid_roles()
 
     security.declareProtected(ManagePortal, 'setRoles')
-    def setRoles(self, roles, RESPONSE=None):
+    def setRoles(self, roles, RESPONSE=None, REQUEST=None):
         """Changes the list of roles mapped to groups by this workflow.
         """
         avail = self.getAvailableRoles()
@@ -191,6 +197,7 @@
             RESPONSE.redirect(
                 "%s/manage_groups?manage_tabs_message=Roles+changed."
                 % self.absolute_url())
+    setRoles = postonly(setRoles)
 
     security.declareProtected(ManagePortal, 'getGuard')
     def getGuard(self):



More information about the CMF-checkins mailing list