';
$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) {
@@ -158,6 +163,9 @@ public function showFailure(string $failure): never
}
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 5756237b6ddf..85cc6be8e021 100644
--- a/src/Plugins/Auth/AuthenticationCookie.php
+++ b/src/Plugins/Auth/AuthenticationCookie.php
@@ -11,14 +11,15 @@
use PhpMyAdmin\Core;
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;
use PhpMyAdmin\ResponseRenderer;
use PhpMyAdmin\Server\Select;
use PhpMyAdmin\Session;
-use PhpMyAdmin\Template;
use PhpMyAdmin\Url;
use PhpMyAdmin\Util;
use PhpMyAdmin\Utils\SessionCache;
@@ -63,11 +64,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
@@ -75,8 +76,8 @@ public function showLoginForm(): never
* 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();
}
/**
@@ -85,8 +86,8 @@ public function showLoginForm(): never
* 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 ']);
}
/**
@@ -94,7 +95,7 @@ public function showLoginForm(): never
* 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();
@@ -159,7 +160,7 @@ public function showLoginForm(): never
$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,
@@ -190,7 +191,7 @@ public function showLoginForm(): never
'config_footer' => $configFooter,
]));
- $response->callExit();
+ return $responseRenderer->response();
}
/**
@@ -206,6 +207,9 @@ public function showLoginForm(): never
* 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
+ * @throws SessionHandlerException
*/
public function readCredentials(): bool
{
@@ -309,19 +313,8 @@ public function readCredentials(): bool
$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;
}
@@ -371,7 +364,7 @@ public function readCredentials(): bool
SessionCache::remove('table_priv');
SessionCache::remove('proc_priv');
- $this->showFailure('no-activity');
+ throw AuthenticationFailure::loggedOutDueToInactivity();
}
// check password cookie
@@ -440,7 +433,7 @@ public function storeCredentials(): bool
/**
* 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
@@ -465,18 +458,18 @@ public function rememberCredentials(): void
// 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;
}
/**
@@ -484,11 +477,11 @@ public function rememberCredentials(): void
*/
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();
}
/**
@@ -539,27 +532,23 @@ public function storePasswordCookie(string $password): void
*
* 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): Response
{
- $GLOBALS['conn_error'] ??= null;
-
- parent::showFailure($failure);
+ $this->logFailure($failure);
// Deletes password cookie and displays the login form
Config::getInstance()->removeCookie('pmaAuth-' . Current::$server);
$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();
+ return $this->showLoginForm();
}
/**
diff --git a/src/Plugins/Auth/AuthenticationHttp.php b/src/Plugins/Auth/AuthenticationHttp.php
index 9707ffe426d4..5fe1e95c9beb 100644
--- a/src/Plugins/Auth/AuthenticationHttp.php
+++ b/src/Plugins/Auth/AuthenticationHttp.php
@@ -12,6 +12,8 @@
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;
@@ -34,23 +36,24 @@ 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();
+ return $this->authForm();
}
/**
* Displays authentication form
*/
- public function authForm(): never
+ public function authForm(): Response
{
$config = Config::getInstance();
if (empty($config->selectedServer['auth_http_realm'])) {
@@ -92,7 +95,7 @@ public function authForm(): never
$response->addHTML(Config::renderFooter());
- $response->callExit();
+ return $response->response();
}
/**
@@ -178,25 +181,24 @@ public function readCredentials(): bool
/**
* 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): Response
{
- parent::showFailure($failure);
+ $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();
+ return $this->authForm();
}
/**
diff --git a/src/Plugins/Auth/AuthenticationSignon.php b/src/Plugins/Auth/AuthenticationSignon.php
index 9e069442018e..9beacf6f6959 100644
--- a/src/Plugins/Auth/AuthenticationSignon.php
+++ b/src/Plugins/Auth/AuthenticationSignon.php
@@ -8,10 +8,13 @@
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;
use PhpMyAdmin\Util;
+use RuntimeException;
use function __;
use function array_merge;
@@ -24,6 +27,7 @@
use function session_set_cookie_params;
use function session_start;
use function session_write_close;
+use function sprintf;
/**
* Handles the SignOn authentication method
@@ -33,25 +37,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();
}
/**
@@ -90,6 +94,8 @@ public function setCookieParams(array|null $sessionCookieParams = null): void
/**
* Gets authentication credentials
+ *
+ * @throws RuntimeException
*/
public function readCredentials(): bool
{
@@ -118,13 +124,10 @@ public function readCredentials(): bool
/* 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;
@@ -233,12 +236,10 @@ public function readCredentials(): bool
/**
* 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): Response
{
- parent::showFailure($failure);
+ $this->logFailure($failure);
/* Session name */
$sessionName = Config::getInstance()->selectedServer['SignonSession'];
@@ -260,7 +261,7 @@ public function showFailure(string $failure): never
$_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 09bde9a24dd8..ceeccbdcdfc9 100644
--- a/src/Plugins/AuthenticationPlugin.php
+++ b/src/Plugins/AuthenticationPlugin.php
@@ -1,19 +1,16 @@
authentication failed
- *
- * @param string $failure String describing why authentication has failed
*/
- public function showFailure(string $failure): void
+ abstract public function showFailure(AuthenticationFailure $failure): Response;
+
+ protected function logFailure(AuthenticationFailure $failure): void
{
- Logging::logUser(Config::getInstance(), $this->user, $failure);
+ Logging::logUser(Config::getInstance(), $this->user, $failure->failureType);
}
/**
@@ -157,38 +157,25 @@ public function getLoginFormURL(): string
/**
* 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 === '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 ($failure->failureType === AuthenticationFailure::SERVER_DENIED) {
+ $dbiError = DatabaseInterface::getInstance()->getError();
+ if ($dbiError !== '') {
+ return htmlspecialchars($dbiError);
+ }
- if (isset($GLOBALS['errno'])) {
- return '#' . $GLOBALS['errno'] . ' '
- . __('Cannot log in to the MySQL server');
+ if (isset($GLOBALS['errno'])) {
+ return '#' . $GLOBALS['errno'] . ' ' . $failure->getMessage();
+ }
}
- return __('Cannot log in to the MySQL server');
+ return $failure->getMessage();
}
/**
@@ -235,28 +222,23 @@ public function setSessionAccessTime(): void
* High level authentication interface
*
* Gets the credentials or shows login form if necessary
+ *
+ * @throws AuthenticationFailure
+ * @throws Exception
*/
- public function authenticate(): void
+ public function authenticate(): Response|null
{
$success = $this->readCredentials();
/* Show login form (this exits) */
if (! $success) {
/* Force generating of new session */
- try {
- 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();
- }
+ Session::secure();
- $this->showLoginForm();
+ $response = $this->showLoginForm();
+ if ($response !== null) {
+ return $response;
+ }
}
/* Store credentials (eg. in cookies) */
@@ -265,10 +247,14 @@ public function authenticate(): void
$this->checkRules();
/* clear user cache */
Util::clearUserCache();
+
+ return null;
}
/**
* Check configuration defined restrictions for authentication
+ *
+ * @throws AuthenticationFailure
*/
public function checkRules(): void
{
@@ -287,13 +273,13 @@ public function checkRules(): void
// Ejects the user if banished
if ($allowDenyForbidden) {
- $this->showFailure('allow-denied');
+ throw AuthenticationFailure::deniedByAllowDenyRules();
}
}
// is root allowed?
if (! $config->selectedServer['AllowRoot'] && $config->selectedServer['user'] === 'root') {
- $this->showFailure('root-denied');
+ throw AuthenticationFailure::rootDeniedByConfiguration();
}
// is a login without password allowed?
@@ -301,39 +287,37 @@ public function checkRules(): void
return;
}
- $this->showFailure('empty-denied');
+ throw AuthenticationFailure::emptyPasswordDeniedByConfiguration();
}
/**
- * 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/Exceptions/AuthenticationFailureTest.php b/tests/unit/Exceptions/AuthenticationFailureTest.php
new file mode 100644
index 000000000000..2743787552f0
--- /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::emptyPasswordDeniedByConfiguration();
+ 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::loggedOutDueToInactivity();
+ 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::rootDeniedByConfiguration();
+ self::assertSame('root-denied', $exception->failureType);
+ self::assertSame('Access denied!', $exception->getMessage());
+ }
+
+ public function testServerDenied(): void
+ {
+ $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 9548c614e371..0c04236868be 100644
--- a/tests/unit/Plugins/Auth/AuthenticationConfigTest.php
+++ b/tests/unit/Plugins/Auth/AuthenticationConfigTest.php
@@ -7,17 +7,15 @@
use PhpMyAdmin\Config;
use PhpMyAdmin\Current;
use PhpMyAdmin\DatabaseInterface;
-use PhpMyAdmin\Exceptions\ExitException;
+use PhpMyAdmin\Exceptions\AuthenticationFailure;
use PhpMyAdmin\Plugins\Auth\AuthenticationConfig;
use PhpMyAdmin\ResponseRenderer;
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;
+use function json_decode;
#[CoversClass(AuthenticationConfig::class)]
#[Medium]
@@ -55,12 +53,25 @@ protected function tearDown(): void
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
@@ -89,17 +100,9 @@ public function testAuthFails(): void
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
- ob_start();
- try {
- $this->object->showFailure('');
- } catch (Throwable $throwable) {
- }
-
- $html = ob_get_clean();
-
- self::assertInstanceOf(ExitException::class, $throwable);
+ $response = $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer());
- 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 dcab3642bdec..593c5a32e771 100644
--- a/tests/unit/Plugins/Auth/AuthenticationCookieTest.php
+++ b/tests/unit/Plugins/Auth/AuthenticationCookieTest.php
@@ -4,10 +4,11 @@
namespace PhpMyAdmin\Tests\Plugins\Auth;
+use Fig\Http\Message\StatusCodeInterface;
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;
@@ -24,6 +25,7 @@
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,37 +78,21 @@ public function testAuthErrorAJAX(): void
{
$GLOBALS['conn_error'] = true;
- $responseStub = new ResponseRendererStub();
- $responseStub->setAjax(true);
- (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub);
-
- try {
- $this->object->showLoginForm();
- } catch (Throwable $throwable) {
- }
-
- self::assertInstanceOf(ExitException::class, $throwable);
- $response = $responseStub->getResponse();
- self::assertSame(200, $response->getStatusCode());
- self::assertFalse($responseStub->hasSuccessState());
- 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;
+ (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
+ $responseRenderer = ResponseRenderer::getInstance();
+ $responseRenderer->setAjax(true);
+
+ $response = $this->object->showLoginForm();
+
+ 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
@@ -132,17 +118,11 @@ public function testAuthError(): void
Current::$table = 'testTable';
$config->settings['Servers'] = [1, 2];
- $responseStub = new ResponseRendererStub();
- (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub);
-
- try {
- $this->object->showLoginForm();
- } catch (Throwable $throwable) {
- }
+ (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
- $result = $responseStub->getHTMLResult();
+ $response = $this->object->showLoginForm();
- self::assertInstanceOf(ExitException::class, $throwable);
+ $result = (string) $response->getBody();
self::assertStringContainsString(' id="imLogo"', $result);
@@ -202,14 +182,9 @@ public function testAuthCaptcha(): void
$responseStub = new ResponseRendererStub();
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub);
- try {
- $this->object->showLoginForm();
- } catch (Throwable $throwable) {
- }
-
- $result = $responseStub->getHTMLResult();
+ $response = $this->object->showLoginForm();
- self::assertInstanceOf(ExitException::class, $throwable);
+ $result = (string) $response->getBody();
self::assertStringContainsString('id="imLogo"', $result);
@@ -263,14 +238,9 @@ public function testAuthCaptchaCheckbox(): void
$responseStub = new ResponseRendererStub();
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub);
- try {
- $this->object->showLoginForm();
- } catch (Throwable $throwable) {
- }
-
- $result = $responseStub->getHTMLResult();
+ $response = $this->object->showLoginForm();
- self::assertInstanceOf(ExitException::class, $throwable);
+ $result = (string) $response->getBody();
self::assertStringContainsString('id="imLogo"', $result);
@@ -569,18 +539,14 @@ public function testAuthCheckAuthFails(): void
// mock for blowfish function
$this->object = $this->getMockBuilder(AuthenticationCookie::class)
->disableOriginalConstructor()
- ->onlyMethods(['showFailure', 'cookieDecrypt'])
+ ->onlyMethods(['cookieDecrypt'])
->getMock();
$this->object->expects(self::once())
->method('cookieDecrypt')
->willReturn('testBF');
- $this->object->expects(self::once())
- ->method('showFailure')
- ->willThrowException(new ExitException());
-
- $this->expectException(ExitException::class);
+ $this->expectExceptionObject(AuthenticationFailure::loggedOutDueToInactivity());
$this->object->readCredentials();
}
@@ -626,6 +592,7 @@ public function testAuthSetUserWithHeaders(): void
$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;
@@ -635,8 +602,13 @@ public function testAuthSetUserWithHeaders(): void
(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
@@ -656,11 +628,11 @@ public function testAuthFailsNoPass(): void
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub);
try {
- $this->object->showFailure('empty-denied');
+ $this->object->showFailure(AuthenticationFailure::emptyPasswordDeniedByConfiguration());
} 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'));
@@ -668,7 +640,7 @@ public function testAuthFailsNoPass(): void
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,11 +696,11 @@ public function testAuthFailsDeny(): void
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub);
try {
- $this->object->showFailure('allow-denied');
+ $this->object->showFailure(AuthenticationFailure::deniedByAllowDenyRules());
} 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'));
@@ -756,11 +728,11 @@ public function testAuthFailsActivity(): void
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub);
try {
- $this->object->showFailure('no-activity');
+ $this->object->showFailure(AuthenticationFailure::loggedOutDueToInactivity());
} 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'));
@@ -801,17 +773,17 @@ public function testAuthFailsDBI(): void
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub);
try {
- $this->object->showFailure('');
+ $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer());
} 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'));
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,17 +814,17 @@ public function testAuthFailsErrno(): void
(new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, $responseStub);
try {
- $this->object->showFailure('');
+ $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer());
} 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'));
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
@@ -954,9 +926,10 @@ public function testAuthenticate(): void
$_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);
@@ -999,31 +972,20 @@ public function testCheckRules(
$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 +993,9 @@ public static function checkRulesProvider(): array
{
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 +1012,7 @@ public static function checkRulesProvider(): array
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 +1030,7 @@ public static function checkRulesProvider(): array
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 +1048,7 @@ public static function checkRulesProvider(): array
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 49614ac3aeec..47f4eb5bf9da 100644
--- a/tests/unit/Plugins/Auth/AuthenticationHttpTest.php
+++ b/tests/unit/Plugins/Auth/AuthenticationHttpTest.php
@@ -7,7 +7,7 @@
use PhpMyAdmin\Config;
use PhpMyAdmin\Current;
use PhpMyAdmin\DatabaseInterface;
-use PhpMyAdmin\Exceptions\ExitException;
+use PhpMyAdmin\Exceptions\AuthenticationFailure;
use PhpMyAdmin\Plugins\Auth\AuthenticationHttp;
use PhpMyAdmin\ResponseRenderer;
use PhpMyAdmin\Tests\AbstractTestCase;
@@ -16,11 +16,9 @@
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Medium;
use ReflectionProperty;
-use Throwable;
use function base64_encode;
-use function ob_get_clean;
-use function ob_start;
+use function json_decode;
#[CoversClass(AuthenticationHttp::class)]
#[Medium]
@@ -82,13 +80,8 @@ public function testAuthVerbose(): void
$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);
- $response = $responseStub->getResponse();
self::assertSame(['Basic realm="phpMyAdmin verboseMessag"'], $response->getHeader('WWW-Authenticate'));
self::assertSame(401, $response->getStatusCode());
}
@@ -103,13 +96,8 @@ public function testAuthHost(): void
$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);
- $response = $responseStub->getResponse();
self::assertSame(['Basic realm="phpMyAdmin hst"'], $response->getHeader('WWW-Authenticate'));
self::assertSame(401, $response->getStatusCode());
}
@@ -124,13 +112,8 @@ public function testAuthRealm(): void
$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);
- $response = $responseStub->getResponse();
self::assertSame(['Basic realm="realmmessage"'], $response->getHeader('WWW-Authenticate'));
self::assertSame(401, $response->getStatusCode());
}
@@ -271,6 +254,8 @@ public function testAuthFails(): void
$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)
@@ -284,40 +269,48 @@ public function testAuthFails(): void
DatabaseInterface::$instance = $dbi;
$GLOBALS['errno'] = 31;
- ob_start();
- try {
- $this->object->showFailure('');
- } catch (Throwable $throwable) {
- }
-
- $result = ob_get_clean();
-
- self::assertInstanceOf(ExitException::class, $throwable);
+ (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
+ ResponseRenderer::getInstance()->setAjax(false);
- self::assertIsString($result);
+ $response = $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer());
+ $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('');
- } catch (ExitException) {
- }
+ (new ReflectionProperty(ResponseRenderer::class, 'instance'))->setValue(null, null);
+ ResponseRenderer::getInstance()->setAjax(false);
+
+ $response = $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer());
+ $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('');
+ $response = $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer());
+ $result = (string) $response->getBody();
+ self::assertStringContainsString('Wrong username/password. Access denied.', $result);
+ }
+
+ 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 bd3f3fcb539f..be56ae1a675a 100644
--- a/tests/unit/Plugins/Auth/AuthenticationSignonTest.php
+++ b/tests/unit/Plugins/Auth/AuthenticationSignonTest.php
@@ -8,6 +8,7 @@
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;
@@ -15,10 +16,7 @@
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;
@@ -61,20 +59,8 @@ public function testAuth(): void
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
@@ -260,12 +246,12 @@ public function testAuthFailsForbidden(): void
->willThrowException(new ExitException());
try {
- $this->object->showFailure('empty-denied');
+ $this->object->showFailure(AuthenticationFailure::emptyPasswordDeniedByConfiguration());
} 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 +271,7 @@ public function testAuthFailsDeny(): void
->willThrowException(new ExitException());
try {
- $this->object->showFailure('allow-denied');
+ $this->object->showFailure(AuthenticationFailure::deniedByAllowDenyRules());
} catch (ExitException) {
}
@@ -310,7 +296,7 @@ public function testAuthFailsTimeout(): void
$config->settings['LoginCookieValidity'] = '1440';
try {
- $this->object->showFailure('no-activity');
+ $this->object->showFailure(AuthenticationFailure::loggedOutDueToInactivity());
} catch (ExitException) {
}
@@ -347,7 +333,7 @@ public function testAuthFailsMySQLError(): void
DatabaseInterface::$instance = $dbi;
try {
- $this->object->showFailure('');
+ $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer());
} catch (ExitException) {
}
@@ -380,11 +366,11 @@ public function testAuthFailsConnect(): void
DatabaseInterface::$instance = $dbi;
try {
- $this->object->showFailure('');
+ $this->object->showFailure(AuthenticationFailure::deniedByDatabaseServer());
} 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 2a149cb7e7ed..6d52611872be 100644
--- a/tests/unit/Plugins/AuthenticationPluginTest.php
+++ b/tests/unit/Plugins/AuthenticationPluginTest.php
@@ -5,8 +5,10 @@
namespace PhpMyAdmin\Tests\Plugins;
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;
@@ -26,14 +28,20 @@ public function testCheckTwoFactor(): void
DatabaseInterface::$instance = $dbi;
$object = new class extends AuthenticationPlugin {
- public function showLoginForm(): void
+ public function showLoginForm(): Response|null
{
+ return null;
}
public function readCredentials(): bool
{
return false;
}
+
+ public function showFailure(AuthenticationFailure $failure): Response
+ {
+ throw new ExitException();
+ }
};
$_SESSION['two_factor_check'] = false;
@@ -45,12 +53,9 @@ public function readCredentials(): bool
$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(),
|