hooks/security.py
changeset 9395 96dba2efd16d
parent 9254 e1369f2dba79
child 9412 8aa6c923d6c0
child 9469 032825bbacab
equal deleted inserted replaced
9394:4b89ca0b11ad 9395:96dba2efd16d
     1 # copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     1 # copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
     3 #
     3 #
     4 # This file is part of CubicWeb.
     4 # This file is part of CubicWeb.
     5 #
     5 #
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
    18 """Security hooks: check permissions to add/delete/update entities according to
    18 """Security hooks: check permissions to add/delete/update entities according to
    19 the user connected to a session
    19 the user connected to a session
    20 """
    20 """
    21 
    21 
    22 __docformat__ = "restructuredtext en"
    22 __docformat__ = "restructuredtext en"
       
    23 from warnings import warn
    23 
    24 
    24 from logilab.common.registry import objectify_predicate
    25 from logilab.common.registry import objectify_predicate
    25 
    26 
    26 from yams import buildobjs
    27 from yams import buildobjs
    27 
    28 
    28 from cubicweb import Unauthorized
    29 from cubicweb import Unauthorized
    29 from cubicweb.server import BEFORE_ADD_RELATIONS, ON_COMMIT_ADD_RELATIONS, hook
    30 from cubicweb.server import BEFORE_ADD_RELATIONS, ON_COMMIT_ADD_RELATIONS, hook
    30 
    31 
    31 
    32 
    32 _DEFAULT_UPDATE_ATTRPERM = buildobjs.DEFAULT_ATTRPERMS['update']
    33 
    33 def check_entity_attributes(session, entity, editedattrs=None, creation=False):
    34 def check_entity_attributes(session, entity, action, editedattrs=None):
    34     eid = entity.eid
    35     eid = entity.eid
    35     eschema = entity.e_schema
    36     eschema = entity.e_schema
    36     # ._cw_skip_security_attributes is there to bypass security for attributes
    37     # ._cw_skip_security_attributes is there to bypass security for attributes
    37     # set by hooks by modifying the entity's dictionary
    38     # set by hooks by modifying the entity's dictionary
    38     if editedattrs is None:
    39     if editedattrs is None:
    41     for attr in editedattrs:
    42     for attr in editedattrs:
    42         if attr in dontcheck:
    43         if attr in dontcheck:
    43             continue
    44             continue
    44         rdef = eschema.rdef(attr)
    45         rdef = eschema.rdef(attr)
    45         if rdef.final: # non final relation are checked by standard hooks
    46         if rdef.final: # non final relation are checked by standard hooks
    46             # attributes only have a specific 'update' permission
    47             perms = rdef.permissions.get(action)
    47             updateperm = rdef.permissions.get('update')
       
    48             # comparison below works because the default update perm is:
    48             # comparison below works because the default update perm is:
    49             #
    49             #
    50             #  ('managers', ERQLExpression(Any X WHERE U has_update_permission X, X eid %(x)s, U eid %(u)s))
    50             #  ('managers', ERQLExpression(Any X WHERE U has_update_permission X,
       
    51             #                              X eid %(x)s, U eid %(u)s))
    51             #
    52             #
    52             # is deserialized in this order (groups first), and ERQLExpression
    53             # is deserialized in this order (groups first), and ERQLExpression
    53             # implements comparison by expression.
    54             # implements comparison by rql expression.
    54             if updateperm == _DEFAULT_UPDATE_ATTRPERM:
    55             if perms == buildobjs.DEFAULT_ATTRPERMS[action]:
    55                 # The default update permission is to delegate to the entity
    56                 # The default rule is to delegate to the entity
    56                 # update permission. This is an historical artefact but it is
    57                 # rule. This is an historical artefact. Hence we take
    57                 # costly (in general). Hence we take this permission object as a
    58                 # this object as a marker saying "no specific"
    58                 # marker saying "no specific" update permissions for this
    59                 # permission rule for this attribute. Thus we just do
    59                 # attribute. Thus we just do nothing.
    60                 # nothing.
    60                 continue
    61                 continue
    61             if creation and updateperm == ():
    62             if perms == ():
    62                 # That actually means an immutable attribute.  We make an
    63                 # That means an immutable attribute.
    63                 # _exception_ to the `check attr update perms at entity create &
    64                 raise Unauthorized(action, str(rdef))
    64                 # update time` rule for this case.
    65             rdef.check_perm(session, action, eid=eid)
    65                 continue
       
    66             rdef.check_perm(session, 'update', eid=eid)
       
    67 
    66 
    68 
    67 
    69 class CheckEntityPermissionOp(hook.DataOperationMixIn, hook.LateOperation):
    68 class CheckEntityPermissionOp(hook.DataOperationMixIn, hook.LateOperation):
    70     def precommit_event(self):
    69     def precommit_event(self):
    71         session = self.session
    70         session = self.session
    72         for eid, action, edited in self.get_data():
    71         for eid, action, edited in self.get_data():
    73             entity = session.entity_from_eid(eid)
    72             entity = session.entity_from_eid(eid)
    74             entity.cw_check_perm(action)
    73             entity.cw_check_perm(action)
    75             check_entity_attributes(session, entity, edited,
    74             check_entity_attributes(session, entity, action, edited)
    76                                     creation=(action == 'add'))
       
    77 
    75 
    78 
    76 
    79 class CheckRelationPermissionOp(hook.DataOperationMixIn, hook.LateOperation):
    77 class CheckRelationPermissionOp(hook.DataOperationMixIn, hook.LateOperation):
    80     def precommit_event(self):
    78     def precommit_event(self):
    81         session = self.session
    79         session = self.session