From 39f73b760771eef9fd11302db6111efc20a8c957 Mon Sep 17 00:00:00 2001
From: Leonardo Rochael Almeida <leonardo@nexedi.com>
Date: Fri, 5 Aug 2011 16:23:40 +0200
Subject: [PATCH] Make before-commit interactions immune to security changes

---
 product/ERP5/InteractionWorkflow.py           | 18 ++++++++++++++----
 product/ERP5/tests/testInteractionWorkflow.py |  3 +++
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/product/ERP5/InteractionWorkflow.py b/product/ERP5/InteractionWorkflow.py
index 4df51bf540..2463d71189 100644
--- a/product/ERP5/InteractionWorkflow.py
+++ b/product/ERP5/InteractionWorkflow.py
@@ -22,6 +22,7 @@ from Products.ERP5Type import Globals
 import App
 from types import StringTypes
 from AccessControl import getSecurityManager, ClassSecurityInfo
+from AccessControl.SecurityManagement import setSecurityManager
 from Acquisition import aq_base
 from Products.CMFCore.utils import getToolByName
 from Products.DCWorkflow.DCWorkflow import DCWorkflowDefinition
@@ -290,10 +291,11 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
         # Pass lots of info to the script in a single parameter.
         script(sci)  # May throw an exception
 
-      # Execute Before Commit
+      # Queue the "Before Commit" scripts
+      sm = getSecurityManager()
       for script_name in tdef.before_commit_script_name:
         transaction.get().addBeforeCommitHook(self._before_commit,
-                                              (sci, script_name))
+                                              (sci, script_name, sm))
 
       # Execute "activity" scripts
       for script_name in tdef.activate_script_name:
@@ -301,14 +303,22 @@ class InteractionWorkflowDefinition (DCWorkflowDefinition, ActiveObject):
             .activeScript(script_name, ob.getRelativeUrl(),
                           status, tdef.id)
 
-  def _before_commit(self, sci, script_name):
+  def _before_commit(self, sci, script_name, security_manager):
     # check the object still exists before calling the script
     ob = sci.object
     while ob.isTempObject():
       ob = ob.getParentValue()
     if aq_base(self.unrestrictedTraverse(ob.getPhysicalPath(), None)) is \
        aq_base(ob):
-      self.scripts[script_name](sci)
+      current_security_manager = getSecurityManager()
+      try:
+        # Who knows what happened to the authentication context
+        # between here and when the interaction was executed... So we
+        # need to switch to the security manager as it was back then
+        setSecurityManager(security_manager)
+        self.scripts[script_name](sci)
+      finally:
+        setSecurityManager(current_security_manager)
 
   security.declarePrivate('activeScript')
   def activeScript(self, script_name, ob_url, status, tdef_id):
diff --git a/product/ERP5/tests/testInteractionWorkflow.py b/product/ERP5/tests/testInteractionWorkflow.py
index d67cc06101..4dab707318 100644
--- a/product/ERP5/tests/testInteractionWorkflow.py
+++ b/product/ERP5/tests/testInteractionWorkflow.py
@@ -531,7 +531,10 @@ context.setDescription('%s,%s,%s' % (d, args, result))
     self.assertEqual(organisation.getDescription(), 'bad')
     organisation.getProperty('description', d='toto')
     self.assertEqual(organisation.getDescription(), 'bad')
+    # before-commit interactions should be immune to security changes
+    self.logout()
     transaction.commit()
+    self.login()
     self.assertEqual(organisation.getDescription(), "toto,('description',),bad")
 
   def test_17_activity_interaction(self, quiet=0, run=run_all_test):
-- 
2.30.9