From cfdaedb6232f3ce92118387c3ba60efb7aad6edc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 9 May 2024 11:16:51 -0300 Subject: [PATCH 1/9] Create AuthenticationFailure exception MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactors the AuthenticationPlugin::showFailure() to receive the new exception and move the showFailure calls to the Authentication middleware. Signed-off-by: Maurício Meneghini Fauth --- docs/faq.rst | 5 +- src/Exceptions/AuthenticationFailure.php | 78 +++++++++++++++++++ src/Http/Middleware/Authentication.php | 25 +++--- src/Plugins/Auth/AuthenticationConfig.php | 11 ++- src/Plugins/Auth/AuthenticationCookie.php | 13 ++-- src/Plugins/Auth/AuthenticationHttp.php | 7 +- src/Plugins/Auth/AuthenticationSignon.php | 7 +- src/Plugins/AuthenticationPlugin.php | 60 +++++++------- .../Exceptions/AuthenticationFailureTest.php | 55 +++++++++++++ .../Plugins/Auth/AuthenticationConfigTest.php | 3 +- .../Plugins/Auth/AuthenticationCookieTest.php | 76 ++++++------------ .../Plugins/Auth/AuthenticationHttpTest.php | 7 +- .../Plugins/Auth/AuthenticationSignonTest.php | 15 ++-- .../unit/Plugins/AuthenticationPluginTest.php | 6 ++ 14 files changed, 238 insertions(+), 130 deletions(-) create mode 100644 src/Exceptions/AuthenticationFailure.php create mode 100644 tests/unit/Exceptions/AuthenticationFailureTest.php diff --git a/docs/faq.rst b/docs/faq.rst index 42a9ea2d3d..4fbc5f25a9 100644 --- a/docs/faq.rst +++ b/docs/faq.rst @@ -2235,9 +2235,10 @@ logs. Currently there are two variables available: User name of currently active user (they do not have to be logged in). ``userStatus`` Status of currently active user, one of ``ok`` (user is logged in), - ``mysql-denied`` (MySQL denied user login), ``allow-denied`` (user denied + ``server-denied`` (database server denied user login), ``allow-denied`` (user denied by allow/deny rules), ``root-denied`` (root is denied in configuration), - ``empty-denied`` (empty password is denied). + ``empty-denied`` (empty password is denied), + ``no-activity`` (automatically logged out due to inactivity). ``LogFormat`` directive for Apache can look like following: diff --git a/src/Exceptions/AuthenticationFailure.php b/src/Exceptions/AuthenticationFailure.php new file mode 100644 index 0000000000..cb37827d36 --- /dev/null +++ b/src/Exceptions/AuthenticationFailure.php @@ -0,0 +1,78 @@ +authenticate(); + try { + $authPlugin->authenticate(); + } catch (AuthenticationFailure $exception) { + $authPlugin->showFailure($exception); + } + $currentServer = new Server(Config::getInstance()->selectedServer); /* Enable LOAD DATA LOCAL INFILE for LDI plugin */ @@ -71,7 +76,11 @@ final class Authentication implements MiddlewareInterface // phpcs:enable } - $this->connectToDatabaseServer(DatabaseInterface::getInstance(), $authPlugin, $currentServer); + try { + $this->connectToDatabaseServer(DatabaseInterface::getInstance(), $currentServer); + } catch (AuthenticationFailure $exception) { + $authPlugin->showFailure($exception); + } // Relation should only be initialized after the connection is successful /** @var Relation $relation */ @@ -94,11 +103,9 @@ final class Authentication implements MiddlewareInterface return $handler->handle($request); } - private function connectToDatabaseServer( - DatabaseInterface $dbi, - AuthenticationPlugin $auth, - Server $currentServer, - ): void { + /** @throws AuthenticationFailure */ + private function connectToDatabaseServer(DatabaseInterface $dbi, Server $currentServer): void + { /** * Try to connect MySQL with the control user profile (will be used to get the privileges list for the current * user but the true user link must be open after this one, so it would be default one for all the scripts). @@ -111,7 +118,7 @@ final class Authentication implements MiddlewareInterface // Connects to the server (validates user's login) $userConnection = $dbi->connect($currentServer, ConnectionType::User); if ($userConnection === null) { - $auth->showFailure('mysql-denied'); + throw AuthenticationFailure::serverDenied(); } if ($controlConnection !== null) { diff --git a/src/Plugins/Auth/AuthenticationConfig.php b/src/Plugins/Auth/AuthenticationConfig.php index 673ad930ee..d059ef6bd3 100644 --- a/src/Plugins/Auth/AuthenticationConfig.php +++ b/src/Plugins/Auth/AuthenticationConfig.php @@ -10,6 +10,7 @@ namespace PhpMyAdmin\Plugins\Auth; use PhpMyAdmin\Config; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Error\ErrorHandler; +use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Html\Generator; use PhpMyAdmin\Plugins\AuthenticationPlugin; use PhpMyAdmin\ResponseRenderer; @@ -65,12 +66,10 @@ class AuthenticationConfig extends AuthenticationPlugin /** * User is not allowed to login to MySQL -> authentication failed - * - * @param string $failure String describing why authentication has failed */ - public function showFailure(string $failure): never + public function showFailure(AuthenticationFailure $failure): never { - parent::showFailure($failure); + $this->logFailure($failure); $connError = DatabaseInterface::getInstance()->getError(); if ($connError === '' || $connError === '0') { @@ -95,8 +94,8 @@ class AuthenticationConfig extends AuthenticationPlugin '; $config = Config::getInstance(); - if ($failure === 'allow-denied') { - trigger_error(__('Access denied!'), E_USER_NOTICE); + if ($failure->failureType === AuthenticationFailure::ALLOW_DENIED) { + trigger_error($failure->getMessage(), E_USER_NOTICE); } else { // Check whether user has configured something if ($config->sourceMtime == 0) { diff --git a/src/Plugins/Auth/AuthenticationCookie.php b/src/Plugins/Auth/AuthenticationCookie.php index 5756237b6d..c8d097ee00 100644 --- a/src/Plugins/Auth/AuthenticationCookie.php +++ b/src/Plugins/Auth/AuthenticationCookie.php @@ -11,6 +11,7 @@ use PhpMyAdmin\Config; use PhpMyAdmin\Core; use PhpMyAdmin\Current; use PhpMyAdmin\Error\ErrorHandler; +use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Exceptions\SessionHandlerException; use PhpMyAdmin\LanguageManager; use PhpMyAdmin\Message; @@ -206,6 +207,8 @@ class AuthenticationCookie extends AuthenticationPlugin * it returns true if all seems ok which usually leads to auth_set_user() * * it directly switches to showFailure() if user inactivity timeout is reached + * + * @throws AuthenticationFailure */ public function readCredentials(): bool { @@ -371,7 +374,7 @@ class AuthenticationCookie extends AuthenticationPlugin SessionCache::remove('table_priv'); SessionCache::remove('proc_priv'); - $this->showFailure('no-activity'); + throw AuthenticationFailure::noActivity(); } // check password cookie @@ -539,14 +542,10 @@ class AuthenticationCookie extends AuthenticationPlugin * * prepares error message and switches to showLoginForm() which display the error * and the login form - * - * @param string $failure String describing why authentication has failed */ - public function showFailure(string $failure): never + public function showFailure(AuthenticationFailure $failure): never { - $GLOBALS['conn_error'] ??= null; - - parent::showFailure($failure); + $this->logFailure($failure); // Deletes password cookie and displays the login form Config::getInstance()->removeCookie('pmaAuth-' . Current::$server); diff --git a/src/Plugins/Auth/AuthenticationHttp.php b/src/Plugins/Auth/AuthenticationHttp.php index 9707ffe426..eaf21a43e3 100644 --- a/src/Plugins/Auth/AuthenticationHttp.php +++ b/src/Plugins/Auth/AuthenticationHttp.php @@ -12,6 +12,7 @@ use Fig\Http\Message\StatusCodeInterface; use PhpMyAdmin\Config; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\LanguageManager; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins\AuthenticationPlugin; @@ -178,12 +179,10 @@ class AuthenticationHttp extends AuthenticationPlugin /** * User is not allowed to login to MySQL -> authentication failed - * - * @param string $failure String describing why authentication has failed */ - public function showFailure(string $failure): never + public function showFailure(AuthenticationFailure $failure): never { - parent::showFailure($failure); + $this->logFailure($failure); $error = DatabaseInterface::getInstance()->getError(); if ($error && $GLOBALS['errno'] != 1045) { diff --git a/src/Plugins/Auth/AuthenticationSignon.php b/src/Plugins/Auth/AuthenticationSignon.php index 9e06944201..bbb8d61e5f 100644 --- a/src/Plugins/Auth/AuthenticationSignon.php +++ b/src/Plugins/Auth/AuthenticationSignon.php @@ -8,6 +8,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Plugins\Auth; use PhpMyAdmin\Config; +use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\LanguageManager; use PhpMyAdmin\Plugins\AuthenticationPlugin; use PhpMyAdmin\ResponseRenderer; @@ -233,12 +234,10 @@ class AuthenticationSignon extends AuthenticationPlugin /** * User is not allowed to login to MySQL -> authentication failed - * - * @param string $failure String describing why authentication has failed */ - public function showFailure(string $failure): never + public function showFailure(AuthenticationFailure $failure): never { - parent::showFailure($failure); + $this->logFailure($failure); /* Session name */ $sessionName = Config::getInstance()->selectedServer['SignonSession']; diff --git a/src/Plugins/AuthenticationPlugin.php b/src/Plugins/AuthenticationPlugin.php index 09bde9a24d..3cfc174cec 100644 --- a/src/Plugins/AuthenticationPlugin.php +++ b/src/Plugins/AuthenticationPlugin.php @@ -9,6 +9,7 @@ namespace PhpMyAdmin\Plugins; use PhpMyAdmin\Config; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Exceptions\SessionHandlerException; use PhpMyAdmin\Http\ServerRequest; @@ -67,6 +68,8 @@ abstract class AuthenticationPlugin /** * Gets authentication credentials + * + * @throws AuthenticationFailure */ abstract public function readCredentials(): bool; @@ -93,12 +96,12 @@ abstract class AuthenticationPlugin /** * User is not allowed to login to MySQL -> authentication failed - * - * @param string $failure String describing why authentication has failed */ - public function showFailure(string $failure): void + abstract public function showFailure(AuthenticationFailure $failure): never; + + protected function logFailure(AuthenticationFailure $failure): void { - Logging::logUser(Config::getInstance(), $this->user, $failure); + Logging::logUser(Config::getInstance(), $this->user, $failure->failureType); } /** @@ -157,38 +160,25 @@ abstract class AuthenticationPlugin /** * Returns error message for failed authentication. - * - * @param string $failure String describing why authentication has failed */ - public function getErrorMessage(string $failure): string + public function getErrorMessage(AuthenticationFailure $failure): string { - if ($failure === 'empty-denied') { - return __('Login without a password is forbidden by configuration (see AllowNoPassword)'); + if ($failure->failureType === AuthenticationFailure::NO_ACTIVITY) { + return sprintf($failure->getMessage(), (int) Config::getInstance()->settings['LoginCookieValidity']); } - if ($failure === 'root-denied' || $failure === 'allow-denied') { - return __('Access denied!'); + if ($failure->failureType === AuthenticationFailure::SERVER_DENIED) { + $dbiError = DatabaseInterface::getInstance()->getError(); + if ($dbiError !== '') { + return htmlspecialchars($dbiError); + } + + if (isset($GLOBALS['errno'])) { + return '#' . $GLOBALS['errno'] . ' ' . $failure->getMessage(); + } } - if ($failure === 'no-activity') { - return sprintf( - __('You have been automatically logged out due to inactivity of %s seconds.' - . ' Once you log in again, you should be able to resume the work where you left off.'), - (int) Config::getInstance()->settings['LoginCookieValidity'], - ); - } - - $dbiError = DatabaseInterface::getInstance()->getError(); - if ($dbiError !== '') { - return htmlspecialchars($dbiError); - } - - if (isset($GLOBALS['errno'])) { - return '#' . $GLOBALS['errno'] . ' ' - . __('Cannot log in to the MySQL server'); - } - - return __('Cannot log in to the MySQL server'); + return $failure->getMessage(); } /** @@ -235,6 +225,8 @@ abstract class AuthenticationPlugin * High level authentication interface * * Gets the credentials or shows login form if necessary + * + * @throws AuthenticationFailure */ public function authenticate(): void { @@ -269,6 +261,8 @@ abstract class AuthenticationPlugin /** * Check configuration defined restrictions for authentication + * + * @throws AuthenticationFailure */ public function checkRules(): void { @@ -287,13 +281,13 @@ abstract class AuthenticationPlugin // Ejects the user if banished if ($allowDenyForbidden) { - $this->showFailure('allow-denied'); + throw AuthenticationFailure::allowDenied(); } } // is root allowed? if (! $config->selectedServer['AllowRoot'] && $config->selectedServer['user'] === 'root') { - $this->showFailure('root-denied'); + throw AuthenticationFailure::rootDenied(); } // is a login without password allowed? @@ -301,7 +295,7 @@ abstract class AuthenticationPlugin return; } - $this->showFailure('empty-denied'); + throw AuthenticationFailure::emptyDenied(); } /** diff --git a/tests/unit/Exceptions/AuthenticationFailureTest.php b/tests/unit/Exceptions/AuthenticationFailureTest.php new file mode 100644 index 0000000000..e19ac70df9 --- /dev/null +++ b/tests/unit/Exceptions/AuthenticationFailureTest.php @@ -0,0 +1,55 @@ +failureType); + self::assertSame('Access denied!', $exception->getMessage()); + } + + public function testEmptyDenied(): void + { + $exception = AuthenticationFailure::emptyDenied(); + self::assertSame('empty-denied', $exception->failureType); + self::assertSame( + 'Login without a password is forbidden by configuration (see AllowNoPassword).', + $exception->getMessage(), + ); + } + + public function testNoActivity(): void + { + $exception = AuthenticationFailure::noActivity(); + self::assertSame('no-activity', $exception->failureType); + self::assertSame( + 'You have been automatically logged out due to inactivity of %s seconds.' + . ' Once you log in again, you should be able to resume the work where you left off.', + $exception->getMessage(), + ); + } + + public function testRootDenied(): void + { + $exception = AuthenticationFailure::rootDenied(); + self::assertSame('root-denied', $exception->failureType); + self::assertSame('Access denied!', $exception->getMessage()); + } + + public function testServerDenied(): void + { + $exception = AuthenticationFailure::serverDenied(); + self::assertSame('server-denied', $exception->failureType); + self::assertSame('Cannot log in to the database server.', $exception->getMessage()); + } +} diff --git a/tests/unit/Plugins/Auth/AuthenticationConfigTest.php b/tests/unit/Plugins/Auth/AuthenticationConfigTest.php index 9548c614e3..fc64aae94c 100644 --- a/tests/unit/Plugins/Auth/AuthenticationConfigTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationConfigTest.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Tests\Plugins\Auth; use PhpMyAdmin\Config; use PhpMyAdmin\Current; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Plugins\Auth\AuthenticationConfig; use PhpMyAdmin\ResponseRenderer; @@ -91,7 +92,7 @@ class AuthenticationConfigTest extends AbstractTestCase ob_start(); try { - $this->object->showFailure(''); + $this->object->showFailure(AuthenticationFailure::serverDenied()); } catch (Throwable $throwable) { } diff --git a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php index dcab3642bd..8ea4dfb3d7 100644 --- a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php @@ -7,7 +7,7 @@ namespace PhpMyAdmin\Tests\Plugins\Auth; use PhpMyAdmin\Config; use PhpMyAdmin\Current; use PhpMyAdmin\DatabaseInterface; -use PhpMyAdmin\Error\ErrorHandler; +use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Plugins\Auth\AuthenticationCookie; use PhpMyAdmin\ResponseRenderer; @@ -92,23 +92,6 @@ class AuthenticationCookieTest extends AbstractTestCase self::assertSame(['redirect_flag' => '1'], $responseStub->getJSONResult()); } - private function getAuthErrorMockResponse(): void - { - // mock error handler - - $mockErrorHandler = $this->getMockBuilder(ErrorHandler::class) - ->disableOriginalConstructor() - ->onlyMethods(['hasDisplayErrors']) - ->getMock(); - - $mockErrorHandler->expects(self::once()) - ->method('hasDisplayErrors') - ->with() - ->willReturn(true); - - ErrorHandler::$instance = $mockErrorHandler; - } - public function testAuthError(): void { $_REQUEST = []; @@ -576,11 +559,7 @@ class AuthenticationCookieTest extends AbstractTestCase ->method('cookieDecrypt') ->willReturn('testBF'); - $this->object->expects(self::once()) - ->method('showFailure') - ->willThrowException(new ExitException()); - - $this->expectException(ExitException::class); + $this->expectExceptionObject(AuthenticationFailure::noActivity()); $this->object->readCredentials(); } @@ -656,7 +635,7 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); try { - $this->object->showFailure('empty-denied'); + $this->object->showFailure(AuthenticationFailure::emptyDenied()); } catch (Throwable $throwable) { } @@ -668,7 +647,7 @@ class AuthenticationCookieTest extends AbstractTestCase self::assertSame( $GLOBALS['conn_error'], - 'Login without a password is forbidden by configuration (see AllowNoPassword)', + 'Login without a password is forbidden by configuration (see AllowNoPassword).', ); } @@ -724,7 +703,7 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); try { - $this->object->showFailure('allow-denied'); + $this->object->showFailure(AuthenticationFailure::allowDenied()); } catch (Throwable $throwable) { } @@ -756,7 +735,7 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); try { - $this->object->showFailure('no-activity'); + $this->object->showFailure(AuthenticationFailure::noActivity()); } catch (Throwable $throwable) { } @@ -801,7 +780,7 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); try { - $this->object->showFailure(''); + $this->object->showFailure(AuthenticationFailure::serverDenied()); } catch (Throwable $throwable) { } @@ -811,7 +790,7 @@ class AuthenticationCookieTest extends AbstractTestCase self::assertSame(['no-cache'], $response->getHeader('Pragma')); self::assertSame(200, $response->getStatusCode()); - self::assertSame($GLOBALS['conn_error'], '#42 Cannot log in to the MySQL server'); + self::assertSame($GLOBALS['conn_error'], '#42 Cannot log in to the database server.'); } public function testAuthFailsErrno(): void @@ -842,7 +821,7 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); try { - $this->object->showFailure(''); + $this->object->showFailure(AuthenticationFailure::serverDenied()); } catch (Throwable $throwable) { } @@ -852,7 +831,7 @@ class AuthenticationCookieTest extends AbstractTestCase self::assertSame(['no-cache'], $response->getHeader('Pragma')); self::assertSame(200, $response->getStatusCode()); - self::assertSame($GLOBALS['conn_error'], 'Cannot log in to the MySQL server'); + self::assertSame($GLOBALS['conn_error'], 'Cannot log in to the database server.'); } public function testGetEncryptionSecretEmpty(): void @@ -999,31 +978,20 @@ class AuthenticationCookieTest extends AbstractTestCase $config->selectedServer['AllowNoPassword'] = $nopass; $config->selectedServer['AllowDeny'] = $rules; - if ($expected !== '') { - $this->getAuthErrorMockResponse(); - } - - $responseStub = new ResponseRendererStub(); - (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); - + $exception = null; try { $this->object->checkRules(); - } catch (Throwable $throwable) { - } - - $result = $responseStub->getHTMLResult(); - - if ($expected !== '') { - self::assertInstanceOf(ExitException::class, $throwable ?? null); + } catch (AuthenticationFailure $exception) { } if ($expected === '') { - self::assertSame($expected, $result); - } else { - self::assertStringContainsString($expected, $result); + self::assertNull($exception, 'checkRules() should not throw an exception.'); + + return; } - ErrorHandler::$instance = null; + self::assertInstanceOf(AuthenticationFailure::class, $exception); + self::assertSame($expected, $exception->failureType); } /** @return mixed[] */ @@ -1031,9 +999,9 @@ class AuthenticationCookieTest extends AbstractTestCase { return [ 'nopass-ok' => ['testUser', '', '1.2.3.4', true, true, [], ''], - 'nopass' => ['testUser', '', '1.2.3.4', true, false, [], 'Login without a password is forbidden'], + 'nopass' => ['testUser', '', '1.2.3.4', true, false, [], AuthenticationFailure::EMPTY_DENIED], 'root-ok' => ['root', 'root', '1.2.3.4', true, true, [], ''], - 'root' => ['root', 'root', '1.2.3.4', false, true, [], 'Access denied!'], + 'root' => ['root', 'root', '1.2.3.4', false, true, [], AuthenticationFailure::ROOT_DENIED], 'rules-deny-allow-ok' => [ 'root', 'root', @@ -1050,7 +1018,7 @@ class AuthenticationCookieTest extends AbstractTestCase true, true, ['order' => 'deny,allow', 'rules' => ['allow root 1.2.3.4', 'deny % from all']], - 'Access denied!', + AuthenticationFailure::ALLOW_DENIED, ], 'rules-allow-deny-ok' => [ 'root', @@ -1068,7 +1036,7 @@ class AuthenticationCookieTest extends AbstractTestCase true, true, ['order' => 'allow,deny', 'rules' => ['deny user from all', 'allow root 1.2.3.4']], - 'Access denied!', + AuthenticationFailure::ALLOW_DENIED, ], 'rules-explicit-ok' => [ 'root', @@ -1086,7 +1054,7 @@ class AuthenticationCookieTest extends AbstractTestCase true, true, ['order' => 'explicit', 'rules' => ['deny user from all', 'allow root 1.2.3.4']], - 'Access denied!', + AuthenticationFailure::ALLOW_DENIED, ], ]; } diff --git a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php index 49614ac3ae..4ce58da1b7 100644 --- a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php @@ -7,6 +7,7 @@ namespace PhpMyAdmin\Tests\Plugins\Auth; use PhpMyAdmin\Config; use PhpMyAdmin\Current; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Plugins\Auth\AuthenticationHttp; use PhpMyAdmin\ResponseRenderer; @@ -286,7 +287,7 @@ class AuthenticationHttpTest extends AbstractTestCase ob_start(); try { - $this->object->showFailure(''); + $this->object->showFailure(AuthenticationFailure::serverDenied()); } catch (Throwable $throwable) { } @@ -311,13 +312,13 @@ class AuthenticationHttpTest extends AbstractTestCase $GLOBALS['errno'] = 1045; try { - $this->object->showFailure(''); + $this->object->showFailure(AuthenticationFailure::serverDenied()); } catch (ExitException) { } // case 3 $GLOBALS['errno'] = 1043; $this->expectException(ExitException::class); - $this->object->showFailure(''); + $this->object->showFailure(AuthenticationFailure::serverDenied()); } } diff --git a/tests/unit/Plugins/Auth/AuthenticationSignonTest.php b/tests/unit/Plugins/Auth/AuthenticationSignonTest.php index bd3f3fcb53..51f4a8bf68 100644 --- a/tests/unit/Plugins/Auth/AuthenticationSignonTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationSignonTest.php @@ -8,6 +8,7 @@ use PhpMyAdmin\Config; use PhpMyAdmin\Config\Settings\Server; use PhpMyAdmin\Current; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Plugins\Auth\AuthenticationSignon; use PhpMyAdmin\ResponseRenderer; @@ -260,12 +261,12 @@ class AuthenticationSignonTest extends AbstractTestCase ->willThrowException(new ExitException()); try { - $this->object->showFailure('empty-denied'); + $this->object->showFailure(AuthenticationFailure::emptyDenied()); } catch (ExitException) { } self::assertSame( - 'Login without a password is forbidden by configuration (see AllowNoPassword)', + 'Login without a password is forbidden by configuration (see AllowNoPassword).', $_SESSION['PMA_single_signon_error_message'], ); } @@ -285,7 +286,7 @@ class AuthenticationSignonTest extends AbstractTestCase ->willThrowException(new ExitException()); try { - $this->object->showFailure('allow-denied'); + $this->object->showFailure(AuthenticationFailure::allowDenied()); } catch (ExitException) { } @@ -310,7 +311,7 @@ class AuthenticationSignonTest extends AbstractTestCase $config->settings['LoginCookieValidity'] = '1440'; try { - $this->object->showFailure('no-activity'); + $this->object->showFailure(AuthenticationFailure::noActivity()); } catch (ExitException) { } @@ -347,7 +348,7 @@ class AuthenticationSignonTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; try { - $this->object->showFailure(''); + $this->object->showFailure(AuthenticationFailure::serverDenied()); } catch (ExitException) { } @@ -380,11 +381,11 @@ class AuthenticationSignonTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; try { - $this->object->showFailure(''); + $this->object->showFailure(AuthenticationFailure::serverDenied()); } catch (ExitException) { } - self::assertSame('Cannot log in to the MySQL server', $_SESSION['PMA_single_signon_error_message']); + self::assertSame('Cannot log in to the database server.', $_SESSION['PMA_single_signon_error_message']); } public function testSetCookieParamsDefaults(): void diff --git a/tests/unit/Plugins/AuthenticationPluginTest.php b/tests/unit/Plugins/AuthenticationPluginTest.php index 2a149cb7e7..f06ccd26f1 100644 --- a/tests/unit/Plugins/AuthenticationPluginTest.php +++ b/tests/unit/Plugins/AuthenticationPluginTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Tests\Plugins; use PhpMyAdmin\DatabaseInterface; +use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Http\Factory\ServerRequestFactory; use PhpMyAdmin\Plugins\AuthenticationPlugin; @@ -34,6 +35,11 @@ final class AuthenticationPluginTest extends AbstractTestCase { return false; } + + public function showFailure(AuthenticationFailure $failure): never + { + throw new ExitException(); + } }; $_SESSION['two_factor_check'] = false; From ad98ad27cbb591b72f4b59f3eada7432792ed9ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 9 May 2024 12:58:46 -0300 Subject: [PATCH 2/9] Change AuthenticationPlugin::showFailure() return type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of throwing an ExitException, showFailure() now returns a Response object. Signed-off-by: Maurício Meneghini Fauth --- psalm-baseline.xml | 4 ++++ src/Http/Middleware/Authentication.php | 4 ++-- src/Plugins/Auth/AuthenticationConfig.php | 18 +++++++++++++----- src/Plugins/Auth/AuthenticationCookie.php | 9 +++++---- src/Plugins/Auth/AuthenticationHttp.php | 10 ++++++---- src/Plugins/Auth/AuthenticationSignon.php | 3 ++- src/Plugins/AuthenticationPlugin.php | 3 ++- .../Plugins/Auth/AuthenticationConfigTest.php | 16 ++-------------- .../Plugins/Auth/AuthenticationCookieTest.php | 12 ++++++------ .../Plugins/Auth/AuthenticationHttpTest.php | 14 ++------------ .../unit/Plugins/AuthenticationPluginTest.php | 3 ++- 11 files changed, 46 insertions(+), 50 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 4b925e6f88..1be1667e8f 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -7679,6 +7679,7 @@ + @@ -7768,6 +7769,9 @@ selectedServer]]> selectedServer, $singleSignonCfgUpdate)]]> + + + selectedServer['SignonURL'])]]> diff --git a/src/Http/Middleware/Authentication.php b/src/Http/Middleware/Authentication.php index ffb70422ea..0066889ea5 100644 --- a/src/Http/Middleware/Authentication.php +++ b/src/Http/Middleware/Authentication.php @@ -63,7 +63,7 @@ final class Authentication implements MiddlewareInterface try { $authPlugin->authenticate(); } catch (AuthenticationFailure $exception) { - $authPlugin->showFailure($exception); + return $authPlugin->showFailure($exception); } $currentServer = new Server(Config::getInstance()->selectedServer); @@ -79,7 +79,7 @@ final class Authentication implements MiddlewareInterface try { $this->connectToDatabaseServer(DatabaseInterface::getInstance(), $currentServer); } catch (AuthenticationFailure $exception) { - $authPlugin->showFailure($exception); + return $authPlugin->showFailure($exception); } // Relation should only be initialized after the connection is successful diff --git a/src/Plugins/Auth/AuthenticationConfig.php b/src/Plugins/Auth/AuthenticationConfig.php index d059ef6bd3..dda2df7d07 100644 --- a/src/Plugins/Auth/AuthenticationConfig.php +++ b/src/Plugins/Auth/AuthenticationConfig.php @@ -12,6 +12,7 @@ use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Error\ErrorHandler; use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Html\Generator; +use PhpMyAdmin\Http\Response; use PhpMyAdmin\Plugins\AuthenticationPlugin; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Select; @@ -19,6 +20,8 @@ use PhpMyAdmin\Util; use function __; use function count; +use function ob_get_clean; +use function ob_start; use function sprintf; use function trigger_error; @@ -67,7 +70,7 @@ class AuthenticationConfig extends AuthenticationPlugin /** * User is not allowed to login to MySQL -> authentication failed */ - public function showFailure(AuthenticationFailure $failure): never + public function showFailure(AuthenticationFailure $failure): Response { $this->logFailure($failure); @@ -77,12 +80,14 @@ class AuthenticationConfig extends AuthenticationPlugin } /* HTML header */ - $response = ResponseRenderer::getInstance(); - $response->setMinimalFooter(); - $header = $response->getHeader(); + $responseRenderer = ResponseRenderer::getInstance(); + $responseRenderer->setMinimalFooter(); + $header = $responseRenderer->getHeader(); $header->setBodyId('loginform'); $header->setTitle(__('Access denied!')); $header->disableMenuAndConsole(); + + ob_start(); echo '

'; @@ -157,6 +162,9 @@ class AuthenticationConfig extends AuthenticationPlugin } echo '' , "\n"; - $response->callExit(); + + $responseRenderer->addHTML((string) ob_get_clean()); + + return $responseRenderer->response(); } } diff --git a/src/Plugins/Auth/AuthenticationCookie.php b/src/Plugins/Auth/AuthenticationCookie.php index c8d097ee00..f2ed76e244 100644 --- a/src/Plugins/Auth/AuthenticationCookie.php +++ b/src/Plugins/Auth/AuthenticationCookie.php @@ -13,6 +13,7 @@ use PhpMyAdmin\Current; use PhpMyAdmin\Error\ErrorHandler; use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Exceptions\SessionHandlerException; +use PhpMyAdmin\Http\Response; use PhpMyAdmin\LanguageManager; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins\AuthenticationPlugin; @@ -543,7 +544,7 @@ class AuthenticationCookie extends AuthenticationPlugin * prepares error message and switches to showLoginForm() which display the error * and the login form */ - public function showFailure(AuthenticationFailure $failure): never + public function showFailure(AuthenticationFailure $failure): Response { $this->logFailure($failure); @@ -552,11 +553,11 @@ class AuthenticationCookie extends AuthenticationPlugin $GLOBALS['conn_error'] = $this->getErrorMessage($failure); - $response = ResponseRenderer::getInstance(); + $responseRenderer = ResponseRenderer::getInstance(); // needed for PHP-CGI (not need for FastCGI or mod-php) - $response->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); - $response->addHeader('Pragma', 'no-cache'); + $responseRenderer->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); + $responseRenderer->addHeader('Pragma', 'no-cache'); $this->showLoginForm(); } diff --git a/src/Plugins/Auth/AuthenticationHttp.php b/src/Plugins/Auth/AuthenticationHttp.php index eaf21a43e3..b1195ed2c4 100644 --- a/src/Plugins/Auth/AuthenticationHttp.php +++ b/src/Plugins/Auth/AuthenticationHttp.php @@ -13,6 +13,7 @@ use PhpMyAdmin\Config; use PhpMyAdmin\Core; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Exceptions\AuthenticationFailure; +use PhpMyAdmin\Http\Response; use PhpMyAdmin\LanguageManager; use PhpMyAdmin\Message; use PhpMyAdmin\Plugins\AuthenticationPlugin; @@ -180,19 +181,20 @@ class AuthenticationHttp extends AuthenticationPlugin /** * User is not allowed to login to MySQL -> authentication failed */ - public function showFailure(AuthenticationFailure $failure): never + public function showFailure(AuthenticationFailure $failure): Response { $this->logFailure($failure); $error = DatabaseInterface::getInstance()->getError(); if ($error && $GLOBALS['errno'] != 1045) { - echo $this->template->render('error/generic', [ + $responseRenderer = ResponseRenderer::getInstance(); + $responseRenderer->addHTML($this->template->render('error/generic', [ 'lang' => $GLOBALS['lang'] ?? 'en', 'dir' => LanguageManager::$textDir, 'error_message' => $error, - ]); + ])); - ResponseRenderer::getInstance()->callExit(); + return $responseRenderer->response(); } $this->authForm(); diff --git a/src/Plugins/Auth/AuthenticationSignon.php b/src/Plugins/Auth/AuthenticationSignon.php index bbb8d61e5f..3ea2d0201c 100644 --- a/src/Plugins/Auth/AuthenticationSignon.php +++ b/src/Plugins/Auth/AuthenticationSignon.php @@ -9,6 +9,7 @@ namespace PhpMyAdmin\Plugins\Auth; use PhpMyAdmin\Config; use PhpMyAdmin\Exceptions\AuthenticationFailure; +use PhpMyAdmin\Http\Response; use PhpMyAdmin\LanguageManager; use PhpMyAdmin\Plugins\AuthenticationPlugin; use PhpMyAdmin\ResponseRenderer; @@ -235,7 +236,7 @@ class AuthenticationSignon extends AuthenticationPlugin /** * User is not allowed to login to MySQL -> authentication failed */ - public function showFailure(AuthenticationFailure $failure): never + public function showFailure(AuthenticationFailure $failure): Response { $this->logFailure($failure); diff --git a/src/Plugins/AuthenticationPlugin.php b/src/Plugins/AuthenticationPlugin.php index 3cfc174cec..4174e50b1d 100644 --- a/src/Plugins/AuthenticationPlugin.php +++ b/src/Plugins/AuthenticationPlugin.php @@ -12,6 +12,7 @@ use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Exceptions\SessionHandlerException; +use PhpMyAdmin\Http\Response; use PhpMyAdmin\Http\ServerRequest; use PhpMyAdmin\IpAllowDeny; use PhpMyAdmin\LanguageManager; @@ -97,7 +98,7 @@ abstract class AuthenticationPlugin /** * User is not allowed to login to MySQL -> authentication failed */ - abstract public function showFailure(AuthenticationFailure $failure): never; + abstract public function showFailure(AuthenticationFailure $failure): Response; protected function logFailure(AuthenticationFailure $failure): void { diff --git a/tests/unit/Plugins/Auth/AuthenticationConfigTest.php b/tests/unit/Plugins/Auth/AuthenticationConfigTest.php index fc64aae94c..8e150297fc 100644 --- a/tests/unit/Plugins/Auth/AuthenticationConfigTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationConfigTest.php @@ -15,10 +15,6 @@ use PhpMyAdmin\Tests\AbstractTestCase; use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Medium; use ReflectionProperty; -use Throwable; - -use function ob_get_clean; -use function ob_start; #[CoversClass(AuthenticationConfig::class)] #[Medium] @@ -90,17 +86,9 @@ class AuthenticationConfigTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); - ob_start(); - try { - $this->object->showFailure(AuthenticationFailure::serverDenied()); - } catch (Throwable $throwable) { - } + $response = $this->object->showFailure(AuthenticationFailure::serverDenied()); - $html = ob_get_clean(); - - self::assertInstanceOf(ExitException::class, $throwable); - - self::assertIsString($html); + $html = (string) $response->getBody(); self::assertStringContainsString( 'You probably did not create a configuration file. You might want ' . diff --git a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php index 8ea4dfb3d7..c5eefdbecb 100644 --- a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php @@ -552,7 +552,7 @@ class AuthenticationCookieTest extends AbstractTestCase // mock for blowfish function $this->object = $this->getMockBuilder(AuthenticationCookie::class) ->disableOriginalConstructor() - ->onlyMethods(['showFailure', 'cookieDecrypt']) + ->onlyMethods(['cookieDecrypt']) ->getMock(); $this->object->expects(self::once()) @@ -639,7 +639,7 @@ class AuthenticationCookieTest extends AbstractTestCase } catch (Throwable $throwable) { } - self::assertInstanceOf(ExitException::class, $throwable); + self::assertInstanceOf(ExitException::class, $throwable ?? null); $response = $responseStub->getResponse(); self::assertSame(['no-store, no-cache, must-revalidate'], $response->getHeader('Cache-Control')); self::assertSame(['no-cache'], $response->getHeader('Pragma')); @@ -707,7 +707,7 @@ class AuthenticationCookieTest extends AbstractTestCase } catch (Throwable $throwable) { } - self::assertInstanceOf(ExitException::class, $throwable); + self::assertInstanceOf(ExitException::class, $throwable ?? null); $response = $responseStub->getResponse(); self::assertSame(['no-store, no-cache, must-revalidate'], $response->getHeader('Cache-Control')); self::assertSame(['no-cache'], $response->getHeader('Pragma')); @@ -739,7 +739,7 @@ class AuthenticationCookieTest extends AbstractTestCase } catch (Throwable $throwable) { } - self::assertInstanceOf(ExitException::class, $throwable); + self::assertInstanceOf(ExitException::class, $throwable ?? null); $response = $responseStub->getResponse(); self::assertSame(['no-store, no-cache, must-revalidate'], $response->getHeader('Cache-Control')); self::assertSame(['no-cache'], $response->getHeader('Pragma')); @@ -784,7 +784,7 @@ class AuthenticationCookieTest extends AbstractTestCase } catch (Throwable $throwable) { } - self::assertInstanceOf(ExitException::class, $throwable); + self::assertInstanceOf(ExitException::class, $throwable ?? null); $response = $responseStub->getResponse(); self::assertSame(['no-store, no-cache, must-revalidate'], $response->getHeader('Cache-Control')); self::assertSame(['no-cache'], $response->getHeader('Pragma')); @@ -825,7 +825,7 @@ class AuthenticationCookieTest extends AbstractTestCase } catch (Throwable $throwable) { } - self::assertInstanceOf(ExitException::class, $throwable); + self::assertInstanceOf(ExitException::class, $throwable ?? null); $response = $responseStub->getResponse(); self::assertSame(['no-store, no-cache, must-revalidate'], $response->getHeader('Cache-Control')); self::assertSame(['no-cache'], $response->getHeader('Pragma')); diff --git a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php index 4ce58da1b7..219453f751 100644 --- a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php @@ -20,8 +20,6 @@ use ReflectionProperty; use Throwable; use function base64_encode; -use function ob_get_clean; -use function ob_start; #[CoversClass(AuthenticationHttp::class)] #[Medium] @@ -285,17 +283,9 @@ class AuthenticationHttpTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; $GLOBALS['errno'] = 31; - ob_start(); - try { - $this->object->showFailure(AuthenticationFailure::serverDenied()); - } catch (Throwable $throwable) { - } + $response = $this->object->showFailure(AuthenticationFailure::serverDenied()); - $result = ob_get_clean(); - - self::assertInstanceOf(ExitException::class, $throwable); - - self::assertIsString($result); + $result = (string) $response->getBody(); self::assertStringContainsString('

error 123

', $result); diff --git a/tests/unit/Plugins/AuthenticationPluginTest.php b/tests/unit/Plugins/AuthenticationPluginTest.php index f06ccd26f1..5c575b35ee 100644 --- a/tests/unit/Plugins/AuthenticationPluginTest.php +++ b/tests/unit/Plugins/AuthenticationPluginTest.php @@ -8,6 +8,7 @@ use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Exceptions\AuthenticationFailure; use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Http\Factory\ServerRequestFactory; +use PhpMyAdmin\Http\Response; use PhpMyAdmin\Plugins\AuthenticationPlugin; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Tests\AbstractTestCase; @@ -36,7 +37,7 @@ final class AuthenticationPluginTest extends AbstractTestCase return false; } - public function showFailure(AuthenticationFailure $failure): never + public function showFailure(AuthenticationFailure $failure): Response { throw new ExitException(); } From aa70f48537fb6ee8e74f37b1773ff5e0fc8a37c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 9 May 2024 13:10:17 -0300 Subject: [PATCH 3/9] Remove callExit() from AuthenticationPlugin::authenticate() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- src/Http/Middleware/Authentication.php | 5 ++++- src/Plugins/AuthenticationPlugin.php | 6 ++++-- tests/unit/Plugins/Auth/AuthenticationCookieTest.php | 3 ++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/Http/Middleware/Authentication.php b/src/Http/Middleware/Authentication.php index 0066889ea5..e2413027cd 100644 --- a/src/Http/Middleware/Authentication.php +++ b/src/Http/Middleware/Authentication.php @@ -61,7 +61,10 @@ final class Authentication implements MiddlewareInterface try { try { - $authPlugin->authenticate(); + $response = $authPlugin->authenticate(); + if ($response !== null) { + return $response; + } } catch (AuthenticationFailure $exception) { return $authPlugin->showFailure($exception); } diff --git a/src/Plugins/AuthenticationPlugin.php b/src/Plugins/AuthenticationPlugin.php index 4174e50b1d..a803c005c5 100644 --- a/src/Plugins/AuthenticationPlugin.php +++ b/src/Plugins/AuthenticationPlugin.php @@ -229,7 +229,7 @@ abstract class AuthenticationPlugin * * @throws AuthenticationFailure */ - public function authenticate(): void + public function authenticate(): Response|null { $success = $this->readCredentials(); @@ -246,7 +246,7 @@ abstract class AuthenticationPlugin 'error_message' => $exception->getMessage(), ])); - $responseRenderer->callExit(); + return $responseRenderer->response(); } $this->showLoginForm(); @@ -258,6 +258,8 @@ abstract class AuthenticationPlugin $this->checkRules(); /* clear user cache */ Util::clearUserCache(); + + return null; } /** diff --git a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php index c5eefdbecb..46ae623566 100644 --- a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php @@ -933,9 +933,10 @@ class AuthenticationCookieTest extends AbstractTestCase $_POST['pma_password'] = 'testPassword'; ob_start(); - $this->object->authenticate(); + $response = $this->object->authenticate(); $result = ob_get_clean(); + self::assertNull($response); /* Nothing should be printed */ self::assertSame('', $result); From d0121dcf5de25d2aabb0112684e041ab98ad7d26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 9 May 2024 14:31:19 -0300 Subject: [PATCH 4/9] Remove callExit() from AuthenticationPlugin::showLoginForm() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- src/Plugins/Auth/AuthenticationConfig.php | 15 ++--- src/Plugins/Auth/AuthenticationCookie.php | 20 +++---- src/Plugins/Auth/AuthenticationHttp.php | 13 +++-- src/Plugins/Auth/AuthenticationSignon.php | 20 +++---- src/Plugins/AuthenticationPlugin.php | 7 ++- .../Plugins/Auth/AuthenticationConfigTest.php | 22 +++++-- .../Plugins/Auth/AuthenticationCookieTest.php | 57 +++++++------------ .../Plugins/Auth/AuthenticationHttpTest.php | 25 +++++++- .../Plugins/Auth/AuthenticationSignonTest.php | 19 +------ .../unit/Plugins/AuthenticationPluginTest.php | 3 +- 10 files changed, 105 insertions(+), 96 deletions(-) diff --git a/src/Plugins/Auth/AuthenticationConfig.php b/src/Plugins/Auth/AuthenticationConfig.php index dda2df7d07..8bb09392cc 100644 --- a/src/Plugins/Auth/AuthenticationConfig.php +++ b/src/Plugins/Auth/AuthenticationConfig.php @@ -36,17 +36,18 @@ class AuthenticationConfig extends AuthenticationPlugin /** * Displays authentication form */ - public function showLoginForm(): void + public function showLoginForm(): Response|null { - $response = ResponseRenderer::getInstance(); - if (! $response->isAjax()) { - return; + $responseRenderer = ResponseRenderer::getInstance(); + if (! $responseRenderer->isAjax()) { + return null; } - $response->setRequestStatus(false); + $responseRenderer->setRequestStatus(false); // reload_flag removes the token parameter from the URL and reloads - $response->addJSON('reload_flag', '1'); - $response->callExit(); + $responseRenderer->addJSON('reload_flag', '1'); + + return $responseRenderer->response(); } /** diff --git a/src/Plugins/Auth/AuthenticationCookie.php b/src/Plugins/Auth/AuthenticationCookie.php index f2ed76e244..bfc891e3b5 100644 --- a/src/Plugins/Auth/AuthenticationCookie.php +++ b/src/Plugins/Auth/AuthenticationCookie.php @@ -65,11 +65,11 @@ class AuthenticationCookie extends AuthenticationPlugin * * @global string $conn_error the last connection error */ - public function showLoginForm(): never + public function showLoginForm(): Response { $GLOBALS['conn_error'] ??= null; - $response = ResponseRenderer::getInstance(); + $responseRenderer = ResponseRenderer::getInstance(); /** * When sending login modal after session has expired, send the @@ -77,8 +77,8 @@ class AuthenticationCookie extends AuthenticationPlugin * in all the forms having a hidden token. */ $sessionExpired = isset($_REQUEST['check_timeout']) || isset($_REQUEST['session_timedout']); - if (! $sessionExpired && $response->loginPage()) { - $response->callExit(); + if (! $sessionExpired && $responseRenderer->loginPage()) { + return $responseRenderer->response(); } /** @@ -87,8 +87,8 @@ class AuthenticationCookie extends AuthenticationPlugin * in all the forms having a hidden token. */ if ($sessionExpired) { - $response->setRequestStatus(false); - $response->addJSON('new_token', $_SESSION[' PMA_token ']); + $responseRenderer->setRequestStatus(false); + $responseRenderer->addJSON('new_token', $_SESSION[' PMA_token ']); } /** @@ -96,7 +96,7 @@ class AuthenticationCookie extends AuthenticationPlugin * using the modal was successful after session expiration. */ if (isset($_REQUEST['session_timedout'])) { - $response->addJSON('logged_in', 0); + $responseRenderer->addJSON('logged_in', 0); } $config = Config::getInstance(); @@ -161,7 +161,7 @@ class AuthenticationCookie extends AuthenticationPlugin $configFooter = Config::renderFooter(); - $response->addHTML($this->template->render('login/form', [ + $responseRenderer->addHTML($this->template->render('login/form', [ 'login_header' => $loginHeader, 'is_demo' => $config->config->debug->demo, 'error_messages' => $errorMessages, @@ -192,7 +192,7 @@ class AuthenticationCookie extends AuthenticationPlugin 'config_footer' => $configFooter, ])); - $response->callExit(); + return $responseRenderer->response(); } /** @@ -559,7 +559,7 @@ class AuthenticationCookie extends AuthenticationPlugin $responseRenderer->addHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); $responseRenderer->addHeader('Pragma', 'no-cache'); - $this->showLoginForm(); + return $this->showLoginForm(); } /** diff --git a/src/Plugins/Auth/AuthenticationHttp.php b/src/Plugins/Auth/AuthenticationHttp.php index b1195ed2c4..e43ebf56a8 100644 --- a/src/Plugins/Auth/AuthenticationHttp.php +++ b/src/Plugins/Auth/AuthenticationHttp.php @@ -36,14 +36,15 @@ class AuthenticationHttp extends AuthenticationPlugin /** * Displays authentication form and redirect as necessary */ - public function showLoginForm(): never + public function showLoginForm(): Response { - $response = ResponseRenderer::getInstance(); - if ($response->isAjax()) { - $response->setRequestStatus(false); + $responseRenderer = ResponseRenderer::getInstance(); + if ($responseRenderer->isAjax()) { + $responseRenderer->setRequestStatus(false); // reload_flag removes the token parameter from the URL and reloads - $response->addJSON('reload_flag', '1'); - $response->callExit(); + $responseRenderer->addJSON('reload_flag', '1'); + + return $responseRenderer->response(); } $this->authForm(); diff --git a/src/Plugins/Auth/AuthenticationSignon.php b/src/Plugins/Auth/AuthenticationSignon.php index 3ea2d0201c..22f02c7cf6 100644 --- a/src/Plugins/Auth/AuthenticationSignon.php +++ b/src/Plugins/Auth/AuthenticationSignon.php @@ -35,25 +35,25 @@ class AuthenticationSignon extends AuthenticationPlugin /** * Displays authentication form */ - public function showLoginForm(): never + public function showLoginForm(): Response { - $response = ResponseRenderer::getInstance(); - $response->disable(); + $responseRenderer = ResponseRenderer::getInstance(); + $responseRenderer->disable(); unset($_SESSION['LAST_SIGNON_URL']); $config = Config::getInstance(); if (empty($config->selectedServer['SignonURL'])) { - echo $this->template->render('error/generic', [ + $responseRenderer->addHTML($this->template->render('error/generic', [ 'lang' => $GLOBALS['lang'] ?? 'en', 'dir' => LanguageManager::$textDir, 'error_message' => 'You must set SignonURL!', - ]); + ])); - $response->callExit(); - } else { - $response->redirect($config->selectedServer['SignonURL']); + return $responseRenderer->response(); } - $response->callExit(); + $responseRenderer->redirect($config->selectedServer['SignonURL']); + + return $responseRenderer->response(); } /** @@ -260,7 +260,7 @@ class AuthenticationSignon extends AuthenticationPlugin $_SESSION['PMA_single_signon_error_message'] = $this->getErrorMessage($failure); } - $this->showLoginForm(); + return $this->showLoginForm(); } /** diff --git a/src/Plugins/AuthenticationPlugin.php b/src/Plugins/AuthenticationPlugin.php index a803c005c5..10a1c2293b 100644 --- a/src/Plugins/AuthenticationPlugin.php +++ b/src/Plugins/AuthenticationPlugin.php @@ -65,7 +65,7 @@ abstract class AuthenticationPlugin /** * Displays authentication form */ - abstract public function showLoginForm(): void; + abstract public function showLoginForm(): Response|null; /** * Gets authentication credentials @@ -249,7 +249,10 @@ abstract class AuthenticationPlugin return $responseRenderer->response(); } - $this->showLoginForm(); + $response = $this->showLoginForm(); + if ($response !== null) { + return $response; + } } /* Store credentials (eg. in cookies) */ diff --git a/tests/unit/Plugins/Auth/AuthenticationConfigTest.php b/tests/unit/Plugins/Auth/AuthenticationConfigTest.php index 8e150297fc..ccbdc913c1 100644 --- a/tests/unit/Plugins/Auth/AuthenticationConfigTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationConfigTest.php @@ -8,7 +8,6 @@ use PhpMyAdmin\Config; use PhpMyAdmin\Current; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Exceptions\AuthenticationFailure; -use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Plugins\Auth\AuthenticationConfig; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Tests\AbstractTestCase; @@ -16,6 +15,8 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\Medium; use ReflectionProperty; +use function json_decode; + #[CoversClass(AuthenticationConfig::class)] #[Medium] class AuthenticationConfigTest extends AbstractTestCase @@ -52,12 +53,25 @@ class AuthenticationConfigTest extends AbstractTestCase unset($this->object); } - public function testAuth(): void + public function testShowLoginFormWithoutAjax(): void + { + (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); + ResponseRenderer::getInstance()->setAjax(false); + self::assertNull($this->object->showLoginForm()); + } + + public function testShowLoginFormWithAjax(): void { (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); ResponseRenderer::getInstance()->setAjax(true); - $this->expectException(ExitException::class); - $this->object->showLoginForm(); + $response = $this->object->showLoginForm(); + self::assertNotNull($response); + $body = (string) $response->getBody(); + self::assertJson($body); + $json = json_decode($body, true); + self::assertIsArray($json); + self::assertArrayHasKey('reload_flag', $json); + self::assertSame('1', $json['reload_flag']); } public function testAuthCheck(): void diff --git a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php index 46ae623566..c5319e617f 100644 --- a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace PhpMyAdmin\Tests\Plugins\Auth; +use Fig\Http\Message\StatusCodeInterface; use PhpMyAdmin\Config; use PhpMyAdmin\Current; use PhpMyAdmin\DatabaseInterface; @@ -24,6 +25,7 @@ use Throwable; use function base64_decode; use function base64_encode; use function is_readable; +use function json_decode; use function json_encode; use function mb_strlen; use function ob_get_clean; @@ -76,20 +78,21 @@ class AuthenticationCookieTest extends AbstractTestCase { $GLOBALS['conn_error'] = true; - $responseStub = new ResponseRendererStub(); - $responseStub->setAjax(true); - (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); + (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); + $responseRenderer = ResponseRenderer::getInstance(); + $responseRenderer->setAjax(true); - try { - $this->object->showLoginForm(); - } catch (Throwable $throwable) { - } + $response = $this->object->showLoginForm(); - self::assertInstanceOf(ExitException::class, $throwable); - $response = $responseStub->getResponse(); - self::assertSame(200, $response->getStatusCode()); - self::assertFalse($responseStub->hasSuccessState()); - self::assertSame(['redirect_flag' => '1'], $responseStub->getJSONResult()); + self::assertSame(StatusCodeInterface::STATUS_OK, $response->getStatusCode()); + $body = (string) $response->getBody(); + self::assertJson($body); + $json = json_decode($body, true); + self::assertIsArray($json); + self::assertArrayHasKey('success', $json); + self::assertFalse($json['success']); + self::assertArrayHasKey('redirect_flag', $json); + self::assertSame('1', $json['redirect_flag']); } public function testAuthError(): void @@ -115,17 +118,9 @@ class AuthenticationCookieTest extends AbstractTestCase Current::$table = 'testTable'; $config->settings['Servers'] = [1, 2]; - $responseStub = new ResponseRendererStub(); - (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); + $response = $this->object->showLoginForm(); - try { - $this->object->showLoginForm(); - } catch (Throwable $throwable) { - } - - $result = $responseStub->getHTMLResult(); - - self::assertInstanceOf(ExitException::class, $throwable); + $result = (string) $response->getBody(); self::assertStringContainsString(' id="imLogo"', $result); @@ -185,14 +180,9 @@ class AuthenticationCookieTest extends AbstractTestCase $responseStub = new ResponseRendererStub(); (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); - try { - $this->object->showLoginForm(); - } catch (Throwable $throwable) { - } + $response = $this->object->showLoginForm(); - $result = $responseStub->getHTMLResult(); - - self::assertInstanceOf(ExitException::class, $throwable); + $result = (string) $response->getBody(); self::assertStringContainsString('id="imLogo"', $result); @@ -246,14 +236,9 @@ class AuthenticationCookieTest extends AbstractTestCase $responseStub = new ResponseRendererStub(); (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); - try { - $this->object->showLoginForm(); - } catch (Throwable $throwable) { - } + $response = $this->object->showLoginForm(); - $result = $responseStub->getHTMLResult(); - - self::assertInstanceOf(ExitException::class, $throwable); + $result = (string) $response->getBody(); self::assertStringContainsString('id="imLogo"', $result); diff --git a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php index 219453f751..2616563553 100644 --- a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php @@ -20,6 +20,7 @@ use ReflectionProperty; use Throwable; use function base64_encode; +use function json_decode; #[CoversClass(AuthenticationHttp::class)] #[Medium] @@ -86,7 +87,7 @@ class AuthenticationHttpTest extends AbstractTestCase } catch (Throwable $throwable) { } - self::assertInstanceOf(ExitException::class, $throwable); + self::assertInstanceOf(ExitException::class, $throwable ?? null); $response = $responseStub->getResponse(); self::assertSame(['Basic realm="phpMyAdmin verboseMessag"'], $response->getHeader('WWW-Authenticate')); self::assertSame(401, $response->getStatusCode()); @@ -107,7 +108,7 @@ class AuthenticationHttpTest extends AbstractTestCase } catch (Throwable $throwable) { } - self::assertInstanceOf(ExitException::class, $throwable); + self::assertInstanceOf(ExitException::class, $throwable ?? null); $response = $responseStub->getResponse(); self::assertSame(['Basic realm="phpMyAdmin hst"'], $response->getHeader('WWW-Authenticate')); self::assertSame(401, $response->getStatusCode()); @@ -128,7 +129,7 @@ class AuthenticationHttpTest extends AbstractTestCase } catch (Throwable $throwable) { } - self::assertInstanceOf(ExitException::class, $throwable); + self::assertInstanceOf(ExitException::class, $throwable ?? null); $response = $responseStub->getResponse(); self::assertSame(['Basic realm="realmmessage"'], $response->getHeader('WWW-Authenticate')); self::assertSame(401, $response->getStatusCode()); @@ -270,6 +271,8 @@ class AuthenticationHttpTest extends AbstractTestCase $config = Config::getInstance(); $config->selectedServer['host'] = ''; $_REQUEST = []; + Current::$server = 0; + (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); ResponseRenderer::getInstance()->setAjax(false); $dbi = $this->getMockBuilder(DatabaseInterface::class) @@ -311,4 +314,20 @@ class AuthenticationHttpTest extends AbstractTestCase $this->expectException(ExitException::class); $this->object->showFailure(AuthenticationFailure::serverDenied()); } + + public function testShowLoginFormWithAjax(): void + { + Current::$database = ''; + Current::$table = ''; + (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); + ResponseRenderer::getInstance()->setAjax(true); + $response = (new AuthenticationHttp())->showLoginForm(); + + $body = (string) $response->getBody(); + self::assertJson($body); + $json = json_decode($body, true); + self::assertIsArray($json); + self::assertArrayHasKey('reload_flag', $json); + self::assertSame('1', $json['reload_flag']); + } } diff --git a/tests/unit/Plugins/Auth/AuthenticationSignonTest.php b/tests/unit/Plugins/Auth/AuthenticationSignonTest.php index 51f4a8bf68..18230342e4 100644 --- a/tests/unit/Plugins/Auth/AuthenticationSignonTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationSignonTest.php @@ -16,10 +16,7 @@ use PhpMyAdmin\Tests\AbstractTestCase; use PhpMyAdmin\Tests\Stubs\ResponseRenderer as ResponseRendererStub; use PHPUnit\Framework\Attributes\CoversClass; use ReflectionProperty; -use Throwable; -use function ob_get_clean; -use function ob_start; use function session_get_cookie_params; use function session_id; use function session_name; @@ -62,20 +59,8 @@ class AuthenticationSignonTest extends AbstractTestCase Config::getInstance()->selectedServer['SignonURL'] = ''; $_REQUEST = []; ResponseRenderer::getInstance()->setAjax(false); - - ob_start(); - try { - $this->object->showLoginForm(); - } catch (Throwable $throwable) { - } - - $result = ob_get_clean(); - - self::assertInstanceOf(ExitException::class, $throwable); - - self::assertIsString($result); - - self::assertStringContainsString('You must set SignonURL!', $result); + $response = $this->object->showLoginForm(); + self::assertStringContainsString('You must set SignonURL!', (string) $response->getBody()); } public function testAuthLogoutURL(): void diff --git a/tests/unit/Plugins/AuthenticationPluginTest.php b/tests/unit/Plugins/AuthenticationPluginTest.php index 5c575b35ee..8fe6c0f9b9 100644 --- a/tests/unit/Plugins/AuthenticationPluginTest.php +++ b/tests/unit/Plugins/AuthenticationPluginTest.php @@ -28,8 +28,9 @@ final class AuthenticationPluginTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; $object = new class extends AuthenticationPlugin { - public function showLoginForm(): void + public function showLoginForm(): Response|null { + return null; } public function readCredentials(): bool From 70757ceede8c1e99da2b7d0c93f8b30240ab0bcc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 9 May 2024 14:59:58 -0300 Subject: [PATCH 5/9] Remove callExit() from AuthenticationCookie::rememberCredentials() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- psalm-baseline.xml | 1 + src/Http/Middleware/Authentication.php | 6 ++++- src/Plugins/Auth/AuthenticationCookie.php | 22 +++++++++---------- src/Plugins/AuthenticationPlugin.php | 3 ++- .../Plugins/Auth/AuthenticationCookieTest.php | 10 +++++++-- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 1be1667e8f..609ae7e1a3 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -14333,6 +14333,7 @@ settings]]> settings]]> settings]]> + settings]]> diff --git a/src/Http/Middleware/Authentication.php b/src/Http/Middleware/Authentication.php index e2413027cd..b6caa0f85d 100644 --- a/src/Http/Middleware/Authentication.php +++ b/src/Http/Middleware/Authentication.php @@ -93,7 +93,11 @@ final class Authentication implements MiddlewareInterface // Tracker can only be activated after the relation has been initialized Tracker::enable(); - $authPlugin->rememberCredentials(); + $response = $authPlugin->rememberCredentials(); + if ($response !== null) { + return $response; + } + assert($request instanceof ServerRequest); $authPlugin->checkTwoFactor($request); } catch (ExitException) { diff --git a/src/Plugins/Auth/AuthenticationCookie.php b/src/Plugins/Auth/AuthenticationCookie.php index bfc891e3b5..879fd587ba 100644 --- a/src/Plugins/Auth/AuthenticationCookie.php +++ b/src/Plugins/Auth/AuthenticationCookie.php @@ -444,7 +444,7 @@ class AuthenticationCookie extends AuthenticationPlugin /** * Stores user credentials after successful login. */ - public function rememberCredentials(): void + public function rememberCredentials(): Response|null { // Name and password cookies need to be refreshed each time // Duration = one month for username @@ -469,18 +469,18 @@ class AuthenticationCookie extends AuthenticationPlugin // user logged in successfully after session expiration if (isset($_REQUEST['session_timedout'])) { - $response = ResponseRenderer::getInstance(); - $response->addJSON('logged_in', 1); - $response->addJSON('success', 1); - $response->addJSON('new_token', $_SESSION[' PMA_token ']); + $responseRenderer = ResponseRenderer::getInstance(); + $responseRenderer->addJSON('logged_in', 1); + $responseRenderer->addJSON('success', 1); + $responseRenderer->addJSON('new_token', $_SESSION[' PMA_token ']); - $response->callExit(); + return $responseRenderer->response(); } // Set server cookies if required (once per session) and, in this case, // force reload to ensure the client accepts cookies if ($GLOBALS['from_cookie']) { - return; + return null; } /** @@ -488,11 +488,11 @@ class AuthenticationCookie extends AuthenticationPlugin */ Util::clearUserCache(); - $response = ResponseRenderer::getInstance(); - $response->disable(); - $response->redirect('./index.php?route=/' . Url::getCommonRaw($urlParams, '&')); + $responseRenderer = ResponseRenderer::getInstance(); + $responseRenderer->disable(); + $responseRenderer->redirect('./index.php?route=/' . Url::getCommonRaw($urlParams, '&')); - $response->callExit(); + return $responseRenderer->response(); } /** diff --git a/src/Plugins/AuthenticationPlugin.php b/src/Plugins/AuthenticationPlugin.php index 10a1c2293b..5eea357f07 100644 --- a/src/Plugins/AuthenticationPlugin.php +++ b/src/Plugins/AuthenticationPlugin.php @@ -91,8 +91,9 @@ abstract class AuthenticationPlugin /** * Stores user credentials after successful login. */ - public function rememberCredentials(): void + public function rememberCredentials(): Response|null { + return null; } /** diff --git a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php index c5319e617f..436d3eeddf 100644 --- a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php @@ -590,6 +590,7 @@ class AuthenticationCookieTest extends AbstractTestCase $config->selectedServer['user'] = 'pmaUser'; $config->settings['Servers'][1] = $arr; $config->settings['AllowArbitraryServer'] = true; + $config->settings['PmaAbsoluteUri'] = 'http://localhost/phpmyadmin'; $GLOBALS['pma_auth_server'] = 'b 2'; $this->object->password = 'testPW'; $config->settings['LoginCookieStore'] = 100; @@ -599,8 +600,13 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); $this->object->storeCredentials(); - $this->expectException(ExitException::class); - $this->object->rememberCredentials(); + $response = $this->object->rememberCredentials(); + self::assertNotNull($response); + self::assertSame(StatusCodeInterface::STATUS_FOUND, $response->getStatusCode()); + self::assertStringEndsWith( + '/phpmyadmin/index.php?route=/&db=db&table=table&lang=en', + $response->getHeaderLine('Location'), + ); } public function testAuthFailsNoPass(): void From 02044f216090949fcedc82082720422bc1ec77b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 9 May 2024 15:13:17 -0300 Subject: [PATCH 6/9] Remove callExit() from AuthenticationPlugin::checkTwoFactor() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- src/Http/Middleware/Authentication.php | 5 +++- src/Plugins/AuthenticationPlugin.php | 29 +++++++++---------- .../unit/Plugins/AuthenticationPluginTest.php | 7 ++--- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/Http/Middleware/Authentication.php b/src/Http/Middleware/Authentication.php index b6caa0f85d..c3eb54eba1 100644 --- a/src/Http/Middleware/Authentication.php +++ b/src/Http/Middleware/Authentication.php @@ -99,7 +99,10 @@ final class Authentication implements MiddlewareInterface } assert($request instanceof ServerRequest); - $authPlugin->checkTwoFactor($request); + $response = $authPlugin->checkTwoFactor($request); + if ($response !== null) { + return $response; + } } catch (ExitException) { return ResponseRenderer::getInstance()->response(); } diff --git a/src/Plugins/AuthenticationPlugin.php b/src/Plugins/AuthenticationPlugin.php index 5eea357f07..d7bc2c4140 100644 --- a/src/Plugins/AuthenticationPlugin.php +++ b/src/Plugins/AuthenticationPlugin.php @@ -10,7 +10,6 @@ namespace PhpMyAdmin\Plugins; use PhpMyAdmin\Config; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Exceptions\AuthenticationFailure; -use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Exceptions\SessionHandlerException; use PhpMyAdmin\Http\Response; use PhpMyAdmin\Http\ServerRequest; @@ -306,35 +305,33 @@ abstract class AuthenticationPlugin } /** - * Checks whether two factor authentication is active - * for given user and performs it. - * - * @throws ExitException + * Checks whether two-factor authentication is active for given user and performs it. */ - public function checkTwoFactor(ServerRequest $request): void + public function checkTwoFactor(ServerRequest $request): Response|null { $twofactor = new TwoFactor($this->user); /* Do we need to show the form? */ if ($twofactor->check($request)) { - return; + return null; } - $response = ResponseRenderer::getInstance(); - if ($response->loginPage()) { - $response->callExit(); + $responseRenderer = ResponseRenderer::getInstance(); + if ($responseRenderer->loginPage()) { + return $responseRenderer->response(); } - $response->addHTML($this->template->render('login/header', ['session_expired' => false])); - $response->addHTML(Message::rawNotice( + $responseRenderer->addHTML($this->template->render('login/header', ['session_expired' => false])); + $responseRenderer->addHTML(Message::rawNotice( __('You have enabled two factor authentication, please confirm your login.'), )->getDisplay()); - $response->addHTML($this->template->render('login/twofactor', [ + $responseRenderer->addHTML($this->template->render('login/twofactor', [ 'form' => $twofactor->render($request), 'show_submit' => $twofactor->showSubmit(), ])); - $response->addHTML($this->template->render('login/footer')); - $response->addHTML(Config::renderFooter()); - $response->callExit(); + $responseRenderer->addHTML($this->template->render('login/footer')); + $responseRenderer->addHTML(Config::renderFooter()); + + return $responseRenderer->response(); } } diff --git a/tests/unit/Plugins/AuthenticationPluginTest.php b/tests/unit/Plugins/AuthenticationPluginTest.php index 8fe6c0f9b9..6d52611872 100644 --- a/tests/unit/Plugins/AuthenticationPluginTest.php +++ b/tests/unit/Plugins/AuthenticationPluginTest.php @@ -53,12 +53,9 @@ final class AuthenticationPluginTest extends AbstractTestCase $request = ServerRequestFactory::create()->createServerRequest('GET', 'http://example.com/'); $object->user = 'test_user'; - try { - $object->checkTwoFactor($request); - } catch (ExitException) { - } + $response = $object->checkTwoFactor($request); - $response = $responseRenderer->response(); + self::assertNotNull($response); self::assertStringContainsString( 'You have enabled two factor authentication, please confirm your login.', (string) $response->getBody(), From e435bb7129f5520c2bb4b49463f136d8feecd397 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 9 May 2024 15:32:46 -0300 Subject: [PATCH 7/9] Remove callExit() from AuthenticationHttp::authForm() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- src/Plugins/Auth/AuthenticationHttp.php | 8 +-- .../Plugins/Auth/AuthenticationCookieTest.php | 2 + .../Plugins/Auth/AuthenticationHttpTest.php | 53 +++++++------------ 3 files changed, 24 insertions(+), 39 deletions(-) diff --git a/src/Plugins/Auth/AuthenticationHttp.php b/src/Plugins/Auth/AuthenticationHttp.php index e43ebf56a8..5fe1e95c9b 100644 --- a/src/Plugins/Auth/AuthenticationHttp.php +++ b/src/Plugins/Auth/AuthenticationHttp.php @@ -47,13 +47,13 @@ class AuthenticationHttp extends AuthenticationPlugin return $responseRenderer->response(); } - $this->authForm(); + return $this->authForm(); } /** * Displays authentication form */ - public function authForm(): never + public function authForm(): Response { $config = Config::getInstance(); if (empty($config->selectedServer['auth_http_realm'])) { @@ -95,7 +95,7 @@ class AuthenticationHttp extends AuthenticationPlugin $response->addHTML(Config::renderFooter()); - $response->callExit(); + return $response->response(); } /** @@ -198,7 +198,7 @@ class AuthenticationHttp extends AuthenticationPlugin return $responseRenderer->response(); } - $this->authForm(); + return $this->authForm(); } /** diff --git a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php index 436d3eeddf..01098be2cc 100644 --- a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php @@ -118,6 +118,8 @@ class AuthenticationCookieTest extends AbstractTestCase Current::$table = 'testTable'; $config->settings['Servers'] = [1, 2]; + (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); + $response = $this->object->showLoginForm(); $result = (string) $response->getBody(); diff --git a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php index 2616563553..d9c2e44081 100644 --- a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php @@ -8,7 +8,6 @@ use PhpMyAdmin\Config; use PhpMyAdmin\Current; use PhpMyAdmin\DatabaseInterface; use PhpMyAdmin\Exceptions\AuthenticationFailure; -use PhpMyAdmin\Exceptions\ExitException; use PhpMyAdmin\Plugins\Auth\AuthenticationHttp; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Tests\AbstractTestCase; @@ -17,7 +16,6 @@ use PHPUnit\Framework\Attributes\CoversClass; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Medium; use ReflectionProperty; -use Throwable; use function base64_encode; use function json_decode; @@ -82,13 +80,8 @@ class AuthenticationHttpTest extends AbstractTestCase $responseStub = new ResponseRendererStub(); (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); - try { - $this->object->showLoginForm(); - } catch (Throwable $throwable) { - } + $response = $this->object->showLoginForm(); - self::assertInstanceOf(ExitException::class, $throwable ?? null); - $response = $responseStub->getResponse(); self::assertSame(['Basic realm="phpMyAdmin verboseMessag"'], $response->getHeader('WWW-Authenticate')); self::assertSame(401, $response->getStatusCode()); } @@ -103,13 +96,8 @@ class AuthenticationHttpTest extends AbstractTestCase $responseStub = new ResponseRendererStub(); (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); - try { - $this->object->showLoginForm(); - } catch (Throwable $throwable) { - } + $response = $this->object->showLoginForm(); - self::assertInstanceOf(ExitException::class, $throwable ?? null); - $response = $responseStub->getResponse(); self::assertSame(['Basic realm="phpMyAdmin hst"'], $response->getHeader('WWW-Authenticate')); self::assertSame(401, $response->getStatusCode()); } @@ -124,13 +112,8 @@ class AuthenticationHttpTest extends AbstractTestCase $responseStub = new ResponseRendererStub(); (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); - try { - $this->object->showLoginForm(); - } catch (Throwable $throwable) { - } + $response = $this->object->showLoginForm(); - self::assertInstanceOf(ExitException::class, $throwable ?? null); - $response = $responseStub->getResponse(); self::assertSame(['Basic realm="realmmessage"'], $response->getHeader('WWW-Authenticate')); self::assertSame(401, $response->getStatusCode()); } @@ -286,33 +269,33 @@ class AuthenticationHttpTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; $GLOBALS['errno'] = 31; + (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); + ResponseRenderer::getInstance()->setAjax(false); + $response = $this->object->showFailure(AuthenticationFailure::serverDenied()); $result = (string) $response->getBody(); - self::assertStringContainsString('

error 123

', $result); - $this->object = $this->getMockBuilder(AuthenticationHttp::class) - ->disableOriginalConstructor() - ->onlyMethods(['authForm']) - ->getMock(); - - $this->object->expects(self::exactly(2)) - ->method('authForm') - ->willThrowException(new ExitException()); // case 2 $config->selectedServer['host'] = 'host'; $GLOBALS['errno'] = 1045; - try { - $this->object->showFailure(AuthenticationFailure::serverDenied()); - } catch (ExitException) { - } + (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); + ResponseRenderer::getInstance()->setAjax(false); + + $response = $this->object->showFailure(AuthenticationFailure::serverDenied()); + $result = (string) $response->getBody(); + self::assertStringContainsString('Wrong username/password. Access denied.', $result); + + (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); + ResponseRenderer::getInstance()->setAjax(false); // case 3 $GLOBALS['errno'] = 1043; - $this->expectException(ExitException::class); - $this->object->showFailure(AuthenticationFailure::serverDenied()); + $response = $this->object->showFailure(AuthenticationFailure::serverDenied()); + $result = (string) $response->getBody(); + self::assertStringContainsString('Wrong username/password. Access denied.', $result); } public function testShowLoginFormWithAjax(): void From bc00b69050536b569905f49aec1343906afa90de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 9 May 2024 15:52:11 -0300 Subject: [PATCH 8/9] Remove callExit() from AuthenticationPlugin::readCredentials() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- src/Http/Middleware/Authentication.php | 9 +++++++++ src/Plugins/Auth/AuthenticationCookie.php | 17 +++------------- src/Plugins/Auth/AuthenticationSignon.php | 15 +++++++------- src/Plugins/AuthenticationPlugin.php | 24 +++++------------------ 4 files changed, 25 insertions(+), 40 deletions(-) diff --git a/src/Http/Middleware/Authentication.php b/src/Http/Middleware/Authentication.php index c3eb54eba1..89aa5a7999 100644 --- a/src/Http/Middleware/Authentication.php +++ b/src/Http/Middleware/Authentication.php @@ -26,6 +26,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; +use Throwable; use function assert; use function define; @@ -67,6 +68,14 @@ final class Authentication implements MiddlewareInterface } } catch (AuthenticationFailure $exception) { return $authPlugin->showFailure($exception); + } catch (Throwable $exception) { + $response = $this->responseFactory->createResponse(StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR); + + return $response->write($this->template->render('error/generic', [ + 'lang' => $GLOBALS['lang'] ?? 'en', + 'dir' => LanguageManager::$textDir, + 'error_message' => $exception->getMessage(), + ])); } $currentServer = new Server(Config::getInstance()->selectedServer); diff --git a/src/Plugins/Auth/AuthenticationCookie.php b/src/Plugins/Auth/AuthenticationCookie.php index 879fd587ba..1f379d2579 100644 --- a/src/Plugins/Auth/AuthenticationCookie.php +++ b/src/Plugins/Auth/AuthenticationCookie.php @@ -20,7 +20,6 @@ use PhpMyAdmin\Plugins\AuthenticationPlugin; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Server\Select; use PhpMyAdmin\Session; -use PhpMyAdmin\Template; use PhpMyAdmin\Url; use PhpMyAdmin\Util; use PhpMyAdmin\Utils\SessionCache; @@ -210,6 +209,7 @@ class AuthenticationCookie extends AuthenticationPlugin * it directly switches to showFailure() if user inactivity timeout is reached * * @throws AuthenticationFailure + * @throws SessionHandlerException */ public function readCredentials(): bool { @@ -313,19 +313,8 @@ class AuthenticationCookie extends AuthenticationPlugin $GLOBALS['pma_auth_server'] = Core::sanitizeMySQLHost($_REQUEST['pma_servername']); } - try { - /* Secure current session on login to avoid session fixation */ - Session::secure(); - } catch (SessionHandlerException $exception) { - $responseRenderer = ResponseRenderer::getInstance(); - $responseRenderer->addHTML((new Template())->render('error/generic', [ - 'lang' => $GLOBALS['lang'] ?? 'en', - 'dir' => LanguageManager::$textDir, - 'error_message' => $exception->getMessage(), - ])); - - $responseRenderer->callExit(); - } + /* Secure current session on login to avoid session fixation */ + Session::secure(); return true; } diff --git a/src/Plugins/Auth/AuthenticationSignon.php b/src/Plugins/Auth/AuthenticationSignon.php index 22f02c7cf6..9beacf6f69 100644 --- a/src/Plugins/Auth/AuthenticationSignon.php +++ b/src/Plugins/Auth/AuthenticationSignon.php @@ -14,6 +14,7 @@ use PhpMyAdmin\LanguageManager; use PhpMyAdmin\Plugins\AuthenticationPlugin; use PhpMyAdmin\ResponseRenderer; use PhpMyAdmin\Util; +use RuntimeException; use function __; use function array_merge; @@ -26,6 +27,7 @@ use function session_name; use function session_set_cookie_params; use function session_start; use function session_write_close; +use function sprintf; /** * Handles the SignOn authentication method @@ -92,6 +94,8 @@ class AuthenticationSignon extends AuthenticationPlugin /** * Gets authentication credentials + * + * @throws RuntimeException */ public function readCredentials(): bool { @@ -120,13 +124,10 @@ class AuthenticationSignon extends AuthenticationPlugin /* Handle script based auth */ if ($scriptName !== '') { if (! @file_exists($scriptName)) { - echo $this->template->render('error/generic', [ - 'lang' => $GLOBALS['lang'] ?? 'en', - 'dir' => LanguageManager::$textDir, - 'error_message' => __('Can not find signon authentication script:') . ' ' . $scriptName, - ]); - - ResponseRenderer::getInstance()->callExit(); + throw new RuntimeException(sprintf( + __('Can not find signon authentication script: %s'), + '$cfg[\'Servers\'][$i][\'SignonScript\']', + )); } include $scriptName; diff --git a/src/Plugins/AuthenticationPlugin.php b/src/Plugins/AuthenticationPlugin.php index d7bc2c4140..bec9777a6c 100644 --- a/src/Plugins/AuthenticationPlugin.php +++ b/src/Plugins/AuthenticationPlugin.php @@ -1,20 +1,16 @@ addHTML((new Template())->render('error/generic', [ - 'lang' => $GLOBALS['lang'] ?? 'en', - 'dir' => LanguageManager::$textDir, - 'error_message' => $exception->getMessage(), - ])); - - return $responseRenderer->response(); - } + Session::secure(); $response = $this->showLoginForm(); if ($response !== null) { From 6a425a2d00e070b6ceb29387ed4ef73a34db1623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maur=C3=ADcio=20Meneghini=20Fauth?= Date: Thu, 9 May 2024 18:06:52 -0300 Subject: [PATCH 9/9] Add better method names for Exceptions\AuthenticationFailure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maurício Meneghini Fauth --- src/Exceptions/AuthenticationFailure.php | 10 +++++----- src/Http/Middleware/Authentication.php | 2 +- src/Plugins/Auth/AuthenticationCookie.php | 2 +- src/Plugins/AuthenticationPlugin.php | 6 +++--- tests/unit/Exceptions/AuthenticationFailureTest.php | 10 +++++----- tests/unit/Plugins/Auth/AuthenticationConfigTest.php | 2 +- tests/unit/Plugins/Auth/AuthenticationCookieTest.php | 12 ++++++------ tests/unit/Plugins/Auth/AuthenticationHttpTest.php | 6 +++--- tests/unit/Plugins/Auth/AuthenticationSignonTest.php | 10 +++++----- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/Exceptions/AuthenticationFailure.php b/src/Exceptions/AuthenticationFailure.php index cb37827d36..ab3b9f6634 100644 --- a/src/Exceptions/AuthenticationFailure.php +++ b/src/Exceptions/AuthenticationFailure.php @@ -30,7 +30,7 @@ final class AuthenticationFailure extends RuntimeException /** * Database server denied user login */ - public static function serverDenied(): self + public static function deniedByDatabaseServer(): self { return new self(self::SERVER_DENIED, __('Cannot log in to the database server.')); } @@ -38,7 +38,7 @@ final class AuthenticationFailure extends RuntimeException /** * User denied by allow/deny rules */ - public static function allowDenied(): self + public static function deniedByAllowDenyRules(): self { return new self(self::ALLOW_DENIED, __('Access denied!')); } @@ -46,7 +46,7 @@ final class AuthenticationFailure extends RuntimeException /** * User 'root' is denied in configuration */ - public static function rootDenied(): self + public static function rootDeniedByConfiguration(): self { return new self(self::ROOT_DENIED, __('Access denied!')); } @@ -54,7 +54,7 @@ final class AuthenticationFailure extends RuntimeException /** * Empty password is denied */ - public static function emptyDenied(): self + public static function emptyPasswordDeniedByConfiguration(): self { return new self( self::EMPTY_DENIED, @@ -65,7 +65,7 @@ final class AuthenticationFailure extends RuntimeException /** * Automatically logged out due to inactivity */ - public static function noActivity(): self + public static function loggedOutDueToInactivity(): self { return new self( self::NO_ACTIVITY, diff --git a/src/Http/Middleware/Authentication.php b/src/Http/Middleware/Authentication.php index 89aa5a7999..1983cde60a 100644 --- a/src/Http/Middleware/Authentication.php +++ b/src/Http/Middleware/Authentication.php @@ -137,7 +137,7 @@ final class Authentication implements MiddlewareInterface // Connects to the server (validates user's login) $userConnection = $dbi->connect($currentServer, ConnectionType::User); if ($userConnection === null) { - throw AuthenticationFailure::serverDenied(); + throw AuthenticationFailure::deniedByDatabaseServer(); } if ($controlConnection !== null) { diff --git a/src/Plugins/Auth/AuthenticationCookie.php b/src/Plugins/Auth/AuthenticationCookie.php index 1f379d2579..85cc6be8e0 100644 --- a/src/Plugins/Auth/AuthenticationCookie.php +++ b/src/Plugins/Auth/AuthenticationCookie.php @@ -364,7 +364,7 @@ class AuthenticationCookie extends AuthenticationPlugin SessionCache::remove('table_priv'); SessionCache::remove('proc_priv'); - throw AuthenticationFailure::noActivity(); + throw AuthenticationFailure::loggedOutDueToInactivity(); } // check password cookie diff --git a/src/Plugins/AuthenticationPlugin.php b/src/Plugins/AuthenticationPlugin.php index bec9777a6c..ceeccbdcdf 100644 --- a/src/Plugins/AuthenticationPlugin.php +++ b/src/Plugins/AuthenticationPlugin.php @@ -273,13 +273,13 @@ abstract class AuthenticationPlugin // Ejects the user if banished if ($allowDenyForbidden) { - throw AuthenticationFailure::allowDenied(); + throw AuthenticationFailure::deniedByAllowDenyRules(); } } // is root allowed? if (! $config->selectedServer['AllowRoot'] && $config->selectedServer['user'] === 'root') { - throw AuthenticationFailure::rootDenied(); + throw AuthenticationFailure::rootDeniedByConfiguration(); } // is a login without password allowed? @@ -287,7 +287,7 @@ abstract class AuthenticationPlugin return; } - throw AuthenticationFailure::emptyDenied(); + throw AuthenticationFailure::emptyPasswordDeniedByConfiguration(); } /** diff --git a/tests/unit/Exceptions/AuthenticationFailureTest.php b/tests/unit/Exceptions/AuthenticationFailureTest.php index e19ac70df9..2743787552 100644 --- a/tests/unit/Exceptions/AuthenticationFailureTest.php +++ b/tests/unit/Exceptions/AuthenticationFailureTest.php @@ -13,14 +13,14 @@ final class AuthenticationFailureTest extends TestCase { public function testAllowDenied(): void { - $exception = AuthenticationFailure::allowDenied(); + $exception = AuthenticationFailure::deniedByAllowDenyRules(); self::assertSame('allow-denied', $exception->failureType); self::assertSame('Access denied!', $exception->getMessage()); } public function testEmptyDenied(): void { - $exception = AuthenticationFailure::emptyDenied(); + $exception = AuthenticationFailure::emptyPasswordDeniedByConfiguration(); self::assertSame('empty-denied', $exception->failureType); self::assertSame( 'Login without a password is forbidden by configuration (see AllowNoPassword).', @@ -30,7 +30,7 @@ final class AuthenticationFailureTest extends TestCase public function testNoActivity(): void { - $exception = AuthenticationFailure::noActivity(); + $exception = AuthenticationFailure::loggedOutDueToInactivity(); self::assertSame('no-activity', $exception->failureType); self::assertSame( 'You have been automatically logged out due to inactivity of %s seconds.' @@ -41,14 +41,14 @@ final class AuthenticationFailureTest extends TestCase public function testRootDenied(): void { - $exception = AuthenticationFailure::rootDenied(); + $exception = AuthenticationFailure::rootDeniedByConfiguration(); self::assertSame('root-denied', $exception->failureType); self::assertSame('Access denied!', $exception->getMessage()); } public function testServerDenied(): void { - $exception = AuthenticationFailure::serverDenied(); + $exception = AuthenticationFailure::deniedByDatabaseServer(); self::assertSame('server-denied', $exception->failureType); self::assertSame('Cannot log in to the database server.', $exception->getMessage()); } diff --git a/tests/unit/Plugins/Auth/AuthenticationConfigTest.php b/tests/unit/Plugins/Auth/AuthenticationConfigTest.php index ccbdc913c1..0c04236868 100644 --- a/tests/unit/Plugins/Auth/AuthenticationConfigTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationConfigTest.php @@ -100,7 +100,7 @@ class AuthenticationConfigTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); - $response = $this->object->showFailure(AuthenticationFailure::serverDenied()); + $response = $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer()); $html = (string) $response->getBody(); diff --git a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php index 01098be2cc..593c5a32e7 100644 --- a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php @@ -546,7 +546,7 @@ class AuthenticationCookieTest extends AbstractTestCase ->method('cookieDecrypt') ->willReturn('testBF'); - $this->expectExceptionObject(AuthenticationFailure::noActivity()); + $this->expectExceptionObject(AuthenticationFailure::loggedOutDueToInactivity()); $this->object->readCredentials(); } @@ -628,7 +628,7 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); try { - $this->object->showFailure(AuthenticationFailure::emptyDenied()); + $this->object->showFailure(AuthenticationFailure::emptyPasswordDeniedByConfiguration()); } catch (Throwable $throwable) { } @@ -696,7 +696,7 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); try { - $this->object->showFailure(AuthenticationFailure::allowDenied()); + $this->object->showFailure(AuthenticationFailure::deniedByAllowDenyRules()); } catch (Throwable $throwable) { } @@ -728,7 +728,7 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); try { - $this->object->showFailure(AuthenticationFailure::noActivity()); + $this->object->showFailure(AuthenticationFailure::loggedOutDueToInactivity()); } catch (Throwable $throwable) { } @@ -773,7 +773,7 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); try { - $this->object->showFailure(AuthenticationFailure::serverDenied()); + $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer()); } catch (Throwable $throwable) { } @@ -814,7 +814,7 @@ class AuthenticationCookieTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub); try { - $this->object->showFailure(AuthenticationFailure::serverDenied()); + $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer()); } catch (Throwable $throwable) { } diff --git a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php index d9c2e44081..47f4eb5bf9 100644 --- a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php @@ -272,7 +272,7 @@ class AuthenticationHttpTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); ResponseRenderer::getInstance()->setAjax(false); - $response = $this->object->showFailure(AuthenticationFailure::serverDenied()); + $response = $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer()); $result = (string) $response->getBody(); self::assertStringContainsString('

error 123

', $result); @@ -284,7 +284,7 @@ class AuthenticationHttpTest extends AbstractTestCase (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null); ResponseRenderer::getInstance()->setAjax(false); - $response = $this->object->showFailure(AuthenticationFailure::serverDenied()); + $response = $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer()); $result = (string) $response->getBody(); self::assertStringContainsString('Wrong username/password. Access denied.', $result); @@ -293,7 +293,7 @@ class AuthenticationHttpTest extends AbstractTestCase // case 3 $GLOBALS['errno'] = 1043; - $response = $this->object->showFailure(AuthenticationFailure::serverDenied()); + $response = $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer()); $result = (string) $response->getBody(); self::assertStringContainsString('Wrong username/password. Access denied.', $result); } diff --git a/tests/unit/Plugins/Auth/AuthenticationSignonTest.php b/tests/unit/Plugins/Auth/AuthenticationSignonTest.php index 18230342e4..be56ae1a67 100644 --- a/tests/unit/Plugins/Auth/AuthenticationSignonTest.php +++ b/tests/unit/Plugins/Auth/AuthenticationSignonTest.php @@ -246,7 +246,7 @@ class AuthenticationSignonTest extends AbstractTestCase ->willThrowException(new ExitException()); try { - $this->object->showFailure(AuthenticationFailure::emptyDenied()); + $this->object->showFailure(AuthenticationFailure::emptyPasswordDeniedByConfiguration()); } catch (ExitException) { } @@ -271,7 +271,7 @@ class AuthenticationSignonTest extends AbstractTestCase ->willThrowException(new ExitException()); try { - $this->object->showFailure(AuthenticationFailure::allowDenied()); + $this->object->showFailure(AuthenticationFailure::deniedByAllowDenyRules()); } catch (ExitException) { } @@ -296,7 +296,7 @@ class AuthenticationSignonTest extends AbstractTestCase $config->settings['LoginCookieValidity'] = '1440'; try { - $this->object->showFailure(AuthenticationFailure::noActivity()); + $this->object->showFailure(AuthenticationFailure::loggedOutDueToInactivity()); } catch (ExitException) { } @@ -333,7 +333,7 @@ class AuthenticationSignonTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; try { - $this->object->showFailure(AuthenticationFailure::serverDenied()); + $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer()); } catch (ExitException) { } @@ -366,7 +366,7 @@ class AuthenticationSignonTest extends AbstractTestCase DatabaseInterface::$instance = $dbi; try { - $this->object->showFailure(AuthenticationFailure::serverDenied()); + $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer()); } catch (ExitException) { }