Some enhancements to token logins

This commit is contained in:
Deon George 2011-10-12 14:52:04 +11:00
parent 718c42be65
commit c419b50bac
3 changed files with 121 additions and 28 deletions

View File

@ -146,31 +146,58 @@ class Auth_OSB extends Auth_ORM {
* @return mixed The user * @return mixed The user
*/ */
private function _get_token_user($token) { private function _get_token_user($token) {
// This has been implemented, as we sometimes we seem to come here twice
static $user = NULL;
if (! is_null($user))
return $user;
$mmto = ORM::factory('module_method_token',array('token'=>$token)); $mmto = ORM::factory('module_method_token',array('token'=>$token));
$user = FALSE; $user = FALSE;
if ($mmto->loaded()) { if ($mmto->loaded()) {
if ($mmto->date_expire < time()) { if (! is_null($mmto->date_expire) AND $mmto->date_expire < time()) {
SystemMessage::add(array( SystemMessage::add(array(
'title'=>_('Token Not Valid'), 'title'=>_('Token Not Valid'),
'type'=>'warning', 'type'=>'warning',
'body'=>_('Token expired'))); 'body'=>_('Token expired')));
// @todo Log the token deletion
Session::instance()->delete('token');
$mmto->delete();
} elseif (! is_null($mmto->uses) AND $mmto->uses < 1) {
SystemMessage::add(array(
'title'=>_('Token Not Valid'),
'type'=>'warning',
'body'=>_('Token expired')));
// @todo Log the token deletion
Session::instance()->delete('token'); Session::instance()->delete('token');
$mmto->delete(); $mmto->delete();
} else { } else {
// Check that the token is for this URI // Check that the token is for this URI
$mo = ORM::factory('module',array('name'=>Request::current()->controller())); $mo = ORM::factory('module',array('name'=>Request::current()->controller()));
$mmo = ORM::factory('module_method', $mmo = ORM::factory('module_method',array(
array('name'=>Request::current()->directory() ? sprintf('%s_%s',Request::current()->directory(),Request::current()->action()) : Request::current()->action())); 'module_id'=>$mo->id,
'name'=>Request::current()->directory() ? sprintf('%s_%s',Request::current()->directory(),Request::current()->action()) : Request::current()->action()
));
// Ignore the token if this is not the right method. // Ignore the token if this is not the right method.
if ($mmo->id == $mmto->method_id) { if ($mmo->id == $mmto->method_id) {
// @todo Implement single use tokens // If this is a usage count token, reduce the count.
if (! is_null($mmto->uses))
$mmto->uses -= 1;
// Record the date this token was used
$mmto->date_last = time();
$mmto->save();
Session::instance()->set('token',$token); Session::instance()->set('token',$token);
$user = ORM::factory('account',$mmto->account_id); $user = ORM::factory('account',$mmto->account_id);
$user->log(sprintf('Token %s used for method %s',$mmto->token,$mmto->method_id));
} }
} }
} }

View File

@ -132,40 +132,24 @@ class Controller_lnApp_Login extends Controller_TemplateDefault {
if ($_POST) { if ($_POST) {
// If the email address is correct, create a method token // If the email address is correct, create a method token
if (! empty($_POST['email']) AND ($ao=ORM::factory('account',array('email'=>$_POST['email']))) AND $ao->loaded()) { if (! empty($_POST['email']) AND ($ao=ORM::factory('account',array('email'=>$_POST['email']))) AND $ao->loaded()) {
$mt = ORM::factory('module_method_token'); $mmto = ORM::factory('module_method_token')
->method(array('account','user_resetpassword'))
// Find out our password reset method id ->account($ao)
// @todo move this to a more generic method, so that it can be called by other methods ->expire(time()+$token_expire*60);
$mo = ORM::factory('module',array('name'=>'account'));
$mmo = ORM::factory('module_method',array('name'=>'user_resetpassword','module_id'=>$mo->id));
// Check to see if there is already a token, if so, do nothing.
if ($mt->where('account_id','=',$ao->id)->and_where('method_id','=',$mmo->id)->find()) {
if ($mt->loaded() AND ($mt->date_expire < time())) {
$mt->delete();
$mt->clear();
}
}
if (! $mt->loaded()) {
$mt->account_id = $ao->id;
$mt->method_id = $mmo->id;
$mt->date_expire = time() + $token_expire*60;
$mt->token = md5(sprintf('%s:%s:%s',$mt->account_id,$mt->method_id,$mt->date_expire));
$mt->save();
if ($mmto->generate()) {
// Send our email with the token // Send our email with the token
// @todo Need to provide an option if Email_Template is not installed/activited. // @todo Need to provide an option if Email_Template is not installed/activited.
// @todo Need to provide an option if account_reset_password template doesnt exist. // @todo Need to provide an option if account_reset_password template doesnt exist.
$et = Email_Template::instance('account_reset_password'); $et = Email_Template::instance('account_reset_password');
$et->to = array('account'=>array($mt->account_id)); $et->to = array('account'=>array($mmto->account_id));
$et->variables = array( $et->variables = array(
'SITE'=>URL::base(TRUE,TRUE), 'SITE'=>URL::base(TRUE,TRUE),
'SITE_ADMIN'=>Config::sitename(), 'SITE_ADMIN'=>Config::sitename(),
'SITE_NAME'=>Config::sitename(), 'SITE_NAME'=>Config::sitename(),
'TOKEN'=>$mt->token, 'TOKEN'=>$mmto->token,
'TOKEN_EXPIRE_MIN'=>$token_expire, 'TOKEN_EXPIRE_MIN'=>$token_expire,
'USER_NAME'=>sprintf('%s %s',$mt->account->first_name,$mt->account->last_name), 'USER_NAME'=>sprintf('%s %s',$mmto->account->first_name,$mmto->account->last_name),
); );
$et->send(); $et->send();

View File

@ -22,5 +22,87 @@ class Model_Module_Method_Token extends ORMOSB {
// This module doesnt keep track of column updates automatically // This module doesnt keep track of column updates automatically
protected $_update_column = FALSE; protected $_update_column = FALSE;
public function method(array $modmeth) {
list($module,$method) = $modmeth;
if (! $method instanceof Model_Module_Method) {
if (is_numeric($module))
$mo = ORM::factory('module',$module);
elseif (is_string($module))
$mo = ORM::factory('module',array('name'=>$module));
elseif (! $module instanceof Model_Module)
throw new Kohana_Exception('Unknown module :module',array(':module'=>serialize($module)));
else
$mo = $module;
if (! $mo->loaded())
throw new Kohana_Exception('Unknown module :module - not loaded?',array(':module'=>$mo->id));
if (is_numeric($method))
$mmo = ORM::factory('module_method',$method);
elseif (is_string($method))
$mmo = ORM::factory('module_method',array('name'=>$method,'module_id'=>$mo->id));
else
throw new Kohana_Exception('Unknown method :method',array(':method'=>serialize($method)));
} else
$mmo = $method;
if (! $mmo->loaded())
throw new Kohana_Exception('Unknown method :method - not loaded?',array(':method'=>$mmo->id));
$this->method_id = $mmo->id;
return $this;
}
public function account($account) {
if (! $account instanceof Model_Account) {
if (is_numeric($account))
$ao = ORM::factory('account',$account);
else
throw new Kohana_Exception('Unknown account :account',array(':account'=>serialize($account)));
} else
$ao = $account;
$this->account_id = $ao->id;
return $this;
}
public function uses($uses) {
$this->uses = $uses;
return $this;
}
public function expire($expire) {
$this->date_expire = $expire;
return $this;
}
public function generate() {
if (! $this->account_id OR ! $this->method_id OR ! ($this->date_expire OR $this->uses))
return NULL;
// Check we dont already have a valid token
$mmto = ORM::factory('module_method_token')
->where('account_id','=',$this->account_id)
->where('method_id','=',$this->method_id)
->find();
if ($mmto->loaded()) {
if ((is_null($mmto->date_expire) OR $mmto->date_expire > time()) AND (is_null($mmto->uses) OR $mmto->uses > 0))
return $mmto->token;
else
$mmto->delete();
}
$this->token = md5(sprintf('%s:%s:%s',$this->account_id,$this->method_id,time()));
$this->save();
return $this->saved() ? $this->token : NULL;
}
} }
?> ?>