From 63c3da2b2b6b10f89c5e4cf8af3a77c702306b1f Mon Sep 17 00:00:00 2001
From: Vincent Pelletier <vincent@nexedi.com>
Date: Fri, 10 Jul 2015 12:32:51 +0000
Subject: [PATCH] erp5_core: Merge erp5_auto_logout.

Disabled by default (configurable by user preference).

Also, reorganise erp5_auto_logout code:
- logout: Do not duplicate original code.
- twiddleAuthCookie: Simplify & factorise.
- setAuthCookie: Resync features with Cookie Crumbler's, and set http_only flag.
- ERP5Site_getMaxUserInactivityDuration: Cached access takes the same time as actual access (and access is surprisingly slow, actually), so do not cache.
- Base_getAutoLogoutSessionKey: New script, to factorise session key generation.
---
 bt5/erp5_auto_logout/bt/change_log            |  5 ---
 bt5/erp5_auto_logout/bt/copyright_list        |  1 -
 bt5/erp5_auto_logout/bt/description           |  1 -
 bt5/erp5_auto_logout/bt/license               |  1 -
 bt5/erp5_auto_logout/bt/maintainer_list       |  1 -
 .../bt/template_format_version                |  1 -
 bt5/erp5_auto_logout/bt/title                 |  1 -
 .../portal_skins/erp5_auto_logout.xml         |  0
 .../Base_getAutoLogoutSessionKey.xml          | 20 ++++------
 .../portal_skins/erp5_auto_logout/logout.xml  | 13 +++---
 .../erp5_auto_logout/setAuthCookie.xml        | 40 +++++++++----------
 .../erp5_auto_logout/twiddleAuthCookie.xml    | 21 ++--------
 .../bootstrap/erp5_core/bt/provision_list     |  0
 .../erp5_core/bt/template_skin_id_list        |  1 +
 14 files changed, 34 insertions(+), 72 deletions(-)
 delete mode 100644 bt5/erp5_auto_logout/bt/change_log
 delete mode 100644 bt5/erp5_auto_logout/bt/copyright_list
 delete mode 100644 bt5/erp5_auto_logout/bt/description
 delete mode 100644 bt5/erp5_auto_logout/bt/license
 delete mode 100644 bt5/erp5_auto_logout/bt/maintainer_list
 delete mode 100644 bt5/erp5_auto_logout/bt/template_format_version
 delete mode 100644 bt5/erp5_auto_logout/bt/title
 rename {bt5/erp5_auto_logout => product/ERP5/bootstrap/erp5_core}/SkinTemplateItem/portal_skins/erp5_auto_logout.xml (100%)
 rename bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/ERP5Site_getMaxUserInactivityDuration.xml => product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/Base_getAutoLogoutSessionKey.xml (75%)
 rename {bt5/erp5_auto_logout => product/ERP5/bootstrap/erp5_core}/SkinTemplateItem/portal_skins/erp5_auto_logout/logout.xml (93%)
 rename {bt5/erp5_auto_logout => product/ERP5/bootstrap/erp5_core}/SkinTemplateItem/portal_skins/erp5_auto_logout/setAuthCookie.xml (86%)
 rename {bt5/erp5_auto_logout => product/ERP5/bootstrap/erp5_core}/SkinTemplateItem/portal_skins/erp5_auto_logout/twiddleAuthCookie.xml (87%)
 rename bt5/erp5_auto_logout/bt/template_skin_id_list => product/ERP5/bootstrap/erp5_core/bt/provision_list (100%)

