diff --git a/app/modules/web/Controllers/ControllerBase.php b/app/modules/web/Controllers/ControllerBase.php index 6bf6b50c..5fc460d7 100644 --- a/app/modules/web/Controllers/ControllerBase.php +++ b/app/modules/web/Controllers/ControllerBase.php @@ -26,15 +26,23 @@ namespace SP\Modules\Web\Controllers; defined('APP_ROOT') || die(); -use DI\DependencyException; -use DI\NotFoundException; use Exception; +use Klein\Klein; use Psr\Container\ContainerInterface; +use SP\Bootstrap; +use SP\Config\Config; +use SP\Config\ConfigDataInterface; +use SP\Core\Acl\Acl; +use SP\Core\Context\ContextInterface; use SP\Core\Crypt\Hash; +use SP\Core\Events\EventDispatcher; use SP\Core\Exceptions\FileNotFoundException; use SP\Core\Exceptions\SessionTimeout; use SP\Core\Exceptions\SPException; +use SP\Core\PhpExtensionChecker; +use SP\Core\UI\ThemeInterface; use SP\DataModel\ProfileData; +use SP\Http\Request; use SP\Modules\Web\Controllers\Helpers\LayoutHelper; use SP\Modules\Web\Controllers\Traits\WebControllerTrait; use SP\Mvc\View\Template; @@ -49,45 +57,63 @@ abstract class ControllerBase { use WebControllerTrait; - /** - * Constantes de errores - */ - public const ERR_UNAVAILABLE = 0; - public const ERR_ACCOUNT_NO_PERMISSION = 1; - public const ERR_PAGE_NO_PERMISSION = 2; - public const ERR_UPDATE_MPASS = 3; - public const ERR_OPERATION_NO_PERMISSION = 4; - public const ERR_EXCEPTION = 5; - /** - * @var Template Instancia del motor de plantillas a utilizar - */ - protected Template $view; - protected ?UserLoginResponse $userData = null; - protected ?ProfileData $userProfileData = null; + protected const ERR_UNAVAILABLE = 0; + + // TODO: remove when controllers are ready protected ContainerInterface $dic; - protected bool $isAjax = false; + + protected EventDispatcher $eventDispatcher; + protected Config $config; + protected ContextInterface $session; + protected ThemeInterface $theme; + protected Klein $router; + protected Acl $acl; + protected ConfigDataInterface $configData; + protected Request $request; + protected PhpExtensionChecker $extensionChecker; + protected Template $view; + protected ?string $actionName = null; + protected ?UserLoginResponse $userData = null; + protected ?ProfileData $userProfileData = null; + protected bool $isAjax; + protected LayoutHelper $layoutHelper; + private Browser $browser; /** - * Constructor - * - * @param \Psr\Container\ContainerInterface $container - * @param string $actionName - * + * @throws \SP\Core\Exceptions\SessionTimeout * @throws \JsonException */ - final public function __construct( - ContainerInterface $container, - string $actionName - ) - { - $this->dic = $container; - $this->actionName = $actionName; + public function __construct( + EventDispatcher $eventDispatcher, + Config $config, + ContextInterface $session, + ThemeInterface $theme, + Klein $router, + Acl $acl, + Request $request, + PhpExtensionChecker $extensionChecker, + Template $template, + Browser $browser, + LayoutHelper $layoutHelper + ) { + // TODO: remove when controllers are ready + $this->dic = Bootstrap::getContainer(); - $this->setUp($container); + $this->controllerName = $this->getControllerName(); + $this->configData = $config->getConfigData(); + $this->eventDispatcher = $eventDispatcher; + $this->config = $config; + $this->session = $session; + $this->theme = $theme; + $this->router = $router; + $this->acl = $acl; + $this->request = $request; + $this->extensionChecker = $extensionChecker; + $this->browser = $browser; + $this->layoutHelper = $layoutHelper; - $this->view = $this->dic->get(Template::class); + $this->view = $template; $this->view->setBase(strtolower($this->controllerName)); - $this->isAjax = $this->request->isAjax(); $loggedIn = $this->session->isLoggedIn(); @@ -99,10 +125,19 @@ abstract class ControllerBase $this->setViewVars($loggedIn); + $this->setup = true; + + // TODO: call handleSessionTimeout from controller::initialize directly try { - $this->initialize(); + if (method_exists($this, 'initialize')) { + $this->initialize(); + } } catch (SessionTimeout $sessionTimeout) { - $this->handleSessionTimeout(); + $this->handleSessionTimeout( + function () { + return true; + } + ); throw $sessionTimeout; } @@ -143,25 +178,7 @@ abstract class ControllerBase $this->view->assign('configData', $this->configData); // Pass the action name to the template as a variable - $this->view->assign($this->actionName, true); - } - - abstract protected function initialize(): void; - - /** - * @throws \JsonException - */ - private function handleSessionTimeout(): void - { - $this->sessionLogout( - $this->request, - $this->configData, - function ($redirect) { - $this->router->response() - ->redirect($redirect) - ->send(true); - } - ); + $this->view->assign('action', true); } /** @@ -213,8 +230,7 @@ abstract class ControllerBase ); try { - $this->dic->get(LayoutHelper::class) - ->getFullLayout('main', $this->acl); + $this->layoutHelper->getFullLayout('main', $this->acl); } catch (Exception $e) { processException($e); } @@ -240,10 +256,10 @@ abstract class ControllerBase /** * Comprobar si el usuario está logado. * - * @throws AuthException - * @throws DependencyException - * @throws NotFoundException - * @throws SessionTimeout + * @param bool $requireAuthCompleted + * + * @throws \SP\Core\Exceptions\SessionTimeout + * @throws \SP\Services\Auth\AuthException */ protected function checkLoggedIn(bool $requireAuthCompleted = true): void { @@ -253,18 +269,14 @@ abstract class ControllerBase throw new SessionTimeout(); } + // Comprobar si se ha identificado mediante el servidor web y el usuario coincide if ($this->session->isLoggedIn() && $this->session->getAuthCompleted() === $requireAuthCompleted && $this->configData->isAuthBasicEnabled() + && $this->browser->checkServerAuthUser($this->userData->getLogin()) === false + && $this->browser->checkServerAuthUser($this->userData->getSsoLogin()) === false ) { - $browser = $this->dic->get(Browser::class); - - // Comprobar si se ha identificado mediante el servidor web y el usuario coincide - if ($browser->checkServerAuthUser($this->userData->getLogin()) === false - && $browser->checkServerAuthUser($this->userData->getSsoLogin()) === false - ) { - throw new AuthException('Invalid browser auth'); - } + throw new AuthException('Invalid browser auth'); } } @@ -295,11 +307,11 @@ abstract class ControllerBase /** * Comprobar si está permitido el acceso al módulo/página. * - * @param int $action La acción a comprobar + * @param int $action La acción a comprobar */ protected function checkAccess(int $action): bool { return $this->userData->getIsAdminApp() - || $this->acl->checkUserAccess($action); + || $this->acl->checkUserAccess($action); } } \ No newline at end of file diff --git a/app/modules/web/Controllers/InstallController.php b/app/modules/web/Controllers/InstallController.php index 21c77050..7764fbeb 100644 --- a/app/modules/web/Controllers/InstallController.php +++ b/app/modules/web/Controllers/InstallController.php @@ -24,16 +24,23 @@ namespace SP\Modules\Web\Controllers; -use DI\DependencyException; -use DI\NotFoundException; use Exception; +use Klein\Klein; +use SP\Config\Config; +use SP\Core\Acl\Acl; +use SP\Core\Context\ContextInterface; +use SP\Core\Events\EventDispatcher; use SP\Core\Exceptions\SPException; use SP\Core\Language; use SP\Core\PhpExtensionChecker; +use SP\Core\UI\ThemeInterface; use SP\Http\JsonResponse; +use SP\Http\Request; use SP\Modules\Web\Controllers\Helpers\LayoutHelper; use SP\Modules\Web\Controllers\Traits\JsonTrait; use SP\Mvc\View\Components\SelectItemAdapter; +use SP\Mvc\View\Template; +use SP\Providers\Auth\Browser\Browser; use SP\Services\Install\InstallData; use SP\Services\Install\Installer; @@ -46,28 +53,57 @@ final class InstallController extends ControllerBase { use JsonTrait; - /** - * @throws DependencyException - * @throws NotFoundException - */ + private Installer $installer; + + public function __construct( + EventDispatcher $eventDispatcher, + Config $config, + ContextInterface $session, + ThemeInterface $theme, + Klein $router, + Acl $acl, + Request $request, + PhpExtensionChecker $extensionChecker, + Template $template, + Browser $browser, + LayoutHelper $layoutHelper, + Installer $installer + ) { + parent::__construct( + $eventDispatcher, + $config, + $session, + $theme, + $router, + $acl, + $request, + $extensionChecker, + $template, + $browser, + $layoutHelper + ); + + $this->installer = $installer; + } + public function indexAction(): void { if ($this->configData->isInstalled()) { $this->router->response() ->redirect('index.php?r=login'); + return; } - $layoutHelper = $this->dic->get(LayoutHelper::class); - $layoutHelper->getPublicLayout('index', 'install'); + $this->layoutHelper->getPublicLayout('index', 'install'); $errors = []; - foreach ($this->dic->get(PhpExtensionChecker::class)->getMissing() as $module) { - $error[] = [ - 'type' => SPException::WARNING, + foreach ($this->extensionChecker->getMissing() as $module) { + $errors[] = [ + 'type' => SPException::WARNING, 'description' => sprintf('%s (%s)', __('Module unavailable'), $module), - 'hint' => __('Without this module the application could not run correctly') + 'hint' => __('Without this module the application could not run correctly'), ]; } @@ -83,8 +119,6 @@ final class InstallController extends ControllerBase /** * @return bool - * @throws DependencyException - * @throws NotFoundException * @throws \JsonException */ public function installAction(): bool @@ -101,7 +135,7 @@ final class InstallController extends ControllerBase $installData->setHostingMode($this->request->analyzeBool('hostingmode', false)); try { - $this->dic->get(Installer::class)->run($installData); + $this->installer->run($installData); return $this->returnJsonResponse( JsonResponse::JSON_SUCCESS, @@ -113,12 +147,4 @@ final class InstallController extends ControllerBase return $this->returnJsonResponseException($e); } } - - /** - * @return void - */ - protected function initialize(): void - { - // TODO: Implement initialize() method. - } } \ No newline at end of file diff --git a/app/modules/web/Controllers/LoginController.php b/app/modules/web/Controllers/LoginController.php index 4c5150bf..a8b16e76 100644 --- a/app/modules/web/Controllers/LoginController.php +++ b/app/modules/web/Controllers/LoginController.php @@ -25,16 +25,26 @@ namespace SP\Modules\Web\Controllers; use Exception; +use Klein\Klein; use Psr\Container\ContainerExceptionInterface; use Psr\Container\NotFoundExceptionInterface; use SP\Bootstrap; +use SP\Config\Config; +use SP\Core\Acl\Acl; use SP\Core\Context\ContextBase; +use SP\Core\Context\ContextInterface; use SP\Core\Events\Event; +use SP\Core\Events\EventDispatcher; use SP\Core\Events\EventMessage; +use SP\Core\PhpExtensionChecker; use SP\Core\SessionUtil; +use SP\Core\UI\ThemeInterface; +use SP\Http\Request; use SP\Http\Uri; use SP\Modules\Web\Controllers\Helpers\LayoutHelper; use SP\Modules\Web\Controllers\Traits\JsonTrait; +use SP\Mvc\View\Template; +use SP\Providers\Auth\Browser\Browser; use SP\Services\Auth\LoginService; /** @@ -46,6 +56,40 @@ final class LoginController extends ControllerBase { use JsonTrait; + private LoginService $loginService; + + public function __construct( + EventDispatcher $eventDispatcher, + Config $config, + ContextInterface $session, + ThemeInterface $theme, + Klein $router, + Acl $acl, + Request $request, + PhpExtensionChecker $extensionChecker, + Template $template, + Browser $browser, + LayoutHelper $layoutHelper, + LoginService $loginService + ) { + parent::__construct( + $eventDispatcher, + $config, + $session, + $theme, + $router, + $acl, + $request, + $extensionChecker, + $template, + $browser, + $layoutHelper + ); + + $this->loginService = $loginService; + } + + /** * Login action * @@ -56,12 +100,10 @@ final class LoginController extends ControllerBase public function loginAction(): bool { try { - $loginService = $this->dic->get(LoginService::class); + $from = $this->getSignedUriFromRequest($this->request); + $this->loginService->setFrom($from); - $from = $this->getSignedUriFromRequest(); - $loginService->setFrom($from); - - $loginResponmse = $loginService->doLogin(); + $loginResponse = $this->loginService->doLogin(); $this->checkForwarded(); @@ -88,7 +130,7 @@ final class LoginController extends ControllerBase return $this->returnJsonResponseData([ 'url' => $this->session->getTrasientKey('redirect') - ?: $loginResponmse->getRedirect() + ?: $loginResponse->getRedirect(), ]); } catch (Exception $e) { processException($e); @@ -137,8 +179,8 @@ final class LoginController extends ControllerBase EventMessage::factory() ->addDescription(__u('Logout session')) ->addDetail(__u('User'), $this->session->getUserData()->getLogin()) - ->addDetail(__u('Inactive time'), $inactiveTime . ' min.') - ->addDetail(__u('Total time'), $totalTime . ' min.') + ->addDetail(__u('Inactive time'), $inactiveTime.' min.') + ->addDetail(__u('Total time'), $totalTime.' min.') ) ); @@ -146,8 +188,7 @@ final class LoginController extends ControllerBase $this->session->setAppStatus(ContextBase::APP_STATUS_LOGGEDOUT); - $layoutHelper = $this->dic->get(LayoutHelper::class); - $layoutHelper->getCustomLayout('logout', 'logout'); + $this->layoutHelper->getCustomLayout('logout', 'logout'); $this->view(); } else { @@ -157,14 +198,12 @@ final class LoginController extends ControllerBase /** * Index action - * - * @throws ContainerExceptionInterface - * @throws NotFoundExceptionInterface */ public function indexAction(): void { - $this->dic->get(LayoutHelper::class) - ->getCustomLayout('index', 'login'); + SessionUtil::cleanSession(); + + $this->layoutHelper->getCustomLayout('index', 'login'); $this->view->assign( 'mailEnabled', @@ -175,12 +214,4 @@ final class LoginController extends ControllerBase $this->view(); } - - /** - * @return void - */ - protected function initialize(): void - { - // TODO: Implement initialize() method. - } } \ No newline at end of file diff --git a/app/modules/web/Controllers/SimpleControllerBase.php b/app/modules/web/Controllers/SimpleControllerBase.php index 3d78cb01..c7ce234c 100644 --- a/app/modules/web/Controllers/SimpleControllerBase.php +++ b/app/modules/web/Controllers/SimpleControllerBase.php @@ -24,10 +24,19 @@ namespace SP\Modules\Web\Controllers; +use Klein\Klein; use Psr\Container\ContainerInterface; +use SP\Bootstrap; +use SP\Config\Config; +use SP\Core\Acl\Acl; use SP\Core\Acl\UnauthorizedPageException; +use SP\Core\Context\ContextInterface; +use SP\Core\Events\EventDispatcher; use SP\Core\Exceptions\SessionTimeout; use SP\Core\Exceptions\SPException; +use SP\Core\PhpExtensionChecker; +use SP\Core\UI\ThemeInterface; +use SP\Http\Request; use SP\Modules\Web\Controllers\Traits\WebControllerTrait; /** @@ -39,27 +48,59 @@ abstract class SimpleControllerBase { use WebControllerTrait; + // TODO: remove when controllers are ready protected ContainerInterface $dic; + protected EventDispatcher $eventDispatcher; + protected Config $config; + protected ContextInterface $session; + protected ThemeInterface $theme; + protected Klein $router; + protected Acl $acl; + protected Request $request; + protected PhpExtensionChecker $extensionChecker; + /** - * SimpleControllerBase constructor. - * + * @throws \SP\Core\Exceptions\SessionTimeout * @throws \JsonException */ public function __construct( - ContainerInterface $container, - string $actionName - ) - { - $this->dic = $container; - $this->actionName = $actionName; + EventDispatcher $eventDispatcher, + Config $config, + ContextInterface $session, + ThemeInterface $theme, + Klein $router, + Acl $acl, + Request $request, + PhpExtensionChecker $extensionChecker + ) { + // TODO: remove when controllers are ready + $this->dic = Bootstrap::getContainer(); - $this->setUp($container); + $this->controllerName = $this->getControllerName(); + $this->configData = $config->getConfigData(); + $this->eventDispatcher = $eventDispatcher; + $this->config = $config; + $this->session = $session; + $this->theme = $theme; + $this->router = $router; + $this->acl = $acl; + $this->request = $request; + $this->extensionChecker = $extensionChecker; + $this->setup = true; + + // TODO: call handleSessionTimeout from controller::initialize directly try { - $this->initialize(); + if (method_exists($this, 'initialize')) { + $this->initialize(); + } } catch (SessionTimeout $sessionTimeout) { - $this->handleSessionTimeout(); + $this->handleSessionTimeout( + function () { + return true; + } + ); throw $sessionTimeout; } @@ -67,22 +108,6 @@ abstract class SimpleControllerBase abstract protected function initialize(): void; - /** - * @throws \JsonException - */ - public function handleSessionTimeout(): void - { - $this->sessionLogout( - $this->request, - $this->configData, - function ($redirect) { - $this->router->response() - ->redirect($redirect) - ->send(true); - } - ); - } - /** * Comprobaciones * diff --git a/app/modules/web/Controllers/Traits/WebControllerTrait.php b/app/modules/web/Controllers/Traits/WebControllerTrait.php index 85352544..69789bb1 100644 --- a/app/modules/web/Controllers/Traits/WebControllerTrait.php +++ b/app/modules/web/Controllers/Traits/WebControllerTrait.php @@ -24,17 +24,9 @@ namespace SP\Modules\Web\Controllers\Traits; -use Klein\Klein; -use Psr\Container\ContainerInterface; -use SP\Config\Config; -use SP\Config\ConfigDataInterface; -use SP\Core\Acl\Acl; -use SP\Core\Context\ContextInterface; -use SP\Core\Context\SessionContext; -use SP\Core\Events\EventDispatcher; +use Closure; +use SP\Core\Exceptions\SessionTimeout; use SP\Core\Exceptions\SPException; -use SP\Core\PhpExtensionChecker; -use SP\Core\UI\ThemeInterface; use SP\Http\Request; use SP\Mvc\Controller\ControllerTrait; @@ -45,34 +37,23 @@ trait WebControllerTrait { use ControllerTrait; - protected ?string $controllerName = null; - protected ?EventDispatcher $eventDispatcher = null; - protected ?Config $config = null; - protected ?SessionContext $session = null; - protected ?ThemeInterface $theme = null; - protected ?string $actionName = null; - protected ?Klein $router = null; - protected ?Acl $acl = null; - protected ConfigDataInterface $configData; - protected ?Request $request = null; - protected ?PhpExtensionChecker $extensionChecker = null; private bool $setup = false; /** * Returns the signed URI component after validating its signature. * This component is used for deep linking */ - final protected function getSignedUriFromRequest(): ?string + final protected function getSignedUriFromRequest(Request $request): ?string { if (!$this->setup) { return null; } - $from = $this->request->analyzeString('from'); + $from = $request->analyzeString('from'); if ($from) { try { - $this->request->verifySignature( + $request->verifySignature( $this->configData->getPasswordSalt(), 'from' ); @@ -86,20 +67,23 @@ trait WebControllerTrait return $from; } - private function setUp(ContainerInterface $dic): void + /** + * @throws \JsonException + * @throws SessionTimeout + */ + private function handleSessionTimeout(Closure $checker): void { - $this->controllerName = $this->getControllerName(); + if ($checker->call($this) === true) { + $this->sessionLogout( + $this->request, + function ($redirect) { + $this->router->response() + ->redirect($redirect) + ->send(true); + } + ); - $this->config = $dic->get(Config::class); - $this->configData = $this->config->getConfigData(); - $this->session = $dic->get(ContextInterface::class); - $this->theme = $dic->get(ThemeInterface::class); - $this->eventDispatcher = $dic->get(EventDispatcher::class); - $this->router = $dic->get(Klein::class); - $this->request = $dic->get(Request::class); - $this->acl = $dic->get(Acl::class); - $this->extensionChecker = $dic->get(PhpExtensionChecker::class); - - $this->setup = true; + throw new SessionTimeout(); + } } } \ No newline at end of file diff --git a/lib/SP/Mvc/Controller/ControllerTrait.php b/lib/SP/Mvc/Controller/ControllerTrait.php index b4987b67..e166ba00 100644 --- a/lib/SP/Mvc/Controller/ControllerTrait.php +++ b/lib/SP/Mvc/Controller/ControllerTrait.php @@ -43,6 +43,9 @@ use SP\Util\Util; */ trait ControllerTrait { + protected ConfigDataInterface $configData; + protected string $controllerName; + protected function getControllerName(): string { $class = static::class; @@ -56,11 +59,9 @@ trait ControllerTrait * @throws \JsonException */ protected function sessionLogout( - Request $request, - ConfigDataInterface $configData, - Closure $onRedirect - ): void - { + Request $request, + Closure $onRedirect + ): void { if ($request->isJson()) { $jsonResponse = new JsonResponse(__u('Session not started or timed out')); $jsonResponse->setStatus(10); @@ -76,11 +77,11 @@ trait ControllerTrait $route = $request->analyzeString('r'); $hash = $request->analyzeString('h'); - $uri = new Uri(Bootstrap::$WEBROOT . Bootstrap::$SUBURI); + $uri = new Uri(Bootstrap::$WEBROOT.Bootstrap::$SUBURI); $uri->addParam('_r', 'login'); if ($route && $hash) { - $key = $configData->getPasswordSalt(); + $key = $this->configData->getPasswordSalt(); $request->verifySignature($key); $uri->addParam('from', $route);