details:   https://code.tryton.org/tryton/commit/2bad239629b3
branch:    default
user:      Cédric Krier <[email protected]>
date:      Fri Oct 30 16:25:08 2026 +0100
description:
        Restrict the wizard session to the user who created it

        Closes #15206
diffstat:

 trytond/CHANGELOG                    |   1 +
 trytond/trytond/tests/test_wizard.py |  32 ++++++++++++++++++++++++++++++++
 trytond/trytond/wizard/wizard.py     |  16 +++++++++++++---
 3 files changed, 46 insertions(+), 3 deletions(-)

diffs (97 lines):

diff -r 2e84ffa5c760 -r 2bad239629b3 trytond/CHANGELOG
--- a/trytond/CHANGELOG Fri Oct 30 15:49:54 2026 +0100
+++ b/trytond/CHANGELOG Fri Oct 30 16:25:08 2026 +0100
@@ -1,3 +1,4 @@
+* Restrict the wizard session to the user who created it (issue15206)
 * Only permit administrators to execute wizards without models or groups 
(issue15205)
 
 Version 8.2.0 - 2026-10-05
diff -r 2e84ffa5c760 -r 2bad239629b3 trytond/trytond/tests/test_wizard.py
--- a/trytond/trytond/tests/test_wizard.py      Fri Oct 30 15:49:54 2026 +0100
+++ b/trytond/trytond/tests/test_wizard.py      Fri Oct 30 16:25:08 2026 +0100
@@ -31,6 +31,22 @@
         Wizard.delete(session_id)
 
     @with_transaction()
+    def test_delete_different_user(self):
+        "Delete session from a different user"
+        pool = Pool()
+        Wizard = pool.get('test.test_wizard', type='wizard')
+        User = pool.get('res.user')
+
+        user = User(login='foo')
+        user.save()
+
+        session_id, _, _ = Wizard.create()
+
+        with Transaction().set_user(user.id):
+            with self.assertRaises(AccessError):
+                Wizard.delete(session_id)
+
+    @with_transaction()
     def test_session(self):
         'Session Wizard'
         pool = Pool()
@@ -90,6 +106,22 @@
                 session_id, start_state, end_state = Wizard.create()
 
     @with_transaction()
+    def test_session_different_user(self):
+        "Use session from a different user"
+        pool = Pool()
+        Wizard = pool.get('test.test_wizard', type='wizard')
+        User = pool.get('res.user')
+
+        user = User(login='foo')
+        user.save()
+
+        session_id, _, _ = Wizard.create()
+
+        with Transaction().set_user(user.id):
+            with self.assertRaises(AccessError):
+                Wizard(session_id)
+
+    @with_transaction()
     def test_execute(self):
         'Execute Wizard'
         pool = Pool()
diff -r 2e84ffa5c760 -r 2bad239629b3 trytond/trytond/wizard/wizard.py
--- a/trytond/trytond/wizard/wizard.py  Fri Oct 30 15:49:54 2026 +0100
+++ b/trytond/trytond/wizard/wizard.py  Fri Oct 30 16:25:08 2026 +0100
@@ -318,14 +318,20 @@
     @classmethod
     def delete(cls, session_id):
         "Delete the session"
-        Session = Pool().get('ir.session.wizard')
+        pool = Pool()
+        Session = pool.get('ir.session.wizard')
+        transaction = Transaction()
+        session = Session(session_id)
+        if session.create_uid.id != transaction.user:
+            raise AccessError(
+                gettext('ir.msg_access_wizard_error', wizard=cls.__name__))
         end = getattr(cls, cls.end_state, None)
         if end:
             wizard = cls(session_id)
             action = end(wizard)
         else:
             action = None
-        Session.delete([Session(session_id)])
+        Session.delete([session])
         return action
 
     @classmethod
@@ -407,8 +413,12 @@
     def __init__(self, session_id):
         pool = Pool()
         Session = pool.get('ir.session.wizard')
-        self._session_id = session_id
+        transaction = Transaction()
         session = Session(session_id)
+        if session.create_uid.id != transaction.user:
+            raise AccessError(
+                gettext('ir.msg_access_wizard_error', wizard=self.__name__))
+        self._session_id = session.id
         data = defaultdict(dict)
         data.update(json.loads(session.data, object_hook=JSONDecoder()))
         for state_name, state in self.states.items():

Reply via email to