Commit fd844dca authored by Tres Seaver's avatar Tres Seaver Committed by GitHub

Merge pull request #83 from zopefoundation/hotfix-copy-213

Don't copy items the user is not allowed to view. [2.13]
parents 1057219b d336b029
...@@ -8,6 +8,9 @@ http://docs.zope.org/zope2/ ...@@ -8,6 +8,9 @@ http://docs.zope.org/zope2/
2.13.25 (unreleased) 2.13.25 (unreleased)
-------------------- --------------------
- Don't copy items the user is not allowed to view.
From Products.PloneHotfix20161129. [maurits]
- Quote variables in manage_tabs and manage_container to avoid XSS. - Quote variables in manage_tabs and manage_container to avoid XSS.
From Products.PloneHotfix20160830. [maurits] From Products.PloneHotfix20160830. [maurits]
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
from cgi import escape from cgi import escape
from marshal import dumps from marshal import dumps
from marshal import loads from marshal import loads
import logging
import re import re
import sys import sys
import tempfile import tempfile
...@@ -61,8 +62,8 @@ class CopyError(Exception): ...@@ -61,8 +62,8 @@ class CopyError(Exception):
pass pass
copy_re = re.compile('^copy([0-9]*)_of_(.*)') copy_re = re.compile('^copy([0-9]*)_of_(.*)')
logger = logging.getLogger('OFS')
_marker=[] _marker = []
class CopyContainer(Base): class CopyContainer(Base):
...@@ -587,7 +588,42 @@ class CopySource(Base): ...@@ -587,7 +588,42 @@ class CopySource(Base):
f.seek(0) f.seek(0)
ob=container._p_jar.importFile(f) ob=container._p_jar.importFile(f)
f.close() f.close()
# Cleanup the copy. It may contain private objects that the current
# user is not allowed to see.
sm = getSecurityManager()
if not sm.checkPermission('View', self):
# The user is not allowed to view the object that is currently
# being copied, so it makes no sense to check any of its sub
# objects. It probably means we are in a test.
return ob return ob
return self._cleanupCopy(ob, container)
def _cleanupCopy(self, cp, container):
sm = getSecurityManager()
ob = aq_base(self)
if hasattr(ob, 'objectIds'):
for k in self.objectIds():
v = self._getOb(k)
if not sm.checkPermission('View', v):
# We do not use cp._delObject, because this would fire
# events that are needless for objects that are not even in
# an Acquisition chain yet.
logger.warn(
'While copying %s to %s, removed %s from copy '
'because user is not allowed to view the original.',
'/'.join(self.getPhysicalPath()),
'/'.join(container.getPhysicalPath()),
'/'.join(v.getPhysicalPath())
)
cp._delOb(k)
# We need to cleanup the internal objects list, even when
# in some implementations this is always an empty tuple.
cp._objects = tuple([
i for i in cp._objects if i['id'] != k])
else:
# recursively check
v._cleanupCopy(cp._getOb(k), container)
return cp
def _postCopy(self, container, op=0): def _postCopy(self, container, op=0):
# Called after the copy is finished to accomodate special cases. # Called after the copy is finished to accomodate special cases.
......
...@@ -428,6 +428,34 @@ class TestCopySupportSecurity( CopySupportTestBase ): ...@@ -428,6 +428,34 @@ class TestCopySupportSecurity( CopySupportTestBase ):
, ce_regex='Not Supported' , ce_regex='Not Supported'
) )
def test_copy_cant_copy_invisible_items(self):
# User can view folder1.
# User cannot view private file in folder1.
# When user copies folder1, the private file should not be copied,
# because the user would get the Owner role on the copy,
# and be able to view it anyway.
from AccessControl.Permissions import add_folders
from AccessControl.Permissions import view
folder1, folder2 = self._initFolders()
manage_addFile(folder1, 'private',
file='', content_type='text/plain')
manage_addFile(folder1, 'public',
file='', content_type='text/plain')
folder1.private.manage_permission(view, roles=(), acquire=0)
folder2.manage_permission(add_folders, roles=('Anonymous',), acquire=1)
copy_info = folder2.manage_pasteObjects(
self.app.manage_copyObjects('folder1')
)
new_id = copy_info[0]['new_id']
new_folder = folder2[new_id]
# The private item should not be in the copy.
self.assertTrue('private' not in new_folder.objectIds())
# There is nothing wrong with copying the public item.
self.assertTrue('public' in new_folder.objectIds())
def test_move_baseline( self ): def test_move_baseline( self ):
folder1, folder2 = self._initFolders() folder1, folder2 = self._initFolders()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment