def setUp(self): super(Test, self).setUp() component.provideUtility(Permission(P1), IPermission, P1) component.provideUtility(Permission(P2), IPermission, P2) class B(object): def m1(self): return "m1" def m2(self): return "m2" class C(B): implements(I) def m3(self): return "m3" def m4(self): return "m4" TestModule.test_base = B TestModule.test_class = C TestModule.test_instance = C() self.assertState()
class IRedefinePermission(Interface): """Define a permission to replace another permission.""" from_ = Permission(title=u"Original permission", description=u"Original permission ID to redefine.", required=True) to = Permission(title=u"Substituted permission", description=u"Substituted permission ID.", required=True)
def test_subclass(self): # Mock schema model class ITestSchema(Interface): test = zope.schema.TextLine(title=u"Test") ITestSchema.setTaggedValue(READ_PERMISSIONS_KEY, dict(test='zope2.View', foo='foo.View')) class Foo(Item): pass # Mock FTI fti_mock = self.mocker.mock(DexterityFTI) self.expect(fti_mock.lookupSchema()).result(ITestSchema) self.expect(fti_mock.lookupSchema()).result(ITestSchema) self.expect(fti_mock.lookupSchema()).result(ITestSchema) self.mock_utility(fti_mock, IDexterityFTI, u'testtype') # Mock permissions self.mock_utility(Permission(u'zope2.View', u"View"), IPermission, u'zope2.View') self.mock_utility(Permission(u'foo.View', u"View foo"), IPermission, u'foo.View') # Content item item = Foo('test') item.portal_type = u"testtype" item.test = u"foo" item.foo = u"bar" # Check permission securityManager_mock = self.mocker.mock() self.expect(securityManager_mock.checkPermission("View", item)).result(False) self.expect(securityManager_mock.checkPermission("View foo", item)).result(True) getSecurityManager_mock = self.mocker.replace( 'AccessControl.getSecurityManager') self.expect( getSecurityManager_mock()).result(securityManager_mock).count(2) self.mocker.replay() self.assertFalse( item.__allow_access_to_unprotected_subobjects__('test', u"foo")) self.assertTrue( item.__allow_access_to_unprotected_subobjects__('foo', u"bar")) # Unknown attributes are allowed self.assertTrue( item.__allow_access_to_unprotected_subobjects__( 'random', u"stuff"))
class IRedefinePermission(Interface): """Define a permission to replace another permission.""" from_ = Permission( title=_u("Original permission"), description=_u("Original permission id to redefine."), required=True) to = Permission( title=_u("Substituted permission"), description=_u("Substituted permission id."), required=True)
def testProtectedPageViews(self): component.provideUtility(Permission('p', 'P'), IPermission, 'p') request = TestRequest() self.assertEqual( component.queryMultiAdapter((ob, request), name='test'), None) xmlconfig( StringIO(template % u''' <include package="zope.security" file="meta.zcml" /> <permission id="zope.TestPermission" title="Test permission" /> <browser:pages class="zope.browserpage.tests.test_page.V1" for="zope.browserpage.tests.test_page.IC" permission="zope.TestPermission" > <browser:page name="index.html" attribute="index" /> <browser:page name="action.html" attribute="action" /> </browser:pages> ''')) v = component.getMultiAdapter((ob, request), name='index.html') v = ProxyFactory(v) zope.security.management.getInteraction().add(request) self.assertRaises(Exception, v) v = component.getMultiAdapter((ob, request), name='action.html') v = ProxyFactory(v) self.assertRaises(Exception, v)
def after(self): permission = Permission(self.id, self.title, self.description) utility(self.context, IPermission, permission, name=self.id) zope2_permission = str(self.title) if self.roles: addPermission(zope2_permission, default_roles=tuple(self.roles)) else: addPermission(zope2_permission)
def zcml_transition_permission(pid, title, roles): ZCML_LINES.append(ZCML_INDENT) ZCML_LINES.append('%s<permission id="%s" title="%s" />' % ( ZCML_INDENT, pid, title)) provideUtility(Permission(pid), IPermission, pid) for role in roles: ZCML_LINES.append( '%s<grant permission="%s" role="%s" />' % (ZCML_INDENT, pid, role)) rpm.grantPermissionToRole(pid, role, check=False)
def testAllRolePermissionsFormForLocalPermissions(self): permission = Permission(u"id", u"Local Permission") zope.component.provideUtility(permission, IPermission) self.testAllRolePermissions() response = self.publish( '/++etc++site/@@AllRolePermissions.html', basic='mgr:mgrpw') body = response.getBody() self.assert_('Local Permission' in body)
def setUp(self): # On Zope 2.10, the default is True, on 2.12 it's False self.defaultWrap = plone.directives.form.meta.DEFAULT_WRAP plone.directives.form.meta.DEFAULT_WRAP = False grokcore.component.testing.grok('grokcore.component.meta') grokcore.component.testing.grok('grokcore.security.meta') grokcore.component.testing.grok('grokcore.view.meta.templates') grokcore.component.testing.grok('grokcore.view.meta.views') grokcore.component.testing.grok('grokcore.view.meta.skin') grokcore.component.testing.grok('five.grok.meta') grokcore.component.testing.grok('plone.directives.form.meta') grokcore.component.testing.grok('grokcore.view.templatereg') provideUtility(Permission('zope2.View'), name='zope2.View') provideUtility(Permission('cmf.ModifyPortalContent'), name='cmf.ModifyPortalContent') provideUtility(Permission('cmf.AddPortalContent'), name='cmf.AddPortalContent')
def addCheckerPublic(): """Add the CheckerPublic permission as 'zope.Public'""" perm = Permission( 'zope.Public', 'Public', """Special permission used for resources that are always public The public permission is effectively an optimization, sine it allows security computation to be bypassed. """) gsm = component.getGlobalSiteManager() gsm.registerUtility(perm, interfaces.IPermission, perm.id)
def grok(self, name, module, context, module_info, templates): permissions = module_info.getAnnotation('grok.define_permission', []) for permission in permissions: # IPermission.title says that permission ids (and titles, # descriptions) *must* be unicode objects. Good news is # that the directive handler already made sure we either # got pure ASCII or unicode here: permission = unicode(permission) # TODO permission title and description component.provideUtility(Permission(permission, title=permission), name=permission) return True
def setUp(self): from zope.security.permission import Permission provideUtility(Permission('foo', u'foo', u''), name=u'foo') class DummySecurityManager(object): checks = [] def checkPermission(self, perm, context): self.checks.append(perm) return False self.secman = DummySecurityManager() setSecurityManager(self.secman)
def grok(self, name, factory, context, module_info, templates): permission_name = util.class_annotation(factory, 'grok.name', None) if permission_name is None: raise GrokError( "A permission needs to have a dotted name for its id. Use " "grok.name to specify one.", factory) permission_name = unicode(permission_name) title = unicode( util.class_annotation(factory, 'grok.title', permission_name)) # TODO permission description component.provideUtility(Permission(permission_name, title=title), name=permission_name) return True
def add_retract_transitions(wf): def getRoles(transition): original_roles = transition.user_data.get("_roles", []) allowed_roles = set() #transitions to source tx_to_source = wf.get_transitions_to(transition.source) for tx in tx_to_source: if tx.source is None: allowed_roles.update(set(original_roles)) else: for role in tx.user_data.get("_roles", []): if role in original_roles: allowed_roles.add(role) if not len(allowed_roles): allowed_roles = original_roles return allowed_roles transitions = wf._transitions_by_id.values() terminal_transitions = [ transition for transition in transitions if (wf.get_transitions_from(transition.destination) == [] and transition.source and transition.trigger in [MANUAL, SYSTEM]) ] for transition in terminal_transitions: roles = getRoles(transition) if roles: title = _("revert_transition_title", default="Undo - ${title}", mapping={ "title": translate(transition.title, domain="bungeni") }) title = "Undo - %s" % transition.title tid = "%s.%s" % (transition.destination, transition.source) pid = "bungeni.%s.wf.%s" % (wf.name, tid) ntransition = Transition(title, transition.destination, transition.source, trigger=MANUAL, condition=allow_retract, permission=pid, condition_args=True, roles=roles) if ntransition.id in wf._transitions_by_id: continue log.debug("adding transition %s", ntransition.id) provideUtility(Permission(pid), IPermission, pid) for role in roles: role_perm_mgr.grantPermissionToRole(pid, role, check=False) transitions.append(ntransition) wf.refresh(wf._states_by_id.values(), transitions)
def testInherited(self): class B1(object): def g(self): return 'B1.g' class B2(object): def h(self): return 'B2.h' class S(B1, B2): pass component.provideUtility(Permission('B1', ''), IPermission, 'B1') component.provideUtility(Permission('S', ''), IPermission, 'S') protectName(B1, 'g', 'B1') protectName(S, 'g', 'S') protectName(S, 'h', 'S') self.assertEqual(selectChecker(B1()).permission_id('g'), 'B1') self.assertEqual(selectChecker(B2()).permission_id('h'), None) self.assertEqual(selectChecker(S()).permission_id('g'), 'S') self.assertEqual(selectChecker(S()).permission_id('h'), 'S') self.assertEqual(S().g(), 'B1.g') self.assertEqual(S().h(), 'B2.h')
def testRolesWithPermissionsFormForLocalPermission(self): permission = Permission(u"id", u"Local Permission") zope.component.provideUtility(permission, IPermission, 'id') response = self.publish( '/++etc++site/@@AllRolePermissions.html', form={'role_id': 'zope.Manager', 'Allow': ['id'], 'Deny': ['id'], 'SUBMIT_ROLE': 'Save Changes'}, basic='mgr:mgrpw', handle_errors=True) body = response.getBody() self.assert_('You choose both allow and deny for permission' ' "Local Permission". This is not allowed.' in body)
def test_no_read_permission(self): # Mock schema model class ITestSchema(Interface): test = zope.schema.TextLine(title='Test') ITestSchema.setTaggedValue(READ_PERMISSIONS_KEY, dict(foo='foo.View')) # Mock FTI fti_mock = self.mocker.proxy(DexterityFTI('testtype')) self.expect(fti_mock.lookupSchema()).result(ITestSchema) self.expect(fti_mock.behaviors).result(tuple()) self.mock_utility(fti_mock, IDexterityFTI, 'testtype') # Mock permissions self.mock_utility(Permission('foo.View', u'View foo'), IPermission, u'foo.View') # Content item item = Item('test') item.portal_type = 'testtype' item.test = 'foo' item.foo = 'bar' # Check permission securityManager_mock = self.mocker.mock() self.expect(securityManager_mock.checkPermission('View foo', item)).result(True) getSecurityManager_mock = self.mocker.replace( 'zopepolicy.ZopeSecurityPolicy.getSecurityManager') self.expect( getSecurityManager_mock()).result(securityManager_mock).count(1) self.mocker.replay() SCHEMA_CACHE.clear() self.assertTrue( item.__allow_access_to_unprotected_subobjects__('test', 'foo')) self.assertTrue( item.__allow_access_to_unprotected_subobjects__('foo', 'bar')) # Unknown attributes are allowed self.assertTrue( item.__allow_access_to_unprotected_subobjects__('random', 'stuff'))
def test_no_read_permission(self): # Mock schema model class ITestSchema(Interface): test = zope.schema.TextLine(title=u"Test") ITestSchema.setTaggedValue(READ_PERMISSIONS_KEY, dict(foo='foo.View')) # Mock FTI fti_mock = DexterityFTI(u"testtype") fti_mock.lookupSchema = Mock(return_value=ITestSchema) fti_mock.behaviors = () self.mock_utility(fti_mock, IDexterityFTI, u'testtype') # Mock permissions self.mock_utility(Permission(u'foo.View', u"View foo"), IPermission, u'foo.View') # Content item item = Item('test') item.portal_type = u"testtype" item.test = u"foo" item.foo = u"bar" # Check permission security_manager_mock = Mock() security_manager_mock.checkPermission = Mock(return_value=True) from AccessControl import getSecurityManager self.patch_global(getSecurityManager, return_value=security_manager_mock) SCHEMA_CACHE.clear() self.assertTrue( item.__allow_access_to_unprotected_subobjects__('test', u"foo")) self.assertTrue( item.__allow_access_to_unprotected_subobjects__('foo', u"bar")) # Unknown attributes are allowed self.assertTrue( item.__allow_access_to_unprotected_subobjects__( 'random', u"stuff"))
def permission(_context, id, title, description=u''): from zope.security.interfaces import IPermission from zope.security.permission import Permission from zope.component.zcml import utility permission = Permission(id, title, description) utility(_context, IPermission, permission, name=id)
def _load(workflow_name, workflow): """ (workflow_name:str, workflow:etree_doc) -> Workflow """ workflow_title = xas(workflow, "title") naming.MSGIDS.add(workflow_title) workflow_description = xas(workflow, "description") naming.MSGIDS.add(workflow_description) transitions = [] states = [] note = xas(workflow, "note") # initial_state, in XML indicated with a transition.@source="" initial_state = None ZCML_PROCESSED = bool(workflow_name in ZCML_WORKFLOWS_PROCESSED) if not ZCML_PROCESSED: ZCML_WORKFLOWS_PROCESSED.add(workflow_name) ZCML_LINES.append(ZCML_INDENT) ZCML_LINES.append(ZCML_INDENT) ZCML_LINES.append("%s<!-- %s -->" % (ZCML_INDENT, workflow_name)) def validate_id(id, tag): """Ensure that ID values are unique within the same XML doc scope. """ m = "Invalid element <%s> id=%r in workflow %r" % (tag, id, workflow_name) assert id not in validate_id.wuids, "%s -- id not unique in workflow document" % (m) validate_id.wuids.add(id) validate_id.wuids = set() # unique IDs in this XML workflow file def get_from_state(state_id): if state_id is None: return for state in states: if state.id == state_id: return state raise ValueError("Invalid value: permissions_from_state=%r" % (state_id)) def check_not_global_grant(pid, role): # ensure global and local assignments are distinct # (global: global_pid_roles, workflow_name) global_proles = global_pid_roles.get(pid, "") assert role not in global_proles, ("Workflow [%s] may not mix " "global and local granting of a same permission [%s] to a " "same role [%s].") % (workflow_name, pid, role) # permission_actions -> permissions for this type for (key, permission_action) in capi.schema.qualified_permission_actions( workflow_name, xas(workflow, "permission_actions", "").split() ): pid = "bungeni.%s.%s" % (key, permission_action) title = "%s %s" % ( permission_action, naming.split_camel(naming.model_name(key))) # !+ add to a Workflow.defines_permissions list ZCML_LINES.append( '%s<permission id="%s" title="%s" />' % (ZCML_INDENT, pid, title)) provideUtility(Permission(pid), IPermission, pid) # global grants global_pid_roles = {} # {pid: [role]} global_grants = get_permissions_from_allows(workflow_name, workflow) for (setting, pid, role) in global_grants: # for each global permission, build list of roles it is set to global_pid_roles.setdefault(pid, []).append(role) assert setting and pid and role, \ "Global grant must specify valid permission/role" #!+RNC # !+ add to a Workflow.global_grants list ZCML_LINES.append( '%s<grant permission="%s" role="%s" />' % (ZCML_INDENT, pid, role)) # no real need to check that the permission and role of a global grant # are properly registered in the system -- an error should be raised # by the zcml if either is not defined. rpm.grantPermissionToRole(pid, role, check=False) for perm, roles in global_pid_roles.items(): # assert roles mix limitations for state permissions assert_distinct_permission_scopes(perm, roles, workflow_name, "global grants") # all workflow features (enabled AND disabled) workflow_features = load_features(workflow_name, workflow) enabled_feature_names = [None] + [ f.name for f in workflow_features if f.enabled ] # !+EVENT_FEATURE_TYPES add each as enabled_feature_names, or extend the # facet quailifer by feature_name(sub_type_key).facet_ref? # workflow facets workflow_facets = load_facets(workflow_name, workflow) # states for s in workflow.iterchildren("state"): # @id state_id = xas(s, "id") assert state_id, "Workflow State must define @id" #!+RNC validate_id(state_id, "state") # @actions - transition-to-state actions state_actions = [] for action_name in xas(s, "actions", "").split(): state_actions.append(capi.get_workflow_action(action_name)) # @permissions_from_state permissions = [] # [ tuple(bool:int, permission:str, role:str) ] # state.@permissions_from_state : to reduce repetition and enhance # maintainibility of workflow XML files, a state may inherit ALL # permissions defined by the specified state. NO other permissions # may be specified by this state. from_state = get_from_state(xas(s, "permissions_from_state")) parent_permissions = xab(s, "parent_permissions") if parent_permissions: pass # no own permission definitions allowed elif from_state: # assimilate (no more no less) the state's permissions !+tuple, use same? permissions[:] = from_state.permissions else: used_facets_fq = resolve_state_facets( workflow_name, workflow_facets, enabled_feature_names, s) # assimilate permissions from facets from None and all enabled features def add_facet_permissions(facet): for perm in facet.permissions: check_add_assign_permission(workflow_name, permissions, perm) check_not_global_grant(perm[1], perm[2]) for (feature_name, qtk) in used_facets_fq: # debug check that feature is enabled assert feature_name in enabled_feature_names facet = used_facets_fq[(feature_name, qtk)] if facet is not None: add_facet_permissions(facet) # states state_title = xas(s, "title") naming.MSGIDS.add(state_title) states.append( State(state_id, state_title, xas(s, "note"), state_actions, permissions, parent_permissions, xab(s, "obsolete"), ) ) STATE_IDS = [ s.id for s in states ] # transitions for t in workflow.iterchildren("transition"): title = xas(t, "title") naming.MSGIDS.add(title) # sources, empty string -> initial_state sources = t.get("source").split() or [initial_state] assert len(sources) == len(set(sources)), \ "Transition contains duplicate sources [%s]" % (sources) for source in sources: if source is not initial_state: assert source in STATE_IDS, \ "Unknown transition source state [%s]" % (source) # destination must be a valid state destination = t.get("destination") assert destination in STATE_IDS, \ "Unknown transition destination state [%s]" % (destination) # optionals -- only set on kw IFF explicitly defined kw = {} for i in TRANS_ATTRS_OPTIONALS: val = xas(t, i) if not val: # we let setting of defaults be handled downstream continue kw[i] = val # data up-typing # # trigger if "trigger" in kw: kw["trigger"] = trigger_value_map[kw["trigger"]] # roles -> permission - one-to-one per transition roles = capi.schema.qualified_roles(kw.pop("roles", "")) if not is_zcml_permissionable(t): assert not roles, "Workflow [%s] - non-permissionable transition " \ "does not allow @roles [%s]." % (workflow_name, roles) #!+RNC kw["permission"] = None # None -> CheckerPublic # !+CAN_EDIT_AS_DEFAULT_TRANSITION_PERMISSION(mr, oct-2011) this feature # is functional (uncomment following elif clause) but as yet not enabled. # # Advantage would be that it would be easier to keep transitions # permissions in sync with object permissions (set in state) as the # majority of transition require exactly this as privilege; for the # occassional transition needing a different privilege, the current # transition.@roles mechanism may be used to make this explicit. # # Need to consider implications further; the zope_principal_role_map db # table, that caches contextual roles for principals, should probably # first be reworked to be db-less (as for zope_role_permission_map). # #elif not roles: # # then as fallback transition permission use can modify object # kw["permission"] = "bungeni.%s.Edit" % (workflow_name) # fallback permission else: # Dedicated permission for XML multi-source transition. # Given that, irrespective of how sources are grouped into # multi-source XML <transition> elements, there may be only *one* # path from any given *source* to any given *destination* state, # it suffices to use only the first source element + the destination # to guarantee a unique identifier for an XML transition element. # # Note: the "-" char is not allowed within a permission id # (so we use "." also here). # tid = "%s.%s" % (sources[0] or "", destination) pid = "bungeni.%s.wf.%s" % (workflow_name, tid) if not ZCML_PROCESSED: zcml_transition_permission(pid, title, roles) # remember list of roles from xml kw["_roles"] = roles kw["permission"] = pid # python resolvables if "condition" in kw: kw["condition"] = capi.get_workflow_condition(kw["condition"]) # numeric if "order" in kw: kw["order"] = float(kw["order"]) # ValueError if not numeric # bool if "require_confirmation" in kw: try: kw["require_confirmation"] = misc.as_bool(kw["require_confirmation"]) assert kw["require_confirmation"] is not None #!+RNC except: raise ValueError("Invalid transition value " '[require_confirmation="%s"]' % ( t.get("require_confirmation"))) # multiple-source transitions are really multiple "transition paths" for source in sources: args = (title, source, destination) transitions.append(Transition(*args, **kw)) log.debug("[%s] adding transition [%s-%s] [%s]" % ( workflow_name, source or "", destination, kw)) return Workflow(workflow_name, workflow_features, workflow_facets, states, transitions, global_grants, workflow_title, workflow_description, note)
def test_item(self): # Mock schema model class ITestSchema(Interface): test = zope.schema.TextLine(title=u"Test") ITestSchema.setTaggedValue(READ_PERMISSIONS_KEY, dict(test='zope2.View', foo='foo.View')) from plone.autoform.interfaces import IFormFieldProvider @provider(IFormFieldProvider) class ITestBehavior(Interface): test2 = zope.schema.TextLine(title=u"Test") ITestBehavior.setTaggedValue(READ_PERMISSIONS_KEY, dict(test2='zope2.View', foo2='foo.View')) # Mock a test behavior from plone.behavior.registration import BehaviorRegistration registration = BehaviorRegistration( title=u"Test Behavior", description=u"Provides test behavior", interface=ITestBehavior, marker=Interface, factory=None) from plone.behavior.interfaces import IBehavior self.mock_utility(registration, IBehavior, ITestBehavior.__identifier__) from plone.dexterity.behavior import DexterityBehaviorAssignable from plone.dexterity.interfaces import IDexterityContent from plone.behavior.interfaces import IBehaviorAssignable self.mock_adapter(DexterityBehaviorAssignable, IBehaviorAssignable, (IDexterityContent, )) # Mock FTI fti_mock = self.mocker.proxy(DexterityFTI(u"testtype")) self.mock_utility(fti_mock, IDexterityFTI, u'testtype') # Mock permissions self.mock_utility(Permission(u'zope2.View', u"View"), IPermission, u'zope2.View') self.mock_utility(Permission(u'foo.View', u"View foo"), IPermission, u'foo.View') # Content item item = Item('test') item.portal_type = u"testtype" item.test = u"foo" item.foo = u"bar" # mock security manager securityManager_mock = self.mocker.mock() getSecurityManager_mock = self.mocker.replace( 'AccessControl.getSecurityManager') # expectations # run 1 # lookupSchema is always called twice: cache and __providedBy__ self.expect(fti_mock.lookupSchema()).result(ITestSchema) self.expect(fti_mock.behaviors).result(tuple()) self.expect(securityManager_mock.checkPermission("View", item)).result(False) # run 2 self.expect(fti_mock.lookupSchema()).result(ITestSchema) self.expect(fti_mock.behaviors).result(tuple()) self.expect(securityManager_mock.checkPermission("View foo", item)).result(True) # run 3 self.expect(fti_mock.lookupSchema()).result(ITestSchema) self.expect(fti_mock.behaviors).result(tuple()) # # run 4 self.expect(fti_mock.lookupSchema()).result(ITestSchema) self.expect(fti_mock.behaviors).result([ITestBehavior.__identifier__]) self.expect(securityManager_mock.checkPermission("View", item)).result(True) # # run 5 self.expect(fti_mock.lookupSchema()).result(None) self.expect(fti_mock.behaviors).result([ITestBehavior.__identifier__]) self.expect(securityManager_mock.checkPermission("View", item)).result(True) # for all 5 runs self.expect( getSecurityManager_mock()).result(securityManager_mock).count(4) self.mocker.replay() # run 1: schema and no behavior access to schema protected attribute SCHEMA_CACHE.clear() self.assertFalse( item.__allow_access_to_unprotected_subobjects__('test', u"foo")) # # run 2: schema and no behavior access to known non schema attribute SCHEMA_CACHE.clear() self.assertTrue( item.__allow_access_to_unprotected_subobjects__('foo', u"bar")) # # run 3: schema and no behavior, unknown attributes are allowed SCHEMA_CACHE.clear() self.assertTrue( item.__allow_access_to_unprotected_subobjects__( 'random', u"stuff")) # # run 4: schema and behavior SCHEMA_CACHE.clear() self.assertTrue( item.__allow_access_to_unprotected_subobjects__('test2', u"foo2")) # run 5: no schema but behavior SCHEMA_CACHE.clear() self.assertTrue( item.__allow_access_to_unprotected_subobjects__('test2', u"foo2"))
def setUp(self): super(TestFormDirectives, self).setUp() self.mock_utility( Permission(u'cmf.AddPortalContent', u"Add portal content"), IPermission, u'cmf.AddPortalContent') grok('plone.directives.dexterity.form')
def test_item(self): # Mock schema model class ITestSchema(Interface): test = zope.schema.TextLine(title=u"Test") ITestSchema.setTaggedValue(READ_PERMISSIONS_KEY, dict(test='zope2.View', foo='foo.View')) from plone.autoform.interfaces import IFormFieldProvider @provider(IFormFieldProvider) class ITestBehavior(Interface): test2 = zope.schema.TextLine(title=u"Test") ITestBehavior.setTaggedValue(READ_PERMISSIONS_KEY, dict(test2='zope2.View', foo2='foo.View')) # Mock a test behavior from plone.behavior.registration import BehaviorRegistration registration = BehaviorRegistration( title=u"Test Behavior", description=u"Provides test behavior", interface=ITestBehavior, marker=Interface, factory=None) from plone.behavior.interfaces import IBehavior self.mock_utility(registration, IBehavior, ITestBehavior.__identifier__) from plone.dexterity.behavior import DexterityBehaviorAssignable from plone.dexterity.interfaces import IDexterityContent from plone.behavior.interfaces import IBehaviorAssignable self.mock_adapter(DexterityBehaviorAssignable, IBehaviorAssignable, (IDexterityContent, )) # Mock FTI fti_mock = DexterityFTI(u"testtype") fti_mock.behaviors = () fti_mock.lookupSchema = Mock(return_value=ITestSchema) self.mock_utility(fti_mock, IDexterityFTI, u'testtype') # Mock permissions self.mock_utility(Permission(u'zope2.View', u"View"), IPermission, u'zope2.View') self.mock_utility(Permission(u'foo.View', u"View foo"), IPermission, u'foo.View') # Content item item = Item('test') item.portal_type = u"testtype" item.test = u"foo" item.foo = u"bar" # mock security manager security_manager_mock = Mock() from AccessControl import getSecurityManager self.patch_global(getSecurityManager, return_value=security_manager_mock) # run 1: schema and no behavior access to schema protected attribute security_manager_mock.checkPermission = Mock(return_value=False) SCHEMA_CACHE.clear() self.assertFalse( item.__allow_access_to_unprotected_subobjects__('test', u"foo")) security_manager_mock.checkPermission.assert_called_with('View', item) # run 2: schema and no behavior access to known non schema attribute security_manager_mock.checkPermission = Mock(return_value=True) SCHEMA_CACHE.clear() self.assertTrue( item.__allow_access_to_unprotected_subobjects__('foo', u"bar")) security_manager_mock.checkPermission.assert_called_with( 'View foo', item) # run 3: schema and no behavior, unknown attributes are allowed SCHEMA_CACHE.clear() self.assertTrue( item.__allow_access_to_unprotected_subobjects__( 'random', u"stuff")) # run 4: schema and behavior security_manager_mock.checkPermission = Mock(return_value=True) fti_mock.behaviors = [ITestBehavior.__identifier__] SCHEMA_CACHE.clear() self.assertTrue( item.__allow_access_to_unprotected_subobjects__('test2', u"foo2")) security_manager_mock.checkPermission.assert_called_with('View', item) # run 5: no schema but behavior security_manager_mock.checkPermission = Mock(return_value=True) fti_mock.lookupSchema = Mock(return_value=None) SCHEMA_CACHE.clear() self.assertTrue( item.__allow_access_to_unprotected_subobjects__('test2', u"foo2")) security_manager_mock.checkPermission.assert_called_with('View', item)