diff --git a/docs/en/authenticators.rst b/docs/en/authenticators.rst index a3bfc1b3..7ea4ff58 100644 --- a/docs/en/authenticators.rst +++ b/docs/en/authenticators.rst @@ -18,13 +18,12 @@ Configuration options: - **sessionKey**: The session key for the user data, default is ``Auth`` -- **identify**: Set this key with a value of bool ``true`` to enable checking - the session credentials against the identifiers. When ``true``, the configured - :doc:`/identifiers` are used to identify the user using data - stored in the session on each request. Default value is ``false``. +- **identify**: Deprecated in 3.4.0. This option only verifies that the + username exists in the database, it does not verify passwords as the + documentation previously suggested. Use ``PrimaryKeySessionAuthenticator`` + instead if you need to fetch fresh user data from the database on each request. - **fields**: Allows you to map the ``username`` field to the unique - identifier in your user storage. Defaults to ``username``. This option is - used when the ``identify`` option is set to true. + identifier in your user storage. Defaults to ``username``. PrimaryKeySession ================= diff --git a/docs/en/index.rst b/docs/en/index.rst index 4f12ea25..01f22317 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -32,7 +32,6 @@ imports:: use Authentication\AuthenticationServiceInterface; use Authentication\AuthenticationServiceProviderInterface; use Authentication\Identifier\AbstractIdentifier; - use Authentication\Identifier\IdentifierInterface; use Authentication\Middleware\AuthenticationMiddleware; use Cake\Http\MiddlewareQueue; use Cake\Routing\Router; @@ -94,23 +93,20 @@ define the ``AuthenticationService`` it wants to use. Add the following method t 'queryParam' => 'redirect', ]); - // Define identifiers $fields = [ AbstractIdentifier::CREDENTIAL_USERNAME => 'email', - AbstractIdentifier::CREDENTIAL_PASSWORD => 'password' - ]; - $passwordIdentifier = [ - 'Authentication.Password' => [ - 'fields' => $fields, - ], + AbstractIdentifier::CREDENTIAL_PASSWORD => 'password', ]; // Load the authenticators. Session should be first. - $service->loadAuthenticator('Authentication.Session', [ - 'identifier' => $passwordIdentifier, - ]); + // Session just uses session data directly as identity, no identifier needed. + $service->loadAuthenticator('Authentication.Session'); $service->loadAuthenticator('Authentication.Form', [ - 'identifier' => $passwordIdentifier, + 'identifier' => [ + 'Authentication.Password' => [ + 'fields' => $fields, + ], + ], 'fields' => $fields, 'loginUrl' => Router::url([ 'prefix' => false, @@ -126,9 +122,9 @@ define the ``AuthenticationService`` it wants to use. Add the following method t First, we configure what to do with users when they are not authenticated. Next, we attach the ``Session`` and ``Form`` :doc:`/authenticators` which define the mechanisms that our application will use to authenticate users. ``Session`` enables us to identify -users based on data in the session while ``Form`` enables us -to handle a login form at the ``loginUrl``. Finally we attach an :doc:`identifier -` to convert the credentials users will give us into an +users based on data in the session - it uses the session data directly as identity without any +database lookup. ``Form`` enables us to handle a login form at the ``loginUrl`` and uses an +:doc:`identifier ` to convert the credentials users will give us into an :doc:`identity ` which represents our logged in user. If one of the configured authenticators was able to validate the credentials, diff --git a/src/Authenticator/SessionAuthenticator.php b/src/Authenticator/SessionAuthenticator.php index a6c98dea..00ec5b37 100644 --- a/src/Authenticator/SessionAuthenticator.php +++ b/src/Authenticator/SessionAuthenticator.php @@ -21,6 +21,7 @@ use Cake\Http\Exception\UnauthorizedException; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use function Cake\Core\deprecationWarning; /** * Session Authenticator @@ -31,9 +32,10 @@ class SessionAuthenticator extends AbstractAuthenticator implements PersistenceI * Default config for this object. * - `fields` The fields to use to verify a user by. * - `sessionKey` Session key. - * - `identify` Whether to identify user data stored in a session. This is - * useful if you want to remotely end sessions that have a different password stored, - * or if your identification logic needs additional conditions before a user can login. + * - `identify` Whether to identify user data stored in a session. + * Deprecated: This option only verifies that the username exists in the database, + * it does not verify passwords. Use `PrimaryKeySessionAuthenticator` instead if you + * need to fetch fresh user data from the database on each request. * * @var array */ @@ -65,6 +67,12 @@ public function authenticate(ServerRequestInterface $request): ResultInterface } if ($this->getConfig('identify') === true) { + deprecationWarning( + '3.4.0', + 'The `identify` option is deprecated. ' . + 'This option only verifies that the username exists, not the password. ' . + 'Use `PrimaryKeySessionAuthenticator` instead to fetch fresh user data on each request.', + ); $credentials = []; foreach ($this->getConfig('fields') as $key => $field) { $credentials[$key] = $user[$field]; diff --git a/tests/TestCase/AuthenticationServiceTest.php b/tests/TestCase/AuthenticationServiceTest.php index 0a11738d..2b96b8b8 100644 --- a/tests/TestCase/AuthenticationServiceTest.php +++ b/tests/TestCase/AuthenticationServiceTest.php @@ -172,9 +172,15 @@ public function testAuthenticateWithChallengeDisabled() * Integration test for session auth + identify always getting a fresh user record. * * @return void + * @deprecated The `identify` option is deprecated. */ public function testAuthenticationWithSessionIdentify() { + $this->skipIf( + version_compare(Version::id(), '11.0', '<'), + 'For some reason PHPUnit doesn\'t pick up the deprecation on v10', + ); + $users = $this->fetchTable('Users'); $user = $users->get(1); @@ -197,25 +203,28 @@ public function testAuthenticationWithSessionIdentify() ], ]); }; - $service = $factory(); - $result = $service->authenticate($request); - $this->assertTrue($result->isValid()); - - $dateValue = new DateTime('2022-01-01 10:11:12'); - $identity = $result->getData(); - $this->assertEquals($identity->username, $user->username); - $this->assertNotEquals($identity->created, $dateValue); - - // Update the user so that we can ensure session is reading from the db. - $user->created = $dateValue; - $users->saveOrFail($user); - $service = $factory(); - $result = $service->authenticate($request); - $this->assertTrue($result->isValid()); - $identity = $result->getData(); - $this->assertEquals($identity->username, $user->username); - $this->assertEquals($identity->created, $dateValue); + $this->deprecated(function () use ($factory, $request, $users, $user) { + $service = $factory(); + $result = $service->authenticate($request); + $this->assertTrue($result->isValid()); + + $dateValue = new DateTime('2022-01-01 10:11:12'); + $identity = $result->getData(); + $this->assertEquals($identity->username, $user->username); + $this->assertNotEquals($identity->created, $dateValue); + + // Update the user so that we can ensure session is reading from the db. + $user->created = $dateValue; + $users->saveOrFail($user); + + $service = $factory(); + $result = $service->authenticate($request); + $this->assertTrue($result->isValid()); + $identity = $result->getData(); + $this->assertEquals($identity->username, $user->username); + $this->assertEquals($identity->created, $dateValue); + }); } /** diff --git a/tests/TestCase/Authenticator/SessionAuthenticatorTest.php b/tests/TestCase/Authenticator/SessionAuthenticatorTest.php index bd22d5ea..a2590200 100644 --- a/tests/TestCase/Authenticator/SessionAuthenticatorTest.php +++ b/tests/TestCase/Authenticator/SessionAuthenticatorTest.php @@ -27,6 +27,7 @@ use Cake\Http\ServerRequestFactory; use Cake\Http\Session; use Cake\ORM\TableRegistry; +use PHPUnit\Runner\Version; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; @@ -203,9 +204,15 @@ public function testAuthenticateFailure() * Test successful session data verification by database lookup * * @return void + * @deprecated The `identify` option is deprecated. */ public function testVerifyByDatabaseSuccess() { + $this->skipIf( + version_compare(Version::id(), '11.0', '<'), + 'For some reason PHPUnit doesn\'t pick up the deprecation on v10', + ); + $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/']); $this->sessionMock->expects($this->once()) @@ -221,19 +228,27 @@ public function testVerifyByDatabaseSuccess() $authenticator = new SessionAuthenticator($this->identifiers, [ 'identify' => true, ]); - $result = $authenticator->authenticate($request); + $this->deprecated(function () use ($authenticator, $request) { + $result = $authenticator->authenticate($request); - $this->assertInstanceOf(Result::class, $result); - $this->assertSame(Result::SUCCESS, $result->getStatus()); + $this->assertInstanceOf(Result::class, $result); + $this->assertSame(Result::SUCCESS, $result->getStatus()); + }); } /** * Test session data verification by database lookup failure * * @return void + * @deprecated The `identify` option is deprecated. */ public function testVerifyByDatabaseFailure() { + $this->skipIf( + version_compare(Version::id(), '11.0', '<'), + 'For some reason PHPUnit doesn\'t pick up the deprecation on v10', + ); + $request = ServerRequestFactory::fromGlobals(['REQUEST_URI' => '/']); $this->sessionMock->expects($this->once()) @@ -249,10 +264,12 @@ public function testVerifyByDatabaseFailure() $authenticator = new SessionAuthenticator($this->identifiers, [ 'identify' => true, ]); - $result = $authenticator->authenticate($request); + $this->deprecated(function () use ($authenticator, $request) { + $result = $authenticator->authenticate($request); - $this->assertInstanceOf(Result::class, $result); - $this->assertSame(Result::FAILURE_CREDENTIALS_INVALID, $result->getStatus()); + $this->assertInstanceOf(Result::class, $result); + $this->assertSame(Result::FAILURE_CREDENTIALS_INVALID, $result->getStatus()); + }); } /**