testAuthenticationPolicy.py 26.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (c) 2004, 2005, 2006 Nexedi SARL and Contributors.
# All Rights Reserved.
#          Ivan Tyagov <ivan@nexedi.com>
#
# 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 adviced 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################

import unittest
import time
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
from Products.ERP5Type.tests.backportUnittest import expectedFailure
35
from Products.Formulator.Errors import ValidationError
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
from Products.ERP5Type.Document import newTempBase
from DateTime import DateTime

class TestAuthenticationPolicy(ERP5TypeTestCase):
  """
  Test for erp5_authentication_policy business template.
  """
  manager_username = 'zope'
  manager_password = 'zope'

  credential = '%s:%s' % (manager_username, manager_password)
  def getTitle(self):
    return "TestAuthenticationPolicy"

  def getBusinessTemplateList(self):
    """
    Return the list of required business templates.
    """
    return ('erp5_core_proxy_field_legacy',
            'erp5_base',
            'erp5_web',
            'erp5_credential',
58
            'erp5_system_event',
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
            'erp5_authentication_policy',)

  def afterSetUp(self):
    portal = self.getPortal()

    uf = portal.acl_users
    uf._doAddUser(self.manager_username, self.manager_password, ['Manager'], [])
    self.login(self.manager_username)
    kw = dict(portal_type='Person',
              reference = 'test')
    if portal.portal_catalog.getResultValue(**kw) is None:
      # add a loggable Person
      person = portal.person_module.newContent(password = 'test', 
                                               first_name = 'First',
                                               last_name = 'Last', 
                                               **kw)
      person.validate()
76 77
      assignment = person.newContent(portal_type = 'Assignment')
      assignment.open()
78 79 80 81 82 83 84
                                      
      # Setup auth policy
      preference = portal.portal_preferences.newContent(
                                              portal_type = 'System Preference',
                                              title = 'Authentication',
                                              preferred_max_authentication_failure = 3,
                                              preferred_authentication_failure_check_duration = 600,
85 86
                                              preferred_authentication_failure_block_duration = 600,
                                              preferred_authentication_policy_enabled = True)
87
      preference.enable()
88
      self.tic()
89 90

  def _clearCache(self):
91 92 93 94
    self.portal.portal_caches.clearCache(
      cache_factory_list=('erp5_ui_short', # for preference cache
                          'erp5_content_short', # for authentication cache
                          ))
95

96 97 98 99 100 101
  def _getPasswordEventList(self, person):
    return [x.getObject() for x in self.portal.portal_catalog(
                                                 portal_type = 'Password Event',
                                                 default_destination_uid = person.getUid(),
                                                 sort_on = (('creation_date', 'DESC',),))]

102
  def _cleanUpPerson(self, person):
103
    self.portal.system_event_module.manage_delObjects([x.getId() for x in self._getPasswordEventList(person)])
104 105 106 107 108 109 110


  def test_01_BlockLogin(self):
    """
      Test that a recataloging works for Web Site documents
    """
    portal = self.getPortal()
111
    self.assertTrue(portal.portal_preferences.isAuthenticationPolicyEnabled())
112 113 114 115 116 117 118 119
    
    person = portal.portal_catalog.getResultValue(portal_type = 'Person', 
                                                  reference = 'test')
    preference = portal.portal_catalog.getResultValue(portal_type = 'System Preference',
                                                      title = 'Authentication',)                                                  
    # login should be allowed
    self.assertFalse(person.isLoginBlocked())
    
120 121 122 123
    # file some failures so we should detect and block account
    person.notifyLoginFailure()
    person.notifyLoginFailure()
    person.notifyLoginFailure()
124
    self.tic()
125

126
    # should be blocked
127 128 129 130 131
    self.assertTrue(person.isLoginBlocked())
    
    # set check back interval to actualy disable blocking
    preference.setPreferredAuthenticationFailureCheckDuration(0)
    self._clearCache()
132
    self.tic()
