From 88110550b89617dcda16441212599b8a40faa20c Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Fri, 16 Feb 2018 21:51:44 +0100 Subject: Refactor client session hijacking protection Signed-off-by: VirtualTam --- index.php | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) (limited to 'index.php') diff --git a/index.php b/index.php index 2fe3f821..08a69327 100644 --- a/index.php +++ b/index.php @@ -207,7 +207,7 @@ function setup_login_state($conf) } // If session does not exist on server side, or IP address has changed, or session has expired, logout. if (empty($_SESSION['uid']) - || ($conf->get('security.session_protection_disabled') === false && $_SESSION['ip'] != allIPs()) + || ($conf->get('security.session_protection_disabled') === false && $_SESSION['ip'] != client_ip_id($_SERVER)) || time() >= $_SESSION['expires_on']) { logout(); @@ -231,16 +231,6 @@ $userIsLoggedIn = setup_login_state($conf); // ------------------------------------------------------------------------------------------ // Session management -// Returns the IP address of the client (Used to prevent session cookie hijacking.) -function allIPs() -{ - $ip = $_SERVER['REMOTE_ADDR']; - // Then we use more HTTP headers to prevent session hijacking from users behind the same proxy. - if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip=$ip.'_'.$_SERVER['HTTP_X_FORWARDED_FOR']; } - if (isset($_SERVER['HTTP_CLIENT_IP'])) { $ip=$ip.'_'.$_SERVER['HTTP_CLIENT_IP']; } - return $ip; -} - /** * Load user session. * @@ -249,7 +239,7 @@ function allIPs() function fillSessionInfo($conf) { $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid) - $_SESSION['ip']=allIPs(); // We store IP address(es) of the client to make sure session is not hijacked. + $_SESSION['ip'] = client_ip_id($_SERVER); $_SESSION['username']= $conf->get('credentials.login'); $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. } -- cgit v1.2.3 From db45a36a53dbd722e5e891827e49d9e7651f2a5e Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Fri, 16 Feb 2018 22:21:59 +0100 Subject: Refactor SessionManager::$INACTIVITY_TIMEOUT Changed: - move INACTIVITY_TIMEOUT to SessionManager - inject a dependency to a SessionManager instance in: - fillSessionInfo() - setup_login_state() - check_auth() - cleanup related code and comments Signed-off-by: VirtualTam --- index.php | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'index.php') diff --git a/index.php b/index.php index 08a69327..9cbc9241 100644 --- a/index.php +++ b/index.php @@ -101,8 +101,6 @@ if (dirname($_SERVER['SCRIPT_NAME']) != '/') { // Set default cookie expiration and path. session_set_cookie_params($cookie['lifetime'], $cookiedir, $_SERVER['SERVER_NAME']); // Set session parameters on server side. -// If the user does not access any page within this time, his/her session is considered expired. -define('INACTIVITY_TIMEOUT', 3600); // in seconds. // Use cookies to store session. ini_set('session.use_cookies', 1); // Force cookies for session (phpsessionID forbidden in URL). @@ -183,11 +181,12 @@ define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['R /** * Checking session state (i.e. is the user still logged in) * - * @param ConfigManager $conf The configuration manager. + * @param ConfigManager $conf Configuration Manager instance. + * @param SessionManager $sessionManager SessionManager instance * - * @return bool: true if the user is logged in, false otherwise. + * @return bool true if the user is logged in, false otherwise. */ -function setup_login_state($conf) +function setup_login_state($conf, $sessionManager) { if ($conf->get('security.open_shaarli')) { return true; @@ -202,7 +201,7 @@ function setup_login_state($conf) $_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN && !$loginFailure) { - fillSessionInfo($conf); + fillSessionInfo($conf, $sessionManager); $userIsLoggedIn = true; } // If session does not exist on server side, or IP address has changed, or session has expired, logout. @@ -216,9 +215,8 @@ function setup_login_state($conf) } if (!empty($_SESSION['longlastingsession'])) { $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // In case of "Stay signed in" checked. - } - else { - $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Standard session expiration date. + } else { + $_SESSION['expires_on'] = time() + $sessionManager::$INACTIVITY_TIMEOUT; } if (!$loginFailure) { $userIsLoggedIn = true; @@ -226,39 +224,42 @@ function setup_login_state($conf) return $userIsLoggedIn; } -$userIsLoggedIn = setup_login_state($conf); + +$userIsLoggedIn = setup_login_state($conf, $sessionManager); // ------------------------------------------------------------------------------------------ // Session management /** - * Load user session. + * Load user session * - * @param ConfigManager $conf Configuration Manager instance. + * @param ConfigManager $conf Configuration Manager instance. + * @param SessionManager $sessionManager SessionManager instance */ -function fillSessionInfo($conf) +function fillSessionInfo($conf, $sessionManager) { $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid) $_SESSION['ip'] = client_ip_id($_SERVER); $_SESSION['username']= $conf->get('credentials.login'); - $_SESSION['expires_on']=time()+INACTIVITY_TIMEOUT; // Set session expiration. + $_SESSION['expires_on'] = time() + $sessionManager::$INACTIVITY_TIMEOUT; } /** * Check that user/password is correct. * - * @param string $login Username - * @param string $password User password - * @param ConfigManager $conf Configuration Manager instance. + * @param string $login Username + * @param string $password User password + * @param ConfigManager $conf Configuration Manager instance. + * @param SessionManager $sessionManager SessionManager instance * * @return bool: authentication successful or not. */ -function check_auth($login, $password, $conf) +function check_auth($login, $password, $conf, $sessionManager) { $hash = sha1($password . $login . $conf->get('credentials.salt')); - if ($login == $conf->get('credentials.login') && $hash == $conf->get('credentials.hash')) - { // Login/password is correct. - fillSessionInfo($conf); + if ($login == $conf->get('credentials.login') && $hash == $conf->get('credentials.hash')) { + // Login/password is correct. + fillSessionInfo($conf, $sessionManager); logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login successful'); return true; } @@ -287,14 +288,13 @@ function logout() { // ------------------------------------------------------------------------------------------ // Process login form: Check if login/password is correct. -if (isset($_POST['login'])) -{ +if (isset($_POST['login'])) { if (! $loginManager->canLogin($_SERVER)) { die(t('I said: NO. You are banned for the moment. Go away.')); } if (isset($_POST['password']) && $sessionManager->checkToken($_POST['token']) - && (check_auth($_POST['login'], $_POST['password'], $conf)) + && (check_auth($_POST['login'], $_POST['password'], $conf, $sessionManager)) ) { // Login/password is OK. $loginManager->handleSuccessfulLogin($_SERVER); -- cgit v1.2.3 From 49f183231662c642ca9df6ceabf43fe128a5ffc1 Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Sat, 17 Feb 2018 01:14:58 +0100 Subject: Refactor PHP session handling during login/logout Changed: - move $_SESSION handling to SessionManager - code cleanup Signed-off-by: VirtualTam --- index.php | 49 +++++++++++++------------------------------------ 1 file changed, 13 insertions(+), 36 deletions(-) (limited to 'index.php') diff --git a/index.php b/index.php index 9cbc9241..34785209 100644 --- a/index.php +++ b/index.php @@ -197,11 +197,11 @@ function setup_login_state($conf, $sessionManager) $userIsLoggedIn = false; // Shaarli is not configured yet. $loginFailure = true; } - if (isset($_COOKIE['shaarli_staySignedIn']) && - $_COOKIE['shaarli_staySignedIn']===STAY_SIGNED_IN_TOKEN && - !$loginFailure) - { - fillSessionInfo($conf, $sessionManager); + if (isset($_COOKIE[SessionManager::$LOGGED_IN_COOKIE]) + && $_COOKIE[SessionManager::$LOGGED_IN_COOKIE] === STAY_SIGNED_IN_TOKEN + && !$loginFailure + ) { + $sessionManager->storeLoginInfo($_SERVER); $userIsLoggedIn = true; } // If session does not exist on server side, or IP address has changed, or session has expired, logout. @@ -209,7 +209,7 @@ function setup_login_state($conf, $sessionManager) || ($conf->get('security.session_protection_disabled') === false && $_SESSION['ip'] != client_ip_id($_SERVER)) || time() >= $_SESSION['expires_on']) { - logout(); + $sessionManager->logout(WEB_PATH); $userIsLoggedIn = false; $loginFailure = true; } @@ -230,20 +230,6 @@ $userIsLoggedIn = setup_login_state($conf, $sessionManager); // ------------------------------------------------------------------------------------------ // Session management -/** - * Load user session - * - * @param ConfigManager $conf Configuration Manager instance. - * @param SessionManager $sessionManager SessionManager instance - */ -function fillSessionInfo($conf, $sessionManager) -{ - $_SESSION['uid'] = sha1(uniqid('',true).'_'.mt_rand()); // Generate unique random number (different than phpsessionid) - $_SESSION['ip'] = client_ip_id($_SERVER); - $_SESSION['username']= $conf->get('credentials.login'); - $_SESSION['expires_on'] = time() + $sessionManager::$INACTIVITY_TIMEOUT; -} - /** * Check that user/password is correct. * @@ -259,7 +245,7 @@ function check_auth($login, $password, $conf, $sessionManager) $hash = sha1($password . $login . $conf->get('credentials.salt')); if ($login == $conf->get('credentials.login') && $hash == $conf->get('credentials.hash')) { // Login/password is correct. - fillSessionInfo($conf, $sessionManager); + $sessionManager->storeLoginInfo($_SERVER); logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login successful'); return true; } @@ -274,18 +260,6 @@ function isLoggedIn() return $userIsLoggedIn; } -// Force logout. -function logout() { - if (isset($_SESSION)) { - unset($_SESSION['uid']); - unset($_SESSION['ip']); - unset($_SESSION['username']); - unset($_SESSION['visibility']); - unset($_SESSION['untaggedonly']); - } - setcookie('shaarli_staySignedIn', FALSE, 0, WEB_PATH); -} - // ------------------------------------------------------------------------------------------ // Process login form: Check if login/password is correct. if (isset($_POST['login'])) { @@ -303,10 +277,13 @@ if (isset($_POST['login'])) { if (!empty($_POST['longlastingsession'])) { $_SESSION['longlastingsession'] = 31536000; // (31536000 seconds = 1 year) $expiration = time() + $_SESSION['longlastingsession']; // calculate relative cookie expiration (1 year from now) - setcookie('shaarli_staySignedIn', STAY_SIGNED_IN_TOKEN, $expiration, WEB_PATH); + setcookie($sessionManager::$LOGGED_IN_COOKIE, STAY_SIGNED_IN_TOKEN, $expiration, WEB_PATH); $_SESSION['expires_on'] = $expiration; // Set session expiration on server-side. - $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/'; + $cookiedir = ''; + if (dirname($_SERVER['SCRIPT_NAME']) != '/') { + $cookiedir = dirname($_SERVER["SCRIPT_NAME"]) . '/'; + } session_set_cookie_params($_SESSION['longlastingsession'],$cookiedir,$_SERVER['SERVER_NAME']); // Set session cookie expiration on client side // Note: Never forget the trailing slash on the cookie path! session_regenerate_id(true); // Send cookie with new expiration date to browser. @@ -676,7 +653,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) { invalidateCaches($conf->get('resource.page_cache')); - logout(); + $sessionManager->logout(WEB_PATH); header('Location: ?'); exit; } -- cgit v1.2.3 From 63ea23c2a67d2a1cf6cda79fa2fe49a143571cde Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Sat, 17 Feb 2018 01:46:27 +0100 Subject: Refactor user credential validation at login time Changed: - move login/password verification to LoginManager - code cleanup Signed-off-by: VirtualTam --- index.php | 144 +++++++++++++++++--------------------------------------------- 1 file changed, 38 insertions(+), 106 deletions(-) (limited to 'index.php') diff --git a/index.php b/index.php index 34785209..5e15b9c2 100644 --- a/index.php +++ b/index.php @@ -121,8 +121,8 @@ if (isset($_COOKIE['shaarli']) && !SessionManager::checkId($_COOKIE['shaarli'])) } $conf = new ConfigManager(); -$loginManager = new LoginManager($GLOBALS, $conf); $sessionManager = new SessionManager($_SESSION, $conf); +$loginManager = new LoginManager($GLOBALS, $conf, $sessionManager); // LC_MESSAGES isn't defined without php-intl, in this case use LC_COLLATE locale instead. if (! defined('LC_MESSAGES')) { @@ -178,88 +178,20 @@ if (! is_file($conf->getConfigFileExt())) { // a token depending of deployment salt, user password, and the current ip define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt'))); -/** - * Checking session state (i.e. is the user still logged in) - * - * @param ConfigManager $conf Configuration Manager instance. - * @param SessionManager $sessionManager SessionManager instance - * - * @return bool true if the user is logged in, false otherwise. - */ -function setup_login_state($conf, $sessionManager) -{ - if ($conf->get('security.open_shaarli')) { - return true; - } - $userIsLoggedIn = false; // By default, we do not consider the user as logged in; - $loginFailure = false; // If set to true, every attempt to authenticate the user will fail. This indicates that an important condition isn't met. - if (! $conf->exists('credentials.login')) { - $userIsLoggedIn = false; // Shaarli is not configured yet. - $loginFailure = true; - } - if (isset($_COOKIE[SessionManager::$LOGGED_IN_COOKIE]) - && $_COOKIE[SessionManager::$LOGGED_IN_COOKIE] === STAY_SIGNED_IN_TOKEN - && !$loginFailure - ) { - $sessionManager->storeLoginInfo($_SERVER); - $userIsLoggedIn = true; - } - // If session does not exist on server side, or IP address has changed, or session has expired, logout. - if (empty($_SESSION['uid']) - || ($conf->get('security.session_protection_disabled') === false && $_SESSION['ip'] != client_ip_id($_SERVER)) - || time() >= $_SESSION['expires_on']) - { - $sessionManager->logout(WEB_PATH); - $userIsLoggedIn = false; - $loginFailure = true; - } - if (!empty($_SESSION['longlastingsession'])) { - $_SESSION['expires_on']=time()+$_SESSION['longlastingsession']; // In case of "Stay signed in" checked. - } else { - $_SESSION['expires_on'] = time() + $sessionManager::$INACTIVITY_TIMEOUT; - } - if (!$loginFailure) { - $userIsLoggedIn = true; - } - - return $userIsLoggedIn; -} - -$userIsLoggedIn = setup_login_state($conf, $sessionManager); - -// ------------------------------------------------------------------------------------------ -// Session management +$loginManager->checkLoginState($_SERVER, $_SESSION, $_COOKIE, WEB_PATH, STAY_SIGNED_IN_TOKEN); /** - * Check that user/password is correct. - * - * @param string $login Username - * @param string $password User password - * @param ConfigManager $conf Configuration Manager instance. - * @param SessionManager $sessionManager SessionManager instance + * Adapter function for PageBuilder * - * @return bool: authentication successful or not. + * TODO: update PageBuilder and tests */ -function check_auth($login, $password, $conf, $sessionManager) -{ - $hash = sha1($password . $login . $conf->get('credentials.salt')); - if ($login == $conf->get('credentials.login') && $hash == $conf->get('credentials.hash')) { - // Login/password is correct. - $sessionManager->storeLoginInfo($_SERVER); - logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login successful'); - return true; - } - logm($conf->get('resource.log'), $_SERVER['REMOTE_ADDR'], 'Login failed for user '.$login); - return false; -} - -// Returns true if the user is logged in. function isLoggedIn() { - global $userIsLoggedIn; - return $userIsLoggedIn; + global $loginManager; + return $loginManager->isLoggedIn(); } + // ------------------------------------------------------------------------------------------ // Process login form: Check if login/password is correct. if (isset($_POST['login'])) { @@ -268,7 +200,7 @@ if (isset($_POST['login'])) { } if (isset($_POST['password']) && $sessionManager->checkToken($_POST['token']) - && (check_auth($_POST['login'], $_POST['password'], $conf, $sessionManager)) + && $loginManager->checkCredentials($_SERVER, $_POST['login'], $_POST['password']) ) { // Login/password is OK. $loginManager->handleSuccessfulLogin($_SERVER); @@ -347,15 +279,16 @@ if (!isset($_SESSION['tokens'])) $_SESSION['tokens']=array(); // Token are atta * Gives the last 7 days (which have links). * This RSS feed cannot be filtered. * - * @param ConfigManager $conf Configuration Manager instance. + * @param ConfigManager $conf Configuration Manager instance + * @param LoginManager $loginManager LoginManager instance */ -function showDailyRSS($conf) { +function showDailyRSS($conf, $loginManager) { // Cache system $query = $_SERVER['QUERY_STRING']; $cache = new CachedPage( $conf->get('config.PAGE_CACHE'), page_url($_SERVER), - startsWith($query,'do=dailyrss') && !isLoggedIn() + startsWith($query,'do=dailyrss') && !$loginManager->isLoggedIn() ); $cached = $cache->cachedVersion(); if (!empty($cached)) { @@ -367,7 +300,7 @@ function showDailyRSS($conf) { // Read links from database (and filter private links if used it not logged in). $LINKSDB = new LinkDB( $conf->get('resource.datastore'), - isLoggedIn(), + $loginManager->isLoggedIn(), $conf->get('privacy.hide_public_links'), $conf->get('redirector.url'), $conf->get('redirector.encode_url') @@ -509,7 +442,7 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) /* Hook is called before column construction so that plugins don't have to deal with columns. */ - $pluginManager->executeHooks('render_daily', $data, array('loggedin' => isLoggedIn())); + $pluginManager->executeHooks('render_daily', $data, array('loggedin' => $loginManager->isLoggedIn())); /* We need to spread the articles on 3 columns. I did not want to use a JavaScript lib like http://masonry.desandro.com/ @@ -553,8 +486,8 @@ function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) * @param ConfigManager $conf Configuration Manager instance. * @param PluginManager $pluginManager Plugin Manager instance. */ -function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager) { - buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager); // Compute list of links to display +function showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) { + buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager, $loginManager); $PAGE->renderPage('linklist'); } @@ -574,7 +507,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, read_updates_file($conf->get('resource.updates')), $LINKSDB, $conf, - isLoggedIn() + $loginManager->isLoggedIn() ); try { $newUpdates = $updater->update(); @@ -596,11 +529,11 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, // Determine which page will be rendered. $query = (isset($_SERVER['QUERY_STRING'])) ? $_SERVER['QUERY_STRING'] : ''; - $targetPage = Router::findPage($query, $_GET, isLoggedIn()); + $targetPage = Router::findPage($query, $_GET, $loginManager->isLoggedIn()); if ( // if the user isn't logged in - !isLoggedIn() && + !$loginManager->isLoggedIn() && // and Shaarli doesn't have public content... $conf->get('privacy.hide_public_links') && // and is configured to enforce the login @@ -628,7 +561,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, $pluginManager->executeHooks('render_' . $name, $plugin_data, array( 'target' => $targetPage, - 'loggedin' => isLoggedIn() + 'loggedin' => $loginManager->isLoggedIn() ) ); $PAGE->assign('plugins_' . $name, $plugin_data); @@ -680,7 +613,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, $data = array( 'linksToDisplay' => $linksToDisplay, ); - $pluginManager->executeHooks('render_picwall', $data, array('loggedin' => isLoggedIn())); + $pluginManager->executeHooks('render_picwall', $data, array('loggedin' => $loginManager->isLoggedIn())); foreach ($data as $key => $value) { $PAGE->assign($key, $value); @@ -727,7 +660,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, 'search_tags' => $searchTags, 'tags' => $tagList, ); - $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => isLoggedIn())); + $pluginManager->executeHooks('render_tagcloud', $data, array('loggedin' => $loginManager->isLoggedIn())); foreach ($data as $key => $value) { $PAGE->assign($key, $value); @@ -760,7 +693,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, 'search_tags' => $searchTags, 'tags' => $tags, ]; - $pluginManager->executeHooks('render_taglist', $data, ['loggedin' => isLoggedIn()]); + $pluginManager->executeHooks('render_taglist', $data, ['loggedin' => $loginManager->isLoggedIn()]); foreach ($data as $key => $value) { $PAGE->assign($key, $value); @@ -787,7 +720,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, $cache = new CachedPage( $conf->get('resource.page_cache'), page_url($_SERVER), - startsWith($query,'do='. $targetPage) && !isLoggedIn() + startsWith($query,'do='. $targetPage) && !$loginManager->isLoggedIn() ); $cached = $cache->cachedVersion(); if (!empty($cached)) { @@ -796,15 +729,15 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, } // Generate data. - $feedGenerator = new FeedBuilder($LINKSDB, $feedType, $_SERVER, $_GET, isLoggedIn()); + $feedGenerator = new FeedBuilder($LINKSDB, $feedType, $_SERVER, $_GET, $loginManager->isLoggedIn()); $feedGenerator->setLocale(strtolower(setlocale(LC_COLLATE, 0))); - $feedGenerator->setHideDates($conf->get('privacy.hide_timestamps') && !isLoggedIn()); + $feedGenerator->setHideDates($conf->get('privacy.hide_timestamps') && !$loginManager->isLoggedIn()); $feedGenerator->setUsePermalinks(isset($_GET['permalinks']) || !$conf->get('feed.rss_permalinks')); $data = $feedGenerator->buildData(); // Process plugin hook. $pluginManager->executeHooks('render_feed', $data, array( - 'loggedin' => isLoggedIn(), + 'loggedin' => $loginManager->isLoggedIn(), 'target' => $targetPage, )); @@ -952,7 +885,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, } // -------- Handle other actions allowed for non-logged in users: - if (!isLoggedIn()) + if (!$loginManager->isLoggedIn()) { // User tries to post new link but is not logged in: // Show login screen, then redirect to ?post=... @@ -968,7 +901,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, exit; } - showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); + showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); if (isset($_GET['edit_link'])) { header('Location: ?do=login&edit_link='. escape($_GET['edit_link'])); exit; @@ -1019,7 +952,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, $conf->set('credentials.salt', sha1(uniqid('', true) .'_'. mt_rand())); $conf->set('credentials.hash', sha1($_POST['setpassword'] . $conf->get('credentials.login') . $conf->get('credentials.salt'))); try { - $conf->write(isLoggedIn()); + $conf->write($loginManager->isLoggedIn()); } catch(Exception $e) { error_log( @@ -1070,7 +1003,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, $conf->set('translation.language', escape($_POST['language'])); try { - $conf->write(isLoggedIn()); + $conf->write($loginManager->isLoggedIn()); $history->updateSettings(); invalidateCaches($conf->get('resource.page_cache')); } @@ -1522,7 +1455,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, else { $conf->set('general.enabled_plugins', save_plugin_config($_POST)); } - $conf->write(isLoggedIn()); + $conf->write($loginManager->isLoggedIn()); $history->updateSettings(); } catch (Exception $e) { @@ -1547,7 +1480,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, } // -------- Otherwise, simply display search form and links: - showLinkList($PAGE, $LINKSDB, $conf, $pluginManager); + showLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); exit; } @@ -1559,8 +1492,9 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, * @param LinkDB $LINKSDB LinkDB instance. * @param ConfigManager $conf Configuration Manager instance. * @param PluginManager $pluginManager Plugin Manager instance. + * @param LoginManager $loginManager LoginManager instance */ -function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) +function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager) { // Used in templates if (isset($_GET['searchtags'])) { @@ -1599,8 +1533,6 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) $keys[] = $key; } - - // Select articles according to paging. $pagecount = ceil(count($keys) / $_SESSION['LINKS_PER_PAGE']); $pagecount = $pagecount == 0 ? 1 : $pagecount; @@ -1681,7 +1613,7 @@ function buildLinkList($PAGE,$LINKSDB, $conf, $pluginManager) $data['pagetitle'] .= '- '. $conf->get('general.title'); } - $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => isLoggedIn())); + $pluginManager->executeHooks('render_linklist', $data, array('loggedin' => $loginManager->isLoggedIn())); foreach ($data as $key => $value) { $PAGE->assign($key, $value); @@ -1952,7 +1884,7 @@ function install($conf, $sessionManager) { ); try { // Everything is ok, let's create config file. - $conf->write(isLoggedIn()); + $conf->write($loginManager->isLoggedIn()); } catch(Exception $e) { error_log( @@ -2216,7 +2148,7 @@ try { $linkDb = new LinkDB( $conf->get('resource.datastore'), - isLoggedIn(), + $loginManager->isLoggedIn(), $conf->get('privacy.hide_public_links'), $conf->get('redirector.url'), $conf->get('redirector.encode_url') -- cgit v1.2.3 From 847420847455c1339f3302b1b67568ee0f382a11 Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Wed, 18 Apr 2018 23:09:45 +0200 Subject: Pass the client IP ID to LoginManager Signed-off-by: VirtualTam --- index.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'index.php') diff --git a/index.php b/index.php index 5e15b9c2..04b0e4ba 100644 --- a/index.php +++ b/index.php @@ -123,6 +123,7 @@ if (isset($_COOKIE['shaarli']) && !SessionManager::checkId($_COOKIE['shaarli'])) $conf = new ConfigManager(); $sessionManager = new SessionManager($_SESSION, $conf); $loginManager = new LoginManager($GLOBALS, $conf, $sessionManager); +$clientIpId = client_ip_id($_SERVER); // LC_MESSAGES isn't defined without php-intl, in this case use LC_COLLATE locale instead. if (! defined('LC_MESSAGES')) { @@ -178,7 +179,7 @@ if (! is_file($conf->getConfigFileExt())) { // a token depending of deployment salt, user password, and the current ip define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt'))); -$loginManager->checkLoginState($_SERVER, $_SESSION, $_COOKIE, WEB_PATH, STAY_SIGNED_IN_TOKEN); +$loginManager->checkLoginState($_SESSION, $_COOKIE, WEB_PATH, $clientIpId, STAY_SIGNED_IN_TOKEN); /** * Adapter function for PageBuilder @@ -200,7 +201,7 @@ if (isset($_POST['login'])) { } if (isset($_POST['password']) && $sessionManager->checkToken($_POST['token']) - && $loginManager->checkCredentials($_SERVER, $_POST['login'], $_POST['password']) + && $loginManager->checkCredentials($_SERVER['REMOTE_ADDR'], $clientIpId, $_POST['login'], $_POST['password']) ) { // Login/password is OK. $loginManager->handleSuccessfulLogin($_SERVER); -- cgit v1.2.3 From 89ccc83ba497fa91eaaf2a2a52d8549aea5e2aee Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Wed, 18 Apr 2018 23:45:05 +0200 Subject: Login: update PageBuilder and default/vintage templates Signed-off-by: VirtualTam --- index.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'index.php') diff --git a/index.php b/index.php index 04b0e4ba..c87ebf65 100644 --- a/index.php +++ b/index.php @@ -182,9 +182,11 @@ define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['R $loginManager->checkLoginState($_SESSION, $_COOKIE, WEB_PATH, $clientIpId, STAY_SIGNED_IN_TOKEN); /** - * Adapter function for PageBuilder + * Adapter function to ensure compatibility with third-party templates * - * TODO: update PageBuilder and tests + * @see https://github.com/shaarli/Shaarli/pull/1086 + * + * @return bool true when the user is logged in, false otherwise */ function isLoggedIn() { @@ -383,9 +385,10 @@ function showDailyRSS($conf, $loginManager) { * @param PageBuilder $pageBuilder Template engine wrapper. * @param LinkDB $LINKSDB LinkDB instance. * @param ConfigManager $conf Configuration Manager instance. - * @param PluginManager $pluginManager Plugin Manager instane. + * @param PluginManager $pluginManager Plugin Manager instance. + * @param LoginManager $loginManager Login Manager instance */ -function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager) +function showDaily($pageBuilder, $LINKSDB, $conf, $pluginManager, $loginManager) { $day = date('Ymd', strtotime('-1 day')); // Yesterday, in format YYYYMMDD. if (isset($_GET['day'])) { @@ -523,7 +526,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, die($e->getMessage()); } - $PAGE = new PageBuilder($conf, $LINKSDB, $sessionManager->generateToken()); + $PAGE = new PageBuilder($conf, $LINKSDB, $sessionManager->generateToken(), $loginManager->isLoggedIn()); $PAGE->assign('linkcount', count($LINKSDB)); $PAGE->assign('privateLinkcount', count_private($LINKSDB)); $PAGE->assign('plugin_errors', $pluginManager->getErrors()); @@ -708,7 +711,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, // Daily page. if ($targetPage == Router::$PAGE_DAILY) { - showDaily($PAGE, $LINKSDB, $conf, $pluginManager); + showDaily($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager); } // ATOM and RSS feed. -- cgit v1.2.3 From 68dcaccfa46649addc66674b627a83064798bbc0 Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Fri, 27 Apr 2018 22:00:35 +0200 Subject: LoginManager: remove unused parameter Signed-off-by: VirtualTam --- index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'index.php') diff --git a/index.php b/index.php index c87ebf65..30bfc170 100644 --- a/index.php +++ b/index.php @@ -179,7 +179,7 @@ if (! is_file($conf->getConfigFileExt())) { // a token depending of deployment salt, user password, and the current ip define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt'))); -$loginManager->checkLoginState($_SESSION, $_COOKIE, WEB_PATH, $clientIpId, STAY_SIGNED_IN_TOKEN); +$loginManager->checkLoginState($_COOKIE, WEB_PATH, $clientIpId, STAY_SIGNED_IN_TOKEN); /** * Adapter function to ensure compatibility with third-party templates -- cgit v1.2.3 From fab87c2696b9d6a26310f1bfc024b018ca5184fe Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Fri, 27 Apr 2018 22:12:22 +0200 Subject: Move LoginManager and SessionManager to the Security namespace Signed-off-by: VirtualTam --- index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'index.php') diff --git a/index.php b/index.php index 30bfc170..139812d7 100644 --- a/index.php +++ b/index.php @@ -78,8 +78,8 @@ require_once 'application/Updater.php'; use \Shaarli\Languages; use \Shaarli\ThemeUtils; use \Shaarli\Config\ConfigManager; -use \Shaarli\LoginManager; -use \Shaarli\SessionManager; +use \Shaarli\Security\LoginManager; +use \Shaarli\Security\SessionManager; // Ensure the PHP version is supported try { -- cgit v1.2.3 From 51f0128cdba52099c40693379e72f094b42a6f80 Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Fri, 27 Apr 2018 23:17:38 +0200 Subject: Refactor session and cookie timeout control Signed-off-by: VirtualTam --- index.php | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) (limited to 'index.php') diff --git a/index.php b/index.php index 139812d7..8e3bade0 100644 --- a/index.php +++ b/index.php @@ -179,7 +179,7 @@ if (! is_file($conf->getConfigFileExt())) { // a token depending of deployment salt, user password, and the current ip define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt'))); -$loginManager->checkLoginState($_COOKIE, WEB_PATH, $clientIpId, STAY_SIGNED_IN_TOKEN); +$loginManager->checkLoginState($_COOKIE, $clientIpId, STAY_SIGNED_IN_TOKEN); /** * Adapter function to ensure compatibility with third-party templates @@ -205,31 +205,35 @@ if (isset($_POST['login'])) { && $sessionManager->checkToken($_POST['token']) && $loginManager->checkCredentials($_SERVER['REMOTE_ADDR'], $clientIpId, $_POST['login'], $_POST['password']) ) { - // Login/password is OK. $loginManager->handleSuccessfulLogin($_SERVER); - // If user wants to keep the session cookie even after the browser closes: - if (!empty($_POST['longlastingsession'])) { - $_SESSION['longlastingsession'] = 31536000; // (31536000 seconds = 1 year) - $expiration = time() + $_SESSION['longlastingsession']; // calculate relative cookie expiration (1 year from now) - setcookie($sessionManager::$LOGGED_IN_COOKIE, STAY_SIGNED_IN_TOKEN, $expiration, WEB_PATH); - $_SESSION['expires_on'] = $expiration; // Set session expiration on server-side. - - $cookiedir = ''; - if (dirname($_SERVER['SCRIPT_NAME']) != '/') { - $cookiedir = dirname($_SERVER["SCRIPT_NAME"]) . '/'; - } - session_set_cookie_params($_SESSION['longlastingsession'],$cookiedir,$_SERVER['SERVER_NAME']); // Set session cookie expiration on client side + $cookiedir = ''; + if (dirname($_SERVER['SCRIPT_NAME']) != '/') { // Note: Never forget the trailing slash on the cookie path! - session_regenerate_id(true); // Send cookie with new expiration date to browser. + $cookiedir = dirname($_SERVER["SCRIPT_NAME"]) . '/'; } - else // Standard session expiration (=when browser closes) - { - $cookiedir = ''; if(dirname($_SERVER['SCRIPT_NAME'])!='/') $cookiedir=dirname($_SERVER["SCRIPT_NAME"]).'/'; - session_set_cookie_params(0,$cookiedir,$_SERVER['SERVER_NAME']); // 0 means "When browser closes" - session_regenerate_id(true); + + if (!empty($_POST['longlastingsession'])) { + // Keep the session cookie even after the browser closes + $sessionManager->setStaySignedIn(true); + $expirationTime = $sessionManager->extendSession(); + + setcookie( + $sessionManager::$LOGGED_IN_COOKIE, + STAY_SIGNED_IN_TOKEN, + $expirationTime, + WEB_PATH + ); + + } else { + // Standard session expiration (=when browser closes) + $expirationTime = 0; } + // Send cookie with the new expiration date to the browser + session_set_cookie_params($expirationTime, $cookiedir, $_SERVER['SERVER_NAME']); + session_regenerate_id(true); + // Optional redirect after login: if (isset($_GET['post'])) { $uri = '?post='. urlencode($_GET['post']); @@ -590,7 +594,8 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, if (isset($_SERVER['QUERY_STRING']) && startsWith($_SERVER['QUERY_STRING'], 'do=logout')) { invalidateCaches($conf->get('resource.page_cache')); - $sessionManager->logout(WEB_PATH); + $sessionManager->logout(); + setcookie(SessionManager::$LOGGED_IN_COOKIE, 'false', 0, WEB_PATH); header('Location: ?'); exit; } -- cgit v1.2.3 From c689e108639a4f6aa9e15928422e14db7cbe30ca Mon Sep 17 00:00:00 2001 From: VirtualTam Date: Sun, 6 May 2018 17:06:36 +0200 Subject: Refactor LoginManager stay-signed-in token management Signed-off-by: VirtualTam --- index.php | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'index.php') diff --git a/index.php b/index.php index 8e3bade0..c34434dd 100644 --- a/index.php +++ b/index.php @@ -123,6 +123,7 @@ if (isset($_COOKIE['shaarli']) && !SessionManager::checkId($_COOKIE['shaarli'])) $conf = new ConfigManager(); $sessionManager = new SessionManager($_SESSION, $conf); $loginManager = new LoginManager($GLOBALS, $conf, $sessionManager); +$loginManager->generateStaySignedInToken($_SERVER['REMOTE_ADDR']); $clientIpId = client_ip_id($_SERVER); // LC_MESSAGES isn't defined without php-intl, in this case use LC_COLLATE locale instead. @@ -176,10 +177,7 @@ if (! is_file($conf->getConfigFileExt())) { install($conf, $sessionManager); } -// a token depending of deployment salt, user password, and the current ip -define('STAY_SIGNED_IN_TOKEN', sha1($conf->get('credentials.hash') . $_SERVER['REMOTE_ADDR'] . $conf->get('credentials.salt'))); - -$loginManager->checkLoginState($_COOKIE, $clientIpId, STAY_SIGNED_IN_TOKEN); +$loginManager->checkLoginState($_COOKIE, $clientIpId); /** * Adapter function to ensure compatibility with third-party templates @@ -219,8 +217,8 @@ if (isset($_POST['login'])) { $expirationTime = $sessionManager->extendSession(); setcookie( - $sessionManager::$LOGGED_IN_COOKIE, - STAY_SIGNED_IN_TOKEN, + $loginManager::$STAY_SIGNED_IN_COOKIE, + $loginManager->getStaySignedInToken(), $expirationTime, WEB_PATH ); @@ -595,7 +593,7 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager, { invalidateCaches($conf->get('resource.page_cache')); $sessionManager->logout(); - setcookie(SessionManager::$LOGGED_IN_COOKIE, 'false', 0, WEB_PATH); + setcookie(LoginManager::$STAY_SIGNED_IN_COOKIE, 'false', 0, WEB_PATH); header('Location: ?'); exit; } -- cgit v1.2.3