diff --git a/CHANGELOG b/CHANGELOG index 0afa32b9aa..8ae1b2edc5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Check read access on field in search order (issue8189) * Add base64 converter to URL map * Add HTML widget * Support import of native numeric, date and datetime data diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py index 3d2d50bc6d..5b4dbc8f05 100644 --- a/trytond/model/modelstorage.py +++ b/trytond/model/modelstorage.py @@ -438,7 +438,7 @@ class ModelStorage(Model): ModelAccess.check(cls.__name__, 'read') - def check(domain, cls, to_check): + def check_domain(domain, cls, to_check): if is_leaf(domain): local, relate = (domain[0].split('.', 1) + [None])[:2] to_check[cls.__name__].add(local) @@ -448,16 +448,29 @@ class ModelStorage(Model): else: target = cls._fields[local].get_target() target_domain = [(relate,) + tuple(domain[1:])] - check(target_domain, target, to_check) + check_domain(target_domain, target, to_check) elif not domain: return else: i = 1 if domain[0] in ['OR', 'AND'] else 0 for d in domain[i:]: - check(d, cls, to_check) + check_domain(d, cls, to_check) + + def check_order(order, cls, to_check): + if not order: + return + for oexpr, otype in order: + local, _, relate = oexpr.partition('.') + to_check[cls.__name__].add(local) + if relate: + target = cls._fields[local].get_target() + target_order = [(relate, otype)] + check_order(target_order, target, to_check) + if transaction.user and transaction.context.get('_check_access'): to_check = defaultdict(set) - check(domain, cls, to_check) + check_domain(domain, cls, to_check) + check_order(order, cls, to_check) for name, fields_names in to_check.items(): ModelAccess.check(name, 'read') ModelFieldAccess.check(name, fields_names, 'read') diff --git a/trytond/tests/test_access.py b/trytond/tests/test_access.py index 850fbd1483..8221b32076 100644 --- a/trytond/tests/test_access.py +++ b/trytond/tests/test_access.py @@ -299,6 +299,7 @@ class ModelAccessReadTestCase(_ModelAccessTestCase): TestAccess.read([record.id], ['relate.value']) TestAccess.search([('relate.value', '=', 42)]) TestAccess.search([('reference.value', '=', 42, 'test.access.relate')]) + TestAccess.search([], order=[('relate.value', 'ASC')]) @with_transaction(context=_context) def test_no_access_relate(self): @@ -321,6 +322,8 @@ class ModelAccessReadTestCase(_ModelAccessTestCase): with self.assertRaises(AccessError): TestAccess.search( [('reference.value', '=', 42, 'test.access.relate')]) + with self.assertRaises(AccessError): + TestAccess.search([], order=[('relate.value', 'ASC')]) class ModelAccessWriteTestCase(_ModelAccessTestCase): @@ -858,6 +861,7 @@ class ModelFieldAccessReadTestCase(_ModelFieldAccessTestCase): TestAccess.search([('relate.value', '=', 42)]) TestAccess.search([('reference.value', '=', 42, 'test.access.relate')]) + TestAccess.search([], order=[('relate.value', 'ASC')]) @with_transaction(context=_context) def test_no_access_search_relate(self): @@ -880,6 +884,8 @@ class ModelFieldAccessReadTestCase(_ModelFieldAccessTestCase): with self.assertRaises(AccessError): TestAccess.search( [('reference.value', '=', 42, 'test.access.relate')]) + with self.assertRaises(AccessError): + TestAccess.search([], order=[('relate.value', 'ASC')]) class ModelFieldAccessWriteTestCase(_ModelFieldAccessTestCase):