133
    time.sleep(1) # we need to give a moment
134 135 136 137 138
    self.assertFalse(person.isLoginBlocked())
    
    # .. and revert it back
    preference.setPreferredAuthenticationFailureCheckDuration(600)
    self._clearCache()
139
    self.tic()
140 141 142 143 144
    self.assertTrue(person.isLoginBlocked())
    
    # increase failures attempts
    preference.setPreferredMaxAuthenticationFailure(4)
    self._clearCache()
145
    self.tic()
146 147 148 149 150
    self.assertFalse(person.isLoginBlocked())
    
    # .. and revert it back
    preference.setPreferredMaxAuthenticationFailure(3)
    self._clearCache()
151
    self.tic()
152 153 154 155 156
    self.assertTrue(person.isLoginBlocked())
    
    # set short block interval so we can test it as well
    preference.setPreferredAuthenticationFailureBlockDuration(3)
    self._clearCache()
157
    self.tic()
158 159
    time.sleep(4)
    self.assertFalse(person.isLoginBlocked())
160 161 162 163 164 165 166
    
    # test multiple concurrent transactions without waiting for activities to be over
    preference.setPreferredAuthenticationFailureCheckDuration(600)
    preference.setPreferredAuthenticationFailureBlockDuration(600)    
    preference.setPreferredMaxAuthenticationFailure(3)    
    person.Person_unblockLogin()
    self._clearCache()
167
    self.tic()
168 169 170 171 172
    
    person.notifyLoginFailure()
    person.notifyLoginFailure()
    person.notifyLoginFailure()
    
173
    self.commit()
174
    self.assertTrue(person.isLoginBlocked())
175
    self.tic()
176 177 178 179
    self.assertTrue(person.isLoginBlocked())
    
    # test unblock account
    person.Person_unblockLogin()
180
    self.tic()
181 182
    self.assertFalse(person.isLoginBlocked())    
    
183 184 185 186 187 188

  def test_02_PasswordHistory(self):
    """
      Test password history.
    """
    portal = self.getPortal()
189
    self.assertTrue(portal.portal_preferences.isAuthenticationPolicyEnabled())
190
    
191 192
    person = portal.person_module.newContent(portal_type = 'Person', 
                                             reference = 'test-02')                                                  
193 194
    preference = portal.portal_catalog.getResultValue(portal_type = 'System Preference',
                                                      title = 'Authentication',)
195
    self.tic()
196 197
                                                      
    # Check that last (X where X is set in preferences) passwords are saved.
198
    self.assertEqual([], self._getPasswordEventList(person))    
199
    preference.setPreferredNumberOfLastPasswordToCheck(10)
200
    self.tic()
201 202 203
    self._clearCache()
    
    person.setPassword('12345678')
204
    self.tic()
205 206
    
    # password change date should be saved as well hashed old password value
207
    old_password = person.getPassword()     
208
    self.assertSameSet([old_password], [x.getPassword() for x in self._getPasswordEventList(person)])
209 210 211
    
    # .. test one more time to check history of password is saved in a list
    person.setPassword('123456789')
212
    self.tic()
213
    old_password1 = person.getPassword()
214 215
    
    # password change date should be saved as well hashed old password value
216 217
    self.assertSameSet([old_password1, old_password], [x.getPassword() for x in self._getPasswordEventList(person)])

218 219
    # other methods (_setPassword)...
    person._setPassword('123456789-1')
220
    self.tic()
221
    old_password2 = person.getPassword()
222 223 224
    self.assertSameSet([old_password2, old_password1, old_password], \
                     [x.getPassword() for x in self._getPasswordEventList(person)])

225 226
    # other methods (_forceSetPassword)...
    person._forceSetPassword('123456789-2')
227
    self.tic()
228
    old_password3 = person.getPassword()
229 230 231
    self.assertSameSet([old_password3, old_password2, old_password1, old_password], \
                     [x.getPassword() for x in self._getPasswordEventList(person)]) 
    
