116 lines
4.2 KiB
PHP
116 lines
4.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace PhpMyAdmin\Middleware;
|
|
|
|
use Fig\Http\Message\StatusCodeInterface;
|
|
use PhpMyAdmin\Config;
|
|
use PhpMyAdmin\Config\Settings\Server;
|
|
use PhpMyAdmin\Core;
|
|
use PhpMyAdmin\DatabaseInterface;
|
|
use PhpMyAdmin\Dbal\Connection;
|
|
use PhpMyAdmin\Exceptions\AuthenticationPluginException;
|
|
use PhpMyAdmin\Exceptions\ExitException;
|
|
use PhpMyAdmin\Http\Factory\ResponseFactory;
|
|
use PhpMyAdmin\Http\ServerRequest;
|
|
use PhpMyAdmin\Logging;
|
|
use PhpMyAdmin\Plugins\AuthenticationPlugin;
|
|
use PhpMyAdmin\Plugins\AuthenticationPluginFactory;
|
|
use PhpMyAdmin\ResponseRenderer;
|
|
use PhpMyAdmin\Template;
|
|
use Psr\Http\Message\ResponseInterface;
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
use Psr\Http\Server\MiddlewareInterface;
|
|
use Psr\Http\Server\RequestHandlerInterface;
|
|
|
|
use function assert;
|
|
use function define;
|
|
|
|
final class Authentication implements MiddlewareInterface
|
|
{
|
|
public function __construct(
|
|
private readonly Config $config,
|
|
private readonly Template $template,
|
|
private readonly ResponseFactory $responseFactory,
|
|
) {
|
|
}
|
|
|
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
|
{
|
|
if ($this->config->getCurrentServer() === null) {
|
|
return $handler->handle($request);
|
|
}
|
|
|
|
/** @var AuthenticationPluginFactory $authPluginFactory */
|
|
$authPluginFactory = Core::getContainerBuilder()->get(AuthenticationPluginFactory::class);
|
|
try {
|
|
$authPlugin = $authPluginFactory->create();
|
|
} catch (AuthenticationPluginException $exception) {
|
|
$response = $this->responseFactory->createResponse(StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR);
|
|
|
|
return $response->write($this->template->render('error/generic', [
|
|
'lang' => $GLOBALS['lang'] ?? 'en',
|
|
'dir' => $GLOBALS['text_dir'] ?? 'ltr',
|
|
'error_message' => $exception->getMessage(),
|
|
]));
|
|
}
|
|
|
|
try {
|
|
$authPlugin->authenticate();
|
|
$currentServer = new Server($GLOBALS['cfg']['Server']);
|
|
|
|
/* Enable LOAD DATA LOCAL INFILE for LDI plugin */
|
|
if ($request->getAttribute('route') === '/import' && ($_POST['format'] ?? '') === 'ldi') {
|
|
// Switch this before the DB connection is done
|
|
// phpcs:disable PSR1.Files.SideEffects
|
|
define('PMA_ENABLE_LDI', 1);
|
|
// phpcs:enable
|
|
}
|
|
|
|
$this->connectToDatabaseServer($GLOBALS['dbi'], $authPlugin, $currentServer);
|
|
$authPlugin->rememberCredentials();
|
|
assert($request instanceof ServerRequest);
|
|
$authPlugin->checkTwoFactor($request);
|
|
} catch (ExitException) {
|
|
return ResponseRenderer::getInstance()->response();
|
|
}
|
|
|
|
/* Log success */
|
|
Logging::logUser($this->config, $currentServer->user);
|
|
|
|
return $handler->handle($request);
|
|
}
|
|
|
|
private function connectToDatabaseServer(
|
|
DatabaseInterface $dbi,
|
|
AuthenticationPlugin $auth,
|
|
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).
|
|
*/
|
|
$controlConnection = null;
|
|
if ($currentServer->controlUser !== '') {
|
|
$controlConnection = $dbi->connect($currentServer, Connection::TYPE_CONTROL);
|
|
}
|
|
|
|
// Connects to the server (validates user's login)
|
|
$userConnection = $dbi->connect($currentServer, Connection::TYPE_USER);
|
|
if ($userConnection === null) {
|
|
$auth->showFailure('mysql-denied');
|
|
}
|
|
|
|
if ($controlConnection !== null) {
|
|
return;
|
|
}
|
|
|
|
/**
|
|
* Open separate connection for control queries, this is needed to avoid problems with table locking used in
|
|
* main connection and phpMyAdmin issuing queries to configuration storage, which is not locked by that time.
|
|
*/
|
|
$dbi->connect($currentServer, Connection::TYPE_USER, Connection::TYPE_CONTROL);
|
|
}
|
|
}
|