From 04e7e6bdc57d44ad829ddd47826b0c9da70f1d2d Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Tue, 9 Jul 2024 14:23:12 +0800 Subject: [PATCH] fix: Prevent invalid session handlers --- system/Config/BaseService.php | 3 ++- system/Config/Services.php | 17 ++++++++++++---- tests/system/Config/ServicesTest.php | 29 ++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index 5bd55403beba..687044be0713 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -75,6 +75,7 @@ use Config\Optimize; use Config\Pager as ConfigPager; use Config\Services as AppServices; +use Config\Session as ConfigSession; use Config\Toolbar as ConfigToolbar; use Config\Validation as ConfigValidation; use Config\View as ConfigView; @@ -130,7 +131,7 @@ * @method static Router router(RouteCollectionInterface $routes = null, Request $request = null, $getShared = true) * @method static RouteCollection routes($getShared = true) * @method static Security security(App $config = null, $getShared = true) - * @method static Session session(App $config = null, $getShared = true) + * @method static Session session(ConfigSession $config = null, $getShared = true) * @method static SiteURIFactory siteurifactory(App $config = null, Superglobals $superglobals = null, $getShared = true) * @method static Superglobals superglobals(array $server = null, array $get = null, bool $getShared = true) * @method static Throttler throttler($getShared = true) diff --git a/system/Config/Services.php b/system/Config/Services.php index 422799e0b87c..e37b1278e9a7 100644 --- a/system/Config/Services.php +++ b/system/Config/Services.php @@ -51,6 +51,7 @@ use CodeIgniter\Router\RouteCollectionInterface; use CodeIgniter\Router\Router; use CodeIgniter\Security\Security; +use CodeIgniter\Session\Handlers\BaseHandler as SessionBaseHandler; use CodeIgniter\Session\Handlers\Database\MySQLiHandler; use CodeIgniter\Session\Handlers\Database\PostgreHandler; use CodeIgniter\Session\Handlers\DatabaseHandler; @@ -88,6 +89,7 @@ use Config\Toolbar as ToolbarConfig; use Config\Validation as ValidationConfig; use Config\View as ViewConfig; +use InvalidArgumentException; use Locale; /** @@ -674,17 +676,24 @@ public static function session(?SessionConfig $config = null, bool $getShared = if ($driverName === DatabaseHandler::class) { $DBGroup = $config->DBGroup ?? config(Database::class)->defaultGroup; - $db = Database::connect($DBGroup); - $driver = $db->getPlatform(); + $driverPlatform = Database::connect($DBGroup)->getPlatform(); - if ($driver === 'MySQLi') { + if ($driverPlatform === 'MySQLi') { $driverName = MySQLiHandler::class; - } elseif ($driver === 'Postgre') { + } elseif ($driverPlatform === 'Postgre') { $driverName = PostgreHandler::class; } } + if (! class_exists($driverName) || ! is_a($driverName, SessionBaseHandler::class, true)) { + throw new InvalidArgumentException(sprintf( + 'Invalid session handler "%s" provided.', + $driverName + )); + } + + /** @var SessionBaseHandler $driver */ $driver = new $driverName($config, AppServices::get('request')->getIPAddress()); $driver->setLogger($logger); diff --git a/tests/system/Config/ServicesTest.php b/tests/system/Config/ServicesTest.php index 7825687841c7..e80e2d394eeb 100644 --- a/tests/system/Config/ServicesTest.php +++ b/tests/system/Config/ServicesTest.php @@ -46,6 +46,9 @@ use Config\App; use Config\Exceptions; use Config\Security as SecurityConfig; +use Config\Session as ConfigSession; +use InvalidArgumentException; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\PreserveGlobalState; use PHPUnit\Framework\Attributes\RunInSeparateProcess; @@ -259,6 +262,32 @@ public function testNewSessionWithNullConfig(): void $this->assertInstanceOf(Session::class, $actual); } + #[DataProvider('provideNewSessionInvalid')] + #[PreserveGlobalState(false)] + #[RunInSeparateProcess] + public function testNewSessionWithInvalidHandler(string $driver): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage(sprintf('Invalid session handler "%s" provided.', $driver)); + + $config = new ConfigSession(); + + $config->driver = $driver; + Services::session($config, false); + } + + /** + * @return iterable + */ + public static function provideNewSessionInvalid(): iterable + { + yield 'just a string' => ['file']; + + yield 'inexistent class' => ['Foo']; + + yield 'other class' => [self::class]; + } + #[PreserveGlobalState(false)] #[RunInSeparateProcess] public function testCallStatic(): void