232 233 234

    # other methods (setEncodedPassword)...
    person.setEncodedPassword('123456789-3')
235
    self.tic()
236
    old_password4 = person.getPassword()
237 238
    self.assertSameSet([old_password4, old_password3, old_password2, old_password1, old_password], \
                     [x.getPassword() for x in self._getPasswordEventList(person)]) 
239 240 241

    # other methods (edit)...
    person.edit(password = '123456789-4')
242
    self.tic()
243
    old_password5 = person.getPassword()
244 245
    self.assertSameSet([old_password5, old_password4, old_password3, old_password2, old_password1, old_password], \
                     [x.getPassword() for x in self._getPasswordEventList(person)]) 
246

247 248 249 250 251 252

  def test_03_PasswordValidity(self):
    """
      Test validity of a password.
    """
    portal = self.getPortal()
253
    request = self.app.REQUEST    
254 255 256 257 258 259 260
    
    regular_expression_list = ['([a-z]+)', # english lowercase
                               '([A-Z]+)', # english uppercase
                               '([0-9]+)', # numerals (0-9)
                               '([\\\\$\\\\!\\\\#\\\\%]+)' # (!, $, #, %)
                              ]
    
261
    self.assertTrue(portal.portal_preferences.isAuthenticationPolicyEnabled())
262 263 264 265 266 267

    person = portal.person_module.newContent(portal_type = 'Person', 
                                             reference = 'test-03',
                                             password = 'test', 
                                             first_name = 'First',
                                             last_name = 'Last')                                                    
268 269
    preference = portal.portal_catalog.getResultValue(portal_type = 'System Preference',
                                                      title = 'Authentication',)
270
    self.tic()
271
    
272 273 274 275 276 277 278
    # by default an empty password if nothing set in preferences is OK
    self.assertTrue(person.isPasswordValid(''))
    
    # Not long enough passwords used
    self._cleanUpPerson(person)    
    preference.setPreferredMinPasswordLength(8)
    preference.setPreferredNumberOfLastPasswordToCheck(0)    
279
    self.tic()
280 281
    self._clearCache()
    
282 283
    self.assertEqual([-1], person.analyzePassword(''))
    self.assertEqual([-1], person.analyzePassword('1234567'))   
284 285 286 287 288 289
    self.assertTrue(person.isPasswordValid('12345678'))
    
    # not changed in last x days
    self._cleanUpPerson(person)    
    preference.setPreferredMinPasswordLifetimeDuration(24)
    preference.setPreferredNumberOfLastPasswordToCheck(3)
290
    self.tic()
291 292
    self._clearCache()
    
293
    self.assertTrue(person.isPasswordValid('12345678'))
294
    person.setPassword('12345678')
295
    self.tic()
296
    
297
    # if we try to change now we should fail with any password
298 299 300
    self.assertSameSet([-3], person.analyzePassword('87654321'))
    self.assertSameSet([-1, -3], person.analyzePassword('short')) # multiple failures
    self.assertFalse(person.isPasswordValid('short')) # multiple failures
301 302
    self.assertRaises(ValueError, person.setPassword, '87654321')
 
303
    preference.setPreferredMinPasswordLifetimeDuration(0) # remove restriction
304
    self.tic()
305 306 307 308 309 310
    self._clearCache()
    self.assertTrue(person.isPasswordValid('87654321')) # it's OK to change
    
    # password not used in previous X passwords
    preference.setPreferredMinPasswordLength(None) # disable for now
    self._cleanUpPerson(person)
311
    self._clearCache()
312
    self.tic()
313 314
    
    person.setPassword('12345678-new')
315
    self.tic()
316
    
317
    self.assertSameSet([-4], person.analyzePassword('12345678-new')) # if we try to change now we should fail with this EXACT password
318
    self.assertRaises(ValueError, person.setPassword, '12345678-new')
319
    self.assertTrue(person.isPasswordValid('12345678_')) # it's OK with another one not used yet
