hooks/security.py
changeset 2835 04034421b072
parent 2647 b0a2e779845c
child 2847 c2ee28f4d4b1
equal deleted inserted replaced
2834:7df3494ae657 2835:04034421b072
       
     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-2009 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 import BEFORE_ADD_RELATIONS, ON_COMMIT_ADD_RELATIONS, hook
       
    13 
       
    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
       
    25     for attr in editedattrs:
       
    26         if attr in defaults:
       
    27             continue
       
    28         rschema = eschema.subject_relation(attr)
       
    29         if rschema.is_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(hook.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(hook.LateOperation):
       
    45     def precommit_event(self):
       
    46         self.rschema.check_perm(self.session, self.action, self.eidfrom, self.eidto)
       
    47 
       
    48     def commit_event(self):
       
    49         pass
       
    50 
       
    51 
       
    52 class SecurityHook(hook.Hook):
       
    53     __abstract__ = True
       
    54     category = 'security'
       
    55     __select__ = hook.Hook.__select__ & hook.regular_session()
       
    56 
       
    57 
       
    58 class AfterAddEntitySecurityHook(SecurityHook):
       
    59     __id__ = 'securityafteraddentity'
       
    60     events = ('after_add_entity',)
       
    61 
       
    62     def __call__(self):
       
    63         _CheckEntityPermissionOp(self.cw_req, entity=self.entity, action='add')
       
    64 
       
    65 
       
    66 class AfterUpdateEntitySecurityHook(SecurityHook):
       
    67     __id__ = 'securityafterupdateentity'
       
    68     events = ('after_update_entity',)
       
    69 
       
    70     def __call__(self):
       
    71         try:
       
    72             # check user has permission right now, if not retry at commit time
       
    73             self.entity.check_perm('update')
       
    74             check_entity_attributes(self.cw_req, self.entity)
       
    75         except Unauthorized:
       
    76             self.entity.clear_local_perm_cache('update')
       
    77             _CheckEntityPermissionOp(self.cw_req, entity=self.entity, action='update')
       
    78 
       
    79 
       
    80 class BeforeDelEntitySecurityHook(SecurityHook):
       
    81     __id__ = 'securitybeforedelentity'
       
    82     events = ('before_delete_entity',)
       
    83 
       
    84     def __call__(self):
       
    85         self.entity.e_schema.check_perm(self.cw_req, 'delete', eid)
       
    86 
       
    87 
       
    88 class BeforeAddRelationSecurityHook(SecurityHook):
       
    89     __id__ = 'securitybeforeaddrelation'
       
    90     events = ('before_add_relation',)
       
    91 
       
    92     def __call__(self):
       
    93         if self.rtype in BEFORE_ADD_RELATIONS:
       
    94             rschema = self.cw_req.repo.schema[self.rtype]
       
    95             rschema.check_perm(self.cw_req, 'add', self.eidfrom, self.eidto)
       
    96 
       
    97 
       
    98 class AfterAddRelationSecurityHook(SecurityHook):
       
    99     __id__ = 'securityafteraddrelation'
       
   100     events = ('after_add_relation',)
       
   101 
       
   102     def __call__(self):
       
   103         if not self.rtype in BEFORE_ADD_RELATIONS:
       
   104             rschema = self.cw_req.repo.schema[self.rtype]
       
   105             if self.rtype in ON_COMMIT_ADD_RELATIONS:
       
   106                 _CheckRelationPermissionOp(self.cw_req, action='add',
       
   107                                            rschema=rschema,
       
   108                                            eidfrom=self.eidfrom,
       
   109                                            eidto=self.eidto)
       
   110             else:
       
   111                 rschema.check_perm(self.cw_req, 'add', self.eidfrom, self.eidto)
       
   112 
       
   113 
       
   114 class BeforeDelRelationSecurityHook(SecurityHook):
       
   115     __id__ = 'securitybeforedelrelation'
       
   116     events = ('before_delete_relation',)
       
   117 
       
   118     def __call__(self):
       
   119         self.cw_req.repo.schema[self.rtype].check_perm(self.cw_req, 'delete',
       
   120                                                        self.eidfrom, self.eidto)
       
   121