diff -r d988eec2d5d3 -r 6c4ae3a06619 hooks/security.py --- a/hooks/security.py Wed Jun 26 14:22:22 2013 +0200 +++ b/hooks/security.py Wed Jul 03 14:16:21 2013 +0200 @@ -23,10 +23,13 @@ from logilab.common.registry import objectify_predicate +from yams import buildobjs + from cubicweb import Unauthorized 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): eid = entity.eid eschema = entity.e_schema @@ -39,9 +42,26 @@ if attr in dontcheck: continue rdef = eschema.rdef(attr) - if rdef.final: # non final relation are checked by other hooks - # add/delete should be equivalent (XXX: unify them into 'update' ?) - if creation and not rdef.permissions.get('update'): + if rdef.final: # non final relation are checked by standard hooks + # attributes only have a specific 'update' permission + updateperm = rdef.permissions.get('update') + # 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)) + # + # 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. + 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)