320
    for password in ['a','b','c','d', 'e', 'f']:
321 322 323 324 325
      # this sleep is not so beautiful, but mysql datetime columns has a
      # precision of one second only, and we use creation_date to order
      # "Password Event" objects. So without this sleep, the test is
      # failing randomly.
      time.sleep(1)
326
      person.setPassword(password)
327
      self.tic()
Ivan Tyagov's avatar
Ivan Tyagov committed
328
    self._clearCache()
329
    self.tic()
330
 
331 332 333
    self.assertTrue(person.isPasswordValid('12345678-new'))
    self.assertTrue(person.isPasswordValid('a'))
    self.assertTrue(person.isPasswordValid('b'))
Ivan Tyagov's avatar
Ivan Tyagov committed
334
    self.assertTrue(person.isPasswordValid('c'))
335
    # only last 3 (including current one are invalid)
336 337 338
    self.assertSameSet([-4], person.analyzePassword('d'))
    self.assertSameSet([-4], person.analyzePassword('e'))     
    self.assertSameSet([-4], person.analyzePassword('f'))
339
  
340 341 342
    # if we remove restricted then all password are usable
    preference.setPreferredNumberOfLastPasswordToCheck(None)
    self._clearCache()    
343
    self.tic()
344
    
345 346 347
    self.assertTrue(person.isPasswordValid('d'))
    self.assertTrue(person.isPasswordValid('e'))
    self.assertTrue(person.isPasswordValid('f'))
348 349 350 351
    
    # if we set only last password to check
    preference.setPreferredNumberOfLastPasswordToCheck(1)
    self._clearCache()    
352
    self.tic()
353 354 355 356
    self.assertTrue(person.isPasswordValid('c'))
    self.assertTrue(person.isPasswordValid('d'))
    self.assertTrue(person.isPasswordValid('e'))
    self.assertSameSet([-4], person.analyzePassword('f'))    
357
       
358 359 360 361 362
    preference.setPreferredRegularExpressionGroupList(regular_expression_list)
    preference.setPreferredMinPasswordLength(7)
    preference.setPreferredNumberOfLastPasswordToCheck(None)
    self._cleanUpPerson(person)    
    self._clearCache() 
363
    self.tic()
364 365 366 367 368 369 370 371 372
    
    four_group_password_list = ['abAB#12', 'ghTK61%', '5Tyui1%','Y22GJ5iu#' ]
    three_group_password_list = ['abAB123 ', 'AB123ab', 'XY123yz', 'dufgQ7xL', 'NAfft8h5', '0LcAiWtT']
    two_group_password_list = ['XY12345', 'yuiffg1', 'abcdef##', '##$aabce']
    one_group_password_list = ['1234567', 'ABZSDFE', '##!!$$%','abzdeffgg']

    # min 4 out of all groups
    preference.setPreferredMinRegularExpressionGroupNumber(4)
    self._clearCache() 
373
    self.tic()
374 375 376
    for password in four_group_password_list:
      self.assertTrue(person.isPasswordValid(password))
    for password in three_group_password_list+two_group_password_list + one_group_password_list:
377
      self.assertSameSet([-2], person.analyzePassword(password))    
378 379 380 381 382

    # min 3 out of all groups
    preference.setPreferredMinRegularExpressionGroupNumber(3)    
    self._clearCache()
    self._cleanUpPerson(person)    
383
    self.tic()
384 385 386
    for password in four_group_password_list + three_group_password_list:
      self.assertTrue(person.isPasswordValid(password))
    for password in two_group_password_list + one_group_password_list:
387
      self.assertSameSet([-2], person.analyzePassword(password))
388 389 390 391
    
    # min 2 out of all groups
    preference.setPreferredMinRegularExpressionGroupNumber(2)
    self._clearCache()
392
    self.tic()
393 394 395
    for password in four_group_password_list + three_group_password_list + two_group_password_list:
      self.assertTrue(person.isPasswordValid(password))
    for password in one_group_password_list:
