diff --git a/.semver b/.semver index 97e89033..bd7c75ac 100644 --- a/.semver +++ b/.semver @@ -1,5 +1,5 @@ --- -:major: 11 -:minor: 3 +:major: 14 +:minor: 1 :patch: 0 :special: '' diff --git a/CHANGELOG.md b/CHANGELOG.md index b24fb4e0..418a4965 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ Changelog ========= Releases for CakePHP 5 ------------- +* 14.1 + * New feature "Account lockout policy" * 14.0 * Set dependecy for CakeDC/Auth to 10.0. Perform 2FA refactoring, @@ -23,7 +25,7 @@ Releases for CakePHP 4.5 * Update Permissions.md * fix: config for updateLastLogin * fix: remove deprecated code on profile logic - * feat:flash message on login, on cake4 + * feat:flash message on login, on cake4 * 11.3.4 * Fix `Detected invalid UTF-8 for field...` issue when storing session data from `Webauthn` in a mongo database. diff --git a/Docs/Documentation/Authentication.md b/Docs/Documentation/Authentication.md index 66f94f40..641de428 100644 --- a/Docs/Documentation/Authentication.md +++ b/Docs/Documentation/Authentication.md @@ -117,6 +117,34 @@ The default list for ``Auth.Identifiers`` is: These identifiers are loaded by the ``\CakeDC\Users\Loader\AuthenticationServiceLoader`` class in the ``loadIdentifiers`` method. See [Authentication Service Loader](#authentication-service-loader) on how to adjust it to your needs. +Account lockout policy +---------------------- +Lock a users account after a number of failed password attempts in a certain time window. + +To enable this updated your config/users.php file with: +```php + 'Auth.Identifiers.Password.className' => 'CakeDC/Users.PasswordLockout', + 'Auth.PasswordRehash' => [ + 'identifiers' => ['PasswordLockout'], + ], +``` +Additionally, you can set number of attempts until lock, lockout time, time window and more, eg: +``` + 'Auth.Identifiers.Password.className' => 'CakeDC/Users.PasswordLockout', + 'Auth.PasswordRehash' => [ + 'identifiers' => ['PasswordLockout'], + ], + 'Auth.Identifiers.Password.lockoutHandler' => [ + 'timeWindowInSeconds' => 30 * 60,//30 minutes (default is 15 minutes) + 'lockoutTimeInSeconds' => 100 * 60,//100 minutes (default is 30 minutes) + 'numberOfAttemptsFail' => 4, (default is 6 attempts) + 'failedPasswordAttemptsModel' => 'CakeDC/Users.FailedPasswordAttempts', + 'userLockoutField' => 'lockout_time',//Field in user entity used to lock the user. + 'usersModel' => 'Users', + ], +``` + + Handling Login Result --------------------- diff --git a/Docs/Home.md b/Docs/Home.md index ca8b2339..253ec9c5 100644 --- a/Docs/Home.md +++ b/Docs/Home.md @@ -224,6 +224,7 @@ I want to - [use user's email to login](./Documentation/Configuration.md#using-the-users-email-to-login) - [override the password hasher](./Documentation/Configuration.md#password-hasher-customization) + - [lock a users account after a number of failed password attempts](./Documentation/Authentication.md#account-lockout-policy) - add custom logic before - [user logout](./Documentation/Events.md#i-want-to-add-custom-logic-before-user-logout) diff --git a/README.md b/README.md index 8c1e7a63..aab55697 100644 --- a/README.md +++ b/README.md @@ -10,18 +10,20 @@ CakeDC Users Plugin Versions and branches --------------------- -| CakePHP | CakeDC Users Plugin | Tag | Notes | -| :-------------: | :------------------------: | :--: | :---- | -| ^5.0 | [12.0](https://github.com/cakedc/users/tree/12.next-cake5) | 12.next-cake5-dev | beta | -| ^4.3 | [11.0](https://github.com/cakedc/users/tree/11.next-cake4) | 11.1.0 | stable | -| ^4.0 | [9.0](https://github.com/cakedc/users/tree/9.next) | 9.0.5 | stable | -| ^3.7 <4.0 | [8.5](https://github.com/cakedc/users/tree/8.next) | 8.5.1 | stable | -| ^3.7 <4.0 | [develop](https://github.com/cakedc/users/tree/develop) | - | unstable | -| 3.6 | [8.1](https://github.com/cakedc/users/tree/8.1.0) | 8.1.0 | stable | -| 3.5 | [6.x](https://github.com/cakedc/users/tree/6.x) | 6.0.1 | stable | -| 3.4 | [5.x](https://github.com/cakedc/users/tree/5.x) | 5.2.0 | stable | -| >=3.2.9 <3.4.0 | [4.x](https://github.com/cakedc/users/tree/4.x) | 4.2.1 | stable | -| ^2.10 | [2.x](https://github.com/cakedc/users/tree/2.x) | 2.2.0 |stable | +| CakePHP | CakeDC Users Plugin | Tag | Notes | +|:--------------:|:----------------------------------------------------------:|:-----------------:| :---- | +| ^5.0 | [14.1](https://github.com/cakedc/users/tree/14.next-cake5) | 14.next-cake5-dev | beta | +| ^4.5 | [13.0](https://github.com/cakedc/users/tree/13.next-cake4) | 13.0.1 | stable | +| ^5.0 | [12.0](https://github.com/cakedc/users/tree/12.next-cake5) | 12.0 | beta | +| ^4.3 | [11.0](https://github.com/cakedc/users/tree/11.next-cake4) | 11.1.0 | stable | +| ^4.0 | [9.0](https://github.com/cakedc/users/tree/9.next) | 9.0.5 | stable | +| ^3.7 <4.0 | [8.5](https://github.com/cakedc/users/tree/8.next) | 8.5.1 | stable | +| ^3.7 <4.0 | [develop](https://github.com/cakedc/users/tree/develop) | - | unstable | +| 3.6 | [8.1](https://github.com/cakedc/users/tree/8.1.0) | 8.1.0 | stable | +| 3.5 | [6.x](https://github.com/cakedc/users/tree/6.x) | 6.0.1 | stable | +| 3.4 | [5.x](https://github.com/cakedc/users/tree/5.x) | 5.2.0 | stable | +| >=3.2.9 <3.4.0 | [4.x](https://github.com/cakedc/users/tree/4.x) | 4.2.1 | stable | +| ^2.10 | [2.x](https://github.com/cakedc/users/tree/2.x) | 2.2.0 |stable | The **Users** plugin covers the following features: diff --git a/src/Identifier/PasswordLockout/LockoutHandler.php b/src/Identifier/PasswordLockout/LockoutHandler.php index 4896ef9a..5fc0180c 100644 --- a/src/Identifier/PasswordLockout/LockoutHandler.php +++ b/src/Identifier/PasswordLockout/LockoutHandler.php @@ -30,8 +30,8 @@ class LockoutHandler implements LockoutHandlerInterface * @var array{timeWindowInSeconds: int, lockoutTimeInSeconds: int, numberOfAttemptsFail:int} */ protected array $_defaultConfig = [ - 'timeWindowInSeconds' => 5 * 60, - 'lockoutTimeInSeconds' => 5 * 60, + 'timeWindowInSeconds' => 15 * 60, + 'lockoutTimeInSeconds' => 30 * 60, 'numberOfAttemptsFail' => 6, 'failedPasswordAttemptsModel' => 'CakeDC/Users.FailedPasswordAttempts', 'userLockoutField' => 'lockout_time', diff --git a/tests/TestCase/Identifier/PasswordLockout/LockoutHandlerTest.php b/tests/TestCase/Identifier/PasswordLockout/LockoutHandlerTest.php index 45c87ef8..3b138de6 100644 --- a/tests/TestCase/Identifier/PasswordLockout/LockoutHandlerTest.php +++ b/tests/TestCase/Identifier/PasswordLockout/LockoutHandlerTest.php @@ -79,9 +79,11 @@ public function testIsUnlockedSaveLockoutAndCompleted() $handler = new LockoutHandler([ 'numberOfAttemptsFail' => 7, ]); + $expiredTimeout = $handler->getConfig('lockoutTimeInSeconds') + 10; + $this->assertGreaterThan(10, $expiredTimeout); $UsersTable = TableRegistry::getTableLocator()->get('Users'); $userId = '00000000-0000-0000-0000-000000000004'; - $UsersTable->updateAll(['lockout_time' => new DateTime('-6 minutes')], ['id' => $userId]); + $UsersTable->updateAll(['lockout_time' => new DateTime('-' . $expiredTimeout . 'minutes')], ['id' => $userId]); $userBefore = $UsersTable->get($userId); $this->assertInstanceOf(DateTime::class, $userBefore->lockout_time);