diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index d0f2ee2..5e47f5f 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -10,6 +10,8 @@ jobs: strategy: matrix: include: + - php: 8.3 + illuminate: ^11.0 - php: 8.2 illuminate: ^10.0 - php: 8.1 @@ -25,7 +27,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup PHP ${{ matrix.php }} uses: shivammathur/setup-php@v2 @@ -38,5 +40,5 @@ jobs: - name: Run test suite run: composer run-script ci-test - - uses: codecov/codecov-action@v3 - if: matrix.php == '8.2' + - uses: codecov/codecov-action@v4 + if: matrix.php == '8.3' diff --git a/composer.json b/composer.json index 3d09989..54c4720 100644 --- a/composer.json +++ b/composer.json @@ -20,16 +20,16 @@ "ci-test": "vendor/bin/phpunit --coverage-clover coverage.xml" }, "require": { - "php": "^7.3|^7.4|^8.0|^8.1|^8.2", - "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0", - "illuminate/container": "^6.0|^7.0|^8.0|^9.0|^10.0", - "illuminate/database": "^6.0|^7.0|^8.0|^9.0|^10.0", - "illuminate/hashing": "^6.0|^7.0|^8.0|^9.0|^10.0", + "php": "^7.3|^7.4|^8.0|^8.1|^8.2|^8.3", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "illuminate/container": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "illuminate/database": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "illuminate/hashing": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", "aws/aws-sdk-php": "^3.0" }, "require-dev": { - "illuminate/auth": "^6.0|^7.0|^8.0|^9.0|^10.0", - "symfony/var-dumper": "^5.0|^6.0", + "illuminate/auth": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0", + "symfony/var-dumper": "^5.0|^6.0|^7.0", "vlucas/phpdotenv": "^4.1|^5.0", "mockery/mockery": "^1.3", "phpunit/phpunit": "^8.0|^9.0|^10.0" diff --git a/src/Kitar/Dynamodb/Model/AuthUserProvider.php b/src/Kitar/Dynamodb/Model/AuthUserProvider.php index 606df42..0b24517 100644 --- a/src/Kitar/Dynamodb/Model/AuthUserProvider.php +++ b/src/Kitar/Dynamodb/Model/AuthUserProvider.php @@ -147,6 +147,25 @@ public function validateCredentials(Authenticatable $user, array $credentials) return $this->hasher->check($plain, $user->getAuthPassword()); } + /** + * Rehash the user's password if required and supported. + * + * @param \Illuminate\Contracts\Auth\Authenticatable $user + * @param array $credentials + * @param bool $force + * @return void + */ + public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false) + { + if (! $this->hasher->needsRehash($user->getAuthPassword()) && ! $force) { + return; + } + + $user->forceFill([ + $user->getAuthPasswordName() => $this->hasher->make($credentials['password']), + ])->save(); + } + /** * Create a new instance of the model. * diff --git a/tests/Model/AuthUserProviderTest.php b/tests/Model/AuthUserProviderTest.php index 869d43d..5859399 100644 --- a/tests/Model/AuthUserProviderTest.php +++ b/tests/Model/AuthUserProviderTest.php @@ -376,4 +376,30 @@ public function it_can_validate_credentials() $this->assertTrue($success); $this->assertFalse($fail); } + + /** @test */ + public function it_can_rehash_password_if_required() + { + if (! method_exists(\Illuminate\Contracts\Auth\UserProvider::class, 'rehashPasswordIfRequired')) { + $this->markTestSkipped('Password rehash is not supported in this version.'); + } + + $connection = $this->newConnectionMock(); + $connection->shouldReceive('putItem')->andReturn($this->sampleAwsResult()); + $this->setConnectionResolver($connection); + + $originalHash = '$2y$10$ouGGlM0C/YKgk8MbQHxVHOblxztk/PlXZbKw7w2wfA8FlXsB0Po9G'; + $user = new UserA([ + 'partition' => 'foo@bar.com', + 'password' => $originalHash, + ]); + $provider = new AuthUserProvider($this->hasher, UserA::class); + $provider->rehashPasswordIfRequired($user, ['password' => 'foo'], true); + $this->assertNotSame($originalHash, $user->password); + $this->assertTrue($this->hasher->check('foo', $user->password)); + + $rehashedHash = $user->password; + $provider->rehashPasswordIfRequired($user, ['password' => 'foo']); + $this->assertSame($rehashedHash, $user->password); + } }