hooks/security.py
branchstable
changeset 9542 79b9bf88be28
parent 9536 1e39c5e91b68
child 9543 39f981482e34
child 9981 7099bbd685aa
--- 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):