diff --git a/bt5/erp5_auto_logout/bt/change_log b/bt5/erp5_auto_logout/bt/change_log
deleted file mode 100644
index bf254cc810..0000000000
--- a/bt5/erp5_auto_logout/bt/change_log
+++ /dev/null
@@ -1,5 +0,0 @@
-2009-01-14 ivan
-* Moved to public bt5 repository
-
-2009-01-12 ivan
-* Initial import
\ No newline at end of file
diff --git a/bt5/erp5_auto_logout/bt/copyright_list b/bt5/erp5_auto_logout/bt/copyright_list
deleted file mode 100644
index 22de975f93..0000000000
--- a/bt5/erp5_auto_logout/bt/copyright_list
+++ /dev/null
@@ -1 +0,0 @@
-Copyright (c) 2001-2006 Nexedi SARL
\ No newline at end of file
diff --git a/bt5/erp5_auto_logout/bt/description b/bt5/erp5_auto_logout/bt/description
deleted file mode 100644
index c3aafb3b0d..0000000000
--- a/bt5/erp5_auto_logout/bt/description
+++ /dev/null
@@ -1 +0,0 @@
-This bt5 provides support for automatically logging out inactive users of ERP5 based on a maximum user inactive duration as specified in preferences.
\ No newline at end of file
diff --git a/bt5/erp5_auto_logout/bt/license b/bt5/erp5_auto_logout/bt/license
deleted file mode 100644
index 3a3e12bcad..0000000000
--- a/bt5/erp5_auto_logout/bt/license
+++ /dev/null
@@ -1 +0,0 @@
-GPL
\ No newline at end of file
diff --git a/bt5/erp5_auto_logout/bt/maintainer_list b/bt5/erp5_auto_logout/bt/maintainer_list
deleted file mode 100644
index 95d930c400..0000000000
--- a/bt5/erp5_auto_logout/bt/maintainer_list
+++ /dev/null
@@ -1 +0,0 @@
-ivan
\ No newline at end of file
diff --git a/bt5/erp5_auto_logout/bt/template_format_version b/bt5/erp5_auto_logout/bt/template_format_version
deleted file mode 100644
index 56a6051ca2..0000000000
--- a/bt5/erp5_auto_logout/bt/template_format_version
+++ /dev/null
@@ -1 +0,0 @@
-1
\ No newline at end of file
diff --git a/bt5/erp5_auto_logout/bt/title b/bt5/erp5_auto_logout/bt/title
deleted file mode 100644
index 1046d94160..0000000000
--- a/bt5/erp5_auto_logout/bt/title
+++ /dev/null
@@ -1 +0,0 @@
-erp5_auto_logout
\ No newline at end of file
diff --git a/bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout.xml
similarity index 100%
rename from bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout.xml
rename to product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout.xml
diff --git a/bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/ERP5Site_getMaxUserInactivityDuration.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/Base_getAutoLogoutSessionKey.xml
similarity index 75%
rename from bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/ERP5Site_getMaxUserInactivityDuration.xml
rename to product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/Base_getAutoLogoutSessionKey.xml
index 65d91a7e6c..1e7a6934e2 100644
--- a/bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/ERP5Site_getMaxUserInactivityDuration.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/Base_getAutoLogoutSessionKey.xml
@@ -50,26 +50,20 @@
         </item>
         <item>
             <key> <string>_body</string> </key>
