Commit 75fe73d0 authored by Ivan Tyagov's avatar Ivan Tyagov

Add unblock user account implementation.

Make sure no more than set in preferences authentication failures are
saved.
Redirect to 'Update Credentials' form if after successful login password
is to expire soon.
parent 7dd043a7
...@@ -55,10 +55,9 @@ ...@@ -55,10 +55,9 @@
"""\n """\n
from Products.ERP5Type.Cache import CachingMethod\n from Products.ERP5Type.Cache import CachingMethod\n
\n \n
portal = context.getPortalObject()\n
portal_preferences = portal.portal_preferences\n
\n
def _isAuthenticationPolicyEnabled():\n def _isAuthenticationPolicyEnabled():\n
portal = context.getPortalObject()\n
portal_preferences = portal.portal_preferences\n
return portal_preferences.getPreferredMaxAuthenticationFailure() or \\\n return portal_preferences.getPreferredMaxAuthenticationFailure() or \\\n
portal_preferences.getPreferredMaxPasswordLifetimeDuration()\n portal_preferences.getPreferredMaxPasswordLifetimeDuration()\n
\n \n
......
...@@ -84,7 +84,7 @@ failures_for_period = [x for x in authentication_failure_list if x >= check_time ...@@ -84,7 +84,7 @@ failures_for_period = [x for x in authentication_failure_list if x >= check_time
if len(failures_for_period)>= max_authentication_failures:\n if len(failures_for_period)>= max_authentication_failures:\n
# block login as too many authentication failure for given time interval back\n # block login as too many authentication failure for given time interval back\n
block_timeout = failures_for_period[-1] + block_duration*one_second\n block_timeout = failures_for_period[-1] + block_duration*one_second\n
context.log(\'check=%s block=%s release=%s-> %s\' %(check_duration, block_duration, block_timeout, failures_for_period))\n #context.log(\'check=%s block=%s release=%s-> %s\' %(check_duration, block_duration, block_timeout, failures_for_period))\n
if block_timeout > now:\n if block_timeout > now:\n
context.log(\'block %s\' %context.getReference())\n context.log(\'block %s\' %context.getReference())\n
request.set(\'is_user_account_blocked\', True)\n request.set(\'is_user_account_blocked\', True)\n
......
...@@ -67,7 +67,6 @@ def _isPasswordExpired():\n ...@@ -67,7 +67,6 @@ def _isPasswordExpired():\n
max_password_lifetime_duration = portal.portal_preferences.getPreferredMaxPasswordLifetimeDuration()\n max_password_lifetime_duration = portal.portal_preferences.getPreferredMaxPasswordLifetimeDuration()\n
password_lifetime_expire_warning_duration = portal.portal_preferences.getPreferredPasswordLifetimeExpireWarningDuration()\n password_lifetime_expire_warning_duration = portal.portal_preferences.getPreferredPasswordLifetimeExpireWarningDuration()\n
last_password_modification_date = context.getLastPasswordModificationDate()\n last_password_modification_date = context.getLastPasswordModificationDate()\n
\n
early_warning = False\n early_warning = False\n
if last_password_modification_date is not None:\n if last_password_modification_date is not None:\n
expire_date = last_password_modification_date + max_password_lifetime_duration*one_hour \n expire_date = last_password_modification_date + max_password_lifetime_duration*one_hour \n
...@@ -88,7 +87,7 @@ is_password_expired, is_user_account_password_expired_warning_on = _isPasswordEx ...@@ -88,7 +87,7 @@ is_password_expired, is_user_account_password_expired_warning_on = _isPasswordEx
\n \n
request.set(\'is_user_account_password_expired\', is_password_expired)\n request.set(\'is_user_account_password_expired\', is_password_expired)\n
request.set(\'is_user_account_password_expired_warning_on\', is_user_account_password_expired_warning_on)\n request.set(\'is_user_account_password_expired_warning_on\', is_user_account_password_expired_warning_on)\n
#context.log(\'in --> %s %s\' %(is_password_expired, is_user_account_password_expired_warning_on))\n \n
return is_password_expired\n return is_password_expired\n
......
...@@ -118,7 +118,6 @@ if portal.portal_preferences.isPrefferedForceUsernameCheckInPassword():\n ...@@ -118,7 +118,6 @@ if portal.portal_preferences.isPrefferedForceUsernameCheckInPassword():\n
if last_name not in MARKER:\n if last_name not in MARKER:\n
last_name = last_name.lower()\n last_name = last_name.lower()\n
\n \n
#context.log(\'%s %s\' %(first_name, last_name))\n
if (first_name not in MARKER and first_name in lower_password) or \\\n if (first_name not in MARKER and first_name in lower_password) or \\\n
(last_name not in MARKER and last_name in lower_password):\n (last_name not in MARKER and last_name in lower_password):\n
# user\'s name must not be contained in password\n # user\'s name must not be contained in password\n
......
...@@ -50,7 +50,9 @@ ...@@ -50,7 +50,9 @@
</item> </item>
<item> <item>
<key> <string>_body</string> </key> <key> <string>_body</string> </key>
<value> <string>"""\n <value> <string encoding="cdata"><![CDATA[
"""\n
File a failed authentication attempt.\n File a failed authentication attempt.\n
"""\n """\n
from DateTime import DateTime\n from DateTime import DateTime\n
...@@ -67,10 +69,25 @@ session = portal.portal_sessions[session_id]\n ...@@ -67,10 +69,25 @@ session = portal.portal_sessions[session_id]\n
if key not in session.keys():\n if key not in session.keys():\n
# init it only once\n # init it only once\n
session[key] = []\n session[key] = []\n
session[key] = session[key] + [DateTime()]\n \n
context.log(\'notify login failure %s %s\' %(session_id, session[key]))\n authentication_failure_list = session[key]\n
authentication_failure_list.append(DateTime())\n
\n
# we care for only recent failures, no need to save all so purge old one\n
max_authentication_failures = portal.portal_preferences.getPreferredMaxAuthenticationFailure()\n
if len(authentication_failure_list)> max_authentication_failures:\n
authentication_failure_list.reverse()\n
authentication_failure_list = authentication_failure_list[0:max_authentication_failures]\n
authentication_failure_list.reverse()\n
\n
# update backend\n
session[key] = authentication_failure_list\n
\n
#context.log(\'notify login failure %s %s %s\' %(session_id, session, len(session[key])))\n
return session[key]\n return session[key]\n
</string> </value>
]]></string> </value>
</item> </item>
<item> <item>
<key> <string>_params</string> </key> <key> <string>_params</string> </key>
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="PythonScript" module="Products.PythonScripts.PythonScript"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>Script_magic</string> </key>
<value> <int>3</int> </value>
</item>
<item>
<key> <string>_bind_names</string> </key>
<value>
<object>
<klass>
<global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/>
</klass>
<tuple/>
<state>
<dictionary>
<item>
<key> <string>_asgns</string> </key>
<value>
<dictionary>
<item>
<key> <string>name_container</string> </key>
<value> <string>container</string> </value>
</item>
<item>
<key> <string>name_context</string> </key>
<value> <string>context</string> </value>
</item>
<item>
<key> <string>name_m_self</string> </key>
<value> <string>script</string> </value>
</item>
<item>
<key> <string>name_subpath</string> </key>
<value> <string>traverse_subpath</string> </value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</state>
</object>
</value>
</item>
<item>
<key> <string>_body</string> </key>
<value> <string>portal = context.getPortalObject()\n
\n
if not context.ERP5Site_isAuthenticationPolicyEnabled():\n
# no policy, no sense to block account\n
return 0\n
\n
key = \'authentication_failure_list\'\n
session_id = context.Person_getAuthenticationSessionId()\n
session = portal.portal_sessions[session_id]\n
session[key] = []\n
</string> </value>
</item>
<item>
<key> <string>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Person_unblockLogin</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -75,10 +75,10 @@ ...@@ -75,10 +75,10 @@
<tal:block tal:condition="not: isAnon"\n <tal:block tal:condition="not: isAnon"\n
tal:define="is_user_account_password_expired_warning_on python:request.get(\'is_user_account_password_expired_warning_on\', False);">\n tal:define="is_user_account_password_expired_warning_on python:request.get(\'is_user_account_password_expired_warning_on\', False);">\n
\n \n
<!-- Password will expire soon just war user ? -->\n <!-- Password will expire soon just warn user ? -->\n
<tal:block tal:condition="is_user_account_password_expired_warning_on">\n <tal:block tal:condition="is_user_account_password_expired_warning_on">\n
<tal:block tal:define="came_from python: request.get(\'came_from\') or here.absolute_url();\n <tal:block tal:define="came_from python: request.get(\'came_from\') or here.absolute_url();\n
dummy python: response.redirect(\'%s?portal_status_message=%s\' %(came_from, here.Base_translateString(\'Your password will expire soon.\')));" />\n dummy python: response.redirect(\'%s/ERP5Site_viewNewPersonCredentialUpdateDialog?portal_status_message=%s&amp;cancel_url=%s\' %(came_from, here.Base_translateString(\'Your password will expire soon. You are advised to change it as soon as possible.\'), came_from));" />\n
</tal:block>\n </tal:block>\n
\n \n
<tal:block tal:condition="not: is_user_account_password_expired_warning_on">\n <tal:block tal:condition="not: is_user_account_password_expired_warning_on">\n
......
4 5
\ No newline at end of file \ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment