details: https://code.tryton.org/tryton/commit/8d3ea53120f2
branch: 7.0
user: Cédric Krier <[email protected]>
date: Thu Nov 05 18:53:44 2026 +0100
description:
Only permit administrators to execute wizards without models or groups
Closes #15205
(grafted from 22897711abb09d83f972c6a2b850cccbfa877021)
diffstat:
trytond/CHANGELOG | 1 +
trytond/trytond/tests/test_wizard.py | 53 +++++++++++++++++++++++++++++++++--
trytond/trytond/tests/wizard.py | 5 +++
trytond/trytond/tests/wizard.xml | 6 ++++
trytond/trytond/wizard/wizard.py | 14 ++++++++-
5 files changed, 73 insertions(+), 6 deletions(-)
diffs (152 lines):
diff -r 91493426a8dd -r 8d3ea53120f2 trytond/CHANGELOG
--- a/trytond/CHANGELOG Fri Oct 30 09:31:43 2026 +0100
+++ b/trytond/CHANGELOG Thu Nov 05 18:53:44 2026 +0100
@@ -1,3 +1,4 @@
+* Only permit administrators to execute wizards without models or groups
(issue15205)
Version 7.0.59 - 2026-10-15
---------------------------
diff -r 91493426a8dd -r 8d3ea53120f2 trytond/trytond/tests/test_wizard.py
--- a/trytond/trytond/tests/test_wizard.py Fri Oct 30 09:31:43 2026 +0100
+++ b/trytond/trytond/tests/test_wizard.py Thu Nov 05 18:53:44 2026 +0100
@@ -145,10 +145,55 @@
"Execute wizard on wrong model"
pool = Pool()
Wizard = pool.get('test.test_wizard', type='wizard')
+ User = pool.get('res.user')
+
+ user = User(login='foo')
+ user.save()
+ session_id, start_state, end_state = Wizard.create()
+
+ with Transaction().set_user(user.id):
+ with self.assertRaises(AccessError):
+ with Transaction().set_context(
+ active_model='test.test_wizard.start'):
+ Wizard.execute(session_id, {}, start_state)
+
+ @with_transaction(context={'_check_access': True})
+ def test_execute_without_model(self):
+ "Execute wizard without model"
+ pool = Pool()
+ Wizard = pool.get('test.test_wizard_no_model', type='wizard')
+ User = pool.get('res.user')
+
+ user = User(login='foo')
+ user.save()
+ session_id, start_state, end_state = Wizard.create()
+
+ with Transaction().set_user(user.id):
+ with self.assertRaises(AccessError):
+ Wizard.execute(session_id, {}, start_state)
+
+ @with_transaction(context={'_check_access': True})
+ def test_execute_without_model_with_group(self):
+ "Execute wizard without model and groups"
+ pool = Pool()
+ Wizard = pool.get('test.test_wizard_no_model', type='wizard')
+ User = pool.get('res.user')
+ Group = pool.get('res.group')
+
+ user = User(login='foo', groups=[Group(name="Group")])
+ user.save()
+ session_id, start_state, end_state = Wizard.create()
+
+ with Transaction().set_user(user.id):
+ with self.assertRaises(AccessError):
+ Wizard.execute(session_id, {}, start_state)
+
+ @with_transaction(context={'_check_access': True})
+ def test_execute_without_model_with_admin(self):
+ "Execute wizard without model"
+ pool = Pool()
+ Wizard = pool.get('test.test_wizard_no_model', type='wizard')
session_id, start_state, end_state = Wizard.create()
- with self.assertRaises(AccessError):
- with Transaction().set_context(
- active_model='test.test_wizard.start'):
- Wizard.execute(session_id, {}, start_state)
+ Wizard.execute(session_id, {}, start_state)
diff -r 91493426a8dd -r 8d3ea53120f2 trytond/trytond/tests/wizard.py
--- a/trytond/trytond/tests/wizard.py Fri Oct 30 09:31:43 2026 +0100
+++ b/trytond/trytond/tests/wizard.py Thu Nov 05 18:53:44 2026 +0100
@@ -49,10 +49,15 @@
return 'end'
+class TestWizardNoModel(TestWizard):
+ __name__ = 'test.test_wizard_no_model'
+
+
def register(module):
Pool.register(
TestWizardStart,
module=module, type_='model')
Pool.register(
TestWizard,
+ TestWizardNoModel,
module=module, type_='wizard')
diff -r 91493426a8dd -r 8d3ea53120f2 trytond/trytond/tests/wizard.xml
--- a/trytond/trytond/tests/wizard.xml Fri Oct 30 09:31:43 2026 +0100
+++ b/trytond/trytond/tests/wizard.xml Thu Nov 05 18:53:44 2026 +0100
@@ -21,5 +21,11 @@
<field name="wiz_name">test.test_wizard</field>
<field name="model">test.access</field>
</record>
+
+ <record model="ir.action.wizard" id="test_wizard_no_model">
+ <field name="name">Test Wizard</field>
+ <field name="wiz_name">test.test_wizard_no_model</field>
+ <field name="model" eval="None"/>
+ </record>
</data>
</tryton>
diff -r 91493426a8dd -r 8d3ea53120f2 trytond/trytond/wizard/wizard.py
--- a/trytond/trytond/wizard/wizard.py Fri Oct 30 09:31:43 2026 +0100
+++ b/trytond/trytond/wizard/wizard.py Thu Nov 05 18:53:44 2026 +0100
@@ -251,11 +251,16 @@
ModelAccess = pool.get('ir.model.access')
ActionWizard = pool.get('ir.action.wizard')
User = pool.get('res.user')
+ ModelData = pool.get('ir.model.data')
context = Transaction().context
if Transaction().user == 0:
return
+ admin_group = ModelData.get_id('res.group_admin')
+ groups = set(User.get_groups())
+ is_admin = admin_group in groups
+
with check_access():
model = context.get('active_model')
if model:
@@ -264,12 +269,11 @@
ModelAccess.check(model, 'read')
models = ActionWizard.get_models(
cls.__name__, action_id=context.get('action_id'))
- if model and models and model not in models:
+ if not is_admin and models and (not model or model not in models):
raise AccessError(gettext(
'ir.msg_access_wizard_model_error',
wizard=cls.__name__,
model=model))
- groups = set(User.get_groups())
wizard_groups = ActionWizard.get_groups(cls.__name__,
action_id=context.get('action_id'))
if wizard_groups:
@@ -282,6 +286,12 @@
or Model.write.__func__ != ModelSQL.write.__func__):
ModelAccess.check(model, 'write')
+ if not is_admin and not models and not wizard_groups:
+ raise AccessError(
+ gettext(
+ 'ir.msg_access_wizard_error',
+ wizard=cls.__name__))
+
if model:
ids = context.get('active_ids') or []
id_ = context.get('active_id')