Commit e349b9d2 authored by Rafael Monnerat's avatar Rafael Monnerat

slapos_erp5: Accelarate Login by ignoring security_uids when scripts...

slapos_erp5: Accelarate Login by ignoring security_uids when scripts Login_is** scripts are called as manager
parent f03390bd
Pipeline #9776 failed with stage
in 0 seconds
###############################################################################
#
# Copyright (c) 2020 Nexedi SA and Contributors. All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly advised to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
##############################################################################
from AccessControl import Unauthorized
from Products.ZSQLCatalog.SQLCatalog import Query
def Login_unrestrictedSearchAuthenticationEvent(self, check_time,
max_authentication_failures, REQUEST=None):
if REQUEST is not None:
raise Unauthorized
kw = {'portal_type': 'Authentication Event',
'default_destination_uid': self.getUid(),
'creation_date': Query(creation_date = check_time,
range='min'),
'validation_state' : 'confirmed',
'sort_on' : (('creation_date', 'ASC',),),
'limit': max_authentication_failures
}
return self.getPortalObject().portal_catalog.unrestrictedSearchResults(**kw)
def Login_unrestrictedSearchPasswordEvent(self, REQUEST=None):
if REQUEST is not None:
raise Unauthorized
return self.getPortalObject().portal_catalog.unrestrictedSearchResults(
select_list=['creation_date'],
portal_type='Password Event',
default_destination_uid=self.getUid(),
validation_state='confirmed',
sort_on=(('creation_date', 'DESC'), ),
limit=1)
def migrateInstanceToERP5Login(self):
assert self.getPortalType() in ( 'Computer', 'Software Instance')
reference = self.getReference()
if not reference:
# no user id and no login is required
return
if not (self.hasUserId() or self.getUserId() == reference):
self.setUserId(reference)
if len(self.objectValues(
portal_type=["Certificate Login", "ERP5 Login"])):
# already migrated
return
login = self.newContent(
portal_type='Certificate Login',
reference=reference,
)
login.validate()
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
</item> </item>
<item> <item>
<key> <string>default_reference</string> </key> <key> <string>default_reference</string> </key>
<value> <string>SlapOSLoginMigration</string> </value> <value> <string>SlapOSLogin</string> </value>
</item> </item>
<item> <item>
<key> <string>description</string> </key> <key> <string>description</string> </key>
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
<value> <string>extension.erp5.SlapOSLoginMigration</string> </value> <value> <string>extension.erp5.SlapOSLogin</string> </value>
</item> </item>
<item> <item>
<key> <string>portal_type</string> </key> <key> <string>portal_type</string> </key>
...@@ -117,6 +117,7 @@ ...@@ -117,6 +117,7 @@
</item> </item>
</dictionary> </dictionary>
</list> </list>
<none/>
</tuple> </tuple>
</pickle> </pickle>
</record> </record>
......
def migrateInstanceToERP5Login(self):
assert self.getPortalType() in ( 'Computer', 'Software Instance')
reference = self.getReference()
if not reference:
# no user id and no login is required
return
if not (self.hasUserId() or self.getUserId() == reference):
self.setUserId(reference)
if len(self.objectValues(
portal_type=["Certificate Login", "ERP5 Login"])):
# already migrated
return
login = self.newContent(
portal_type='Certificate Login',
reference=reference,
)
login.validate()
"""
Return true if user account is blocked.
"""
from DateTime import DateTime
request = context.REQUEST
portal = context.getPortalObject()
portal_preferences = portal.portal_preferences
if not portal_preferences.isAuthenticationPolicyEnabled():
# no policy, no sense to block account
return 0
now = DateTime()
one_second = 1/24.0/60.0/60.0
check_duration = portal_preferences.getPreferredAuthenticationFailureCheckDuration()
block_duration = portal_preferences.getPreferredAuthenticationFailureBlockDuration()
max_authentication_failures = portal_preferences.getPreferredMaxAuthenticationFailure()
check_time = now - check_duration*one_second
# some failures might be still unindexed
tag = 'authentication_event_%s' %context.getReference()
unindexed_failures = portal.portal_activities.countMessageWithTag(tag)
if unindexed_failures >= max_authentication_failures:
# no need to check further
return 1
indexed_failure_list = context.Login_unrestrictedSearchAuthenticationEvent(check_time, max_authentication_failures)
indexed_failures = len(indexed_failure_list)
if (indexed_failures + unindexed_failures) >= max_authentication_failures:
last_authentication_failure = indexed_failure_list[-1].getObject()
block_timeout = last_authentication_failure.getCreationDate() + block_duration*one_second
if block_timeout >= now:
request.set('is_user_account_blocked', True)
return 1
return 0
<?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>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Login_isLoginBlocked</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
"""
Returns if user account is Person's password is expired.
Start password recovery process for expired password (if configured).
"""
portal = context.getPortalObject()
is_password_expired = False
expire_date_warning = 0
password_event_list = context.Login_unrestrictedSearchPasswordEvent()
if password_event_list:
ONE_HOUR = 1 / 24.0
portal_preferences = portal.portal_preferences
expire_date = password_event_list[0].creation_date + portal_preferences.getPreferredMaxPasswordLifetimeDuration() * ONE_HOUR
now = DateTime()
if expire_date < now:
# password is expired
is_password_expired = True
else:
password_lifetime_expire_warning_duration = portal_preferences.getPreferredPasswordLifetimeExpireWarningDuration()
if password_lifetime_expire_warning_duration and now > expire_date - password_lifetime_expire_warning_duration * ONE_HOUR:
expire_date_warning = expire_date
request = portal.REQUEST
request.set('is_user_account_password_expired', is_password_expired)
request.set('is_user_account_password_expired_expire_date', expire_date_warning)
return is_password_expired
<?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>_params</string> </key>
<value> <string></string> </value>
</item>
<item>
<key> <string>_proxy_roles</string> </key>
<value>
<tuple>
<string>Manager</string>
</tuple>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Login_isPasswordExpired</string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ExternalMethod" module="Products.ExternalMethod.ExternalMethod"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_function</string> </key>
<value> <string>Login_unrestrictedSearchAuthenticationEvent</string> </value>
</item>
<item>
<key> <string>_module</string> </key>
<value> <string>SlapOSLogin</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Login_unrestrictedSearchAuthenticationEvent</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ExternalMethod" module="Products.ExternalMethod.ExternalMethod"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_function</string> </key>
<value> <string>Login_unrestrictedSearchPasswordEvent</string> </value>
</item>
<item>
<key> <string>_module</string> </key>
<value> <string>SlapOSLogin</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Login_unrestrictedSearchPasswordEvent</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
</item> </item>
<item> <item>
<key> <string>_module</string> </key> <key> <string>_module</string> </key>
<value> <string>SlapOSLoginMigration</string> </value> <value> <string>SlapOSLogin</string> </value>
</item> </item>
<item> <item>
<key> <string>id</string> </key> <key> <string>id</string> </key>
......
extension.erp5.SlapOSCheckConsistency extension.erp5.SlapOSCheckConsistency
extension.erp5.SlapOSLoginMigration extension.erp5.SlapOSLogin
extension.erp5.SlapOSAdministration extension.erp5.SlapOSAdministration
\ 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