[Erp5-report] r28235 - in /erp5/trunk/products/ERP5: Document/Alarm.py tests/testAlarm.py

nobody at svn.erp5.org nobody at svn.erp5.org
Fri Jul 31 12:45:55 CEST 2009


Author: yo
Date: Fri Jul 31 12:45:54 2009
New Revision: 28235

URL: http://svn.erp5.org?rev=28235&view=rev
Log:
Allow normal users to invoke any alarm manually, if the alarm is enabled and fixit is false.

Modified:
    erp5/trunk/products/ERP5/Document/Alarm.py
    erp5/trunk/products/ERP5/tests/testAlarm.py

Modified: erp5/trunk/products/ERP5/Document/Alarm.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/Document/Alarm.py?rev=28235&r1=28234&r2=28235&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/Document/Alarm.py [utf8] (original)
+++ erp5/trunk/products/ERP5/Document/Alarm.py [utf8] Fri Jul 31 12:45:54 2009
@@ -28,6 +28,7 @@
 
 import zope.interface
 from AccessControl import ClassSecurityInfo
+from AccessControl import Unauthorized
 from Products.CMFCore.utils import getToolByName
 from Products.ERP5Type import Permissions, PropertySheet
 from Products.ERP5Type.XMLObject import XMLObject
@@ -36,6 +37,9 @@
 from Products.ERP5Type.Message import Message
 from Products.ERP5Type.DateUtils import addToDate
 from Products.CMFCore.PortalContent import _getViewFor
+from Products.ERP5Security.ERP5UserManager import SUPER_USER
+from AccessControl.SecurityManagement import getSecurityManager, \
+            setSecurityManager, newSecurityManager
 
 class PeriodicityMixin:
   """
@@ -280,7 +284,7 @@
     """
     return self.hasActivity(only_valid=1)
 
-  security.declareProtected(Permissions.ManagePortal, 'activeSense')
+  security.declareProtected(Permissions.AccessContentsInformation, 'activeSense')
   def activeSense(self, fixit=0):
     """
     This method launches the sensing process as activities.
@@ -291,35 +295,47 @@
     The result of the sensing process can be obtained by invoking
     the sense method or by requesting a report.
     """
-    # LOG('activeSense, self.getPath()',0,self.getPath())
-
-    # Set the next date at which this method should be invoked
-    self.setNextAlarmDate()
-
-    # Find the active sensing method and invoke it
-    # as an activity so that we can benefit from
-    # distribution of alarm processing as soon as possible
-    method_id = self.getActiveSenseMethodId()
-    if method_id not in (None, ''):
-      # A tag is provided as a parameter in order to be
-      # able to notify the user after all processes are ended
-      # Tag is generated from portal_ids so that it can be retrieved
-      # later when creating an active process for example
-      # We do some inspection to keep compatibility
-      # (because fixit and tag were not set previously)
-      tag = str(self.portal_ids.generateNewLengthId(id_group=self.getId()))
-      kw = {}
-      method = getattr(self, method_id)
-      name_list = method.func_code.co_varnames
-      if 'fixit' in name_list or (method.func_defaults is not None
-        and len(method.func_defaults) < len(name_list)):
-        # New API - also if variable number of named parameters
-        getattr(self.activate(tag=tag), method_id)(fixit=fixit, tag=tag)
-      else:
-        # Old API
-        getattr(self.activate(tag=tag), method_id)()
-      if self.isAlarmNotificationMode():
-        self.activate(after_tag=tag).notify(include_active=True)
+    portal_membership = self.getPortalObject().portal_membership
+    if fixit or not self.getEnabled():
+      checkPermission = portal_membership.checkPermission
+      if not checkPermission(Permissions.ManagePortal, self):
+        raise Unauthorized('fixing problems or activating a disabled alarm is not allowed')
+
+    # Switch to the superuser temporarily, so that the behavior would not
+    # change even if this method is invoked by random users.
+    sm = getSecurityManager()
+    newSecurityManager(None, portal_membership.getMemberById(SUPER_USER))
+    try:
+      # Set the next date at which this method should be invoked
+      self.setNextAlarmDate()
+
+      # Find the active sensing method and invoke it
+      # as an activity so that we can benefit from
+      # distribution of alarm processing as soon as possible
+      method_id = self.getActiveSenseMethodId()
+      if method_id not in (None, ''):
+        # A tag is provided as a parameter in order to be
+        # able to notify the user after all processes are ended
+        # Tag is generated from portal_ids so that it can be retrieved
+        # later when creating an active process for example
+        # We do some inspection to keep compatibility
+        # (because fixit and tag were not set previously)
+        tag = str(self.portal_ids.generateNewLengthId(id_group=self.getId()))
+        kw = {}
+        method = getattr(self, method_id)
+        name_list = method.func_code.co_varnames
+        if 'fixit' in name_list or (method.func_defaults is not None
+          and len(method.func_defaults) < len(name_list)):
+          # New API - also if variable number of named parameters
+          getattr(self.activate(tag=tag), method_id)(fixit=fixit, tag=tag)
+        else:
+          # Old API
+          getattr(self.activate(tag=tag), method_id)()
+        if self.isAlarmNotificationMode():
+          self.activate(after_tag=tag).notify(include_active=True)
+    finally:
+      # Restore the original user.
+      setSecurityManager(sm)
 
   security.declareProtected(Permissions.ManagePortal, 'sense')
   def sense(self, process=None):

