Commit a7bda784 authored by Yoshinori Okuji's avatar Yoshinori Okuji

Rewrite resolveCategory so that it does not acquire objects mistakenly.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@17429 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent e7a9b9b2
...@@ -34,6 +34,7 @@ from OFS.Folder import Folder ...@@ -34,6 +34,7 @@ from OFS.Folder import Folder
from Products.CMFCore.utils import UniqueObject from Products.CMFCore.utils import UniqueObject
from Globals import InitializeClass, DTMLFile from Globals import InitializeClass, DTMLFile
from AccessControl import ClassSecurityInfo from AccessControl import ClassSecurityInfo
from AccessControl import Unauthorized, getSecurityManager
from Acquisition import aq_base from Acquisition import aq_base
from Products.ERP5Type import Permissions from Products.ERP5Type import Permissions
from Products.ERP5Type.Base import Base from Products.ERP5Type.Base import Base
...@@ -45,7 +46,7 @@ from OFS.Traversable import NotFound ...@@ -45,7 +46,7 @@ from OFS.Traversable import NotFound
import re import re
from zLOG import LOG, PROBLEM from zLOG import LOG, PROBLEM, WARNING
_marker = object() _marker = object()
...@@ -1511,23 +1512,76 @@ class CategoryTool( UniqueObject, Folder, Base ): ...@@ -1511,23 +1512,76 @@ class CategoryTool( UniqueObject, Folder, Base ):
except KeyError: except KeyError:
pass pass
try: # This below is complicated, because we want to avoid acquisitions
obj = self.restrictedTraverse(relative_url) # in most cases, but we still need to restrict the access.
# For instance, if the relative url is source/person_module/yo,
# only person_module should be acquired. This becomes very critical,
# for example, with source/sale_order_module/1/1/1, because
# we do not want to acquire a Sale Order when a Line or a Cell is
# not present.
#
# In addition, the behavior of resolveCategory is weird, in that
# the relative url might not start with a base category. It can
# be without a base category, and this means that the first
# part must be acquired. This notation makes things quite
# unpredictable. Therefore, we will have to redesign this method
# in the future.
if isinstance(relative_url, basestring):
stack = relative_url.split('/')
else:
stack = list(relative_url)
stack.reverse()
validate = getSecurityManager().validate
key = stack.pop()
obj = self._getOb(key, None)
if obj is not None:
# The first one is a base category.
if not validate(self, self, key, obj):
raise Unauthorized('unauthorized access to element %s' % key)
base_category = obj
# Next, an object must be retrieved from a base category or
# a portal.
if stack:
key = stack.pop()
obj = base_category._getOb(key, None)
if obj is None: if obj is None:
REQUEST = self.REQUEST portal = self.getPortalObject()
url = '%s/%s' % ('/'.join(self.getPhysicalPath()), relative_url) obj = portal._getOb(key, None)
#LOG("CMFCategory:",0,"Trying url %s" % url ) if obj is not None:
obj = self.portal_catalog.resolve_url(url, REQUEST) if not validate(portal, base_category, key, obj):
#LOG('Obj type', 0, str(obj.getUid())) raise Unauthorized('unauthorized access to element %s' % key)
value = obj obj = obj.__of__(base_category)
except (KeyError, AttributeError) : else:
LOG("CMFCategory WARNING",0,"Could not access object relative_url %s" % relative_url ) if not validate(base_category, base_category, key, obj):
value = None raise Unauthorized('unauthorized access to element %s' % key)
else:
# The first one is a module.
portal = self.getPortalObject()
obj = portal._getOb(key, None)
if obj is not None:
if not validate(portal, portal, key, obj):
raise Unauthorized('unauthorized access to element %s' % key)
if obj is not None:
while stack:
container = obj
key = stack.pop()
obj = container._getOb(key, None)
if obj is None:
break
if not validate(container, container, key, obj):
raise Unauthorized('unauthorized access to element %s' % key)
if obj is None:
LOG('CMFCategory', WARNING,
'Could not access object %s' % relative_url)
if cache is not None: if cache is not None:
cache[key] = value cache[key] = obj
return value return obj
InitializeClass( CategoryTool ) InitializeClass( CategoryTool )
......
...@@ -1016,7 +1016,7 @@ class TestCMFCategory(ERP5TypeTestCase): ...@@ -1016,7 +1016,7 @@ class TestCMFCategory(ERP5TypeTestCase):
bc.getCategoryChildTitleItemList(checked_permission=checked_permission, bc.getCategoryChildTitleItemList(checked_permission=checked_permission,
cache=0)) cache=0))
def test_renameBaseCategory(self): def test_29_renameBaseCategory(self):
bc = self.portal.portal_categories.newContent( bc = self.portal.portal_categories.newContent(
portal_type='Base Category', portal_type='Base Category',
id='first_id') id='first_id')
...@@ -1025,6 +1025,36 @@ class TestCMFCategory(ERP5TypeTestCase): ...@@ -1025,6 +1025,36 @@ class TestCMFCategory(ERP5TypeTestCase):
bc.setId('new_id') bc.setId('new_id')
self.assertEquals('new_id', bc.getId()) self.assertEquals('new_id', bc.getId())
def test_30_resolveCategory(self):
portal = self.getPortal()
category_tool = portal.portal_categories
module = portal.sale_order_module
order = module.newContent(id='foo', portal_type='Sale Order')
self.assertNotEquals(order, None)
line = order.newContent(id='bar', portal_type='Sale Order Line')
self.assertNotEquals(line, None)
cell = line.newContent(id='baz', portal_type='Sale Order Cell')
self.assertNotEquals(cell, None)
get_transaction().commit()
self.tic()
for relative_url, value in (
('sale_order_module', module),
('sale_order_module/foo', order),
('sale_order_module/bar', None),
('sale_order_module/sale_order_module', None),
('sale_order_module/foo/bar', line),
('sale_order_module/foo/foo', None),
('sale_order_module/foo/sale_order_module', None),
('sale_order_module/foo/bar/baz', cell),
('sale_order_module/foo/bar/bar', None),
('sale_order_module/foo/bar/foo', None),
('sale_order_module/foo/bar/sale_order_module', None),
):
obj = category_tool.resolveCategory(relative_url)
self.assertEquals(obj, value)
obj = category_tool.resolveCategory('order/' + relative_url)
self.assertEquals(obj, value)
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
......
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