From 34988ab808a8d562d25a4fcd0fd424afebf0a39b Mon Sep 17 00:00:00 2001 From: Bence Date: Sun, 11 Jun 2023 16:34:52 +0100 Subject: [PATCH 01/22] Update Permissions.md Missing comma --- Docs/Documentation/Permissions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Docs/Documentation/Permissions.md b/Docs/Documentation/Permissions.md index d2b55f20f..6447cdca5 100644 --- a/Docs/Documentation/Permissions.md +++ b/Docs/Documentation/Permissions.md @@ -23,7 +23,7 @@ return [ //...... all other rules [ 'controller' => 'Pages', - 'action' => ['home', 'contact', 'projects'] + 'action' => ['home', 'contact', 'projects'], 'bypassAuth' => true, ], ], From 85d913772f3ab5e6f06779b5e1898e6d74e118dc Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Sat, 16 Sep 2023 01:14:45 +0300 Subject: [PATCH 02/22] prepare release --- composer.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.json b/composer.json index 3f18ec532..c187ac4c8 100644 --- a/composer.json +++ b/composer.json @@ -30,10 +30,10 @@ "prefer-stable": true, "require": { "php": ">=8.1", - "cakephp/cakephp": "5.x-dev", - "cakedc/auth": "8.next-cake5-dev", - "cakephp/authorization": "3.x-dev", - "cakephp/authentication": "3.x-dev" + "cakephp/cakephp": "^5.0", + "cakedc/auth": "^8.0", + "cakephp/authorization": "^3.0", + "cakephp/authentication": "^3.0" }, "require-dev": { "phpunit/phpunit": "^10.0", From 4a0497e27c82c5f6f44d9a570d5bcbc8930fe1f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20P=C3=A9rez?= Date: Wed, 22 Nov 2023 16:50:56 +0000 Subject: [PATCH 03/22] Fix Detected invalid UTF-8 for field... issue when storing session data from Webauthn in a mongo database --- CHANGELOG.md | 3 +++ src/Webauthn/AuthenticateAdapter.php | 6 ++++-- src/Webauthn/RegisterAdapter.php | 6 ++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd799ce97..cd67206d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ Changelog ========= Releases for CakePHP 4.5 ------------------------ +* 11.3.4 + * Fix `Detected invalid UTF-8 for field...` issue when storing session data from `Webauthn` in a mongo database. + * 11.3.3 * Add display of unauthorized url in flash message when debug is true diff --git a/src/Webauthn/AuthenticateAdapter.php b/src/Webauthn/AuthenticateAdapter.php index 592c9590a..e899cad43 100644 --- a/src/Webauthn/AuthenticateAdapter.php +++ b/src/Webauthn/AuthenticateAdapter.php @@ -34,7 +34,7 @@ public function getOptions(): PublicKeyCredentialRequestOptions ); $this->request->getSession()->write( 'Webauthn2fa.authenticateOptions', - $options + json_encode($options) ); return $options; @@ -47,7 +47,9 @@ public function getOptions(): PublicKeyCredentialRequestOptions */ public function verifyResponse(): \Webauthn\PublicKeyCredentialSource { - $options = $this->request->getSession()->read('Webauthn2fa.authenticateOptions'); + $options = PublicKeyCredentialRequestOptions::createFromString( + (string)$this->request->getSession()->read('Webauthn2fa.authenticateOptions') + ); return $this->loadAndCheckAssertionResponse($options); } diff --git a/src/Webauthn/RegisterAdapter.php b/src/Webauthn/RegisterAdapter.php index c28b0504a..a4ef2a1f1 100644 --- a/src/Webauthn/RegisterAdapter.php +++ b/src/Webauthn/RegisterAdapter.php @@ -28,7 +28,7 @@ public function getOptions(): PublicKeyCredentialCreationOptions PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE, [] ); - $this->request->getSession()->write('Webauthn2fa.registerOptions', $options); + $this->request->getSession()->write('Webauthn2fa.registerOptions', json_encode($options)); $this->request->getSession()->write('Webauthn2fa.userEntity', $userEntity); return $options; @@ -41,7 +41,9 @@ public function getOptions(): PublicKeyCredentialCreationOptions */ public function verifyResponse(): \Webauthn\PublicKeyCredentialSource { - $options = $this->request->getSession()->read('Webauthn2fa.registerOptions'); + $options = PublicKeyCredentialCreationOptions::createFromString( + (string)$this->request->getSession()->read('Webauthn2fa.registerOptions') + ); $credential = $this->loadAndCheckAttestationResponse($options); $this->repository->saveCredentialSource($credential); From 60515d83280ccd9594ca5c9b402fdd67ef1efcdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodrigo=20P=C3=A9rez?= Date: Wed, 22 Nov 2023 17:16:07 +0000 Subject: [PATCH 04/22] Fux webauthn tests --- src/Webauthn/AuthenticateAdapter.php | 1 + src/Webauthn/RegisterAdapter.php | 1 + tests/TestCase/Webauthn/AuthenticateAdapterTest.php | 2 +- tests/TestCase/Webauthn/RegisterAdapterTest.php | 2 +- 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Webauthn/AuthenticateAdapter.php b/src/Webauthn/AuthenticateAdapter.php index e899cad43..24cd2965f 100644 --- a/src/Webauthn/AuthenticateAdapter.php +++ b/src/Webauthn/AuthenticateAdapter.php @@ -47,6 +47,7 @@ public function getOptions(): PublicKeyCredentialRequestOptions */ public function verifyResponse(): \Webauthn\PublicKeyCredentialSource { + /** @var \Webauthn\PublicKeyCredentialRequestOptions $options */ $options = PublicKeyCredentialRequestOptions::createFromString( (string)$this->request->getSession()->read('Webauthn2fa.authenticateOptions') ); diff --git a/src/Webauthn/RegisterAdapter.php b/src/Webauthn/RegisterAdapter.php index a4ef2a1f1..283bc85ac 100644 --- a/src/Webauthn/RegisterAdapter.php +++ b/src/Webauthn/RegisterAdapter.php @@ -41,6 +41,7 @@ public function getOptions(): PublicKeyCredentialCreationOptions */ public function verifyResponse(): \Webauthn\PublicKeyCredentialSource { + /** @var \Webauthn\PublicKeyCredentialCreationOptions $options */ $options = PublicKeyCredentialCreationOptions::createFromString( (string)$this->request->getSession()->read('Webauthn2fa.registerOptions') ); diff --git a/tests/TestCase/Webauthn/AuthenticateAdapterTest.php b/tests/TestCase/Webauthn/AuthenticateAdapterTest.php index 70c101c90..83773530d 100644 --- a/tests/TestCase/Webauthn/AuthenticateAdapterTest.php +++ b/tests/TestCase/Webauthn/AuthenticateAdapterTest.php @@ -36,7 +36,7 @@ public function testGetOptions() $adapter = new AuthenticateAdapter($request); $options = $adapter->getOptions(); $this->assertInstanceOf(PublicKeyCredentialRequestOptions::class, $options); - $this->assertSame($options, $request->getSession()->read('Webauthn2fa.authenticateOptions')); + $this->assertSame(json_encode($options), $request->getSession()->read('Webauthn2fa.authenticateOptions')); $data = json_decode('{"id":"LFdoCFJTyB82ZzSJUHc-c72yraRc_1mPvGX8ToE8su39xX26Jcqd31LUkKOS36FIAWgWl6itMKqmDvruha6ywA","rawId":"LFdoCFJTyB82ZzSJUHc-c72yraRc_1mPvGX8ToE8su39xX26Jcqd31LUkKOS36FIAWgWl6itMKqmDvruha6ywA","response":{"authenticatorData":"SZYN5YgOjGh0NBcPZHZgW4_krrmihjLHmVzzuoMdl2MBAAAAAA","signature":"MEYCIQCv7EqsBRtf2E4o_BjzZfBwNpP8fLjd5y6TUOLWt5l9DQIhANiYig9newAJZYTzG1i5lwP-YQk9uXFnnDaHnr2yCKXL","userHandle":"","clientDataJSON":"eyJjaGFsbGVuZ2UiOiJ4ZGowQ0JmWDY5MnFzQVRweTBrTmM4NTMzSmR2ZExVcHFZUDh3RFRYX1pFIiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwidHlwZSI6IndlYmF1dGhuLmdldCJ9"},"type":"public-key"}', true); $request = $request->withParsedBody($data); diff --git a/tests/TestCase/Webauthn/RegisterAdapterTest.php b/tests/TestCase/Webauthn/RegisterAdapterTest.php index 3ce86a8e8..e2fe93510 100644 --- a/tests/TestCase/Webauthn/RegisterAdapterTest.php +++ b/tests/TestCase/Webauthn/RegisterAdapterTest.php @@ -37,7 +37,7 @@ public function testGetOptions() $this->assertFalse($adapter->hasCredential()); $options = $adapter->getOptions(); $this->assertInstanceOf(PublicKeyCredentialCreationOptions::class, $options); - $this->assertSame($options, $request->getSession()->read('Webauthn2fa.registerOptions')); + $this->assertSame(json_encode($options), $request->getSession()->read('Webauthn2fa.registerOptions')); $data = '{"id":"LFdoCFJTyB82ZzSJUHc-c72yraRc_1mPvGX8ToE8su39xX26Jcqd31LUkKOS36FIAWgWl6itMKqmDvruha6ywA","rawId":"LFdoCFJTyB82ZzSJUHc-c72yraRc_1mPvGX8ToE8su39xX26Jcqd31LUkKOS36FIAWgWl6itMKqmDvruha6ywA","response":{"clientDataJSON":"eyJjaGFsbGVuZ2UiOiJOeHlab3B3VktiRmw3RW5uTWFlXzVGbmlyN1FKN1FXcDFVRlVLakZIbGZrIiwiY2xpZW50RXh0ZW5zaW9ucyI6e30sImhhc2hBbGdvcml0aG0iOiJTSEEtMjU2Iiwib3JpZ2luIjoiaHR0cDovL2xvY2FsaG9zdDozMDAwIiwidHlwZSI6IndlYmF1dGhuLmNyZWF0ZSJ9","attestationObject":"o2NmbXRoZmlkby11MmZnYXR0U3RtdKJjc2lnWEcwRQIgVzzvX3Nyp_g9j9f2B-tPWy6puW01aZHI8RXjwqfDjtQCIQDLsdniGPO9iKr7tdgVV-FnBYhvzlZLG3u28rVt10YXfGN4NWOBWQJOMIICSjCCATKgAwIBAgIEVxb3wDANBgkqhkiG9w0BAQsFADAuMSwwKgYDVQQDEyNZdWJpY28gVTJGIFJvb3QgQ0EgU2VyaWFsIDQ1NzIwMDYzMTAgFw0xNDA4MDEwMDAwMDBaGA8yMDUwMDkwNDAwMDAwMFowLDEqMCgGA1UEAwwhWXViaWNvIFUyRiBFRSBTZXJpYWwgMjUwNTY5MjI2MTc2MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEZNkcVNbZV43TsGB4TEY21UijmDqvNSfO6y3G4ytnnjP86ehjFK28-FdSGy9MSZ-Ur3BVZb4iGVsptk5NrQ3QYqM7MDkwIgYJKwYBBAGCxAoCBBUxLjMuNi4xLjQuMS40MTQ4Mi4xLjUwEwYLKwYBBAGC5RwCAQEEBAMCBSAwDQYJKoZIhvcNAQELBQADggEBAHibGMqbpNt2IOL4i4z96VEmbSoid9Xj--m2jJqg6RpqSOp1TO8L3lmEA22uf4uj_eZLUXYEw6EbLm11TUo3Ge-odpMPoODzBj9aTKC8oDFPfwWj6l1O3ZHTSma1XVyPqG4A579f3YAjfrPbgj404xJns0mqx5wkpxKlnoBKqo1rqSUmonencd4xanO_PHEfxU0iZif615Xk9E4bcANPCfz-OLfeKXiT-1msixwzz8XGvl2OTMJ_Sh9G9vhE-HjAcovcHfumcdoQh_WM445Za6Pyn9BZQV3FCqMviRR809sIATfU5lu86wu_5UGIGI7MFDEYeVGSqzpzh6mlcn8QSIZoYXV0aERhdGFYxEmWDeWIDoxodDQXD2R2YFuP5K65ooYyx5lc87qDHZdjQQAAAAAAAAAAAAAAAAAAAAAAAAAAAEAsV2gIUlPIHzZnNIlQdz5zvbKtpFz_WY-8ZfxOgTyy7f3Ffbolyp3fUtSQo5LfoUgBaBaXqK0wqqYO-u6FrrLApQECAyYgASFYIPr9-YH8DuBsOnaI3KJa0a39hyxh9LDtHErNvfQSyxQsIlgg4rAuQQ5uy4VXGFbkiAt0uwgJJodp-DymkoBcrGsLtkI"},"type":"public-key"}'; $request = $request->withParsedBody( From 9994c60b3515a120d56bd57108a9faf395979abe Mon Sep 17 00:00:00 2001 From: Alberto Rodriguez Date: Thu, 28 Dec 2023 15:06:51 -0400 Subject: [PATCH 05/22] fix: minor fix on last_login datetime format --- src/Controller/Component/LoginComponent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controller/Component/LoginComponent.php b/src/Controller/Component/LoginComponent.php index 7178ca0ce..2ac11f282 100644 --- a/src/Controller/Component/LoginComponent.php +++ b/src/Controller/Component/LoginComponent.php @@ -239,7 +239,7 @@ protected function updateLastLogin($user) $now = \Cake\I18n\FrozenTime::now(); $user->set('last_login', $now); $this->getController()->getUsersTable()->updateAll( - ['last_login' => $now], + ['last_login' => $now->format('Y-m-d H:i:s')], ['id' => $user->id] ); } From 268d522d888d0434e375be8afb9a022addbbef5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florencio=20Hern=C3=A1ndez?= <110687305+flohdez@users.noreply.github.com> Date: Fri, 29 Dec 2023 11:41:17 +0000 Subject: [PATCH 06/22] Update ci.yml with php8.2 and php8.3 --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 624eacb05..a04c36da4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - php-version: ['7.4', '8.0', '8.1'] + php-version: ['7.4', '8.0', '8.1', '8.2', '8.3'] db-type: [sqlite, mysql, pgsql] prefer-lowest: [''] @@ -117,4 +117,4 @@ jobs: - name: Run phpstan if: success() || failure() - run: composer stan \ No newline at end of file + run: composer stan From b8a78b45a56fb2723c32ab9c29a4272dceaf0a6a Mon Sep 17 00:00:00 2001 From: Alberto Rodriguez Date: Tue, 6 Feb 2024 08:43:45 -0400 Subject: [PATCH 07/22] fix: remove deprecated code on profile logic --- config/users.php | 1 + src/Controller/Traits/ProfileTrait.php | 7 ++++--- templates/Users/profile.php | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/config/users.php b/config/users.php index 679fefa10..5c31b72fa 100644 --- a/config/users.php +++ b/config/users.php @@ -84,6 +84,7 @@ 'Profile' => [ // Allow view other users profiles 'viewOthers' => true, + 'contain' => [], ], 'Key' => [ 'Session' => [ diff --git a/src/Controller/Traits/ProfileTrait.php b/src/Controller/Traits/ProfileTrait.php index a67ac991c..2a54cd9d1 100644 --- a/src/Controller/Traits/ProfileTrait.php +++ b/src/Controller/Traits/ProfileTrait.php @@ -41,10 +41,11 @@ public function profile($id = null) $id = $loggedUserId; } try { - $appContain = (array)Configure::read('Auth.authenticate.' . AuthComponent::ALL . '.contain'); - $socialContain = Configure::read('Users.Social.login') ? ['SocialAccounts'] : []; + $appContain = (array)Configure::read('Users.Profile.contain', []); $user = $this->getUsersTable()->get($id, [ - 'contain' => array_merge((array)$appContain, (array)$socialContain), + 'contain' => array_merge($appContain, [ + 'SocialAccounts', + ]), ]); $this->set('avatarPlaceholder', Configure::read('Users.Avatar.placeholder')); if ($user->id === $loggedUserId) { diff --git a/templates/Users/profile.php b/templates/Users/profile.php index bd786ffc1..aa4759fb7 100644 --- a/templates/Users/profile.php +++ b/templates/Users/profile.php @@ -23,8 +23,9 @@ ) ?> - - Html->link(__d('cake_d_c/users', 'Change Password'), ['plugin' => 'CakeDC/Users', 'controller' => 'Users', 'action' => 'changePassword']); ?> + + Html->link(__d('cake_d_c/users', 'Change Password'), ['plugin' => 'CakeDC/Users', 'controller' => 'Users', 'action' => 'changePassword']); ?> +
From ad6c651319421a4903707ab94212fcaf4e2b3f76 Mon Sep 17 00:00:00 2001 From: Alberto Rodriguez Date: Tue, 6 Feb 2024 08:47:01 -0400 Subject: [PATCH 08/22] cs fix --- src/Controller/Traits/ProfileTrait.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Controller/Traits/ProfileTrait.php b/src/Controller/Traits/ProfileTrait.php index 2a54cd9d1..5f662c57c 100644 --- a/src/Controller/Traits/ProfileTrait.php +++ b/src/Controller/Traits/ProfileTrait.php @@ -13,7 +13,6 @@ namespace CakeDC\Users\Controller\Traits; -use Cake\Controller\Component\AuthComponent; use Cake\Core\Configure; use Cake\Datasource\Exception\InvalidPrimaryKeyException; use Cake\Datasource\Exception\RecordNotFoundException; From 870b86419bc9b72e17fcde34f483996230db0893 Mon Sep 17 00:00:00 2001 From: Alberto Rodriguez Date: Tue, 6 Feb 2024 15:42:08 -0400 Subject: [PATCH 09/22] fix: config for updateLastLogin --- config/users.php | 3 +++ src/Controller/Component/LoginComponent.php | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/config/users.php b/config/users.php index 679fefa10..c70dddcea 100644 --- a/config/users.php +++ b/config/users.php @@ -47,6 +47,9 @@ // determines if registration workflow includes email validation 'validate' => true, ], + 'Login' => [ + 'updateLastLogin' => true, + ], 'Registration' => [ // determines if the register is enabled 'active' => true, diff --git a/src/Controller/Component/LoginComponent.php b/src/Controller/Component/LoginComponent.php index 2ac11f282..9e0626486 100644 --- a/src/Controller/Component/LoginComponent.php +++ b/src/Controller/Component/LoginComponent.php @@ -236,6 +236,10 @@ protected function checkSafeHost(?string $queryRedirect = null): bool */ protected function updateLastLogin($user) { + if (!Configure::read('Users.Login.updateLastLogin', true)) { + return; + } + $now = \Cake\I18n\FrozenTime::now(); $user->set('last_login', $now); $this->getController()->getUsersTable()->updateAll( From a7d7dbea44df596606933f39434015a2e685c874 Mon Sep 17 00:00:00 2001 From: Alberto Rodriguez Date: Tue, 6 Feb 2024 15:52:27 -0400 Subject: [PATCH 10/22] fix: lastLoginField on config --- config/users.php | 1 + src/Controller/Component/LoginComponent.php | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/config/users.php b/config/users.php index c70dddcea..c925911ac 100644 --- a/config/users.php +++ b/config/users.php @@ -49,6 +49,7 @@ ], 'Login' => [ 'updateLastLogin' => true, + 'lastLoginField' => 'last_login', ], 'Registration' => [ // determines if the register is enabled diff --git a/src/Controller/Component/LoginComponent.php b/src/Controller/Component/LoginComponent.php index 9e0626486..a4b956906 100644 --- a/src/Controller/Component/LoginComponent.php +++ b/src/Controller/Component/LoginComponent.php @@ -239,11 +239,11 @@ protected function updateLastLogin($user) if (!Configure::read('Users.Login.updateLastLogin', true)) { return; } - + $field = Configure::read('Users.Login.lastLoginField', 'last_login'); $now = \Cake\I18n\FrozenTime::now(); - $user->set('last_login', $now); + $user->set($field, $now); $this->getController()->getUsersTable()->updateAll( - ['last_login' => $now->format('Y-m-d H:i:s')], + [$field => $now->format('Y-m-d H:i:s')], ['id' => $user->id] ); } From ec1986412f7ee29235f44d2f96b1408036e241e7 Mon Sep 17 00:00:00 2001 From: Alberto Rodriguez Date: Tue, 6 Feb 2024 16:42:32 -0400 Subject: [PATCH 11/22] feat:flash message on login --- config/users.php | 3 +++ src/Controller/Component/LoginComponent.php | 16 ++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/config/users.php b/config/users.php index 679fefa10..3b9876b6b 100644 --- a/config/users.php +++ b/config/users.php @@ -47,6 +47,9 @@ // determines if registration workflow includes email validation 'validate' => true, ], + 'Login' => [ + 'flashMessage' => false, // bool + ], 'Registration' => [ // determines if the register is enabled 'active' => true, diff --git a/src/Controller/Component/LoginComponent.php b/src/Controller/Component/LoginComponent.php index 76794abd1..907a99865 100644 --- a/src/Controller/Component/LoginComponent.php +++ b/src/Controller/Component/LoginComponent.php @@ -76,6 +76,7 @@ public function handleLogin($errorOnlyPost, $redirectFailure) $user = $request->getAttribute('identity')->getOriginalData(); $this->handlePasswordRehash($service, $user, $request); $this->updateLastLogin($user); + $this->addFlashMessage($user); return $this->afterIdentifyUser($user); } @@ -242,4 +243,19 @@ protected function updateLastLogin($user) ['id' => $user->id] ); } + + /** + * Add a flash message informing user is logged in + * + * @param array $user user data + * @return void + */ + protected function addFlashMessage($user) + { + if (!Configure::read('Users.Login.flashMessage')) { + return; + } + + $this->getController()->Flash->success(__d('cake_d_c/users', 'Welcome, {0}', $user->username)); + } } From 6db34ad293de5220c063cdbfc62fac29f99d7f2f Mon Sep 17 00:00:00 2001 From: Alberto Rodriguez Date: Tue, 6 Feb 2024 16:51:58 -0400 Subject: [PATCH 12/22] minor fix --- src/Controller/Component/LoginComponent.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Controller/Component/LoginComponent.php b/src/Controller/Component/LoginComponent.php index 907a99865..5219ae0ff 100644 --- a/src/Controller/Component/LoginComponent.php +++ b/src/Controller/Component/LoginComponent.php @@ -256,6 +256,6 @@ protected function addFlashMessage($user) return; } - $this->getController()->Flash->success(__d('cake_d_c/users', 'Welcome, {0}', $user->username)); + $this->getController()->Flash->success(__d('cake_d_c/users', 'Welcome, {0}', $user['username'])); } } From 4bb06bb31bdd5da5b2080cfac7fac9d4a4f935fc Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Fri, 9 Feb 2024 01:50:32 +0300 Subject: [PATCH 13/22] extract two factor logic into separate classes processing each type of 2fa. --- composer.json | 2 +- src/Loader/AuthenticationServiceLoader.php | 19 ++++++------------- src/Loader/MiddlewareQueueLoader.php | 14 +++----------- .../Integration/LoginTraitIntegrationTest.php | 5 +++++ tests/TestCase/PluginTest.php | 19 +++++++++++++++++++ .../AuthenticationServiceProviderTest.php | 4 ++++ tests/test_app/config/users.php | 5 +++++ 7 files changed, 43 insertions(+), 25 deletions(-) diff --git a/composer.json b/composer.json index d7a8d914f..3481f0386 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "require": { "php": ">=7.4.0", "cakephp/cakephp": "^4.5", - "cakedc/auth": "^7.0", + "cakedc/auth": "^7.3", "cakephp/authorization": "^2.0.0", "cakephp/authentication": "^2.0.0" }, diff --git a/src/Loader/AuthenticationServiceLoader.php b/src/Loader/AuthenticationServiceLoader.php index de1b01b33..e2186ea9f 100644 --- a/src/Loader/AuthenticationServiceLoader.php +++ b/src/Loader/AuthenticationServiceLoader.php @@ -15,7 +15,7 @@ use Cake\Core\Configure; use CakeDC\Auth\Authentication\AuthenticationService; -use CakeDC\Users\Plugin; +use CakeDC\Auth\Authentication\TwoFactorProcessorLoader; use Psr\Http\Message\ServerRequestInterface; /** @@ -34,10 +34,11 @@ class AuthenticationServiceLoader */ public function __invoke(ServerRequestInterface $request) { - $service = new AuthenticationService(); + $processors = TwoFactorProcessorLoader::processors(); + $service = new AuthenticationService(['processors' => $processors]); $this->loadIdentifiers($service); $this->loadAuthenticators($service); - $this->loadTwoFactorAuthenticator($service); + $this->loadTwoFactorAuthenticator($service, $processors); return $service; } @@ -81,17 +82,9 @@ protected function loadAuthenticators($service) * @param \CakeDC\Auth\Authentication\AuthenticationService $service Authentication service to load identifiers * @return void */ - protected function loadTwoFactorAuthenticator($service) + protected function loadTwoFactorAuthenticator($service, $processors) { - $u2fEnabled = Configure::read('U2f.enabled') !== false; - if ($u2fEnabled) { - trigger_error(Plugin::DEPRECATED_MESSAGE_U2F, E_USER_DEPRECATED); - } - if ( - Configure::read('OneTimePasswordAuthenticator.login') !== false - || Configure::read('Webauthn2fa.enabled') !== false - || $u2fEnabled - ) { + if (collection($processors)->some(fn ($processor) => $processor->enabled())) { $service->loadAuthenticator('CakeDC/Auth.TwoFactor', [ 'skipTwoFactorVerify' => true, ]); diff --git a/src/Loader/MiddlewareQueueLoader.php b/src/Loader/MiddlewareQueueLoader.php index bed495ff0..88babe4e9 100644 --- a/src/Loader/MiddlewareQueueLoader.php +++ b/src/Loader/MiddlewareQueueLoader.php @@ -20,10 +20,10 @@ use Authorization\Middleware\RequestAuthorizationMiddleware; use Cake\Core\Configure; use Cake\Http\MiddlewareQueue; +use CakeDC\Auth\Authentication\TwoFactorProcessorLoader; use CakeDC\Auth\Middleware\TwoFactorMiddleware; use CakeDC\Users\Middleware\SocialAuthMiddleware; use CakeDC\Users\Middleware\SocialEmailMiddleware; -use CakeDC\Users\Plugin; /** * Class MiddlewareQueueLoader @@ -96,16 +96,8 @@ protected function loadAuthenticationMiddleware( */ protected function load2faMiddleware(MiddlewareQueue $middlewareQueue) { - $u2fEnabled = Configure::read('U2f.enabled') !== false; - if ($u2fEnabled) { - trigger_error(Plugin::DEPRECATED_MESSAGE_U2F, E_USER_DEPRECATED); - } - - if ( - Configure::read('OneTimePasswordAuthenticator.login') !== false - || Configure::read('Webauthn2fa.enabled') !== false - || $u2fEnabled - ) { + $processors = TwoFactorProcessorLoader::processors(); + if (collection($processors)->some(fn ($processor) => $processor->enabled())) { $middlewareQueue->add(TwoFactorMiddleware::class); } } diff --git a/tests/TestCase/Controller/Traits/Integration/LoginTraitIntegrationTest.php b/tests/TestCase/Controller/Traits/Integration/LoginTraitIntegrationTest.php index 810e92964..da539de1a 100644 --- a/tests/TestCase/Controller/Traits/Integration/LoginTraitIntegrationTest.php +++ b/tests/TestCase/Controller/Traits/Integration/LoginTraitIntegrationTest.php @@ -221,6 +221,11 @@ public function testLoginPostRequestRightPasswordIsEnabledU2f() { EventManager::instance()->on('TestApp.afterPluginBootstrap', function () { Configure::write(['U2f.enabled' => true]); + Configure::write([ + 'TwoFactorProcessors' => [ + \CakeDC\Auth\Authentication\TwoFactorProcessor\U2FProcessor::class, + ], + ]); }); $this->enableRetainFlashMessages(); $this->post('/login', [ diff --git a/tests/TestCase/PluginTest.php b/tests/TestCase/PluginTest.php index d4fedf44f..73cf259a9 100644 --- a/tests/TestCase/PluginTest.php +++ b/tests/TestCase/PluginTest.php @@ -41,6 +41,9 @@ public function testMiddleware() { Configure::write('Users.Social.login', true); Configure::write('OneTimePasswordAuthenticator.login', true); + Configure::write('TwoFactorProcessors', [ + \CakeDC\Auth\Authentication\TwoFactorProcessor\OneTimePasswordProcessor::class, + ]); Configure::write('Auth.Authorization.enable', true); $plugin = new Plugin(); @@ -75,6 +78,9 @@ public function testMiddlewareAuthorizationMiddlewareAndRbacMiddleware() Configure::write('Users.Social.login', true); Configure::write('OneTimePasswordAuthenticator.login', true); Configure::write('Auth.Authorization.enable', true); + Configure::write('TwoFactorProcessors', [ + \CakeDC\Auth\Authentication\TwoFactorProcessor\OneTimePasswordProcessor::class, + ]); $plugin = new Plugin(); @@ -106,6 +112,9 @@ public function testMiddlewareWithoutAuhorization() Configure::write('Users.Social.login', true); Configure::write('OneTimePasswordAuthenticator.login', true); Configure::write('Auth.Authorization.enable', false); + Configure::write('TwoFactorProcessors', [ + \CakeDC\Auth\Authentication\TwoFactorProcessor\OneTimePasswordProcessor::class, + ]); $plugin = new Plugin(); @@ -133,6 +142,10 @@ public function testMiddlewareNotSocial() Configure::write('Users.Social.login', false); Configure::write('OneTimePasswordAuthenticator.login', true); Configure::write('Auth.Authorization.enable', true); + Configure::write('TwoFactorProcessors', [ + \CakeDC\Auth\Authentication\TwoFactorProcessor\OneTimePasswordProcessor::class, + ]); + $plugin = new Plugin(); $middleware = new MiddlewareQueue(); @@ -158,6 +171,9 @@ public function testMiddlewareNotOneTimePasswordAuthenticator() Configure::write('Users.Social.login', true); Configure::write('OneTimePasswordAuthenticator.login', false); Configure::write('Auth.Authorization.enable', true); + Configure::write('TwoFactorProcessors', [ + \CakeDC\Auth\Authentication\TwoFactorProcessor\OneTimePasswordProcessor::class, + ]); $plugin = new Plugin(); $middleware = new MiddlewareQueue(); @@ -185,6 +201,9 @@ public function testMiddlewareNotGoogleAuthenticationAndNotSocial() Configure::write('Users.Social.login', false); Configure::write('OneTimePasswordAuthenticator.login', false); Configure::write('Auth.Authorization.enable', true); + Configure::write('TwoFactorProcessors', [ + \CakeDC\Auth\Authentication\TwoFactorProcessor\OneTimePasswordProcessor::class, + ]); $plugin = new Plugin(); $middleware = new MiddlewareQueue(); diff --git a/tests/TestCase/Provider/AuthenticationServiceProviderTest.php b/tests/TestCase/Provider/AuthenticationServiceProviderTest.php index a3ed282bf..620f229d1 100644 --- a/tests/TestCase/Provider/AuthenticationServiceProviderTest.php +++ b/tests/TestCase/Provider/AuthenticationServiceProviderTest.php @@ -78,6 +78,9 @@ public function testGetAuthenticationService() 'Authentication.JwtSubject', ]); Configure::write('OneTimePasswordAuthenticator.login', true); + Configure::write('TwoFactorProcessors', [ + \CakeDC\Auth\Authentication\TwoFactorProcessor\OneTimePasswordProcessor::class, + ]); $authenticationServiceProvider = new AuthenticationServiceProvider(); $service = $authenticationServiceProvider->getAuthenticationService(new ServerRequest(), new Response()); @@ -215,6 +218,7 @@ public function testGetAuthenticationServiceWithoutOneTimePasswordAuthenticator( 'Authentication.JwtSubject', ]); Configure::write('OneTimePasswordAuthenticator.login', false); + Configure::write('TwoFactorProcessors', []); $authenticationServiceProvider = new AuthenticationServiceProvider(); $service = $authenticationServiceProvider->getAuthenticationService(new ServerRequest(), new Response()); diff --git a/tests/test_app/config/users.php b/tests/test_app/config/users.php index 35e35adcd..3c5850970 100644 --- a/tests/test_app/config/users.php +++ b/tests/test_app/config/users.php @@ -9,4 +9,9 @@ 'OAuth.providers.twitter.options.clientSecret' => '999988899', 'OAuth.providers.google.options.clientId' => '0000000990909090', 'OAuth.providers.google.options.clientSecret' => '1565464559789798', + 'TwoFactorProcessors' => [ + \CakeDC\Auth\Authentication\TwoFactorProcessor\OneTimePasswordProcessor::class, + \CakeDC\Auth\Authentication\TwoFactorProcessor\U2FProcessor::class, + \CakeDC\Auth\Authentication\TwoFactorProcessor\Webauthn2faProcessor::class, + ], ]; From 25ffb4a81c071deb681e4ff6ccdaae9122696126 Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Fri, 9 Feb 2024 20:19:43 +0300 Subject: [PATCH 14/22] update changelogs. Release 13.0.0 --- CHANGELOG.md | 3 +++ composer.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd67206d1..5fb54c669 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ Changelog ========= Releases for CakePHP 4.5 ------------------------ +* 13.0.0 + * Set dependecy for CakeDC/Auth to 9.0. Perform 2FA refactoring, + * 11.3.4 * Fix `Detected invalid UTF-8 for field...` issue when storing session data from `Webauthn` in a mongo database. diff --git a/composer.json b/composer.json index 3481f0386..5b72ac240 100644 --- a/composer.json +++ b/composer.json @@ -31,7 +31,7 @@ "require": { "php": ">=7.4.0", "cakephp/cakephp": "^4.5", - "cakedc/auth": "^7.3", + "cakedc/auth": "^9.0", "cakephp/authorization": "^2.0.0", "cakephp/authentication": "^2.0.0" }, From 80905edc3793536c106ae5724277c90597d6a6e9 Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Fri, 9 Feb 2024 20:24:19 +0300 Subject: [PATCH 15/22] code style fixes --- src/Loader/AuthenticationServiceLoader.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Loader/AuthenticationServiceLoader.php b/src/Loader/AuthenticationServiceLoader.php index e2186ea9f..f92388c1e 100644 --- a/src/Loader/AuthenticationServiceLoader.php +++ b/src/Loader/AuthenticationServiceLoader.php @@ -16,6 +16,7 @@ use Cake\Core\Configure; use CakeDC\Auth\Authentication\AuthenticationService; use CakeDC\Auth\Authentication\TwoFactorProcessorLoader; +use CakeDC\Auth\Authentication\TwoFactorProcessorCollection; use Psr\Http\Message\ServerRequestInterface; /** @@ -80,6 +81,7 @@ protected function loadAuthenticators($service) * Load the CakeDC/Auth.TwoFactor based on config OneTimePasswordAuthenticator.login * * @param \CakeDC\Auth\Authentication\AuthenticationService $service Authentication service to load identifiers + * @param \CakeDC\Auth\Authentication\TwoFactorProcessorCollection $processors TwoFactorProcessors collection * @return void */ protected function loadTwoFactorAuthenticator($service, $processors) From e9acd218593ad818ba67c4cd9da391961ddeb17f Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Fri, 9 Feb 2024 20:28:30 +0300 Subject: [PATCH 16/22] code style fixes --- src/Loader/AuthenticationServiceLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Loader/AuthenticationServiceLoader.php b/src/Loader/AuthenticationServiceLoader.php index f92388c1e..e6f7c75d1 100644 --- a/src/Loader/AuthenticationServiceLoader.php +++ b/src/Loader/AuthenticationServiceLoader.php @@ -15,8 +15,8 @@ use Cake\Core\Configure; use CakeDC\Auth\Authentication\AuthenticationService; -use CakeDC\Auth\Authentication\TwoFactorProcessorLoader; use CakeDC\Auth\Authentication\TwoFactorProcessorCollection; +use CakeDC\Auth\Authentication\TwoFactorProcessorLoader; use Psr\Http\Message\ServerRequestInterface; /** From d10f9806a0f6b3f27347064c29749ea6413c3d9a Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Fri, 9 Feb 2024 20:33:02 +0300 Subject: [PATCH 17/22] code style fixes --- src/Loader/AuthenticationServiceLoader.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Loader/AuthenticationServiceLoader.php b/src/Loader/AuthenticationServiceLoader.php index e6f7c75d1..6c0c454d5 100644 --- a/src/Loader/AuthenticationServiceLoader.php +++ b/src/Loader/AuthenticationServiceLoader.php @@ -15,7 +15,6 @@ use Cake\Core\Configure; use CakeDC\Auth\Authentication\AuthenticationService; -use CakeDC\Auth\Authentication\TwoFactorProcessorCollection; use CakeDC\Auth\Authentication\TwoFactorProcessorLoader; use Psr\Http\Message\ServerRequestInterface; From fbb406a466c6ca5b48a668f2980a36b5694da56b Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Fri, 9 Feb 2024 21:02:17 +0300 Subject: [PATCH 18/22] prepare release 14.0.0 --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72a551546..aaba31a71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ Changelog ========= Releases for CakePHP 5 ------------- +* 14.0 + * Set dependecy for CakeDC/Auth to 10.0. Perform 2FA refactoring, + * 12.0 * Migrated to web-auth/webauthn-lib:^4.4 * Migrated to robthree/twofactorauth:^2.0 From 6d602d56c792614fd254ec8a045964362a706450 Mon Sep 17 00:00:00 2001 From: Evgeny Tomenko Date: Tue, 12 Mar 2024 00:56:23 +0300 Subject: [PATCH 19/22] Update CHANGELOG.md --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cd67206d1..b2640dfc1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ Changelog ========= Releases for CakePHP 4.5 ------------------------ +* 11.3.5 + * Update ci.yml with php8.2 and php8.3 + * fix: minor fix on last_login datetime format + * Update Permissions.md + * fix: config for updateLastLogin + * fix: remove deprecated code on profile logic + * 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. From 36a3bec867ce28dd8c5e1a52658dc63cfca1093c Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Tue, 12 Mar 2024 01:01:32 +0300 Subject: [PATCH 20/22] load default 2fa authenticators --- config/users.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/users.php b/config/users.php index 17bcb28d9..0dc308026 100644 --- a/config/users.php +++ b/config/users.php @@ -154,6 +154,10 @@ 'id' => null,//default value is the current domain 'checker' => \CakeDC\Auth\Authentication\DefaultWebauthn2fAuthenticationChecker::class, ], + 'TwoFactorProcessors' => [ + \CakeDC\Auth\Authentication\TwoFactorProcessor\Webauthn2faProcessor::class, + \CakeDC\Auth\Authentication\TwoFactorProcessor\OneTimePasswordProcessor::class, + ], // default configuration used to auto-load the Auth Component, override to change the way Auth works 'Auth' => [ 'Authentication' => [ From e93a09ec88c0213288fc60aa17fc1ada80faa89c Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Tue, 12 Mar 2024 02:56:30 +0300 Subject: [PATCH 21/22] authentication and behavior tests --- .../Model/Behavior/RegisterBehaviorTest.php | 1 - .../Provider/AuthenticationServiceProviderTest.php | 13 +++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/TestCase/Model/Behavior/RegisterBehaviorTest.php b/tests/TestCase/Model/Behavior/RegisterBehaviorTest.php index 7609e376c..d3e43e0db 100644 --- a/tests/TestCase/Model/Behavior/RegisterBehaviorTest.php +++ b/tests/TestCase/Model/Behavior/RegisterBehaviorTest.php @@ -53,7 +53,6 @@ public function setUp(): void { parent::setUp(); $table = TableRegistry::getTableLocator()->get('CakeDC/Users.Users'); - $table->addBehavior('CakeDC/Users/Register.Register'); $this->Table = $table; $this->Behavior = $table->behaviors()->Register; TransportFactory::setConfig('test', ['className' => 'Debug']); diff --git a/tests/TestCase/Provider/AuthenticationServiceProviderTest.php b/tests/TestCase/Provider/AuthenticationServiceProviderTest.php index c13338b6f..5c8898ec2 100644 --- a/tests/TestCase/Provider/AuthenticationServiceProviderTest.php +++ b/tests/TestCase/Provider/AuthenticationServiceProviderTest.php @@ -98,22 +98,26 @@ public function testGetAuthenticationService() 'identityAttribute' => 'identity', 'skipTwoFactorVerify' => true, 'impersonateSessionKey' => 'AuthImpersonate', + 'className' => 'Authentication.Session', ], FormAuthenticator::class => [ 'loginUrl' => '/login', 'keyCheckEnabledRecaptcha' => 'Users.reCaptcha.login', 'fields' => ['username' => 'email', 'password' => 'alt_password'], + 'className' => 'CakeDC/Auth.Form', ], TokenAuthenticator::class => [ 'header' => null, 'queryParam' => 'api_key', 'tokenPrefix' => null, 'skipTwoFactorVerify' => true, + 'className' => 'Authentication.Token', ], TwoFactorAuthenticator::class => [ 'loginUrl' => null, 'urlChecker' => 'Authentication.Default', 'skipTwoFactorVerify' => true, + 'className' => 'CakeDC/Auth.TwoFactor', ], ]; $actual = []; @@ -135,17 +139,20 @@ public function testGetAuthenticationService() ], 'resolver' => 'Authentication.Orm', 'passwordHasher' => null, + 'className' => 'Authentication.Password', ], TokenIdentifier::class => [ 'tokenField' => 'api_token', 'dataField' => 'token', 'resolver' => 'Authentication.Orm', 'hashAlgorithm' => null, + 'className' => 'Authentication.Token', ], JwtSubjectIdentifier::class => [ 'tokenField' => 'id', 'dataField' => 'sub', 'resolver' => 'Authentication.Orm', + 'className' => 'Authentication.JwtSubject', ], ]; $actual = []; @@ -196,11 +203,13 @@ public function testGetAuthenticationServiceWithoutOneTimePasswordAuthenticator( 'fields' => ['username' => 'email'], 'identify' => true, 'impersonateSessionKey' => 'AuthImpersonate', + 'className' => 'Authentication.Session', ], 'Form' => [ 'className' => 'CakeDC/Auth.Form', 'loginUrl' => '/login', 'fields' => ['username' => 'email', 'password' => 'alt_password'], + 'className' => 'CakeDC/Auth.Form', ], 'Token' => [ 'className' => 'Authentication.Token', @@ -208,6 +217,7 @@ public function testGetAuthenticationServiceWithoutOneTimePasswordAuthenticator( 'header' => null, 'queryParam' => 'api_key', 'tokenPrefix' => null, + 'className' => 'Authentication.Token', ], ]); Configure::write('Auth.Identifiers', [ @@ -237,17 +247,20 @@ public function testGetAuthenticationServiceWithoutOneTimePasswordAuthenticator( 'identityAttribute' => 'identity', 'skipTwoFactorVerify' => true, 'impersonateSessionKey' => 'AuthImpersonate', + 'className' => 'Authentication.Session' ], FormAuthenticator::class => [ 'loginUrl' => '/login', 'fields' => ['username' => 'email', 'password' => 'alt_password'], 'keyCheckEnabledRecaptcha' => 'Users.reCaptcha.login', + 'className' => 'CakeDC/Auth.Form', ], TokenAuthenticator::class => [ 'header' => null, 'queryParam' => 'api_key', 'tokenPrefix' => null, 'skipTwoFactorVerify' => true, + 'className' => 'Authentication.Token', ], ]; $actual = []; From 637258813e8740c6f0cdb34699b67b25e587b237 Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Tue, 12 Mar 2024 02:58:02 +0300 Subject: [PATCH 22/22] cs chore --- tests/TestCase/Provider/AuthenticationServiceProviderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/TestCase/Provider/AuthenticationServiceProviderTest.php b/tests/TestCase/Provider/AuthenticationServiceProviderTest.php index 5c8898ec2..218f7ffbe 100644 --- a/tests/TestCase/Provider/AuthenticationServiceProviderTest.php +++ b/tests/TestCase/Provider/AuthenticationServiceProviderTest.php @@ -247,7 +247,7 @@ public function testGetAuthenticationServiceWithoutOneTimePasswordAuthenticator( 'identityAttribute' => 'identity', 'skipTwoFactorVerify' => true, 'impersonateSessionKey' => 'AuthImpersonate', - 'className' => 'Authentication.Session' + 'className' => 'Authentication.Session', ], FormAuthenticator::class => [ 'loginUrl' => '/login',