396
      self.assertSameSet([-2], person.analyzePassword(password))
397 398 399 400
      
    # min 1 out of all groups
    preference.setPreferredMinRegularExpressionGroupNumber(1)
    self._clearCache()
401
    self.tic()
402 403 404 405 406 407
    for password in four_group_password_list + three_group_password_list + two_group_password_list+one_group_password_list:
      self.assertTrue(person.isPasswordValid(password))

    # not contain the full name of the user
    preference.setPrefferedForceUsernameCheckInPassword(1)
    self._clearCache()
408
    self.tic()
409 410
    self.assertSameSet([-5], person.analyzePassword('abAB#12_%s' %person.getFirstName()))
    self.assertSameSet([-5], person.analyzePassword('abAB#12_%s' %person.getLastName()))
411 412
    preference.setPrefferedForceUsernameCheckInPassword(0)
    self._clearCache()
413
    self.tic()
414 415 416 417 418 419 420 421 422 423 424 425 426 427
    self.assertTrue(person.isPasswordValid('abAB#12_%s' %person.getFirstName()))
    self.assertTrue(person.isPasswordValid('abAB#12_%s' %person.getLastName()))    

    # check on temp objects just passworrd length( i.e. simulating a new user account creation)
    first_name = 'John'
    last_name = 'Doh'
    kw = {'title': '%s %s' %(first_name, last_name),
          'first_name': first_name,
          'last_name': last_name}
    temp_person = newTempBase(portal, kw['title'], **kw)
    
    preference.setPreferredMinPasswordLength(10)
    preference.setPreferredRegularExpressionGroupList(None)
    self._clearCache()    
428
    self.tic()
429
    # in this case which is basically used in new account creation only length of password matters
430 431
    self.assertSameSet([-1], temp_person.Person_analyzePassword('onlyNine1'))
    self.assertSameSet([], temp_person.Person_analyzePassword('longEnough1'))
432 433 434 435 436 437
    
    # make sure re check works on temp as well ( i.e. min 3 out of all groups)
    preference.setPreferredRegularExpressionGroupList(regular_expression_list)    
    preference.setPreferredMinPasswordLength(7)    
    preference.setPreferredMinRegularExpressionGroupNumber(3)    
    self._clearCache()
438
    self.tic()
439
    for password in four_group_password_list + three_group_password_list:
440
      self.assertSameSet([], temp_person.Person_analyzePassword(password))
441
    for password in two_group_password_list + one_group_password_list:
442
      self.assertSameSet([-2], temp_person.Person_analyzePassword(password))
443 444 445 446
      
    # make sure peron's check on username works on temp as well (i.e. not contain the full name of the user)
    preference.setPrefferedForceUsernameCheckInPassword(1)
    self._clearCache()
447
    self.tic()
448 449
    self.assertSameSet([-5], temp_person.Person_analyzePassword('abAB#12_%s' %first_name))
    self.assertSameSet([-5], temp_person.Person_analyzePassword('abAB#12_%s' %last_name))
450 451 452
    
    preference.setPrefferedForceUsernameCheckInPassword(0)
    self._clearCache()
453
    self.tic()
454 455
    self.assertSameSet([], temp_person.Person_analyzePassword('abAB#12_%s' %first_name))
    self.assertSameSet([], temp_person.Person_analyzePassword('abAB#12_%s' %last_name))    
456 457 458 459 460 461 462 463
    
    # check Base_isPasswordValid is able to work in Anonymous User fashion
    # but with already create Person object (i.e. recover password case)
    preference.setPrefferedForceUsernameCheckInPassword(1)
    preference.setPreferredMinPasswordLength(7)
    preference.setPreferredMinRegularExpressionGroupNumber(3)
    preference.setPreferredNumberOfLastPasswordToCheck(1)
    self._clearCache()
464
    self.tic()
465 466 467
    
    person.setPassword('used_ALREADY_1234')
    self._clearCache()