-            <value> <string>""" Get (in seconds) authentication expire interval for an user. """\n
-from Products.ERP5Type.Cache import CachingMethod\n
-\n
-def getMaxUserInactivityDuration():\n
-  return context.portal_preferences.getPreferredMaxUserInactivityDuration()\n
-\n
-getMaxUserInactivityDuration = CachingMethod( \\\n
-                                 getMaxUserInactivityDuration, \\\n
-                                 "ERP5Site_getMaxUserInactivityDuration_%s" % (user_name, ), \\\n
-                                 cache_factory=\'erp5_ui_medium\')\n
-return getMaxUserInactivityDuration()\n
+            <value> <string>from AccessControl import getSecurityManager\n
+from zExceptions import Unauthorized\n
+if REQUEST is not None: # Cheap "do not call from URL" protection - not that the session key is secret\n
+  raise Unauthorized\n
+return \'ac_cookie_\' + str(getSecurityManager().getUser())\n
 </string> </value>
         </item>
         <item>
             <key> <string>_params</string> </key>
-            <value> <string>user_name=None</string> </value>
+            <value> <string>REQUEST=None</string> </value>
         </item>
         <item>
             <key> <string>id</string> </key>
-            <value> <string>ERP5Site_getMaxUserInactivityDuration</string> </value>
+            <value> <string>Base_getAutoLogoutSessionKey</string> </value>
         </item>
       </dictionary>
     </pickle>
diff --git a/bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/logout.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/logout.xml
similarity index 93%
rename from bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/logout.xml
rename to product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/logout.xml
index a90e487377..483bd83ffb 100644
--- a/bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/logout.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/logout.xml
@@ -170,14 +170,11 @@
         </item>
         <item>
             <key> <string>_body</string> </key>
-            <value> <string>REQUEST = context.REQUEST\n
-# delete session\n
-context.portal_sessions.manage_delObjects(\'ac_cookie_%s\' \\\n
-                                            %REQUEST.get(\'__ac_name\', None))\n
-if REQUEST.has_key(\'portal_skin\'):\n
-   context.portal_skins.clearSkinCookie()\n
-REQUEST.RESPONSE.expireCookie(\'__ac\', path=\'/\')\n
-return REQUEST.RESPONSE.redirect(REQUEST.URL1+\'/logged_out\')\n
+            <value> <string>portal = context.getPortalObject()\n
+portal.portal_sessions.manage_delObjects(portal.Base_getAutoLogoutSessionKey())\n
+# XXX: I would like to use skinSuper, but this may not be defined on context (it\'s defined on ERP5Type.Base, and context may be ERP5.ERP5Site).\n
+# As a result, hardcode expected logout location (which is marginally better than duplicating it).\n
+return portal.portal_skins.zpt_control.logout()\n
 </string> </value>
         </item>
         <item>
diff --git a/bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/setAuthCookie.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/setAuthCookie.xml
similarity index 86%
rename from bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/setAuthCookie.xml
rename to product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/setAuthCookie.xml
index c442d5aa49..c4a9516c9a 100644
--- a/bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/setAuthCookie.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/setAuthCookie.xml
@@ -172,29 +172,25 @@
             <key> <string>_body</string> </key>
             <value> <string encoding="cdata"><![CDATA[
 
-from DateTime import DateTime\n
-kw = {\'name\': cookie_name,\n
-      \'value\': cookie_value,\n
-      \'path\': \'/\'}\n
-ac_session_key_pattern = \'ac_cookie_%s\'\n
-user_name = context.REQUEST.get(\'__ac_name\', None)\n
-expire_interval = context.ERP5Site_getMaxUserInactivityDuration(user_name)\n
-\n
-# set cookie expire argument only if it\'s defined for current user\n
-if expire_interval not in (\'\', None):\n
-  expire_interval /= 86400. # seconds -> days\n
-  ac_expires = DateTime() + expire_interval\n
-  ac_renew = DateTime() + expire_interval / 2\n
-  kw[\'expires\'] = ac_expires.toZone(\'GMT\').rfc822()\n
-  # save next \'__ac\' renew time\n
-  context.portal_sessions[ac_session_key_pattern %user_name][\'ac_renew\'] = ac_renew.millis()\n
+portal = context.getPortalObject()\n
+kw = {}\n
+expire_interval = portal.portal_preferences.getPreferredMaxUserInactivityDuration()\n
+if expire_interval in (\'\', None):\n
+  ac_renew = float(\'inf\')\n
 else:\n
-  # cookie will expire at client browser end of session, \n
-  # mark it at server side with zero (0)\n
-  context.portal_sessions[ac_session_key_pattern %user_name][\'ac_renew\'] = 0\n
-\n
-# set cookie\n
-resp.setCookie(**kw)\n
+  expire_interval /= 86400. # seconds -> days\n
+  now = DateTime()\n
+  kw[\'expires\'] = (now + expire_interval).toZone(\'GMT\').rfc822()\n
+  ac_renew = (now + expire_interval / 2).millis()\n
+portal.portal_sessions[portal.Base_getAutoLogoutSessionKey()][\'ac_renew\'] = ac_renew\n
+resp.setCookie(\n
+  name=cookie_name,\n
+  value=cookie_value,\n
+  path=\'/\',\n
+  secure=getattr(portal, \'REQUEST\', {}).get(\'SERVER_URL\', \'\').startswith(\'https:\'),\n
+  http_only=True,\n
+  **kw\n
+)\n
 
 
 ]]></string> </value>
diff --git a/bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/twiddleAuthCookie.xml b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/twiddleAuthCookie.xml
similarity index 87%
rename from bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/twiddleAuthCookie.xml
rename to product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/twiddleAuthCookie.xml
index 46bcda974a..a7c8fda173 100644
--- a/bt5/erp5_auto_logout/SkinTemplateItem/portal_skins/erp5_auto_logout/twiddleAuthCookie.xml
+++ b/product/ERP5/bootstrap/erp5_core/SkinTemplateItem/portal_skins/erp5_auto_logout/twiddleAuthCookie.xml
@@ -172,24 +172,9 @@
             <key> <string>_body</string> </key>
             <value> <string encoding="cdata"><![CDATA[
 
-# check if required to renew cookie from sessios\n
-ac_session_key_pattern = \'ac_cookie_%s\'\n
-user_name = context.REQUEST.cookies.get(\'__ac_name\', None)\n
-try:\n
-  session = context.portal_sessions[ac_session_key_pattern %user_name]\n
-except KeyError:\n
-  session = None\n
-if session is not None:\n
-  from DateTime import DateTime\n
-  now = DateTime()\n
-  ac_renew = session.get(\'ac_renew\', None)\n
-  if ac_renew not in (0, None) and now.millis() >= ac_renew:\n
-    # renew cookie (cookies without expire value  will not be renewed)\n
-    context.setAuthCookie(resp, cookie_name, cookie_value)\n
-  elif ac_renew is None:\n
-    # our portal_session at server side might have expired, either\n
-    # due to a cache expire or server restart, renew cookie anyway\n
-    context.setAuthCookie(resp, cookie_name, cookie_value)\n
+portal = context.getPortalObject()\n
+if DateTime().millis() >= portal.portal_sessions[portal.Base_getAutoLogoutSessionKey()].get(\'ac_renew\', 0):\n
+  portal.setAuthCookie(resp, cookie_name, cookie_value)\n
 
 
 ]]></string> </value>
diff --git a/bt5/erp5_auto_logout/bt/template_skin_id_list b/product/ERP5/bootstrap/erp5_core/bt/provision_list
similarity index 100%
rename from bt5/erp5_auto_logout/bt/template_skin_id_list
rename to product/ERP5/bootstrap/erp5_core/bt/provision_list
diff --git a/product/ERP5/bootstrap/erp5_core/bt/template_skin_id_list b/product/ERP5/bootstrap/erp5_core/bt/template_skin_id_list
index d0ca7aef23..5ebd9dcacf 100644
--- a/product/ERP5/bootstrap/erp5_core/bt/template_skin_id_list
+++ b/product/ERP5/bootstrap/erp5_core/bt/template_skin_id_list
@@ -1 +1,2 @@
+erp5_auto_logout
 erp5_core
\ No newline at end of file
-- 
2.30.9