diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 5bd7119d..79146eb5 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -7,7 +7,14 @@ parameters: path: src/Controller/Component/LoginComponent.php - - message: "#^Call to an undefined method Cake\\\\Controller\\\\Controller\\:\\:getUsersTable\\(\\)\\.$#" + message: '#^Call to an undefined method Cake\\Controller\\Controller\:\:getUsersTable\(\)\.$#' + identifier: method.notFound + count: 1 + path: src/Controller/Component/LoginComponent.php + + - + message: '#^Call to function method_exists\(\) with Authentication\\Authenticator\\AuthenticatorInterface and ''getIdentifier'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType count: 1 path: src/Controller/Component/LoginComponent.php @@ -54,7 +61,8 @@ parameters: path: src/Model/Behavior/LinkSocialBehavior.php - - message: "#^Access to an undefined property Cake\\\\Datasource\\\\EntityInterface\\:\\:\\$activation_date\\.$#" + message: '#^Access to an undefined property Cake\\Datasource\\EntityInterface\:\:\$activation_date\.$#' + identifier: property.notFound count: 1 path: src/Model/Behavior/RegisterBehavior.php diff --git a/src/Controller/Component/LoginComponent.php b/src/Controller/Component/LoginComponent.php index 69b26eae..1b502814 100644 --- a/src/Controller/Component/LoginComponent.php +++ b/src/Controller/Component/LoginComponent.php @@ -205,17 +205,20 @@ protected function handlePasswordRehash($service, $user, \Cake\Http\ServerReques // new way to define identifiers, inside the authenticators $authenticatorNames = (array)Configure::read('Auth.PasswordRehash.authenticators'); + if ($authenticatorNames === []) { + return; + } + + $authenticationProvider = $service->getAuthenticationProvider(); + if (!$authenticationProvider || !method_exists($authenticationProvider, 'getIdentifier')) { + return; + } + + /** @var \Authentication\Identifier\IdentifierCollection $identifierCollection */ + $identifierCollection = $authenticationProvider->getIdentifier(); foreach ($authenticatorNames as $authenticatorName => $identifierName) { - if (!$service->authenticators()->has($authenticatorName)) { - Log::warning("Error saving user id $user->id password after rehashing: authenticator $authenticatorName not found. Check your Auth.PasswordRehash.authenticators configuration."); - continue; - } - /** - * @var \Authentication\Identifier\IdentifierCollection $identifierCollection - */ - $identifierCollection = $service->authenticators()->get($authenticatorName)->getIdentifier(); if (!$identifierCollection->has($identifierName)) { - Log::warning("Error saving user id $user->id password after rehashing: identifier $identifierName not found. Check your Auth.PasswordRehash.authenticators configuration."); + Log::warning("Error saving user id $user->id password after rehashing: identifier $identifierName not found for authenticator $authenticatorName. Check your Auth.PasswordRehash.authenticators configuration."); continue; } diff --git a/src/Controller/Traits/LinkSocialTrait.php b/src/Controller/Traits/LinkSocialTrait.php index e3bfcdf6..d9a64093 100644 --- a/src/Controller/Traits/LinkSocialTrait.php +++ b/src/Controller/Traits/LinkSocialTrait.php @@ -72,7 +72,9 @@ public function callbackLinkSocial($alias = null) $userId = $identity['id'] ?? null; $user = $this->getUsersTable()->get($userId); - $this->getUsersTable()->linkSocialAccount($user, $data); + /** @var \CakeDC\Users\Model\Behavior\LinkSocialBehavior $linkSocial */ + $linkSocial = $this->getUsersTable()->getBehavior('LinkSocial'); + $linkSocial->linkSocialAccount($user, $data); if ($user->getErrors()) { $this->Flash->error($message); diff --git a/src/Model/Behavior/OneTimeLoginLinkBehavior.php b/src/Model/Behavior/OneTimeLoginLinkBehavior.php index 668e9a35..d56f9e9f 100644 --- a/src/Model/Behavior/OneTimeLoginLinkBehavior.php +++ b/src/Model/Behavior/OneTimeLoginLinkBehavior.php @@ -25,7 +25,7 @@ class OneTimeLoginLinkBehavior extends Behavior public function sendLoginLink(string $name): void { $table = $this->table(); - $user = $table->find('byUsernameOrEmail', ['username' => $name])->first(); + $user = $table->find('byUsernameOrEmail', username: $name)->first(); if ($user === null) { throw new RecordNotFoundException(__('Username not found.')); } @@ -65,7 +65,7 @@ public function loginWithToken(string $token): ?EntityInterface { $lifeTime = Configure::read('Auth.OneTimeLogin.tokenLifeTime', 600); $user = $this->table() - ->find('byOneTimeToken', ['token' => $token]) + ->find('byOneTimeToken', token: $token) ->first(); if ($user && ($user->login_token_date >= DateTime::now()->subSeconds($lifeTime))) { @@ -89,7 +89,7 @@ public function loginWithToken(string $token): ?EntityInterface */ public function requestTokenSend(string $username): void { - $user = $this->table()->find('byUsernameOrEmail', ['username' => $username])->first(); + $user = $this->table()->find('byUsernameOrEmail', username: $username)->first(); if ($user) { $this->table()->updateAll([ 'token_send_requested' => true, @@ -103,12 +103,11 @@ public function requestTokenSend(string $username): void * Find by username or email. * * @param \Cake\ORM\Query $query The query builder. - * @param array $options Options. + * @param string|null $username Username or email. * @return \Cake\ORM\Query */ - public function findByUsernameOrEmail(Query $query, array $options = []): Query + public function findByUsernameOrEmail(Query $query, ?string $username = null): Query { - $username = $options['username'] ?? null; if (empty($username)) { throw new OutOfBoundsException('Missing username'); } @@ -125,12 +124,11 @@ public function findByUsernameOrEmail(Query $query, array $options = []): Query * Find by token * * @param \Cake\ORM\Query $query - * @param array $options + * @param string|null $token * @return \Cake\ORM\Query */ - public function findByOneTimeToken(Query $query, array $options = []): Query + public function findByOneTimeToken(Query $query, ?string $token = null): Query { - $token = $options['token'] ?? null; if (empty($token)) { throw new OutOfBoundsException('Missing token'); } diff --git a/tests/TestCase/Controller/Traits/BaseTrait.php b/tests/TestCase/Controller/Traits/BaseTrait.php index 76bba3f8..4c8cf6ce 100644 --- a/tests/TestCase/Controller/Traits/BaseTrait.php +++ b/tests/TestCase/Controller/Traits/BaseTrait.php @@ -16,7 +16,6 @@ use Authentication\Authenticator\Result; use Authentication\Controller\Component\AuthenticationComponent; use Authentication\Identifier\IdentifierCollection; -use Authentication\Identifier\PasswordIdentifier; use Authentication\Identity; use Cake\Controller\ComponentRegistry; use Cake\Controller\Controller; @@ -239,14 +238,7 @@ protected function _mockAuthLoggedIn($user = []) protected function _mockAuthentication($user = null, $failures = [], $identifiers = null) { if ($identifiers === null) { - $passwordIdentifier = $this->getMockBuilder(PasswordIdentifier::class) - ->onlyMethods(['needsPasswordRehash']) - ->getMock(); - $passwordIdentifier->expects($this->any()) - ->method('needsPasswordRehash') - ->willReturn(false); $identifiers = new IdentifierCollection([]); - $identifiers->set('Password', $passwordIdentifier); } $config = [ diff --git a/tests/TestCase/Controller/Traits/LinkSocialTraitTest.php b/tests/TestCase/Controller/Traits/LinkSocialTraitTest.php index 278e70d1..853bd794 100644 --- a/tests/TestCase/Controller/Traits/LinkSocialTraitTest.php +++ b/tests/TestCase/Controller/Traits/LinkSocialTraitTest.php @@ -58,7 +58,7 @@ public function setUp(): void parent::setUp(); $request = new ServerRequest(); $this->Trait = $this->getMockBuilder('CakeDC\Users\Controller\UsersController') - ->onlyMethods(['dispatchEvent', 'redirect', 'set']) + ->onlyMethods(['dispatchEvent', 'redirect', 'set', 'getUsersTable']) ->setConstructorArgs([new ServerRequest()]) ->getMock(); @@ -142,11 +142,11 @@ public function testLinkSocialHappy() $this->Provider->expects($this->any()) ->method('getState') - ->will($this->returnValue('_NEW_STATE_')); + ->willReturn('_NEW_STATE_'); $this->Provider->expects($this->any()) ->method('getAuthorizationUrl') - ->will($this->returnValue('http://facebook.com/redirect/url')); + ->willReturn('http://facebook.com/redirect/url'); $this->Trait->Flash->expects($this->never()) ->method('error'); @@ -157,7 +157,7 @@ public function testLinkSocialHappy() $this->Trait->expects($this->once()) ->method('redirect') ->with($this->equalTo('http://facebook.com/redirect/url')) - ->will($this->returnValue(new Response())); + ->willReturn(new Response()); $this->Trait->linkSocial('facebook'); } @@ -226,14 +226,14 @@ public function testCallbackLinkSocialHappy() $this->equalTo('authorization_code'), $this->equalTo(['code' => 'ZPO9972j3092304230']), ) - ->will($this->returnValue($Token)); + ->willReturn($Token); $this->Provider->expects($this->any()) ->method('getResourceOwner') ->with( $this->equalTo($Token), ) - ->will($this->returnValue($user)); + ->willReturn($user); $this->Trait = $this->getMockBuilder('CakeDC\Users\Controller\UsersController') ->onlyMethods(['dispatchEvent', 'redirect', 'set', 'getUsersTable', 'log']) @@ -258,7 +258,7 @@ public function testCallbackLinkSocialHappy() $this->Trait->expects($this->any()) ->method('getUsersTable') - ->will($this->returnValue($Table)); + ->willReturn($Table); $this->_mockAuthLoggedIn(); $this->_mockDispatchEvent(new Event('event')); @@ -311,19 +311,26 @@ public function testCallbackLinkSocialWithValidationErrors() ]); $Table = $this->getMockBuilder(\CakeDC\Users\Model\Table\UsersTable::class) ->setConstructorArgs([['alias' => 'Users', 'connection' => \Cake\Datasource\ConnectionManager::get('test')]]) - ->onlyMethods(['newEntity', 'get']) - ->addMethods(['linkSocialAccount']) + ->onlyMethods(['newEntity', 'get', 'getBehavior']) + ->getMock(); + $behavior = $this->getMockBuilder(\CakeDC\Users\Model\Behavior\LinkSocialBehavior::class) + ->disableOriginalConstructor() + ->onlyMethods(['linkSocialAccount']) ->getMock(); $Table->setAlias('Users'); $Table->expects($this->once()) ->method('get') - ->will($this->returnValue($user)); + ->willReturn($user); $Table->expects($this->once()) + ->method('getBehavior') + ->with('LinkSocial') + ->willReturn($behavior); + $behavior->expects($this->once()) ->method('linkSocialAccount') - ->will($this->returnValue($user)); + ->willReturn($user); $Token = new \League\OAuth2\Client\Token\AccessToken([ 'access_token' => 'test-token', @@ -377,14 +384,14 @@ public function testCallbackLinkSocialWithValidationErrors() $this->equalTo('authorization_code'), $this->equalTo(['code' => 'ZPO9972j3092304230']), ) - ->will($this->returnValue($Token)); + ->willReturn($Token); $this->Provider->expects($this->any()) ->method('getResourceOwner') ->with( $this->equalTo($Token), ) - ->will($this->returnValue($user)); + ->willReturn($user); $this->Trait = $this->getMockBuilder('CakeDC\Users\Controller\UsersController') ->onlyMethods(['dispatchEvent', 'redirect', 'set', 'getUsersTable', 'log']) @@ -393,7 +400,7 @@ public function testCallbackLinkSocialWithValidationErrors() $this->Trait->expects($this->any()) ->method('getUsersTable') - ->will($this->returnValue($Table)); + ->willReturn($Table); $this->Trait->setRequest(ServerRequestFactory::fromGlobals()); $this->Trait->getRequest()->getSession()->write('oauth2state', '__TEST_STATE__'); diff --git a/tests/TestCase/Controller/Traits/ReCaptchaTraitTest.php b/tests/TestCase/Controller/Traits/ReCaptchaTraitTest.php index c8bc12fc..0fbe1ba6 100644 --- a/tests/TestCase/Controller/Traits/ReCaptchaTraitTest.php +++ b/tests/TestCase/Controller/Traits/ReCaptchaTraitTest.php @@ -110,7 +110,6 @@ public function testGetRecaptchaInstance() Configure::write('Users.reCaptcha.secret', 'secret'); $trait = $this->getMockBuilder('CakeDC\Users\Controller\Traits\ReCaptchaTrait')->getMockForTrait(); $method = new ReflectionMethod(get_class($trait), '_getReCaptchaInstance'); - $method->setAccessible(true); $method->invokeArgs($trait, []); $this->assertNotEmpty($method->invoke($trait)); } @@ -119,7 +118,6 @@ public function testGetRecaptchaInstanceNull() { $trait = $this->getMockBuilder('CakeDC\Users\Controller\Traits\ReCaptchaTrait')->getMockForTrait(); $method = new ReflectionMethod(get_class($trait), '_getReCaptchaInstance'); - $method->setAccessible(true); $method->invokeArgs($trait, []); $this->assertNull($method->invoke($trait)); } diff --git a/tests/TestCase/Mailer/UsersMailerTest.php b/tests/TestCase/Mailer/UsersMailerTest.php index 6bd80ece..dfe8cb7d 100644 --- a/tests/TestCase/Mailer/UsersMailerTest.php +++ b/tests/TestCase/Mailer/UsersMailerTest.php @@ -176,7 +176,6 @@ public function invokeMethod(&$object, $methodName, $parameters = []) { $reflection = new \ReflectionClass(get_class($object)); $method = $reflection->getMethod($methodName); - $method->setAccessible(true); return $method->invokeArgs($object, $parameters); } diff --git a/tests/TestCase/Model/Behavior/LinkSocialBehaviorTest.php b/tests/TestCase/Model/Behavior/LinkSocialBehaviorTest.php index 7a709099..d165c14f 100644 --- a/tests/TestCase/Model/Behavior/LinkSocialBehaviorTest.php +++ b/tests/TestCase/Model/Behavior/LinkSocialBehaviorTest.php @@ -304,7 +304,7 @@ public static function providerFacebookLinkSocialAccountAccountExists() return [ 'provider' => [ - 'data' => [ + [ 'id' => 'reference-2-1', 'username' => null, 'full_name' => 'Full name', @@ -332,8 +332,8 @@ public static function providerFacebookLinkSocialAccountAccountExists() 'link' => 'facebook-link-15579', 'provider' => 'Facebook', ], - 'user' => '00000000-0000-0000-0000-000000000001', - 'result' => [ + '00000000-0000-0000-0000-000000000001', + [ 'id' => '00000000-0000-0000-0000-000000000003', 'provider' => 'Facebook', 'username' => null, diff --git a/tests/TestCase/Model/Behavior/OneTimeLoginLinkBehaviorTest.php b/tests/TestCase/Model/Behavior/OneTimeLoginLinkBehaviorTest.php index 5d372674..5020cf88 100644 --- a/tests/TestCase/Model/Behavior/OneTimeLoginLinkBehaviorTest.php +++ b/tests/TestCase/Model/Behavior/OneTimeLoginLinkBehaviorTest.php @@ -193,7 +193,7 @@ public function testRequestTokenSend(): void public function testFindByUsernameOrEmailMissingUsername(): void { $this->expectException(OutOfBoundsException::class); - $this->table->find('byUsernameOrEmail', [])->first(); + $this->table->find('byUsernameOrEmail')->first(); } /** @@ -204,6 +204,6 @@ public function testFindByUsernameOrEmailMissingUsername(): void public function testFindByOneTimeTokenMissingToken(): void { $this->expectException(OutOfBoundsException::class); - $this->table->find('byOneTimeToken', [])->first(); + $this->table->find('byOneTimeToken')->first(); } } diff --git a/tests/TestCase/Model/Behavior/PasswordBehaviorTest.php b/tests/TestCase/Model/Behavior/PasswordBehaviorTest.php index 2ff502c1..2ee2f6af 100644 --- a/tests/TestCase/Model/Behavior/PasswordBehaviorTest.php +++ b/tests/TestCase/Model/Behavior/PasswordBehaviorTest.php @@ -292,7 +292,6 @@ protected function _executeGetUser($reference) $realBehavior = $this->table->getBehavior('Password'); $method = new ReflectionMethod(get_class($realBehavior), '_getUser'); - $method->setAccessible(true); return $method->invoke($realBehavior, $reference); }