-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Record login timestamp per user. Required for new user managament. #8681
Changes from 9 commits
2c89962
c46fada
bf1f5f2
60274d1
86880ac
09bb8e0
e9fa74b
2e85d5a
7f7999c
c03e7fc
748a219
4a4ea67
3a21c3e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<?php | ||
/** | ||
* Copyright (c) 2014 Arthur Schiwon <[email protected]> | ||
* This file is licensed under the Affero General Public License version 3 or | ||
* later. | ||
* See the COPYING-README file. | ||
*/ | ||
|
||
namespace OC\Core\Command\User; | ||
|
||
use Symfony\Component\Console\Command\Command; | ||
use Symfony\Component\Console\Input\InputInterface; | ||
use Symfony\Component\Console\Output\OutputInterface; | ||
use Symfony\Component\Console\Input\InputArgument; | ||
|
||
class LastSeen extends Command { | ||
protected function configure() { | ||
$this | ||
->setName('user:lastseen') | ||
->setDescription('shows when the user was logged it last time') | ||
->addArgument( | ||
'uid', | ||
InputArgument::REQUIRED, | ||
'the username' | ||
); | ||
} | ||
|
||
protected function execute(InputInterface $input, OutputInterface $output) { | ||
$userManager = \OC::$server->getUserManager(); | ||
$user = $userManager->get($input->getArgument('uid')); | ||
if(is_null($user)) { | ||
$output->writeln('User does not exist'); | ||
return; | ||
} | ||
|
||
$lastLogin = $user->getLastLogin(); | ||
if($lastLogin === 0) { | ||
$output->writeln('User ' . $user->getUID() . | ||
' has never logged in, yet.'); | ||
} else { | ||
$date = new \DateTime(); | ||
$date->setTimestamp($lastLogin); | ||
$output->writeln($user->getUID() . | ||
'`s last login: ' . $date->format('d.m.Y H:i')); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -883,30 +883,24 @@ protected static function tryRememberLogin() { | |
if (defined("DEBUG") && DEBUG) { | ||
OC_Log::write('core', 'Trying to login from cookie', OC_Log::DEBUG); | ||
} | ||
// confirm credentials in cookie | ||
if (isset($_COOKIE['oc_token']) && OC_User::userExists($_COOKIE['oc_username'])) { | ||
// delete outdated cookies | ||
|
||
if(OC_User::userExists($_COOKIE['oc_username'])) { | ||
self::cleanupLoginTokens($_COOKIE['oc_username']); | ||
// get stored tokens | ||
$tokens = OC_Preferences::getKeys($_COOKIE['oc_username'], 'login_token'); | ||
// test cookies token against stored tokens | ||
if (in_array($_COOKIE['oc_token'], $tokens, true)) { | ||
// replace successfully used token with a new one | ||
OC_Preferences::deleteKey($_COOKIE['oc_username'], 'login_token', $_COOKIE['oc_token']); | ||
$token = OC_Util::generateRandomBytes(32); | ||
OC_Preferences::setValue($_COOKIE['oc_username'], 'login_token', $token, time()); | ||
OC_User::setMagicInCookie($_COOKIE['oc_username'], $token); | ||
// login | ||
OC_User::setUserId($_COOKIE['oc_username']); | ||
// confirm credentials in cookie | ||
$granted = OC_User::loginWithCookie( | ||
$_COOKIE['oc_username'], $_COOKIE['oc_token']); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. where did that code goto? OC_User::loginWithCookie? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. to lib/private/user/session.php line 188 (invoked by OC_User::loginWithCookie) |
||
if($granted === true) { | ||
OC_Util::redirectToDefaultPage(); | ||
// doesn't return | ||
} | ||
OC_Log::write('core', 'Authentication cookie rejected for user ' . | ||
$_COOKIE['oc_username'], OC_Log::WARN); | ||
// if you reach this point you have changed your password | ||
// or you are an attacker | ||
// we can not delete tokens here because users may reach | ||
// this point multiple times after a password change | ||
OC_Log::write('core', 'Authentication cookie rejected for user ' . $_COOKIE['oc_username'], OC_Log::WARN); | ||
} | ||
|
||
OC_User::unsetMagicInCookie(); | ||
return true; | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -170,6 +170,38 @@ public function login($uid, $password) { | |
} | ||
} | ||
|
||
/** | ||
* perform login using the magic cookie (remember login) | ||
* | ||
* @param string $uid the username | ||
* @param string $currentToken | ||
* @return bool | ||
*/ | ||
public function loginWithCookie($uid, $currentToken) { | ||
$user = $this->manager->get($uid); | ||
if(is_null($user)) { | ||
// user does not exist | ||
return false; | ||
} | ||
|
||
// get stored tokens | ||
$tokens = \OC_Preferences::getKeys($uid, 'login_token'); | ||
// test cookies token against stored tokens | ||
if(!in_array($currentToken, $tokens, true)) { | ||
return false; | ||
} | ||
// replace successfully used token with a new one | ||
\OC_Preferences::deleteKey($uid, 'login_token', $currentToken); | ||
$newToken = \OC_Util::generateRandomBytes(32); | ||
\OC_Preferences::setValue($uid, 'login_token', $newToken, time()); | ||
$this->setMagicInCookie($user->getUID(), $newToken); | ||
|
||
//login | ||
$this->setUser($user); | ||
$this->manager->emit('\OC\User', 'postRememberedLogin', array($user)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you also add a I need this for the two-factor authentication app. Thanks! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you document this hook somewhere? I see that in user.php some hooks are documented at the beginning of the file. |
||
return true; | ||
} | ||
|
||
/** | ||
* logout the user from the session | ||
*/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -42,6 +42,11 @@ class User { | |
*/ | ||
private $home; | ||
|
||
/** | ||
* @var int $lastLogin | ||
*/ | ||
private $lastLogin; | ||
|
||
/** | ||
* @var \OC\AllConfig $config | ||
*/ | ||
|
@@ -64,6 +69,7 @@ public function __construct($uid, $backend, $emitter = null, $config = null) { | |
} else { | ||
$this->enabled = true; | ||
} | ||
$this->lastLogin = \OC_Preferences::getValue($uid, 'login', 'lastLogin', 0); | ||
} | ||
|
||
/** | ||
|
@@ -107,6 +113,27 @@ public function setDisplayName($displayName) { | |
} | ||
} | ||
|
||
/** | ||
* returns the timestamp of the user's last login or 0 if the user did never | ||
* login | ||
* | ||
* @return int | ||
*/ | ||
public function getLastLogin() { | ||
return $this->lastLogin; | ||
} | ||
|
||
/** | ||
* updates the timestamp of the most recent login of this user | ||
* | ||
* @return null | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this returns See http://www.phpdoc.org/docs/latest/for-users/phpdoc/tags/return.html:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if no specific return is done (→ void) null will be returned, anyway, but I get the point and will drop it. |
||
*/ | ||
public function updateLastLoginTimestamp() { | ||
$this->lastLogin = time(); | ||
\OC_Preferences::setValue( | ||
$this->uid, 'login', 'lastLogin', $this->lastLogin); | ||
} | ||
|
||
/** | ||
* Delete the user | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That statement is not entirely correct as this could also be triggered if an user has only not logged in since this feature has been added.
It may give the administrator a plausible misbelieve that the user has never logged in while this is not the case. Can we adjust this somehow?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"has never logged in, yet." → "has never logged in (since availability of ownCloud 7.0.0)."
OK?