# HG changeset patch # User Sylvain Thénault # Date 1434358173 -7200 # Node ID 90fcddcce1663362095a4fd405f99c3da7a6bb9e # Parent 67890235cb78166f33445434821ed032db19ad82 when some inlined relation is set using cw_edited, its security shouldn't be checked. It's currently checked anyway because upon modification of `cw_edited`, `entity.skip_security` is updated to avoid security checking, but this is only considered for attributes, not relations. Closes #5477315 diff -r 67890235cb78 -r 90fcddcce166 hooks/security.py --- a/hooks/security.py Mon Jun 15 10:46:49 2015 +0200 +++ b/hooks/security.py Mon Jun 15 10:49:33 2015 +0200 @@ -136,6 +136,19 @@ self.entity.cw_check_perm('delete') +def skip_inlined_relation_security(cnx, rschema, eid): + """return True if security for the given inlined relation should be skipped, + in case where the relation has been set through modification of + `entity.cw_edited` in a hook + """ + assert rschema.inlined + try: + entity = cnx.transaction_data['ecache'][eid] + except KeyError: + return False + return rschema.type in entity.cw_edited.skip_security + + class BeforeAddRelationSecurityHook(SecurityHook): __regid__ = 'securitybeforeaddrelation' events = ('before_add_relation',) @@ -146,6 +159,9 @@ if (self.eidfrom, self.rtype, self.eidto) in nocheck: return rschema = self._cw.repo.schema[self.rtype] + if rschema.inlined and skip_inlined_relation_security( + self._cw, rschema, self.eidfrom): + return 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) @@ -156,11 +172,14 @@ events = ('after_add_relation',) def __call__(self): - if not self.rtype in BEFORE_ADD_RELATIONS: + if self.rtype not in BEFORE_ADD_RELATIONS: nocheck = self._cw.transaction_data.get('skip-security', ()) if (self.eidfrom, self.rtype, self.eidto) in nocheck: return rschema = self._cw.repo.schema[self.rtype] + if rschema.inlined and skip_inlined_relation_security( + self._cw, rschema, self.eidfrom): + return if self.rtype in ON_COMMIT_ADD_RELATIONS: CheckRelationPermissionOp.get_instance(self._cw).add_data( ('add', rschema, self.eidfrom, self.eidto) ) @@ -179,6 +198,9 @@ if (self.eidfrom, self.rtype, self.eidto) in nocheck: return rschema = self._cw.repo.schema[self.rtype] + if rschema.inlined and skip_inlined_relation_security( + self._cw, rschema, self.eidfrom): + return 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) diff -r 67890235cb78 -r 90fcddcce166 hooks/test/unittest_security.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hooks/test/unittest_security.py Mon Jun 15 10:49:33 2015 +0200 @@ -0,0 +1,56 @@ +# copyright 2015 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 . + +from cubicweb.devtools.testlib import CubicWebTC +from cubicweb.server import hook +from cubicweb.predicates import is_instance + + +class SecurityHooksTC(CubicWebTC): + def setup_database(self): + with self.admin_access.repo_cnx() as cnx: + self.add_eid = cnx.create_entity('EmailAddress', + address=u'hop@perdu.com', + reverse_use_email=cnx.user.eid).eid + cnx.commit() + + def test_inlined_cw_edited_relation(self): + """modification of cw_edited to add an inlined relation shouldn't trigger a security error. + + Test for https://www.cubicweb.org/ticket/5477315 + """ + sender = self.repo.schema['Email'].rdef('sender') + with self.temporary_permissions((sender, {'add': ()})): + + class MyHook(hook.Hook): + __regid__ = 'test.pouet' + __select__ = hook.Hook.__select__ & is_instance('Email') + events = ('before_add_entity',) + + def __call__(self): + self.entity.cw_edited['sender'] = self._cw.user.primary_email[0].eid + + with self.temporary_appobjects(MyHook): + with self.admin_access.repo_cnx() as cnx: + email = cnx.create_entity('Email', messageid=u'1234') + cnx.commit() + self.assertEqual(email.sender[0].eid, self.add_eid) + +if __name__ == '__main__': + from logilab.common.testlib import unittest_main + unittest_main()