Commit 238be699 authored by Ivan Tyagov's avatar Ivan Tyagov

Define isAuthenticationPolicyEnabled API and use it respectively.

Allow low level password validity checks (if
isAuthenticationPolicyEnabled only).
Adjust tests to handle better password history.
parent 161e5c9c
......@@ -42,6 +42,11 @@ class IEncryptedPassword(Interface):
Check the password, usefull when changing password
"""
def checkPasswordValueAcceptable(value):
"""
Check if the password value is acceptable - i.e. follows site rules.
"""
def setEncodedPassword(value, format='default'):
"""
Set an already encoded password.
......
......@@ -60,4 +60,5 @@ class ILoginAccountProvider(Interface):
Return if password has already been used.
"""
\ No newline at end of file
......@@ -63,6 +63,19 @@ class EncryptedPasswordMixin:
return pw_validate(self.getPassword(), value)
return False
def checkPasswordValueAcceptable(self, value):
"""
Check the password. This method is defined explicitly, because:
- we want to apply an authentication policy which itself may contain explicit password rules
"""
if not self.getPortalObject().portal_preferences.isAuthenticationPolicyEnabled():
# not a policy so basically all passwords are accceptable
return True
result = self.isPasswordValid(value)
if result <= 0:
raise ValueError, "Bad password (%s)." %result
def checkUserCanChangePassword(self):
if not _checkPermission(Permissions.SetOwnPassword, self):
raise AccessControl_Unauthorized('setPassword')
......@@ -87,6 +100,7 @@ class EncryptedPasswordMixin:
def _setPassword(self, value):
self.checkUserCanChangePassword()
self.checkPasswordValueAcceptable(value)
self._forceSetPassword(value)
security.declarePublic('setPassword')
......
......@@ -77,7 +77,7 @@ class LoginAccountProviderMixin:
Return if password has already been used.
"""
preferred_number_of_last_password_to_check = self.portal_preferences.getPreferredNumberOfLastPasswordToCheck()
password_list = self.getLastChangedPasswordValueList() + [self.getPassword()]
password_list = self.getLastChangedPasswordValueList()
password_list.reverse()
for encoded_password in password_list[:preferred_number_of_last_password_to_check]:
if pw_validate(encoded_password, password):
......
......@@ -271,5 +271,31 @@ class PreferenceTool(BaseTool):
finally:
setSecurityManager(security_manager)
security.declarePublic('isAuthenticationPolicyEnabled')
def isAuthenticationPolicyEnabled(self) :
"""
Return True if authentication policy is enabled.
This method exists here due to bootstrap issues.
It should work even if erp5_authentication_policy bt5 is not installed.
"""
# XXX: define an interface
def _isAuthenticationPolicyEnabled():
portal_preferences = self.getPortalObject().portal_preferences
method_id = 'isPreferredAuthenticationPolicyEnabled'
method = getattr(self, method_id, None)
if method is not None and method():
return True
return False
tv = getTransactionalVariable()
tv_key = 'PreferenceTool._isAuthenticationPolicyEnabled.%s' % getSecurityManager().getUser()
if tv.get(tv_key, None) is None:
_isAuthenticationPolicyEnabled = CachingMethod(_isAuthenticationPolicyEnabled,
id='PortalPreferences_isAuthenticationPolicyEnabled',
cache_factory='erp5_content_short')
tv[tv_key] = _isAuthenticationPolicyEnabled()
return tv[tv_key]
InitializeClass(PreferenceTool)
......@@ -171,15 +171,12 @@ class ERP5UserManager(BasePlugin):
except _AuthenticationFailure:
authentication_result = None
method = getattr(self, 'ERP5Site_isAuthenticationPolicyEnabled', None)
if method is None or (method is not None and not method()):
if not self.getPortalObject().portal_preferences.isAuthenticationPolicyEnabled():
# stop here, no authentication policy enabled
# so just return authentication check result
# XXX: move to ERP5 Site API
return authentication_result
# authentication policy enabled, we need person object anyway
# XXX: every request is a MySQL call
user_list = self.getUserByLogin(credentials.get('login'))
if not user_list:
# not an ERP5 Person object
......
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