[Checkins] SVN: z3c.password/trunk/ - Refactor PrincipalMixIn now() into a separate method to facilitate
Adam Groszer
agroszer at gmail.com
Thu Jun 11 09:05:53 EDT 2009
Log message for revision 100870:
- Refactor PrincipalMixIn now() into a separate method to facilitate
override and testing
- Changed the order the password is checked:
1. check password against stored
2. check maxFailedAttempts, raise TooManyLoginFailures if over
3. if password is OK, check expirationDate, raise PasswordExpired if over
4. return whether password matches
This is because I need to be sure that PasswordExpired is raised only if the
password *IS* valid. Entering an invalid password *MUST NOT* raise
PasswordExpired, because I want to use PasswordExpired to allow the user
to change it's password. This should not happen if the user did not enter a
valid password.
Changed:
U z3c.password/trunk/CHANGES.txt
U z3c.password/trunk/src/z3c/password/README.txt
U z3c.password/trunk/src/z3c/password/interfaces.py
U z3c.password/trunk/src/z3c/password/principal.py
-=-
Modified: z3c.password/trunk/CHANGES.txt
===================================================================
--- z3c.password/trunk/CHANGES.txt 2009-06-11 11:28:14 UTC (rev 100869)
+++ z3c.password/trunk/CHANGES.txt 2009-06-11 13:05:53 UTC (rev 100870)
@@ -6,6 +6,21 @@
- Added Russian translation
+- Refactor PrincipalMixIn now() into a separate method to facilitate
+ override and testing
+
+- Changed the order the password is checked:
+ 1. check password against stored
+ 2. check maxFailedAttempts, raise TooManyLoginFailures if over
+ 3. if password is OK, check expirationDate, raise PasswordExpired if over
+ 4. return whether password matches
+
+ This is because I need to be sure that PasswordExpired is raised only if the
+ password *IS* valid. Entering an invalid password *MUST NOT* raise
+ PasswordExpired, because I want to use PasswordExpired to allow the user
+ to change it's password. This should not happen if the user did not enter a
+ valid password.
+
0.5.0 (2008-10-21)
------------------
Modified: z3c.password/trunk/src/z3c/password/README.txt
===================================================================
--- z3c.password/trunk/src/z3c/password/README.txt 2009-06-11 11:28:14 UTC (rev 100869)
+++ z3c.password/trunk/src/z3c/password/README.txt 2009-06-11 13:05:53 UTC (rev 100870)
@@ -261,13 +261,20 @@
>>> user.failedAttempts = 0
-Next we expire password:
+Next we expire the password:
>>> user.passwordSetOn = datetime.datetime.now() + datetime.timedelta(-181)
A corresponding exception should be raised:
>>> user.checkPassword('456456')
+ False
+
+Not yet, because the password did not match.
+
+Once we match the password it is raised:
+
+ >>> user.checkPassword('123123')
Traceback (most recent call last):
...
PasswordExpired: The password has expired.
Modified: z3c.password/trunk/src/z3c/password/interfaces.py
===================================================================
--- z3c.password/trunk/src/z3c/password/interfaces.py 2009-06-11 11:28:14 UTC (rev 100869)
+++ z3c.password/trunk/src/z3c/password/interfaces.py 2009-06-11 13:05:53 UTC (rev 100870)
@@ -111,7 +111,7 @@
if task.minLength is not None and task.maxLength is not None:
if task.minLength > task.minLength:
raise zope.interface.Invalid(
- u"Minimum lnegth must be greater than the maximum length.")
+ u"Minimum length must be greater than the maximum length.")
groupMax = zope.schema.Int(
title=_(u'Maximum Characters of Group'),
Modified: z3c.password/trunk/src/z3c/password/principal.py
===================================================================
--- z3c.password/trunk/src/z3c/password/principal.py 2009-06-11 11:28:14 UTC (rev 100869)
+++ z3c.password/trunk/src/z3c/password/principal.py 2009-06-11 13:05:53 UTC (rev 100870)
@@ -11,7 +11,7 @@
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
-"""Principal MixIn for Advnaced Password Management
+"""Principal MixIn for Advanced Password Management
$Id$
"""
@@ -34,17 +34,16 @@
def setPassword(self, password, passwordManagerName=None):
super(PrincipalMixIn, self).setPassword(password, passwordManagerName)
- self.passwordSetOn = datetime.datetime.now()
+ self.passwordSetOn = self.now()
self.failedAttempts = 0
password = property(getPassword, setPassword)
+ def now(self):
+ #hook to facilitate testing and easier override
+ return datetime.datetime.now()
+
def checkPassword(self, pwd, ignoreExpiration=False, ignoreFailures=False):
- # Make sure the password has not been expired
- if not ignoreExpiration and self.passwordExpiresAfter is not None:
- expirationDate = self.passwordSetOn + self.passwordExpiresAfter
- if expirationDate < datetime.datetime.now():
- raise interfaces.PasswordExpired(self)
# Check the password
same = super(PrincipalMixIn, self).checkPassword(pwd)
# If this was a failed attempt, record it, otherwise reset the failures
@@ -53,9 +52,17 @@
if not same:
self.failedAttempts += 1
# If the maximum amount of failures has been reached notify the system
- # by sending an event and then raising an error.
+ # by raising an error.
if not ignoreFailures and self.maxFailedAttempts is not None:
if (self.maxFailedAttempts and
self.failedAttempts > self.maxFailedAttempts):
raise interfaces.TooManyLoginFailures(self)
+
+ if same:
+ # Make sure the password has not been expired
+ if not ignoreExpiration and self.passwordExpiresAfter is not None:
+ expirationDate = self.passwordSetOn + self.passwordExpiresAfter
+ if expirationDate < self.now():
+ raise interfaces.PasswordExpired(self)
+
return same
More information about the Checkins
mailing list