Add a basic script to compare the db_schema to the fs_schema.
Allow SchemaViewer to be used without a request object Most use of self.req have
been hidden in method that fallback on a simple behaviour when no req are
provided.
Several element have been sorted to ease comparison.
"""Security hooks: check permissions to add/delete/update entities according tothe user connected to a session:organization: Logilab:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses"""__docformat__="restructuredtext en"fromcubicwebimportUnauthorizedfromcubicweb.selectorsimportobjectify_selector,lltracefromcubicweb.serverimportBEFORE_ADD_RELATIONS,ON_COMMIT_ADD_RELATIONS,hookdefcheck_entity_attributes(session,entity,editedattrs=None):eid=entity.eideschema=entity.e_schema# .skip_security_attributes is there to bypass security for attributes# set by hooks by modifying the entity's dictionnarydontcheck=entity.skip_security_attributesifeditedattrsisNone:try:editedattrs=entity.edited_attributesexceptAttributeError:editedattrs=entity# XXX unexpectedforattrineditedattrs:ifattrindontcheck:continuerdef=eschema.rdef(attr)ifrdef.final:# non final relation are checked by other hooks# add/delete should be equivalent (XXX: unify them into 'update' ?)rdef.check_perm(session,'update',eid=eid)# don't update dontcheck until everything went fine: see usage in# after_update_entity, where if we got an Unauthorized at hook time, we will# retry and commit timedontcheck|=frozenset(editedattrs)class_CheckEntityPermissionOp(hook.LateOperation):defprecommit_event(self):#print 'CheckEntityPermissionOp', self.session.user, self.entity, self.actionself.entity.check_perm(self.action)check_entity_attributes(self.session,self.entity,self.editedattrs)defcommit_event(self):passclass_CheckRelationPermissionOp(hook.LateOperation):defprecommit_event(self):rdef=self.rschema.rdef(self.session.describe(self.eidfrom)[0],self.session.describe(self.eidto)[0])rdef.check_perm(self.session,self.action,fromeid=self.eidfrom,toeid=self.eidto)defcommit_event(self):pass@objectify_selector@lltracedefwrite_security_enabled(cls,req,**kwargs):ifreqisNoneornotreq.write_security:return0return1classSecurityHook(hook.Hook):__abstract__=Truecategory='security'__select__=hook.Hook.__select__&write_security_enabled()classAfterAddEntitySecurityHook(SecurityHook):__regid__='securityafteraddentity'events=('after_add_entity',)def__call__(self):_CheckEntityPermissionOp(self._cw,entity=self.entity,editedattrs=tuple(self.entity.edited_attributes),action='add')classAfterUpdateEntitySecurityHook(SecurityHook):__regid__='securityafterupdateentity'events=('after_update_entity',)def__call__(self):try:# check user has permission right now, if not retry at commit timeself.entity.check_perm('update')check_entity_attributes(self._cw,self.entity)exceptUnauthorized:self.entity.clear_local_perm_cache('update')# save back editedattrs in case the entity is reedited later in the# same transaction, which will lead to edited_attributes being# overwritten_CheckEntityPermissionOp(self._cw,entity=self.entity,editedattrs=tuple(self.entity.edited_attributes),action='update')classBeforeDelEntitySecurityHook(SecurityHook):__regid__='securitybeforedelentity'events=('before_delete_entity',)def__call__(self):self.entity.check_perm('delete')classBeforeAddRelationSecurityHook(SecurityHook):__regid__='securitybeforeaddrelation'events=('before_add_relation',)def__call__(self):ifself.rtypeinBEFORE_ADD_RELATIONS:nocheck=self._cw.transaction_data.get('skip-security',())if(self.eidfrom,self.rtype,self.eidto)innocheck:returnrschema=self._cw.repo.schema[self.rtype]rdef=rschema.rdef(self._cw.describe(self.eidfrom)[0],self._cw.describe(self.eidto)[0])rdef.check_perm(self._cw,'add',fromeid=self.eidfrom,toeid=self.eidto)classAfterAddRelationSecurityHook(SecurityHook):__regid__='securityafteraddrelation'events=('after_add_relation',)def__call__(self):ifnotself.rtypeinBEFORE_ADD_RELATIONS:nocheck=self._cw.transaction_data.get('skip-security',())if(self.eidfrom,self.rtype,self.eidto)innocheck:returnrschema=self._cw.repo.schema[self.rtype]ifself.rtypeinON_COMMIT_ADD_RELATIONS:_CheckRelationPermissionOp(self._cw,action='add',rschema=rschema,eidfrom=self.eidfrom,eidto=self.eidto)else:rdef=rschema.rdef(self._cw.describe(self.eidfrom)[0],self._cw.describe(self.eidto)[0])rdef.check_perm(self._cw,'add',fromeid=self.eidfrom,toeid=self.eidto)classBeforeDeleteRelationSecurityHook(SecurityHook):__regid__='securitybeforedelrelation'events=('before_delete_relation',)def__call__(self):nocheck=self._cw.transaction_data.get('skip-security',())if(self.eidfrom,self.rtype,self.eidto)innocheck:returnrschema=self._cw.repo.schema[self.rtype]rdef=rschema.rdef(self._cw.describe(self.eidfrom)[0],self._cw.describe(self.eidto)[0])rdef.check_perm(self._cw,'delete',fromeid=self.eidfrom,toeid=self.eidto)