diff --git a/application/classes/auth/osb.php b/application/classes/auth/osb.php index 6fa762b2..b525f288 100644 --- a/application/classes/auth/osb.php +++ b/application/classes/auth/osb.php @@ -146,31 +146,58 @@ class Auth_OSB extends Auth_ORM { * @return mixed The user */ 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)); $user = FALSE; if ($mmto->loaded()) { - if ($mmto->date_expire < time()) { + if (! is_null($mmto->date_expire) AND $mmto->date_expire < time()) { SystemMessage::add(array( 'title'=>_('Token Not Valid'), 'type'=>'warning', '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'); $mmto->delete(); } else { // Check that the token is for this URI $mo = ORM::factory('module',array('name'=>Request::current()->controller())); - $mmo = ORM::factory('module_method', - array('name'=>Request::current()->directory() ? sprintf('%s_%s',Request::current()->directory(),Request::current()->action()) : Request::current()->action())); + $mmo = ORM::factory('module_method',array( + '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. 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); $user = ORM::factory('account',$mmto->account_id); + $user->log(sprintf('Token %s used for method %s',$mmto->token,$mmto->method_id)); } } } diff --git a/application/classes/controller/lnapp/login.php b/application/classes/controller/lnapp/login.php index a0122d32..d91cfc53 100644 --- a/application/classes/controller/lnapp/login.php +++ b/application/classes/controller/lnapp/login.php @@ -132,40 +132,24 @@ class Controller_lnApp_Login extends Controller_TemplateDefault { if ($_POST) { // 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()) { - $mt = ORM::factory('module_method_token'); - - // Find out our password reset method id - // @todo move this to a more generic method, so that it can be called by other methods - $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(); + $mmto = ORM::factory('module_method_token') + ->method(array('account','user_resetpassword')) + ->account($ao) + ->expire(time()+$token_expire*60); + if ($mmto->generate()) { // 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 account_reset_password template doesnt exist. $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( 'SITE'=>URL::base(TRUE,TRUE), 'SITE_ADMIN'=>Config::sitename(), 'SITE_NAME'=>Config::sitename(), - 'TOKEN'=>$mt->token, + 'TOKEN'=>$mmto->token, '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(); diff --git a/application/classes/model/module/method/token.php b/application/classes/model/module/method/token.php index 42ee3249..61b7208b 100644 --- a/application/classes/model/module/method/token.php +++ b/application/classes/model/module/method/token.php @@ -22,5 +22,87 @@ class Model_Module_Method_Token extends ORMOSB { // This module doesnt keep track of column updates automatically 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; + } } ?>