diff -r 43b4895a150f -r 79b9bf88be28 hooks/security.py --- a/hooks/security.py Fri Feb 14 17:52:49 2014 +0100 +++ b/hooks/security.py Mon Feb 17 11:13:27 2014 +0100 @@ -1,4 +1,4 @@ -# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of CubicWeb. @@ -20,6 +20,7 @@ """ __docformat__ = "restructuredtext en" +from warnings import warn from logilab.common.registry import objectify_predicate @@ -29,8 +30,8 @@ from cubicweb.server import BEFORE_ADD_RELATIONS, ON_COMMIT_ADD_RELATIONS, hook -_DEFAULT_UPDATE_ATTRPERM = buildobjs.DEFAULT_ATTRPERMS['update'] -def check_entity_attributes(session, entity, editedattrs=None, creation=False): + +def check_entity_attributes(session, entity, action, editedattrs=None): eid = entity.eid eschema = entity.e_schema # ._cw_skip_security_attributes is there to bypass security for attributes @@ -43,27 +44,26 @@ continue rdef = eschema.rdef(attr, takefirst=True) if rdef.final: # non final relation are checked by standard hooks - # attributes only have a specific 'update' permission - updateperm = rdef.permissions.get('update') + perms = rdef.permissions.get(action) # comparison below works because the default update perm is: # - # ('managers', ERQLExpression(Any X WHERE U has_update_permission X, X eid %(x)s, U eid %(u)s)) + # ('managers', ERQLExpression(Any X WHERE U has_update_permission X, + # X eid %(x)s, U eid %(u)s)) # # is deserialized in this order (groups first), and ERQLExpression - # implements comparison by expression. - if updateperm == _DEFAULT_UPDATE_ATTRPERM: - # The default update permission is to delegate to the entity - # update permission. This is an historical artefact but it is - # costly (in general). Hence we take this permission object as a - # marker saying "no specific" update permissions for this - # attribute. Thus we just do nothing. + # implements comparison by rql expression. + if perms == buildobjs.DEFAULT_ATTRPERMS[action]: + # The default rule is to delegate to the entity + # rule. This is an historical artefact. Hence we take + # this object as a marker saying "no specific" + # permission rule for this attribute. Thus we just do + # nothing. continue - if creation and updateperm == (): - # That actually means an immutable attribute. We make an - # _exception_ to the `check attr update perms at entity create & - # update time` rule for this case. - continue - rdef.check_perm(session, 'update', eid=eid) + if perms == (): + # That means an immutable attribute; as an optimization, avoid + # going through check_perm. + raise Unauthorized(action, str(rdef)) + rdef.check_perm(session, action, eid=eid) class CheckEntityPermissionOp(hook.DataOperationMixIn, hook.LateOperation): @@ -72,8 +72,7 @@ for eid, action, edited in self.get_data(): entity = session.entity_from_eid(eid) entity.cw_check_perm(action) - check_entity_attributes(session, entity, edited, - creation=(action == 'add')) + check_entity_attributes(session, entity, action, edited) class CheckRelationPermissionOp(hook.DataOperationMixIn, hook.LateOperation): @@ -111,17 +110,11 @@ events = ('after_update_entity',) def __call__(self): - try: - # check user has permission right now, if not retry at commit time - self.entity.cw_check_perm('update') - check_entity_attributes(self._cw, self.entity) - except Unauthorized: - self.entity._cw_clear_local_perm_cache('update') - # save back editedattrs in case the entity is reedited later in the - # same transaction, which will lead to cw_edited being - # overwritten - CheckEntityPermissionOp.get_instance(self._cw).add_data( - (self.entity.eid, 'update', self.entity.cw_edited) ) + # save back editedattrs in case the entity is reedited later in the + # same transaction, which will lead to cw_edited being + # overwritten + CheckEntityPermissionOp.get_instance(self._cw).add_data( + (self.entity.eid, 'update', self.entity.cw_edited) ) class BeforeDelEntitySecurityHook(SecurityHook):