hooks/security.py
changeset 6142 8bc6eac1fac1
parent 5849 9db65b381028
child 6426 541659c39f6a
equal deleted inserted replaced
6141:b8287e54b528 6142:8bc6eac1fac1
    29 def check_entity_attributes(session, entity, editedattrs=None, creation=False):
    29 def check_entity_attributes(session, entity, editedattrs=None, creation=False):
    30     eid = entity.eid
    30     eid = entity.eid
    31     eschema = entity.e_schema
    31     eschema = entity.e_schema
    32     # ._cw_skip_security_attributes is there to bypass security for attributes
    32     # ._cw_skip_security_attributes is there to bypass security for attributes
    33     # set by hooks by modifying the entity's dictionnary
    33     # set by hooks by modifying the entity's dictionnary
    34     dontcheck = entity._cw_skip_security_attributes
       
    35     if editedattrs is None:
    34     if editedattrs is None:
    36         try:
    35         editedattrs = entity.cw_edited
    37             editedattrs = entity.edited_attributes
    36     dontcheck = editedattrs.skip_security
    38         except AttributeError:
       
    39             editedattrs = entity # XXX unexpected
       
    40     for attr in editedattrs:
    37     for attr in editedattrs:
    41         if attr in dontcheck:
    38         if attr in dontcheck:
    42             continue
    39             continue
    43         rdef = eschema.rdef(attr)
    40         rdef = eschema.rdef(attr)
    44         if rdef.final: # non final relation are checked by other hooks
    41         if rdef.final: # non final relation are checked by other hooks
    45             # add/delete should be equivalent (XXX: unify them into 'update' ?)
    42             # add/delete should be equivalent (XXX: unify them into 'update' ?)
    46             if creation and not rdef.permissions.get('update'):
    43             if creation and not rdef.permissions.get('update'):
    47                 continue
    44                 continue
    48             rdef.check_perm(session, 'update', eid=eid)
    45             rdef.check_perm(session, 'update', eid=eid)
    49     # don't update dontcheck until everything went fine: see usage in
       
    50     # after_update_entity, where if we got an Unauthorized at hook time, we will
       
    51     # retry and commit time
       
    52     dontcheck |= frozenset(editedattrs)
       
    53 
    46 
    54 
    47 
    55 class _CheckEntityPermissionOp(hook.LateOperation):
    48 class _CheckEntityPermissionOp(hook.LateOperation):
    56     def precommit_event(self):
    49     def precommit_event(self):
    57         #print 'CheckEntityPermissionOp', self.session.user, self.entity, self.action
    50         #print 'CheckEntityPermissionOp', self.session.user, self.entity, self.action
    58         session = self.session
    51         session = self.session
    59         for values in session.transaction_data.pop('check_entity_perm_op'):
    52         for values in session.transaction_data.pop('check_entity_perm_op'):
    60             entity = session.entity_from_eid(values[0])
    53             eid, action, edited = values
    61             action = values[1]
    54             entity = session.entity_from_eid(eid)
    62             entity.cw_check_perm(action)
    55             entity.cw_check_perm(action)
    63             check_entity_attributes(session, entity, values[2:],
    56             check_entity_attributes(session, entity, edited,
    64                                     creation=self.creation)
    57                                     creation=self.creation)
    65 
       
    66     def commit_event(self):
       
    67         pass
       
    68 
    58 
    69 
    59 
    70 class _CheckRelationPermissionOp(hook.LateOperation):
    60 class _CheckRelationPermissionOp(hook.LateOperation):
    71     def precommit_event(self):
    61     def precommit_event(self):
    72         session = self.session
    62         session = self.session
    73         for args in session.transaction_data.pop('check_relation_perm_op'):
    63         for args in session.transaction_data.pop('check_relation_perm_op'):
    74             action, rschema, eidfrom, eidto = args
    64             action, rschema, eidfrom, eidto = args
    75             rdef = rschema.rdef(session.describe(eidfrom)[0],
    65             rdef = rschema.rdef(session.describe(eidfrom)[0],
    76                                 session.describe(eidto)[0])
    66                                 session.describe(eidto)[0])
    77             rdef.check_perm(session, action, fromeid=eidfrom, toeid=eidto)
    67             rdef.check_perm(session, action, fromeid=eidfrom, toeid=eidto)
    78 
       
    79     def commit_event(self):
       
    80         pass
       
    81 
    68 
    82 
    69 
    83 @objectify_selector
    70 @objectify_selector
    84 @lltrace
    71 @lltrace
    85 def write_security_enabled(cls, req, **kwargs):
    72 def write_security_enabled(cls, req, **kwargs):
    97     __regid__ = 'securityafteraddentity'
    84     __regid__ = 'securityafteraddentity'
    98     events = ('after_add_entity',)
    85     events = ('after_add_entity',)
    99 
    86 
   100     def __call__(self):
    87     def __call__(self):
   101         hook.set_operation(self._cw, 'check_entity_perm_op',
    88         hook.set_operation(self._cw, 'check_entity_perm_op',
   102                            (self.entity.eid, 'add') + tuple(self.entity.edited_attributes),
    89                            (self.entity.eid, 'add', self.entity.cw_edited),
   103                            _CheckEntityPermissionOp, creation=True)
    90                            _CheckEntityPermissionOp, creation=True)
   104 
    91 
   105 
    92 
   106 class AfterUpdateEntitySecurityHook(SecurityHook):
    93 class AfterUpdateEntitySecurityHook(SecurityHook):
   107     __regid__ = 'securityafterupdateentity'
    94     __regid__ = 'securityafterupdateentity'
   113             self.entity.cw_check_perm('update')
   100             self.entity.cw_check_perm('update')
   114             check_entity_attributes(self._cw, self.entity)
   101             check_entity_attributes(self._cw, self.entity)
   115         except Unauthorized:
   102         except Unauthorized:
   116             self.entity._cw_clear_local_perm_cache('update')
   103             self.entity._cw_clear_local_perm_cache('update')
   117             # save back editedattrs in case the entity is reedited later in the
   104             # save back editedattrs in case the entity is reedited later in the
   118             # same transaction, which will lead to edited_attributes being
   105             # same transaction, which will lead to cw_edited being
   119             # overwritten
   106             # overwritten
   120             hook.set_operation(self._cw, 'check_entity_perm_op',
   107             hook.set_operation(self._cw, 'check_entity_perm_op',
   121                                (self.entity.eid, 'update') + tuple(self.entity.edited_attributes),
   108                                (self.entity.eid, 'update', self.entity.cw_edited),
   122                                _CheckEntityPermissionOp, creation=False)
   109                                _CheckEntityPermissionOp, creation=False)
   123 
   110 
   124 
   111 
   125 class BeforeDelEntitySecurityHook(SecurityHook):
   112 class BeforeDelEntitySecurityHook(SecurityHook):
   126     __regid__ = 'securitybeforedelentity'
   113     __regid__ = 'securitybeforedelentity'