Remember me

This commit is contained in:
Diego Najar 2017-11-07 00:18:16 +01:00
parent eb93088f87
commit e8023c308f
6 changed files with 120 additions and 72 deletions

View File

@ -20,6 +20,9 @@ function checkLogin($args)
}
if ($Login->verifyUser($_POST['username'], $_POST['password'])) {
if (isset($_POST['remember'])) {
$Login->setRememberMe($_POST['username']);
}
// Renew the token. This token will be the same inside the session for multiple forms.
$Security->generateTokenCSRF();
Redirect::page('dashboard');
@ -35,16 +38,45 @@ function checkLogin($args)
return false;
}
function checkRememberMe()
{
global $Security;
global $Login;
if ($Security->isBlocked()) {
return false;
}
if (!Cookie::isset(REMEMBER_COOKIE_USERNAME) || !Cookie::isset(REMEMBER_COOKIE_TOKEN)) {
return false;
}
$username = Cookie::get(REMEMBER_COOKIE_USERNAME);
$token = Cookie::get(REMEMBER_COOKIE_TOKEN);
if ($Login->verifyUserByRemember($username, $token)) {
$Security->generateTokenCSRF();
Redirect::page('dashboard');
return true;
}
$Security->addToBlacklist();
return false;
}
// ============================================================================
// Main before POST
// ============================================================================
if ($_SERVER['REQUEST_METHOD']!=='POST') {
checkRememberMe();
}
// ============================================================================
// POST Method
// ============================================================================
if ($_SERVER['REQUEST_METHOD']=='POST')
{
if ($_SERVER['REQUEST_METHOD']=='POST') {
checkLogin($_POST);
}

View File

@ -110,6 +110,11 @@ define('CLI_STATUS', 'published');
// Cli mode, username for new pages
define('CLI_USERNAME', 'admin');
// Remember me
define('REMEMBER_COOKIE_USERNAME', 'BLUDITREMEMBERUSERNAME');
define('REMEMBER_COOKIE_TOKEN', 'BLUDITREMEMBERTOKEN');
define('REMEMBER_COOKIE_EXPIRE_IN_DAYS', 30);
// Filename
define('FILENAME', 'index.txt');

View File

@ -11,8 +11,7 @@ class dbUsers extends dbJSON
'salt'=> array('inFile'=>false, 'value'=>'!Pink Floyd!Welcome to the machine!'),
'email'=> array('inFile'=>false, 'value'=>''),
'registered'=> array('inFile'=>false, 'value'=>'1985-03-15 10:00'),
'tokenEmail'=> array('inFile'=>false, 'value'=>''),
'tokenEmailTTL'=> array('inFile'=>false, 'value'=>'2009-03-15 14:00'),
'tokenRemember'=> array('inFile'=>false, 'value'=>''),
'tokenAuth'=> array('inFile'=>false, 'value'=>''),
'tokenAuthTTL'=> array('inFile'=>false, 'value'=>'2009-03-15 14:00'),
'twitter'=> array('inFile'=>false, 'value'=>''),
@ -119,7 +118,7 @@ class dbUsers extends dbJSON
return md5( uniqid().time().DOMAIN );
}
public function generateEmailToken()
public function generateRememberToken()
{
return $this->generateAuthToken();
}
@ -134,6 +133,13 @@ class dbUsers extends dbJSON
return sha1($password.$salt);
}
public function setRememberToken($username, $token)
{
$args['username'] = $username;
$args['tokenRemember'] = $token;
return $this->set($args);
}
public function setPassword($username, $password)
{
$salt = $this->generateSalt();
@ -170,18 +176,25 @@ class dbUsers extends dbJSON
return false;
}
public function setTokenEmail($username)
// Returns the username with the remember token assigned, FALSE otherwise
public function getByRememberToken($token)
{
// Random hash
$token = $this->generateEmailToken();
$this->db[$username]['tokenEmail'] = $token;
foreach ($this->db as $username=>$fields) {
if ($fields['tokenRemember']==$token) {
return $username;
}
}
return false;
}
// Token time to live, defined by TOKEN_EMAIL_TTL
$this->db[$username]['tokenEmailTTL'] = Date::currentOffset(DB_DATE_FORMAT, TOKEN_EMAIL_TTL);
// Save the database
$this->save();
return $token;
// This function clean all tokens for Remember me
// This function is used when some hacker try to use an invalid remember token
public function invalidateAllRememberTokens()
{
foreach ($this->db as $username=>$values) {
$this->db[$username]['tokenRemember'] = '';
}
return $this->save();
}
// Returns array with the username databases filtered by username, FALSE otherwise

View File

