Create the Authentication middleware
Signed-off-by: Maurício Meneghini Fauth <mauricio@fauth.dev>
This commit is contained in:
parent
73cb80c785
commit
deb3214a55
@ -7,10 +7,7 @@ namespace PhpMyAdmin;
|
||||
use Fig\Http\Message\StatusCodeInterface;
|
||||
use Laminas\HttpHandlerRunner\Emitter\SapiEmitter;
|
||||
use Laminas\HttpHandlerRunner\RequestHandlerRunner;
|
||||
use PhpMyAdmin\Config\Settings\Server;
|
||||
use PhpMyAdmin\ConfigStorage\Relation;
|
||||
use PhpMyAdmin\Dbal\Connection;
|
||||
use PhpMyAdmin\Exceptions\AuthenticationPluginException;
|
||||
use PhpMyAdmin\Http\Factory\ResponseFactory;
|
||||
use PhpMyAdmin\Http\Factory\ServerRequestFactory;
|
||||
use PhpMyAdmin\Http\Handler\ApplicationHandler;
|
||||
@ -19,6 +16,7 @@ use PhpMyAdmin\Http\Response;
|
||||
use PhpMyAdmin\Http\ServerRequest;
|
||||
use PhpMyAdmin\Identifiers\DatabaseName;
|
||||
use PhpMyAdmin\Identifiers\TableName;
|
||||
use PhpMyAdmin\Middleware\Authentication;
|
||||
use PhpMyAdmin\Middleware\ConfigErrorAndPermissionChecking;
|
||||
use PhpMyAdmin\Middleware\ConfigLoading;
|
||||
use PhpMyAdmin\Middleware\CurrentServerGlobalSetting;
|
||||
@ -45,8 +43,6 @@ use PhpMyAdmin\Middleware\TokenRequestParamChecking;
|
||||
use PhpMyAdmin\Middleware\UriSchemeUpdating;
|
||||
use PhpMyAdmin\Middleware\UrlParamsSetting;
|
||||
use PhpMyAdmin\Middleware\UrlRedirection;
|
||||
use PhpMyAdmin\Plugins\AuthenticationPlugin;
|
||||
use PhpMyAdmin\Plugins\AuthenticationPluginFactory;
|
||||
use PhpMyAdmin\Routing\Routing;
|
||||
use PhpMyAdmin\SqlParser\Lexer;
|
||||
use PhpMyAdmin\Theme\ThemeManager;
|
||||
@ -57,7 +53,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Throwable;
|
||||
|
||||
use function __;
|
||||
use function define;
|
||||
use function function_exists;
|
||||
use function hash_equals;
|
||||
use function is_array;
|
||||
@ -128,6 +123,7 @@ class Application
|
||||
$requestHandler->add(new LanguageAndThemeCookieSaving($this->config));
|
||||
$requestHandler->add(new DbiLoading());
|
||||
$requestHandler->add(new LoginCookieValiditySetting($this->config));
|
||||
$requestHandler->add(new Authentication($this->config, $this->template, $this->responseFactory));
|
||||
|
||||
$runner = new RequestHandlerRunner(
|
||||
$requestHandler,
|
||||
@ -148,8 +144,6 @@ class Application
|
||||
|
||||
public function handle(ServerRequest $request): Response|null
|
||||
{
|
||||
$route = $request->getRoute();
|
||||
|
||||
$container = Core::getContainerBuilder();
|
||||
|
||||
$settings = $this->config->getSettings();
|
||||
@ -159,32 +153,6 @@ class Application
|
||||
|
||||
$currentServer = $this->config->getCurrentServer();
|
||||
if ($currentServer !== null) {
|
||||
/** @var AuthenticationPluginFactory $authPluginFactory */
|
||||
$authPluginFactory = $container->get(AuthenticationPluginFactory::class);
|
||||
try {
|
||||
$authPlugin = $authPluginFactory->create();
|
||||
} catch (AuthenticationPluginException $exception) {
|
||||
return $this->getGenericErrorResponse($exception->getMessage());
|
||||
}
|
||||
|
||||
$authPlugin->authenticate();
|
||||
$currentServer = new Server($GLOBALS['cfg']['Server']);
|
||||
|
||||
/* Enable LOAD DATA LOCAL INFILE for LDI plugin */
|
||||
if ($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();
|
||||
$authPlugin->checkTwoFactor($request);
|
||||
|
||||
/* Log success */
|
||||
Logging::logUser($this->config, $currentServer->user);
|
||||
|
||||
if ($GLOBALS['dbi']->getVersion() < $settings->mysqlMinVersion['internal']) {
|
||||
return $this->getGenericErrorResponse(sprintf(
|
||||
__('You should upgrade to %s %s or later.'),
|
||||
@ -359,37 +327,6 @@ class Application
|
||||
$container->setParameter('url_params', $GLOBALS['urlParams']);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
private function getGenericErrorResponse(string $message): Response
|
||||
{
|
||||
$response = $this->responseFactory->createResponse(StatusCodeInterface::STATUS_INTERNAL_SERVER_ERROR);
|
||||
|
||||
115
libraries/classes/Middleware/Authentication.php
Normal file
115
libraries/classes/Middleware/Authentication.php
Normal file
@ -0,0 +1,115 @@
|
||||
<?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);
|
||||
}
|
||||
}
|
||||
@ -45,11 +45,6 @@ parameters:
|
||||
count: 1
|
||||
path: libraries/classes/Advisory/Advisor.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'Server' on mixed\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Application.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'table' on mixed\\.$#"
|
||||
count: 1
|
||||
@ -70,11 +65,6 @@ parameters:
|
||||
count: 1
|
||||
path: libraries/classes/Application.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$dbi of method PhpMyAdmin\\\\Application\\:\\:connectToDatabaseServer\\(\\) expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Application.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$dbi of static method PhpMyAdmin\\\\Profiling\\:\\:check\\(\\) expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#"
|
||||
count: 1
|
||||
@ -85,11 +75,6 @@ parameters:
|
||||
count: 1
|
||||
path: libraries/classes/Application.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$server of class PhpMyAdmin\\\\Config\\\\Settings\\\\Server constructor expects array\\<int\\|string, mixed\\>, mixed given\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Application.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#2 \\$value of method Symfony\\\\Component\\\\DependencyInjection\\\\ContainerInterface\\:\\:setParameter\\(\\) expects array\\|bool\\|float\\|int\\|string\\|UnitEnum\\|null, mixed given\\.$#"
|
||||
count: 1
|
||||
@ -15815,6 +15800,21 @@ parameters:
|
||||
count: 1
|
||||
path: libraries/classes/Message.php
|
||||
|
||||
-
|
||||
message: "#^Cannot access offset 'Server' on mixed\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Middleware/Authentication.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$dbi of method PhpMyAdmin\\\\Middleware\\\\Authentication\\:\\:connectToDatabaseServer\\(\\) expects PhpMyAdmin\\\\DatabaseInterface, mixed given\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Middleware/Authentication.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$server of class PhpMyAdmin\\\\Config\\\\Settings\\\\Server constructor expects array\\<int\\|string, mixed\\>, mixed given\\.$#"
|
||||
count: 1
|
||||
path: libraries/classes/Middleware/Authentication.php
|
||||
|
||||
-
|
||||
message: "#^Parameter \\#1 \\$source of method PhpMyAdmin\\\\Config\\:\\:loadAndCheck\\(\\) expects string\\|null, mixed given\\.$#"
|
||||
count: 1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user