From 71eb6edc8a65b99df3b379bb1cd2c69634bc94c5 Mon Sep 17 00:00:00 2001 From: Hiromi Hishida Date: Mon, 13 May 2024 15:51:26 +0900 Subject: [PATCH] [FEATURE] Laravel 11 update (#575) * Bump dependencies for Laravel 11 * restricted doctrine/orm version to v2 * restricted phpunit/phpunit version to v9 * implemented "getAuthPasswordName()" to Authenticatable trait * implemented "rehashPasswordIfRequired()" method to DoctrineUserProvider * fixed types for phpstan * added assert for lumen --- composer.json | 24 ++++++++-------- src/Auth/Authenticatable.php | 5 ++++ src/Auth/DoctrineUserProvider.php | 16 +++++++++++ src/DoctrineServiceProvider.php | 1 + tests/Auth/DoctrineUserProviderTest.php | 37 +++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index ca5b5c61..9fe37958 100644 --- a/composer.json +++ b/composer.json @@ -21,15 +21,15 @@ "doctrine/dbal": "^3.2", "doctrine/orm": "^2.14", "doctrine/persistence": "^3", - "illuminate/auth": "^9.0|^10.0", - "illuminate/console": "^9.0|^10.0", - "illuminate/container": "^9.0|^10.0", - "illuminate/contracts": "^9.0|^10.0", - "illuminate/pagination": "^9.0|^10.0", - "illuminate/routing": "^9.0|^10.0", - "illuminate/support": "^9.0|^10.0", - "illuminate/validation": "^9.0|^10.0", - "illuminate/view": "^9.0|^10.0", + "illuminate/auth": "^9.0|^10.0|^11.0", + "illuminate/console": "^9.0|^10.0|^11.0", + "illuminate/container": "^9.0|^10.0|^11.0", + "illuminate/contracts": "^9.0|^10.0|^11.0", + "illuminate/pagination": "^9.0|^10.0|^11.0", + "illuminate/routing": "^9.0|^10.0|^11.0", + "illuminate/support": "^9.0|^10.0|^11.0", + "illuminate/validation": "^9.0|^10.0|^11.0", + "illuminate/view": "^9.0|^10.0|^11.0", "symfony/cache": "^6.0|^7.0", "symfony/serializer": "^5.0|^6.0|^7.0", "symfony/yaml": "^5.0|^6.0|^7.0" @@ -40,9 +40,9 @@ "require-dev": { "phpunit/phpunit": "^9.3", "mockery/mockery": "^1.3.1", - "illuminate/log": "^9.0|^10.0", - "illuminate/notifications": "^9.0|^10.0", - "illuminate/queue": "^9.0|^10.0", + "illuminate/log": "^9.0|^10.0|^11.0", + "illuminate/notifications": "^9.0|^10.0|^11.0", + "illuminate/queue": "^9.0|^10.0|^11.0", "phpstan/phpstan": "^1.9", "phpstan/phpstan-deprecation-rules": "^1.1" }, diff --git a/src/Auth/Authenticatable.php b/src/Auth/Authenticatable.php index 0a66be95..683a9253 100644 --- a/src/Auth/Authenticatable.php +++ b/src/Auth/Authenticatable.php @@ -92,4 +92,9 @@ public function getRememberTokenName() { return 'rememberToken'; } + + public function getAuthPasswordName() + { + return 'password'; + } } diff --git a/src/Auth/DoctrineUserProvider.php b/src/Auth/DoctrineUserProvider.php index bc995796..648b3553 100644 --- a/src/Auth/DoctrineUserProvider.php +++ b/src/Auth/DoctrineUserProvider.php @@ -142,4 +142,20 @@ public function getModel() { return $this->entity; } + + /** + * @param array{password: string} $credentials + * @return void + */ + public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false) + { + if (! $this->hasher->needsRehash($user->getAuthPassword()) && ! $force) { + return; + } + assert(method_exists($user, 'setPassword')); + + $user->setPassword($this->hasher->make($credentials['password'])); + $this->em->persist($user); + $this->em->flush(); + } } diff --git a/src/DoctrineServiceProvider.php b/src/DoctrineServiceProvider.php index af8878e2..1cb2b8da 100644 --- a/src/DoctrineServiceProvider.php +++ b/src/DoctrineServiceProvider.php @@ -88,6 +88,7 @@ protected function ensureValidatorIsUsable() if (!$this->isLumen()) { return; } + assert(property_exists($this->app, 'availableBindings')); if ($this->shouldRegisterDoctrinePresenceValidator()) { // due to weirdness the default presence verifier overrides one set by a service provider diff --git a/tests/Auth/DoctrineUserProviderTest.php b/tests/Auth/DoctrineUserProviderTest.php index a0efaaaf..c8841a70 100644 --- a/tests/Auth/DoctrineUserProviderTest.php +++ b/tests/Auth/DoctrineUserProviderTest.php @@ -140,6 +140,43 @@ public function test_can_validate_credentials() )); } + public function test_rehash_password_if_required_rehash() + { + $user = new AuthenticableMock; + + $this->hasher->shouldReceive('needsRehash')->once()->andReturn(true); + $this->hasher->shouldReceive('make')->once()->andReturn('hashedPassword'); + $this->em->shouldReceive('persist')->once(); + $this->em->shouldReceive('flush')->once(); + + $this->provider->rehashPasswordIfRequired($user, ['password' => 'rawPassword'], false); + $this->assertEquals('hashedPassword', $user->getPassword()); + } + + public function test_rehash_password_if_required_rehash_force() + { + $user = new AuthenticableMock; + + $this->hasher->shouldReceive('needsRehash')->once()->andReturn(false); + $this->hasher->shouldReceive('make')->once()->andReturn('hashedPassword'); + $this->em->shouldReceive('persist')->once(); + $this->em->shouldReceive('flush')->once(); + + $this->provider->rehashPasswordIfRequired($user, ['password' => 'rawPassword'], true); + $this->assertEquals('hashedPassword', $user->getPassword()); + } + + public function test_rehash_password_if_required_rehash_norehash_needed() + { + $user = new AuthenticableMock; + $user->setPassword('originalPassword'); + + $this->hasher->shouldReceive('needsRehash')->once()->andReturn(false); + + $this->provider->rehashPasswordIfRequired($user, ['password' => 'rawPassword'], false); + $this->assertEquals('originalPassword', $user->getPassword()); + } + protected function mockGetRepository($class = AuthenticableMock::class) { $this->em->shouldReceive('getRepository')