@ -2,24 +2,28 @@
class Cookie {
public static function get($name)
public static function get($key)
{
if(isset($_COOKIE[$name]))
{
return($_COOKIE[$name]);
if (isset($_COOKIE[$key])) {
return $_COOKIE[$name];
}
return(false);
return false;
}
public static function add($name, $value, $expire = 525600)
public static function set($key, $value, $daysToExpire=30)
{
setcookie($name, $value, time() + ($expire * 60));
// The time the cookie expires.
// This is a Unix timestamp so is in number of seconds since the epoch.
// In other words, you'll most likely set this with the time() function plus the number of seconds before you want it to expire.
// Or you might use mktime(). time()+60*60*24*30 will set the cookie to expire in 30 days.
// If set to 0, or omitted, the cookie will expire at the end of the session (when the browser closes).
$expire = time()+60*60*24*$daysToExpire;
setcookie($key, $value, $expire);
}
public static function isSet($name)
public static function isset($key)
{
return(isset($_COOKIE[$name]));
return isset($_COOKIE[$key]);
}
}
}

View File

@ -9,11 +9,13 @@ class Login {
$this->dbUsers = $dbUsers;
}
// Returns the username of the user logged
public function username()
{
return Session::get('username');
}
// Returns the role of the user logged
public function role()
{
return Session::get('role');
@ -26,9 +28,8 @@ class Login {
$username = Session::get('username');
if (!empty($username)) {
return true;
}
else {
Log::set(__METHOD__.LOG_SEP.'Session username empty, destroy the session.');
} else {
Log::set(__METHOD__.LOG_SEP.'Session username empty, destroying the session.');
Session::destroy();
return false;
}
@ -49,6 +50,19 @@ class Login {
Log::set(__METHOD__.LOG_SEP.'User logged, fingerprint: '.$this->fingerPrint());
}
public function setRememberMe($username)
{
$username = Sanitize::html($username);
// Set the token on the users database
$token = $this->dbUsers->generateRememberToken();
$this->dbUsers->setRememberToken($username, $token);
// Set the token on the cookies
Cookie::set(REMEMBER_COOKIE_USERNAME, $username, REMEMBER_COOKIE_EXPIRE_IN_DAYS);
Cookie::set(REMEMBER_COOKIE_TOKEN, $token, REMEMBER_COOKIE_EXPIRE_IN_DAYS);
}
// Check if the username and the password are valid
// Returns TRUE if valid and set the session
// Returns FALSE for invalid username or password
@ -71,7 +85,7 @@ class Login {
}
$user = $this->dbUsers->getDB($username);
if($user==false) {
if ($user==false) {
Log::set(__METHOD__.LOG_SEP.'Username does not exist: '.$username);
return false;
}
@ -82,65 +96,46 @@ class Login {
Log::set(__METHOD__.LOG_SEP.'User logged succeeded by username and password - Username: '.$username);
return true;
}
else {
Log::set(__METHOD__.LOG_SEP.'Password incorrect.');
}
Log::set(__METHOD__.LOG_SEP.'Password incorrect.');
return false;
}
public function verifyUserByToken($username, $token)
// Verified Remember Token
// If valid log in the user
// If not valid invalidate all remember me tokens
public function verifyUserByRemember($username, $token)
{
$username = Sanitize::html($username);
$token = Sanitize::html($token);
$username = Sanitize::html($username);
$token = Sanitize::html($token);
$username = trim($username);
$token = trim($token);
$username = trim($username);
$token = trim($token);
if(empty($username) || empty($token)) {
Log::set(__METHOD__.LOG_SEP.'Username or Token-email empty. Username: '.$username.' - Token-email: '.$token);
if (empty($username) || empty($token)) {
$this->dbUsers->invalidateAllRememberTokens();
Log::set(__METHOD__.LOG_SEP.'Username or Token empty. Username: '.$username.' - Token: '.$token);
return false;
}
if ($username !== $this->getByRememberToken($token)) {
$this->dbUsers->invalidateAllRememberTokens();
Log::set(__METHOD__.LOG_SEP.'The user has different token or the token doesnt exist.');
return false;
}
// Validate user and login
$user = $this->dbUsers->getDb($username);
if($user==false) {
Log::set(__METHOD__.LOG_SEP.'Username does not exist: '.$username);
return false;
}
$currentTime = Date::current(DB_DATE_FORMAT);
if($user['tokenEmailTTL']<$currentTime) {
Log::set(__METHOD__.LOG_SEP.'Token-email expired: '.$username);
return false;
}
if($token === $user['tokenEmail'])
{
// Set the user loggued.
$this->setLogin($username, $user['role']);
// Invalidate the current token.
$this->dbUsers->setTokenEmail($username);
Log::set(__METHOD__.LOG_SEP.'User logged succeeded by Token-email - Username: '.$username);
return true;
}
else {
Log::set(__METHOD__.LOG_SEP.'Token-email incorrect.');
}
return false;
$this->setLogin($username, $user['role']);
return true;
}
public function fingerPrint()
{
// User agent
$agent = getenv('HTTP_USER_AGENT');
if (empty($agent)) {
$agent = 'Bludit/2.0 (Mr Nibbler Protocol)';
}
return sha1($agent);
}
@ -148,5 +143,4 @@ class Login {
{
return Session::destroy();
}
}

View File

@ -37,7 +37,7 @@ h2 {
}
/* PAGES */
article.page:not(:last-child) {
article.page {
margin-bottom: 100px;
}