سؤال

I have a problem where I need to be able to make custom content accessible for search and retrieval via portal_catalog by anonymous users but not viewable by them.

I used custom content types and a custom workflow, what I'm getting is most likely a permission issue. I defined a custom workflow through ZMI -> portal_workflow and then exported it into source code as an XML definition. I set the permissions for anonymous users as 'Access Content Information' but not 'View'. Note that 'active' in the code snippet is a workflow state that has that permission enabled -- sales_workflow

Brain lookup works for 'Manager' role, but when the role is switched to 'Anonymous', catalog returns an empty list.

import unittest2 as unittest


from . import INTEGRATION_TESTING
from AccessControl import getSecurityManager

from plone.app.testing import setRoles, logout
from plone.app.testing import TEST_USER_ID

from Products.CMFCore.utils import getToolByName

def drop_to_anonymous(self):
    """
    Drop site roles to anonymous user only.
    Note this is a class method and not a function
    assign this method as a class member and then call it
    """
    logout()
    setRoles(self.portal, TEST_USER_ID, ['Anonymous'])
    user = getSecurityManager().getUser()
    roles =  user.getRolesInContext(self.portal)
    self.assertListEqual(['Anonymous'], roles)

class TestSalesRepWorkflow(unittest.TestCase):
    layer = INTEGRATION_TESTING
    drop_to_anonymous = drop_to_anonymous
    def setUp(self):
        self.portal = self.layer['portal']
        self.wftool = getToolByName(self.portal, 'portal_workflow')
        self.catalog = getToolByName(self.portal, 'portal_catalog')
    def test_workflow_lookup_anon(self):
        setRoles(self.portal, TEST_USER_ID, ['Manager'])
        self.portal.invokeFactory(
                                'CustomProduct',
                                'prod1',
                                title="Product 1"
                                )
        prod1 = self.portal['prod1']
        self.wftool.doActionFor(prod1, action='activate')
        review_state = self.wftool.getInfoFor(prod1, 'review_state')
        prod1.reindexObject()
        self.assertEqual('active', review_state)
        lookup = self.catalog(portal_type='CustomProduct', Title='Product 1',
                            review_state='active')
        #This test passes with managerial permissions
        self.assertEqual(len(lookup), 1)
        #Repeat the same test in 'Anonymous' role
        self.drop_to_anonymous()
        lookup1 = self.catalog(portal_type='CustomProduct', Title='Product 1',
                            review_state='active')
        #When dropped to anonymous role, the test fails, 
        #lookup returns an empty list
        self.assertEqual(len(lookup1), 1)

Is there a way to fix this without drastically reworking permissions?

Using unrestrictedSearchResults seems to fix the search, but whenever I attempt to run 'getObject' on a brain, the following error gets raised:

Unauthorized: You are not allowed to access 'XXX' in this context
هل كانت مفيدة؟

المحلول

Your active state needs to give the View permission to Anonymous. Currently it is restricted to these roles:

<state state_id="active" title="">
 <!-- other information elided here --> 
 <permission-map name="View" acquired="False">
   <permission-role>Manager</permission-role>
   <permission-role>Owner</permission-role>
   <permission-role>Reviewer</permission-role>
   <permission-role>SalesRep</permission-role>
   <permission-role>Site Administrator</permission-role>
  </permission-map>

Without the View permission anonymous cannot see your objects even when given the active state, nor can they be found in the catalog by that user.

You can override this behaviour of the catalog by using the .unrestrictedSearchResults() method of the catalog:

lookup1 = self.catalog.unrestrictedSearchResults(
    portal_type='SalesProduct', Title='Product 1', review_state='active')

This method cannot be used from restricted code.

The returned brain objects are perfectly accessible by anonymous users, but you cannot use the getObject() method on them because that'll use the current user's permissions to traverse to it. If you need to get the actual object from the brain, there is again a special, private method to get to the actual object without those restrictions, called ._unrestrictedGetObject():

obj = brain._unrestrictedGetObject()

This method is, once again, only available to unrestricted code.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top