468
    self.tic()
469 470 471 472 473 474 475 476 477 478 479
    
    # emulate Anonymous User
    self.logout()
    request.set('field_user_login', person.getReference())     
    self.assertRaises(ValidationError,  portal.Base_isPasswordValid, 'abAB#12_%s' %person.getFirstName(), request) # contains name
    self.assertRaises(ValidationError,  portal.Base_isPasswordValid, 'abAB#12_%s' %person.getLastName(), request) # contains name
    self.assertRaises(ValidationError,  portal.Base_isPasswordValid, 'abAB#1', request) # too short
    self.assertRaises(ValidationError,  portal.Base_isPasswordValid, 'abABCDEFG', request) # too few groups
    self.assertRaises(ValidationError,  portal.Base_isPasswordValid, 'used_ALREADY_1234', request) # already used 
    self.assertEqual(1, portal.Base_isPasswordValid('abAB#12_', request))
    self.assertEqual(1, portal.Base_isPasswordValid('not_used_ALREADY_1234', request))     
480 481 482 483 484 485

  def test_04_PasswordExpire(self):
    """
      Test password expire.
    """
    portal = self.getPortal()
486 487
    request = self.app.REQUEST
    
488
    self.assertTrue(portal.portal_preferences.isAuthenticationPolicyEnabled())
489
    
490 491 492
    person = portal.person_module.newContent(portal_type = 'Person', 
                                             reference = 'test-04',
                                             password = 'used_ALREADY_1234')                                                    
493 494 495 496
    preference = portal.portal_catalog.getResultValue(portal_type = 'System Preference',
                                                      title = 'Authentication',)
                                                      
    preference.setPreferredMaxPasswordLifetimeDuration(24)
497
    self.tic()
498 499
    self._clearCache()
    self.assertFalse(person.isPasswordExpired())
500
    self.assertFalse(request['is_user_account_password_expired'])
501
    
502
   
503
    # set longer password validity interval
504
    preference.setPreferredMaxPasswordLifetimeDuration(4*24) # password expire in 4 days
505
    self.tic()
506 507 508 509 510 511
    self._clearCache()
    self.assertFalse(person.isPasswordExpired())
    self.assertFalse(request['is_user_account_password_expired'])
    
    # test early warning password expire notification is detected
    preference.setPreferredPasswordLifetimeExpireWarningDuration(4*24) # password expire notification appear immediately
512
    self.tic()
513
    self._clearCache()
514
    self.assertFalse(person.isPasswordExpired())
515
    self.assertTrue(request['is_user_account_password_expired_expire_date'])
516 517 518
    
    # test early warning password expire notification is detected
    preference.setPreferredPasswordLifetimeExpireWarningDuration(4*24-24) # password expire notification appear 3 days befor time
519
    self.tic()
520 521
    self._clearCache()
    self.assertFalse(person.isPasswordExpired())
522
    self.assertFalse(request['is_user_account_password_expired_expire_date']) 
523

524
  def test_05_HttpRequest(self):
525 526 527 528 529 530 531
    """
      Check HTTP responses
    """
    portal = self.getPortal()
    request = self.app.REQUEST
    person = portal.portal_catalog.getResultValue(portal_type = 'Person', 
                                                  reference = 'test')
532 533 534
    preference = portal.portal_catalog.getResultValue(portal_type = 'System Preference',
                                                      title = 'Authentication',)
    person.setPassword('used_ALREADY_1234')
535
    self.tic()
536 537 538 539 540 541 542 543
                                            
    path = portal.absolute_url_path() + '/view?__ac_name=%s&__ac_password=%s'  %('test', 'used_ALREADY_1234')
    response = self.publish(path)
    self.assertTrue('Welcome to ERP5' in response.getBody())
    self.assertFalse(person.isLoginBlocked())
    
    # fail request #1
    path = portal.absolute_url_path() + '/view?__ac_name=%s&__ac_password=%s'  %('test', 'bad_test')
