From: David G. <svn...@pl...> - 2010-03-31 06:33:44
|
Author: davisagli Date: Wed Mar 31 06:33:34 2010 New Revision: 35600 Modified: plone.namedfile/branches/davisagli-image-scales/plone/namedfile/scaling.py plone.namedfile/branches/davisagli-image-scales/plone/namedfile/tests/test_scaling.py Log: add permission checks Modified: plone.namedfile/branches/davisagli-image-scales/plone/namedfile/scaling.py ============================================================================== --- plone.namedfile/branches/davisagli-image-scales/plone/namedfile/scaling.py (original) +++ plone.namedfile/branches/davisagli-image-scales/plone/namedfile/scaling.py Wed Mar 31 06:33:34 2010 @@ -1,6 +1,7 @@ from cgi import escape from logging import exception from Acquisition import aq_base +from AccessControl.ZopeGuards import guarded_getattr from ZODB.POSException import ConflictError from zope.component import queryUtility from zope.interface import implements @@ -25,12 +26,12 @@ url = self.context.absolute_url() extension = self.data.contentType.split('/')[-1].lower() - if 'fieldname' in info: - self.__name__ = info['fieldname'] - self.url = '%s/@@images/%s' % (url, info['fieldname']) - else: + if 'uid' in info: self.__name__ = '%s.%s' % (info['uid'], extension) self.url = '%s/@@images/%s' % (url, self.__name__) + else: + self.__name__ = info['fieldname'] + self.url = '%s/@@images/%s' % (url, info['fieldname']) def absolute_url(self): return self.url @@ -94,11 +95,13 @@ storage = AnnotationStorage(self.context) info = storage.get(uid) if info is not None: + # validate access + self.guarded_orig_image(info['data'].fieldname) scale_view = ImageScale(self.context, self.request, **info) return scale_view.__of__(self.context) else: # otherwise `name` must refer to a field... - value = getattr(self.context, name) + value = self.guarded_orig_image(name) scale_view = ImageScale(self.context, self.request, data=value, fieldname=name) return scale_view.__of__(self.context) if image is not None: @@ -108,8 +111,7 @@ def traverse(self, name, furtherPath): """ used for path traversal, i.e. in zope page templates """ if not furtherPath: - # XXX untested - value = getattr(self.context, name) + value = self.guarded_orig_image(name) image = ImageScale(self.context, self.request, data=value, fieldname=name) else: image = self.scale(name, furtherPath.pop()) @@ -131,10 +133,13 @@ def set(self, value): self._sizes = value return property(get, set) + + def guarded_orig_image(self, fieldname): + return guarded_getattr(self.context, fieldname) def create(self, fieldname, direction='keep', **parameters): """ factory for image scales, see `IImageScaleStorage.scale` """ - orig_value = getattr(self.context, fieldname) + orig_value = self.guarded_orig_image(fieldname) if hasattr(aq_base(orig_value), 'open'): orig_data = orig_value.open() else: @@ -153,6 +158,7 @@ data, format, dimensions = result mimetype = 'image/%s' % format.lower() value = orig_value.__class__(data, contentType=mimetype, filename=orig_value.filename) + value.fieldname = fieldname return value, format, dimensions def modified(self): @@ -161,6 +167,8 @@ return self.context.modified().millis() def scale(self, fieldname=None, scale=None, **parameters): + # validate access to original image + self.guarded_orig_image(fieldname) if scale is not None: available = self.available_sizes if not scale in available: Modified: plone.namedfile/branches/davisagli-image-scales/plone/namedfile/tests/test_scaling.py ============================================================================== --- plone.namedfile/branches/davisagli-image-scales/plone/namedfile/tests/test_scaling.py (original) +++ plone.namedfile/branches/davisagli-image-scales/plone/namedfile/tests/test_scaling.py Wed Mar 31 06:33:34 2010 @@ -1,6 +1,7 @@ import re from DateTime import DateTime from OFS.SimpleItem import SimpleItem +from zExceptions import Unauthorized from plone.namedfile.tests.base import NamedFileTestCase, getFile from plone.namedfile.tests.base import NamedFileFunctionalTestCase @@ -109,6 +110,12 @@ # the scaling adapter self.scaling.available_sizes = {'qux': (12, 12)} self.assertEqual(self.scaling.available_sizes, {'qux': (12, 12)}) + + def testGuardedAccess(self): + # make sure it's not possible to access scales of forbidden images + self.item.__allow_access_to_unprotected_subobjects__ = 0 + self.assertRaises(Unauthorized, self.scaling.guarded_orig_image, 'image') + self.item.__allow_access_to_unprotected_subobjects__ = 1 class ImageTraverseTests(NamedFileTestCase): @@ -178,6 +185,11 @@ self.assertEqual(height, 42) self.assertNotEqual(uid1, uid2, 'scale not updated?') + def testGuardedAccess(self): + # make sure it's not possible to access scales of forbidden images + self.item.__allow_access_to_unprotected_subobjects__ = 0 + self.assertRaises(Unauthorized, self.traverse, 'image/foo') + self.item.__allow_access_to_unprotected_subobjects__ = 1 class ImagePublisherTests(NamedFileFunctionalTestCase): @@ -247,6 +259,15 @@ self.assertEqual(response.getStatus(), 200) self.assertImage(response.getBody(), 'JPEG', (23, 23)) + def testGuardedAccess(self): + # make sure it's not possible to access scales of forbidden images + self.item.__allow_access_to_unprotected_subobjects__ = 0 + ImageScaling.available_sizes = {'foo': (23,23)} + credentials = self.getCredentials() + response = self.publish('/item/@@images/image/foo', basic=credentials) + self.assertEqual(response.getStatus(), 401) + self.item.__allow_access_to_unprotected_subobjects__ = 1 + def test_suite(): from unittest import defaultTestLoader return defaultTestLoader.loadTestsFromName(__name__) |