diff --git a/CHANGES.rst b/CHANGES.rst index df96f8ba..eafa3d16 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -4,7 +4,8 @@ Changelog 2.1.18 (unreleased) ------------------- -- Nothing changed yet. +- Backport CSRF fixes. + [vangheem] [gforcada] 2.1.17 (2015-09-28) diff --git a/Products/ATContentTypes/tests/atctftestcase.py b/Products/ATContentTypes/tests/atctftestcase.py index 7d3861ab..49894c2b 100644 --- a/Products/ATContentTypes/tests/atctftestcase.py +++ b/Products/ATContentTypes/tests/atctftestcase.py @@ -1,3 +1,6 @@ +from zope.component import getUtility +from plone.keyring.interfaces import IKeyManager + from Products.ATContentTypes.tests import atcttestcase from Products.CMFCore.utils import getToolByName @@ -7,6 +10,12 @@ from Products.ATContentTypes.config import HAS_LINGUA_PLONE +import hmac +try: + from hashlib import sha1 as sha +except ImportError: + import sha + class IntegrationTestCase(atcttestcase.ATCTFunctionalSiteTestCase): @@ -33,6 +42,16 @@ def setupTestObject(self): self.obj_url = self.obj.absolute_url() self.obj_path = '/%s' % self.obj.absolute_url(1) + def getAuthToken(self, user=default_user): + manager = getUtility(IKeyManager) + try: + ring = manager[u"_forms"] + except KeyError: + ring = manager[u'_system'] + + secret = ring.random() + return hmac.new(secret, user, sha).hexdigest() + class ATCTIntegrationTestCase(IntegrationTestCase): """Integration tests for view and edit templates @@ -51,9 +70,11 @@ def setupTestObject(self): def test_createObject(self): # create an object using the createObject script - response = self.publish(self.folder_path + - '/createObject?type_name=%s' % self.portal_type, - self.basic_auth) + auth = self.getAuthToken() + response = self.publish( + '%s/createObject?type_name=%s&_authenticator=%s' % ( + self.folder_path, self.portal_type, auth), + self.basic_auth) self.assertEqual(response.getStatus(), 302) # Redirect to edit @@ -61,7 +82,7 @@ def test_createObject(self): self.assertTrue(body.startswith(self.folder_url), body) # The url may end with /edit or /atct_edit depending on method aliases - self.assertTrue(body.endswith('edit'), body) + self.assertTrue('edit' in body, body) # Perform the redirect edit_form_path = body[len(self.app.REQUEST.SERVER_URL):] @@ -78,7 +99,10 @@ def check_newly_created(self): def test_edit_view(self): # edit should work - response = self.publish('%s/atct_edit' % self.obj_path, self.basic_auth) + response = self.publish( + '%s/atct_edit?_authenticator=%s' % ( + self.obj_path, self.getAuthToken()), + self.basic_auth) self.assertEqual(response.getStatus(), 200) # OK def test_base_view(self): diff --git a/Products/ATContentTypes/tests/editing.txt b/Products/ATContentTypes/tests/editing.txt index 2baa4693..c604966c 100644 --- a/Products/ATContentTypes/tests/editing.txt +++ b/Products/ATContentTypes/tests/editing.txt @@ -37,7 +37,8 @@ We'll try and set the title (a required field) to the empty string: >>> document.Schema().getField('title').required 1 - >>> browser.open(url+'/edit') + >>> browser.open(url) + >>> browser.getLink('Edit').click() >>> browser.getControl('Title').value = '' >>> browser.getControl('Save').click() @@ -56,7 +57,8 @@ we want to make sure all of them are validated. >>> document.Schema().getField('title').schemata 'categorization' - >>> browser.open(url+'/edit') + >>> browser.open(url) + >>> browser.getLink('Edit').click() >>> browser.getControl('Title').value = '' >>> browser.getControl('Save').click() >>> document.title_or_id() @@ -70,7 +72,8 @@ Buttons name verification Let's verify that the buttons have the correct name: - >>> browser.open(url+'/edit') + >>> browser.open(url) + >>> browser.getLink('Edit').click() >>> browser.getControl('Save').name 'form.button.save' @@ -95,7 +98,8 @@ and change the schemata of one of its fields >>> document.Schema().getField('text').schemata 'someschemata' - >>> browser.open(url+'/edit') + >>> browser.open(url) + >>> browser.getLink('Edit').click() >>> browser.getControl('Next').name 'form.button.next' diff --git a/Products/ATContentTypes/tests/portaltype_criterion.txt b/Products/ATContentTypes/tests/portaltype_criterion.txt index 8056f990..1f864479 100644 --- a/Products/ATContentTypes/tests/portaltype_criterion.txt +++ b/Products/ATContentTypes/tests/portaltype_criterion.txt @@ -52,7 +52,7 @@ We edit the criteria: >>> browser.getLink('Criteria').click() >>> browser.url - 'http://nohost/plone/my-collection/criterion_edit_form' + 'http://nohost/plone/my-collection/criterion_edit_form?_auth...' >>> 'Add New Search Criteria' in browser.contents True @@ -103,7 +103,7 @@ We now view the collection. >>> browser.getLink('View').click() >>> browser.url - 'http://nohost/plone/my-collection/' + 'http://nohost/plone/my-collection/?_auth...' The test document should be in the collection. diff --git a/Products/ATContentTypes/tests/test_atdocument.py b/Products/ATContentTypes/tests/test_atdocument.py index c943e7c0..8a220ae3 100644 --- a/Products/ATContentTypes/tests/test_atdocument.py +++ b/Products/ATContentTypes/tests/test_atdocument.py @@ -275,16 +275,17 @@ class TestATDocumentFunctional(atctftestcase.ATCTIntegrationTestCase): def test_id_change_on_initial_edit(self): """Make sure Id is taken from title on initial edit and not otherwise""" # first create an object using the createObject script - - response = self.publish(self.folder_path + - '/createObject?type_name=%s' % self.portal_type, - self.basic_auth) + auth = self.getAuthToken() + response = self.publish( + '%s/createObject?type_name=%s&_authenticator=%s' % ( + self.folder_path, self.portal_type, auth), + self.basic_auth) self.assertEqual(response.getStatus(), 302) # Redirect to edit location = response.getHeader('Location') self.assertTrue(location.startswith(self.folder_url), location) - self.assertTrue(location.endswith('edit'), location) + self.assertTrue('edit' in location, location) # Perform the redirect edit_form_path = location[len(self.app.REQUEST.SERVER_URL):] @@ -299,12 +300,12 @@ def test_id_change_on_initial_edit(self): new_obj_path = '/%s' % new_obj.absolute_url(1) self.assertEqual(new_obj.checkCreationFlag(), True) # object is not yet edited - response = self.publish('%s/atct_edit?form.submitted=1&title=%s&text=Blank' % (new_obj_path, obj_title,), self.basic_auth) # Edit object + response = self.publish('%s/atct_edit?form.submitted=1&title=%s&text=Blank&_authenticator=%s' % (new_obj_path, obj_title, auth), self.basic_auth) # Edit object self.assertEqual(response.getStatus(), 302) # OK self.assertEqual(new_obj.getId(), new_id) # does id match self.assertEqual(new_obj.checkCreationFlag(), False) # object is fully created new_title = "Second Title" - response = self.publish('%s/atct_edit?form.submitted=1&title=%s&text=Blank' % ('/%s' % new_obj.absolute_url(1), new_title,), self.basic_auth) # Edit object + response = self.publish('%s/atct_edit?form.submitted=1&title=%s&text=Blank&_authenticator=%s' % ('/%s' % new_obj.absolute_url(1), new_title, auth), self.basic_auth) # Edit object self.assertEqual(response.getStatus(), 302) # OK self.assertEqual(new_obj.getId(), new_id) # id shouldn't have changed diff --git a/Products/ATContentTypes/tests/test_atfolder.py b/Products/ATContentTypes/tests/test_atfolder.py index 3b19ff3a..2d039052 100644 --- a/Products/ATContentTypes/tests/test_atfolder.py +++ b/Products/ATContentTypes/tests/test_atfolder.py @@ -9,6 +9,7 @@ from OFS.interfaces import IOrderedContainer as IOrderedContainer from Products.ATContentTypes.interfaces import IATFolder from Products.ATContentTypes.interfaces import IATBTreeFolder +from Products.PloneTestCase.setup import portal_owner from zope.interface.verify import verifyObject from Products.ATContentTypes.interfaces import ISelectableConstrainTypes @@ -175,9 +176,10 @@ def test_dynamic_view_without_view(self): def test_selectViewTemplate(self): # create an object using the createObject script - self.publish(self.obj_path + - '/selectViewTemplate?templateId=atct_album_view', - self.owner_auth) + self.publish( + '%s/selectViewTemplate?templateId=atct_album_view&_authenticator=%s' % ( + self.obj_path, self.getAuthToken(portal_owner)), + self.owner_auth) self.assertEqual(self.obj.getLayout(), 'atct_album_view') tests.append(TestATFolderFunctional) diff --git a/Products/ATContentTypes/tests/uploading.txt b/Products/ATContentTypes/tests/uploading.txt index d76b1b93..e410db95 100644 --- a/Products/ATContentTypes/tests/uploading.txt +++ b/Products/ATContentTypes/tests/uploading.txt @@ -75,7 +75,7 @@ Now try to empty value of the text field (#7324) >>> browser.getLink('Edit').click() >>> browser.url - 'http://nohost/plone/test-collection/edit' + 'http://nohost/plone/test-collection/edit?_auth...' >>> browser.getControl(name='text').value = '' >>> browser.getControl('Save').click() >>> 'file contents' in browser.contents