[book] stop talking about the hg `forest` extension
# copyright 2003-2013 LOGILAB S.A. (Paris, FRANCE), all rights reserved.# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr## This file is part of CubicWeb.## CubicWeb is free software: you can redistribute it and/or modify it under the# terms of the GNU Lesser General Public License as published by the Free# Software Foundation, either version 2.1 of the License, or (at your option)# any later version.## CubicWeb is distributed in the hope that it will be useful, but WITHOUT# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more# details.## You should have received a copy of the GNU Lesser General Public License along# with CubicWeb. If not, see <http://www.gnu.org/licenses/>."""Security hooks: check permissions to add/delete/update entities according tothe connected user"""__docformat__="restructuredtext en"fromwarningsimportwarnfromlogilab.common.registryimportobjectify_predicatefromyamsimportbuildobjsfromcubicwebimportUnauthorizedfromcubicweb.serverimportBEFORE_ADD_RELATIONS,ON_COMMIT_ADD_RELATIONS,hookdefcheck_entity_attributes(cnx,entity,action,editedattrs=None):eid=entity.eideschema=entity.e_schema# ._cw_skip_security_attributes is there to bypass security for attributes# set by hooks by modifying the entity's dictionaryifeditedattrsisNone:editedattrs=entity.cw_editeddontcheck=editedattrs.skip_securityforattrineditedattrs:ifattrindontcheck:continuerdef=eschema.rdef(attr,takefirst=True)ifrdef.final:# non final relation are checked by standard hooksperms=rdef.permissions.get(action)# comparison below works because the default update perm is:## ('managers', ERQLExpression(Any X WHERE U has_update_permission X,# X eid %(x)s, U eid %(u)s))## is deserialized in this order (groups first), and ERQLExpression# implements comparison by rql expression.ifperms==buildobjs.DEFAULT_ATTRPERMS[action]:# The default rule is to delegate to the entity# rule. This is an historical artefact. Hence we take# this object as a marker saying "no specific"# permission rule for this attribute. Thus we just do# nothing.continueifperms==():# That means an immutable attribute; as an optimization, avoid# going through check_perm.raiseUnauthorized(action,str(rdef))rdef.check_perm(cnx,action,eid=eid)classCheckEntityPermissionOp(hook.DataOperationMixIn,hook.LateOperation):defprecommit_event(self):cnx=self.cnxforeid,action,editedinself.get_data():entity=cnx.entity_from_eid(eid)entity.cw_check_perm(action)check_entity_attributes(cnx,entity,action,edited)classCheckRelationPermissionOp(hook.DataOperationMixIn,hook.LateOperation):defprecommit_event(self):cnx=self.cnxforaction,rschema,eidfrom,eidtoinself.get_data():rdef=rschema.rdef(cnx.entity_metas(eidfrom)['type'],cnx.entity_metas(eidto)['type'])rdef.check_perm(cnx,action,fromeid=eidfrom,toeid=eidto)@objectify_predicatedefwrite_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.get_instance(self._cw).add_data((self.entity.eid,'add',self.entity.cw_edited))classAfterUpdateEntitySecurityHook(SecurityHook):__regid__='securityafterupdateentity'events=('after_update_entity',)def__call__(self):# save back editedattrs in case the entity is reedited later in the# same transaction, which will lead to cw_edited being# overwrittenCheckEntityPermissionOp.get_instance(self._cw).add_data((self.entity.eid,'update',self.entity.cw_edited))classBeforeDelEntitySecurityHook(SecurityHook):__regid__='securitybeforedelentity'events=('before_delete_entity',)def__call__(self):self.entity.cw_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.entity_metas(self.eidfrom)['type'],self._cw.entity_metas(self.eidto)['type'])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.get_instance(self._cw).add_data(('add',rschema,self.eidfrom,self.eidto))else:rdef=rschema.rdef(self._cw.entity_metas(self.eidfrom)['type'],self._cw.entity_metas(self.eidto)['type'])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.entity_metas(self.eidfrom)['type'],self._cw.entity_metas(self.eidto)['type'])rdef.check_perm(self._cw,'delete',fromeid=self.eidfrom,toeid=self.eidto)