From 4bb06bb31bdd5da5b2080cfac7fac9d4a4f935fc Mon Sep 17 00:00:00 2001 From: Yevgeny Tomenko Date: Fri, 9 Feb 2024 01:50:32 +0300 Subject: [PATCH] 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, + ], ];