server/securityhooks.py
branchstable
changeset 4556 43c14e0e8972
parent 4555 8968c50818db
parent 4553 23201259ffeb
child 4560 23e0632df615
equal deleted inserted replaced
4555:8968c50818db 4556:43c14e0e8972
     1 """Security hooks: check permissions to add/delete/update entities according to
       
     2 the user connected to a session
       
     3 
       
     4 :organization: Logilab
       
     5 :copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.
       
     6 :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     7 :license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses
       
     8 """
       
     9 __docformat__ = "restructuredtext en"
       
    10 
       
    11 from cubicweb import Unauthorized
       
    12 from cubicweb.server.pool import LateOperation
       
    13 from cubicweb.server import BEFORE_ADD_RELATIONS, ON_COMMIT_ADD_RELATIONS
       
    14 
       
    15 def check_entity_attributes(session, entity):
       
    16     eid = entity.eid
       
    17     eschema = entity.e_schema
       
    18     # ._default_set is only there on entity creation to indicate unspecified
       
    19     # attributes which has been set to a default value defined in the schema
       
    20     defaults = getattr(entity, '_default_set', ())
       
    21     try:
       
    22         editedattrs = entity.edited_attributes
       
    23     except AttributeError:
       
    24         editedattrs = entity.keys()
       
    25     for attr in editedattrs:
       
    26         if attr in defaults:
       
    27             continue
       
    28         rschema = eschema.subjrels[attr]
       
    29         if rschema.final: # non final relation are checked by other hooks
       
    30             # add/delete should be equivalent (XXX: unify them into 'update' ?)
       
    31             rschema.check_perm(session, 'add', eid)
       
    32 
       
    33 
       
    34 class CheckEntityPermissionOp(LateOperation):
       
    35     def precommit_event(self):
       
    36         #print 'CheckEntityPermissionOp', self.session.user, self.entity, self.action
       
    37         self.entity.check_perm(self.action)
       
    38         check_entity_attributes(self.session, self.entity)
       
    39 
       
    40     def commit_event(self):
       
    41         pass
       
    42 
       
    43 
       
    44 class CheckRelationPermissionOp(LateOperation):
       
    45     def precommit_event(self):
       
    46         self.rschema.check_perm(self.session, self.action, self.fromeid, self.toeid)
       
    47 
       
    48     def commit_event(self):
       
    49         pass
       
    50 
       
    51 def after_add_entity(session, entity):
       
    52     if not session.is_super_session:
       
    53         CheckEntityPermissionOp(session, entity=entity, action='add')
       
    54 
       
    55 def after_update_entity(session, entity):
       
    56     if not session.is_super_session:
       
    57         try:
       
    58             # check user has permission right now, if not retry at commit time
       
    59             entity.check_perm('update')
       
    60             check_entity_attributes(session, entity)
       
    61         except Unauthorized:
       
    62             entity.clear_local_perm_cache('update')
       
    63             CheckEntityPermissionOp(session, entity=entity, action='update')
       
    64 
       
    65 def before_del_entity(session, eid):
       
    66     if not session.is_super_session:
       
    67         eschema = session.repo.schema[session.describe(eid)[0]]
       
    68         eschema.check_perm(session, 'delete', eid)
       
    69 
       
    70 
       
    71 def before_add_relation(session, fromeid, rtype, toeid):
       
    72     if rtype in BEFORE_ADD_RELATIONS and not session.is_super_session:
       
    73         nocheck = session.transaction_data.get('skip-security', ())
       
    74         if (fromeid, rtype, toeid) in nocheck:
       
    75             return
       
    76         rschema = session.repo.schema[rtype]
       
    77         rschema.check_perm(session, 'add', fromeid, toeid)
       
    78 
       
    79 def after_add_relation(session, fromeid, rtype, toeid):
       
    80     if not rtype in BEFORE_ADD_RELATIONS and not session.is_super_session:
       
    81         nocheck = session.transaction_data.get('skip-security', ())
       
    82         if (fromeid, rtype, toeid) in nocheck:
       
    83             return
       
    84         rschema = session.repo.schema[rtype]
       
    85         if rtype in ON_COMMIT_ADD_RELATIONS:
       
    86             CheckRelationPermissionOp(session, action='add', rschema=rschema,
       
    87                                       fromeid=fromeid, toeid=toeid)
       
    88         else:
       
    89             rschema.check_perm(session, 'add', fromeid, toeid)
       
    90 
       
    91 def before_del_relation(session, fromeid, rtype, toeid):
       
    92     if not session.is_super_session:
       
    93         nocheck = session.transaction_data.get('skip-security', ())
       
    94         if (fromeid, rtype, toeid) in nocheck:
       
    95             return
       
    96         session.repo.schema[rtype].check_perm(session, 'delete', fromeid, toeid)
       
    97 
       
    98 def register_security_hooks(hm):
       
    99     """register meta-data related hooks on the hooks manager"""
       
   100     hm.register_hook(after_add_entity, 'after_add_entity', '')
       
   101     hm.register_hook(after_update_entity, 'after_update_entity', '')
       
   102     hm.register_hook(before_del_entity, 'before_delete_entity', '')
       
   103     hm.register_hook(before_add_relation, 'before_add_relation', '')
       
   104     hm.register_hook(after_add_relation, 'after_add_relation', '')
       
   105     hm.register_hook(before_del_relation, 'before_delete_relation', '')
       
   106