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): _______________________________________________ CMF-checkins mailing list [email protected] http://mail.zope.org/mailman/listinfo/cmf-checkins
