]> git.immae.eu Git - github/shaarli/Shaarli.git/blobdiff - application/front/controller/visitor/LoginController.php
Process login through Slim controller
[github/shaarli/Shaarli.git] / application / front / controller / visitor / LoginController.php
index a257766fc61dd4c5f8b3ee434fe292234246fe99..c40b8cc400810b3c945baa8efbddaa2f244fe1a0 100644 (file)
@@ -4,8 +4,12 @@ declare(strict_types=1);
 
 namespace Shaarli\Front\Controller\Visitor;
 
+use Shaarli\Front\Exception\CantLoginException;
 use Shaarli\Front\Exception\LoginBannedException;
+use Shaarli\Front\Exception\WrongTokenException;
 use Shaarli\Render\TemplatePage;
+use Shaarli\Security\CookieManager;
+use Shaarli\Security\SessionManager;
 use Slim\Http\Request;
 use Slim\Http\Response;
 
@@ -19,29 +23,132 @@ use Slim\Http\Response;
  */
 class LoginController extends ShaarliVisitorController
 {
+    /**
+     * GET /login - Display the login page.
+     */
     public function index(Request $request, Response $response): Response
     {
-        if ($this->container->loginManager->isLoggedIn()
-            || $this->container->conf->get('security.open_shaarli', false)
-        ) {
+        try {
+            $this->checkLoginState();
+        } catch (CantLoginException $e) {
             return $this->redirect($response, '/');
         }
 
-        $userCanLogin = $this->container->loginManager->canLogin($request->getServerParams());
-        if ($userCanLogin !== true) {
-            throw new LoginBannedException();
+        if ($request->getParam('login') !== null) {
+            $this->assignView('username', escape($request->getParam('login')));
         }
 
-        if ($request->getParam('username') !== null) {
-            $this->assignView('username', escape($request->getParam('username')));
-        }
+        $returnUrl = $request->getParam('returnurl') ?? $this->container->environment['HTTP_REFERER'] ?? null;
 
         $this
-            ->assignView('returnurl', escape($request->getServerParam('HTTP_REFERER')))
+            ->assignView('returnurl', escape($returnUrl))
             ->assignView('remember_user_default', $this->container->conf->get('privacy.remember_user_default', true))
             ->assignView('pagetitle', t('Login') .' - '. $this->container->conf->get('general.title', 'Shaarli'))
         ;
 
         return $response->write($this->render(TemplatePage::LOGIN));
     }
+
+    /**
+     * POST /login - Process login
+     */
+    public function login(Request $request, Response $response): Response
+    {
+        if (!$this->container->sessionManager->checkToken($request->getParam('token'))) {
+            throw new WrongTokenException();
+        }
+
+        try {
+            $this->checkLoginState();
+        } catch (CantLoginException $e) {
+            return $this->redirect($response, '/');
+        }
+
+        if (!$this->container->loginManager->checkCredentials(
+                $this->container->environment['REMOTE_ADDR'],
+                client_ip_id($this->container->environment),
+                $request->getParam('login'),
+                $request->getParam('password')
+            )
+        ) {
+            $this->container->loginManager->handleFailedLogin($this->container->environment);
+
+            $this->container->sessionManager->setSessionParameter(
+                SessionManager::KEY_ERROR_MESSAGES,
+                [t('Wrong login/password.')]
+            );
+
+            // Call controller directly instead of unnecessary redirection
+            return $this->index($request, $response);
+        }
+
+        $this->container->loginManager->handleSuccessfulLogin($this->container->environment);
+
+        $cookiePath = $this->container->basePath . '/';
+        $expirationTime = $this->saveLongLastingSession($request, $cookiePath);
+        $this->renewUserSession($cookiePath, $expirationTime);
+
+        // Force referer from given return URL
+        $this->container->environment['HTTP_REFERER'] = $request->getParam('returnurl');
+
+        return $this->redirectFromReferer($request, $response, ['login']);
+    }
+
+    /**
+     * Make sure that the user is allowed to login and/or displaying the login page:
+     *   - not already logged in
+     *   - not open shaarli
+     *   - not banned
+     */
+    protected function checkLoginState(): bool
+    {
+        if ($this->container->loginManager->isLoggedIn()
+            || $this->container->conf->get('security.open_shaarli', false)
+        ) {
+            throw new CantLoginException();
+        }
+
+        if (true !== $this->container->loginManager->canLogin($this->container->environment)) {
+            throw new LoginBannedException();
+        }
+
+        return true;
+    }
+
+    /**
+     * @return int Session duration in seconds
+     */
+    protected function saveLongLastingSession(Request $request, string $cookiePath): int
+    {
+        if (empty($request->getParam('longlastingsession'))) {
+            // Standard session expiration (=when browser closes)
+            $expirationTime = 0;
+        } else {
+            // Keep the session cookie even after the browser closes
+            $this->container->sessionManager->setStaySignedIn(true);
+            $expirationTime = $this->container->sessionManager->extendSession();
+        }
+
+        $this->container->cookieManager->setCookieParameter(
+            CookieManager::STAY_SIGNED_IN,
+            $this->container->loginManager->getStaySignedInToken(),
+            $expirationTime,
+            $cookiePath
+        );
+
+        return $expirationTime;
+    }
+
+    protected function renewUserSession(string $cookiePath, int $expirationTime): void
+    {
+        // Send cookie with the new expiration date to the browser
+        $this->container->sessionManager->destroy();
+        $this->container->sessionManager->cookieParameters(
+            $expirationTime,
+            $cookiePath,
+            $this->container->environment['SERVER_NAME']
+        );
+        $this->container->sessionManager->start();
+        $this->container->sessionManager->regenerateId(true);
+    }
 }