From 2563aed9b050da8cdff432a734d68aef2e02493e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Tue, 11 Jan 2022 23:07:45 +0100 Subject: [PATCH] Check read access on parent field of child/parent operators The 4th element of the clause is the parent field for the child_of/parent_of operators, so it must be used to check access as related field. Also we must remove the 4th element when checking related domain. issue11115 review391371002 --- trytond/model/modelstorage.py | 26 ++++++++++++++-------- trytond/tests/access.py | 1 + trytond/tests/test_access.py | 42 +++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 9 deletions(-) diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index b608a79d7e..92cf8b617b 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -496,13 +496,20 @@ class ModelStorage(Model): if is_leaf(domain): local, relate = (domain[0].split('.', 1) + [None])[:2] to_check[cls.__name__].add(local) - if relate: - if len(domain) >= 4: - target = pool.get(domain[3]) - elif hasattr(cls._fields[local], 'get_target'): - target = cls._fields[local].get_target() - else: - return + field = cls._fields[local] + target = None + if hasattr(field, 'get_target'): + target = cls._fields[local].get_target() + if (not relate + and (domain[1].endswith('child_of') + or domain[1].endswith('parent_of')) + and len(domain) >= 4): + relate = domain[3] + domain = domain[:3] + domain[4:] + if field._type == 'reference' and len(domain) >= 4: + target = pool.get(domain[3]) + domain = domain[:3] + domain[4:] + if relate and target: target_domain = [(relate,) + tuple(domain[1:])] check_domain(target_domain, target, to_check) elif not domain: @@ -518,8 +525,9 @@ class ModelStorage(Model): for oexpr, otype in order: local, _, relate = oexpr.partition('.') to_check[cls.__name__].add(local) - if relate and hasattr(cls._fields[local], 'get_target'): - target = cls._fields[local].get_target() + field = cls._fields[local] + if relate and hasattr(field, 'get_target'): + target = field.get_target() target_order = [(relate, otype)] check_order(target_order, target, to_check) diff --git a/trytond/tests/access.py b/trytond/tests/access.py index d42e9b0817..e4c2ef99a9 100644 --- a/trytond/tests/access.py +++ b/trytond/tests/access.py @@ -21,6 +21,7 @@ class TestAccessRelate(ModelSQL): "Test Access" __name__ = 'test.access.relate' value = fields.Integer("Value") + parent = fields.Many2One('test.access.relate', "Parent") class TestAccessModel(TestAccess): diff --git a/trytond/tests/test_access.py b/trytond/tests/test_access.py index 9b5d57dc7e..cf2c1e1cec 100644 --- a/trytond/tests/test_access.py +++ b/trytond/tests/test_access.py @@ -935,6 +935,8 @@ class ModelFieldAccessReadTestCase(_ModelFieldAccessTestCase): TestAccess.search([('relate.value', '=', 42)]) TestAccess.search([('reference.value', '=', 42, 'test.access.relate')]) + TestAccess.search([ + ('reference.parent.value', '=', 42, 'test.access.relate')]) TestAccess.search([], order=[('relate.value', 'ASC')]) @with_transaction(context=_context) @@ -958,9 +960,49 @@ class ModelFieldAccessReadTestCase(_ModelFieldAccessTestCase): with self.assertRaises(AccessError): TestAccess.search( [('reference.value', '=', 42, 'test.access.relate')]) + with self.assertRaises(AccessError): + TestAccess.search( + [('reference.parent.value', '=', 42, 'test.access.relate')]) with self.assertRaises(AccessError): TestAccess.search([], order=[('relate.value', 'ASC')]) + @with_transaction(context=_context) + def test_access_search_relate_parent_field(self): + "Test access on search relate with a parent field" + pool = Pool() + TestAccess = pool.get('test.access') + Field = pool.get('ir.model.field') + FieldAccess = pool.get('ir.model.field.access') + field, = Field.search([ + ('model.model', '=', 'test.access.relate'), + ('name', '=', 'parent'), + ]) + FieldAccess.create([{ + 'field': field.id, + 'perm_read': True, + }]) + + TestAccess.search([('relate', 'child_of', 42, 'parent')]) + + @with_transaction(context=_context) + def test_no_access_search_relate_parent_field(self): + "Test no access on search relate with a parent field" + pool = Pool() + TestAccess = pool.get('test.access') + Field = pool.get('ir.model.field') + FieldAccess = pool.get('ir.model.field.access') + field, = Field.search([ + ('model.model', '=', 'test.access.relate'), + ('name', '=', 'parent'), + ]) + FieldAccess.create([{ + 'field': field.id, + 'perm_read': False, + }]) + + with self.assertRaises(AccessError): + TestAccess.search([('relate', 'child_of', 42, 'parent')]) + class ModelFieldAccessWriteTestCase(_ModelFieldAccessTestCase): _perm = 'perm_write'