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;
*/
class LoginController extends ShaarliVisitorController
{
+ /**
+ * GET /login - Display the login page.
+ */
public function index(Request $request, Response $response): Response
{
- if ($this->container->loginManager->isLoggedIn()
+ try {
+ $this->checkLoginState();
+ } catch (CantLoginException $e) {
+ return $this->redirect($response, '/');
+ }
+
+ if ($request->getParam('login') !== null) {
+ $this->assignView('username', escape($request->getParam('login')));
+ }
+
+ $returnUrl = $request->getParam('returnurl') ?? $this->container->environment['HTTP_REFERER'] ?? null;
+
+ $this
+ ->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(
+ 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', 'install']);
+ }
+
+ /**
+ * 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)
) {
- return $response->withRedirect('./');
+ throw new CantLoginException();
}
- $userCanLogin = $this->container->loginManager->canLogin($request->getServerParams());
- if ($userCanLogin !== true) {
+ if (true !== $this->container->loginManager->canLogin($this->container->environment)) {
throw new LoginBannedException();
}
- if ($request->getParam('username') !== null) {
- $this->assignView('username', escape($request->getParam('username')));
+ 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
- ->assignView('returnurl', escape($request->getServerParam('HTTP_REFERER')))
- ->assignView('remember_user_default', $this->container->conf->get('privacy.remember_user_default', true))
- ->assignView('pagetitle', t('Login') .' - '. $this->container->conf->get('general.title', 'Shaarli'))
- ;
+ $this->container->cookieManager->setCookieParameter(
+ CookieManager::STAY_SIGNED_IN,
+ $this->container->loginManager->getStaySignedInToken(),
+ $expirationTime,
+ $cookiePath
+ );
+
+ return $expirationTime;
+ }
- return $response->write($this->render('loginform'));
+ 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);
}
}