Modified: erp5/trunk/products/ERP5/tests/testAlarm.py
URL: http://svn.erp5.org/erp5/trunk/products/ERP5/tests/testAlarm.py?rev=28235&r1=28234&r2=28235&view=diff
==============================================================================
--- erp5/trunk/products/ERP5/tests/testAlarm.py [utf8] (original)
+++ erp5/trunk/products/ERP5/tests/testAlarm.py [utf8] Fri Jul 31 12:45:54 2009
@@ -31,7 +31,9 @@
 
 from Testing import ZopeTestCase
 from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
-from AccessControl.SecurityManagement import newSecurityManager
+from AccessControl.SecurityManagement import newSecurityManager, \
+        getSecurityManager, setSecurityManager
+from AccessControl import Unauthorized
 from DateTime import DateTime
 from zLOG import LOG
 from Products.ERP5Type.DateUtils import addToDate
@@ -591,7 +593,100 @@
       else:
         raise AssertionError, m.method_id
 
+  def test_19_ManualInvocation(self, quiet=0, run=run_all_test):
+    """
+    test if an alarm can be invoked directly by the user securely,
+    and if the results are identical when allowed.
+    """
+    if not run: return
+    if not quiet:
+      message = 'Test manual invocation'
+      ZopeTestCase._print('\n%s ' % message)
+      LOG('Testing... ', 0, message)
+
+    alarm = self.newAlarm()
+    # Create script that generate active process
+    sense_method_id = 'Alarm_setBogusLocalProperty'
+    skin_folder_id = 'custom'
+    skin_folder = self.getPortal().portal_skins[skin_folder_id]
+    skin_folder.manage_addProduct['PythonScripts']\
+        .manage_addPythonScript(id=sense_method_id)
+    skin_folder[sense_method_id].ZPythonScript_edit('*args,**kw', 
+          'context.setProperty("bogus", str(context.showPermissions()))')
+
+    # update alarm properties
+    alarm.edit(active_sense_method_id=sense_method_id,
+               enabled=False)
+    transaction.commit()
+    self.tic()
+
+    # Make a normal user.
+    uf = self.getPortal().acl_users
+    uf._doAddUser('normal', '', ['Member', 'Auditor'], [])
+    user = uf.getUserById('normal').__of__(uf)
     
+    # Check the pre-conditions.
+    self.assertEquals(alarm.getProperty('bogus', None), None)
+    self.assertEquals(alarm.getEnabled(), False)
+    sm = getSecurityManager()
+    newSecurityManager(None, user)
+
+    # Non-managers must not be able to invoke a disabled alarm.
+    self.assertRaises(Unauthorized, alarm.activeSense)
+    self.assertRaises(Unauthorized, alarm.activeSense, fixit=1)
+
+    # Non-managers must not be able to invoke the automatic fixation.
+    setSecurityManager(sm)
+    alarm.setEnabled(True)
+    self.assertEquals(alarm.getEnabled(), True)
+    newSecurityManager(None, user)
+    self.assertRaises(Unauthorized, alarm.activeSense, fixit=1)
+
+    # Now, check that everybody can invoke an enabled alarm manually.
+    setSecurityManager(sm)
+    correct_answer = str(alarm.showPermissions())
+    self.assertNotEquals(correct_answer, None)
+
+    alarm.activeSense()
+    transaction.commit()
+    self.tic()
+    self.assertEquals(alarm.getProperty('bogus', None), correct_answer)
+    alarm.setProperty('bogus', None)
+    self.assertEquals(alarm.getProperty('bogus', None), None)
+
+    newSecurityManager(None, user)
+    alarm.activeSense()
+    transaction.commit()
+    self.tic()
+    self.assertEquals(alarm.getProperty('bogus', None), correct_answer)
+    setSecurityManager(sm)
+    alarm.setProperty('bogus', None)
+
+    # Check that Manager can invoke an alarm freely.
+    alarm.activeSense(fixit=1)
+    transaction.commit()
+    self.tic()
+    self.assertEquals(alarm.getProperty('bogus', None), correct_answer)
+    alarm.setProperty('bogus', None)
+    self.assertEquals(alarm.getProperty('bogus', None), None)
+
+    alarm.setEnabled(False)
+    self.assertEquals(alarm.getEnabled(), False)
+
+    alarm.activeSense()
+    transaction.commit()
+    self.tic()
+    self.assertEquals(alarm.getProperty('bogus', None), correct_answer)
+    alarm.setProperty('bogus', None)
+    self.assertEquals(alarm.getProperty('bogus', None), None)
+
+    alarm.activeSense(fixit=1)
+    transaction.commit()
+    self.tic()
+    self.assertEquals(alarm.getProperty('bogus', None), correct_answer)
+    alarm.setProperty('bogus', None)
+    self.assertEquals(alarm.getProperty('bogus', None), None)
+
 
 def test_suite():
   suite = unittest.TestSuite()




More information about the Erp5-report mailing list