544
    response = self.publish(path)
545 546 547 548 549 550 551 552 553 554 555 556 557
    self.assertTrue(response.getHeader("Location").endswith("login_form"))
    self.assertFalse(person.isLoginBlocked())
    
    # fail request #2
    response = self.publish(path)
    self.assertTrue(response.getHeader("Location").endswith("login_form"))
    self.assertFalse(person.isLoginBlocked())
    
    # fail request #3    
    response = self.publish(path)
    self.assertTrue(response.getHeader("Location").endswith("login_form"))
    self.assertTrue(person.isLoginBlocked())
    
558
    self.tic()
559 560 561 562 563 564 565 566 567 568
    
    # test message that account is blocked
    self.assertTrue(person.isLoginBlocked())
    path = portal.absolute_url_path() + '/logged_in?__ac_name=%s&__ac_password=%s'  %('test', 'used_ALREADY_1234')
    response = self.publish(path)
    self.assertTrue(response.getHeader("Location").endswith("login_form?portal_status_message=Account is blocked."))
    
    # test expire password message, first unblock it
    person.Person_unblockLogin()
    preference.setPreferredMaxPasswordLifetimeDuration(0)
569
    self.tic()
570 571 572 573 574 575 576 577
    self._clearCache()
    response = self.publish(path)    
    self.assertTrue(response.getHeader("Location").endswith("login_form?portal_status_message=Password is expired."))
    self.assertTrue(person.isPasswordExpired())
    
    # test we're redirected to update password due to soon expire
    preference.setPreferredMaxPasswordLifetimeDuration(24)
    preference.setPreferredPasswordLifetimeExpireWarningDuration(24)    
578
    self.tic()
579 580 581 582 583 584 585 586
    self._clearCache()
    response = self.publish(path) 
    
    self.assertTrue('Your password will expire' in response.getHeader("Location"))
    self.assertTrue('You are advised to change it as soon as possible' in response.getHeader("Location"))
    
    # test proper login
    preference.setPreferredPasswordLifetimeExpireWarningDuration(12)    
587
    self.tic()
588 589 590 591
    self._clearCache()
    path = portal.absolute_url_path() + '/view?__ac_name=%s&__ac_password=%s'  %('test', 'used_ALREADY_1234')    
    response = self.publish(path) 
    self.assertTrue('Welcome to ERP5' in response.getBody())
592 593 594 595 596 597 598 599 600 601 602 603 604 605

  def test_06_ExpireOldAuthenticationEventList(self):
    """
      Check that expiring old Authentication Event list works.
    """
    portal = self.getPortal()
    person = portal.portal_catalog.getResultValue(portal_type = 'Person', 
                                                  reference = 'test')
    preference = portal.portal_catalog.getResultValue(portal_type = 'System Preference',
                                                      title = 'Authentication',)
    # file some failures so we should detect and block account
    person.notifyLoginFailure()
    person.notifyLoginFailure()
    person.notifyLoginFailure()
606
    self.tic()
607 608 609

    # should be blocked
    self.assertTrue(person.isLoginBlocked())
610
    
611 612
    # set 0 check interval
    preference.setPreferredAuthenticationFailureCheckDuration(0)
613
    self.tic()
614 615 616 617 618 619 620
    self._clearCache()
    
    time.sleep(1) # we need to give a moment
    self.assertFalse(person.isLoginBlocked())
    
    # expire manually old
    portal.system_event_module.SystemEventModule_expireAuthenticationEventList()
621
    self.tic()
622 623 624 625 626 627 628
    
    self.assertEqual(3, len(portal.portal_catalog(portal_type ="Authentication Event",
                                                 default_destination_uid = person.getUid(),    
                                                 validation_state = "expired")))
                                                


629 630 631 632
def test_suite():
  suite = unittest.TestSuite()
  suite.addTest(unittest.makeSuite(TestAuthenticationPolicy))
  return suite