|
From: <gem...@li...> - 2011-11-15 09:37:23
|
Revision: 215
http://gemstracker.svn.sourceforge.net/gemstracker/?rev=215&view=rev
Author: mennodekker
Date: 2011-11-15 09:37:16 +0000 (Tue, 15 Nov 2011)
Log Message:
-----------
Almost done putting Auth back in, checkpassword still to be removed
Modified Paths:
--------------
trunk/library/classes/Gems/Auth.php
trunk/library/classes/Gems/Default/IndexAction.php
trunk/library/classes/Gems/User/NoLoginDefinition.php
trunk/library/classes/Gems/User/OldStaffUserDefinition.php
trunk/library/classes/Gems/User/ProjectUserDefinition.php
trunk/library/classes/Gems/User/StaffUserDefinition.php
trunk/library/classes/Gems/User/User.php
trunk/library/classes/Gems/User/UserDefinitionInterface.php
Added Paths:
-----------
trunk/library/classes/Gems/Auth/
trunk/library/classes/Gems/Auth/Adapter/
trunk/library/classes/Gems/Auth/Adapter/Callback.php
Added: trunk/library/classes/Gems/Auth/Adapter/Callback.php
===================================================================
--- trunk/library/classes/Gems/Auth/Adapter/Callback.php (rev 0)
+++ trunk/library/classes/Gems/Auth/Adapter/Callback.php 2011-11-15 09:37:16 UTC (rev 215)
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Copyright (c) 2011, Erasmus MC
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Erasmus MC nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Short description of file
+ *
+ * @package Gems
+ * @subpackage Auth
+ * @copyright Copyright (c) 2011 Erasmus MC
+ * @license New BSD License
+ * @version $Id: Sample.php 215 2011-07-12 08:52:54Z michiel $
+ */
+
+/**
+ * Short description for Callback
+ *
+ * Long description for class Callback (if any)...
+ *
+ * @package Gems
+ * @subpackage Auth
+ * @copyright Copyright (c) 2011 Erasmus MC
+ * @license New BSD License
+ * @since Class available since version 1.0
+ * @deprecated Class deprecated since version 2.0
+ */
+class Gems_Auth_Adapter_Callback implements Zend_Auth_Adapter_Interface
+{
+ private $_callback;
+ private $_identity;
+ private $_params;
+
+ /**
+ * Create an auth adapter from a callback
+ *
+ * Ideally the callback should return a Zend_Auth_Result, when not it should
+ * return true or false and in that case this adapter will wrap the result
+ * in a Zend_Auth_Result
+ *
+ * @param type $callback A valid callback
+ * @param type $identity The identity to use
+ * @param type $params Array of parameters needed for the callback
+ */
+ public function __construct($callback, $identity, $params)
+ {
+ $this->_callback = $callback;
+ $this->_identity = $identity;
+ $this->_params = $params;
+ }
+
+ /**
+ * Perform the authenticate attempt
+ *
+ * @return Zend_Auth_Result
+ */
+ public function authenticate()
+ {
+ $result = call_user_func_array($this->_callback, $this->_params);
+ if ( !($result instanceof Zend_Auth_Result)) {
+ if ($result === true) {
+ $result = new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $this->_identity);
+ } else {
+ $result = new Zend_Auth_Result(Zend_Auth_Result::FAILURE, $this->_identity);
+ }
+ }
+ return $result;
+ }
+}
\ No newline at end of file
Modified: trunk/library/classes/Gems/Auth.php
===================================================================
--- trunk/library/classes/Gems/Auth.php 2011-11-15 08:18:52 UTC (rev 214)
+++ trunk/library/classes/Gems/Auth.php 2011-11-15 09:37:16 UTC (rev 215)
@@ -57,7 +57,7 @@
*/
protected $_messageTemplates = array(
self::ERROR_DATABASE_NOT_INSTALLED => 'Installation not complete! Login is not yet possible!',
- self::ERROR_PASSWORD_DELAY => 'Your account is temporarily blocked, please wait %s minutes'
+ self::ERROR_PASSWORD_DELAY => 'Your account is temporarily blocked, please wait %s seconds'
);
/**
@@ -92,37 +92,76 @@
return new Zend_Auth_Result($code, null, (array) $messages);
}
- public function authenticate(Zend_Auth_Adapter_Interface $adapter, $username = '') {
+ public function authenticate(Zend_Auth_Adapter_Interface $adapter, $formValues) {
try {
- /**
- * Lookup last failed login and number of failed logins
- */
- try {
- $sql = "SELECT gul_failed_logins, UNIX_TIMESTAMP(gul_last_failed) AS gul_last_failed
- FROM gems__user_logins WHERE gul_login = ?";
- $results = $this->db->fetchRow($sql, array($username));
- } catch (Zend_Db_Exception $zde) {
- //If we need to apply a db patch, just use a default value
- $results = 0;
- MUtil_Echo::r(GemsEscort::getInstance()->translate->_('Please update the database'));
- }
+ $login_name = $formValues['userlogin'];
+ $organization = $formValues['organization'];
+ $sql = "SELECT gula_failed_logins, gula_last_failed FROM gems__user_login_attemps WHERE gula_login = ? AND gula_id_organization = ?";
+ $values = $this->db->fetchRow($sql, array($login_name, $organization));
- $delay = pow($results['gul_failed_logins'], $this->_delayFactor);
- $remaining = ($results['gul_last_failed'] + $delay) - time();
+ if (! $values) {
+ $values = array();
+ $values['gula_login'] = $login_name;
+ $values['gula_id_organization'] = $organization;
+ $values['gula_failed_logins'] = 0;
+ $values['gula_last_failed'] = null;
+ } elseif ($values['gula_failed_logins'] > 0) {
+ // Get the datetime
+ $last = new MUtil_Date($values['gula_last_failed'], Zend_Date::ISO_8601);
- if ($results['gul_failed_logins'] > 0 && $remaining > 0) {
- //$this->_obscureValue = false;
- $result = $this->_error(self::ERROR_PASSWORD_DELAY, ceil($remaining / 60));
+ // How long to wait until we can ignore the previous failed attempt
+ $delay = pow($values['gula_failed_logins'], GemsEscort::getInstance()->project->getAccountDelayFactor());
+
+ if (abs($last->diffSeconds()) <= $delay) {
+ // Response gets slowly slower
+ $sleepTime = min($values['gula_failed_logins'], 10);
+ sleep($sleepTime);
+ $remaining = $delay - abs($last->diffSeconds()) - $sleepTime;
+ if ($remaining>0) {
+ $result = $this->_error(self::ERROR_PASSWORD_DELAY, $remaining);
+ }
+ }
}
- } catch (Zend_Db_Exception $zde) {
- $result = $this->_error(self::ERROR_DATABASE_NOT_INSTALLED);
+ } catch (Zend_Db_Exception $e) {
+ // Fall through as this does not work if the database upgrade did not run
+ // MUtil_Echo::r($e);
}
- if (!isset($result)) {
- //Ok we are done without errors, now delegate to the Zend_Auth_Adapter
+ // We only forward to auth adapter when we have no timeout to prevent hammering the auth system
+ if (! isset($result) ) {
$result = parent::authenticate($adapter);
}
+ if ($result->isValid()) {
+ $values['gula_failed_logins'] = 0;
+ $values['gula_last_failed'] = null;
+ } else {
+ if ($values['gula_failed_logins']) {
+ // Only increment when we have no password delay
+ if ($result->getCode() <> self::ERROR_PASSWORD_DELAY) {
+ $values['gula_failed_logins'] += 1;
+ $values['gula_last_failed'] = new Zend_Db_Expr('CURRENT_TIMESTAMP');
+ }
+ } else {
+ $values['gula_failed_logins'] = 1;
+ $values['gula_last_failed'] = new Zend_Db_Expr('CURRENT_TIMESTAMP');
+ }
+ $values['gula_failed_logins'] = max($values['gula_failed_logins'], 1);
+ }
+
+ try {
+ if (isset($values['gula_login'])) {
+ $this->db->insert('gems__user_login_attemps', $values);
+ } else {
+ $where = $this->db->quoteInto('gula_login = ? AND ', $login_name);
+ $where .= $this->db->quoteInto('gula_id_organization = ?', $organization);
+ $this->db->update('gems__user_login_attemps', $values, $where);
+ }
+ } catch (Zend_Db_Exception $e) {
+ // Fall through as this does not work if the database upgrade did not run
+ // MUtil_Echo::r($e);
+ }
+
//Now localize
$result = $this->localize($result);
Modified: trunk/library/classes/Gems/Default/IndexAction.php
===================================================================
--- trunk/library/classes/Gems/Default/IndexAction.php 2011-11-15 08:18:52 UTC (rev 214)
+++ trunk/library/classes/Gems/Default/IndexAction.php 2011-11-15 09:37:16 UTC (rev 215)
@@ -184,7 +184,7 @@
$element->setAttrib('size', 10);
$element->setAttrib('maxlength', 20);
$element->setRequired(true);
- $element->addValidator(new Gems_User_LoginPasswordValidator($this->loader->getUserLoader(), 'userlogin', 'organization', $this->translate));
+ //$element->addValidator(new Gems_User_LoginPasswordValidator($this->loader->getUserLoader(), 'userlogin', 'organization', $this->translate));
return $element;
}
@@ -284,31 +284,42 @@
$user = $this->loader->getUser($request->getParam('userlogin'), $request->getParam('organization'));
if ($user->isActive()) {
- $user->setAsCurrentUser();
+ $formValues = $form->getValues();
+ $authResult = $user->authenticate($formValues);
- /**
- * Fix current locale / organization in cookies
- */
- Gems_Cookies::setLocale($user->getLocale(), $this->basepath->getBasePath());
- Gems_Cookies::setOrganization($user->getOrganizationId(), $this->basepath->getBasePath());
+ if ($authResult->isValid()) {
- /**
- * Ready
- */
- $this->addMessage(sprintf($this->_('Login successful, welcome %s.'), $user->getFullName()));
+ $user->setAsCurrentUser();
- /**
- * Log the login
- */
- Gems_AccessLog::getLog($this->db)->log("index.login", $this->getRequest(), null, $user->getUserId(), true);
+ $user->afterLogin($form->getValues());
- if ($previousRequestParameters = $this->session->previousRequestParameters) {
- $this->_reroute(array('controller' => $previousRequestParameters['controller'], 'action' => $previousRequestParameters['action']), false);
+ /**
+ * Fix current locale / organization in cookies
+ */
+ Gems_Cookies::setLocale($user->getLocale(), $this->basepath->getBasePath());
+ Gems_Cookies::setOrganization($user->getOrganizationId(), $this->basepath->getBasePath());
+
+ /**
+ * Ready
+ */
+ $this->addMessage(sprintf($this->_('Login successful, welcome %s.'), $user->getFullName()));
+
+ /**
+ * Log the login
+ */
+ Gems_AccessLog::getLog($this->db)->log("index.login", $this->getRequest(), null, $user->getUserId(), true);
+
+ if ($previousRequestParameters = $this->session->previousRequestParameters) {
+ $this->_reroute(array('controller' => $previousRequestParameters['controller'], 'action' => $previousRequestParameters['action']), false);
+ } else {
+ // This reroutes to the first available menu page after login
+ $this->_reroute(array('controller' => null, 'action' => null), true);
+ }
+ return;
} else {
- // This reroutes to the first available menu page after login
- $this->_reroute(array('controller' => null, 'action' => null), true);
+ $errors = $authResult->getMessages();
+ $this->addMessage($errors);
}
- return;
}
} else {
$errors = $form->getErrors();
Modified: trunk/library/classes/Gems/User/NoLoginDefinition.php
===================================================================
--- trunk/library/classes/Gems/User/NoLoginDefinition.php 2011-11-15 08:18:52 UTC (rev 214)
+++ trunk/library/classes/Gems/User/NoLoginDefinition.php 2011-11-15 09:37:16 UTC (rev 215)
@@ -74,4 +74,15 @@
//'user_organization_id' => 0, //REMOVED AS IT BREAKS STORING LAST ORGANIZATION
);
}
+
+ public function getAuthAdapter($formValues)
+ {
+ $adapter = new Gems_Auth_Adapter_Callback(array(get_class(),'alwaysFalse'), $formValues['userlogin'], $formValues);
+ return $adapter;
+ }
+
+ private function alwaysFalse($params) {
+ $result = new Zend_Auth_Result(Zend_Auth_Result::FAILURE, $params['userlogin']);
+ return false;
+ }
}
Modified: trunk/library/classes/Gems/User/OldStaffUserDefinition.php
===================================================================
--- trunk/library/classes/Gems/User/OldStaffUserDefinition.php 2011-11-15 08:18:52 UTC (rev 214)
+++ trunk/library/classes/Gems/User/OldStaffUserDefinition.php 2011-11-15 09:37:16 UTC (rev 215)
@@ -178,4 +178,75 @@
{
return md5($password);
}
+
+ public function getAuthAdapter($formValues)
+ {
+ $adapter = new Zend_Auth_Adapter_DbTable(null, 'gems__staff', 'gsf_login', 'gsf_password');
+
+ $pwd_hash = $this->hashPassword($formValues['password']);
+
+ $select = $adapter->getDbSelect();
+ $select->where('gsf_active = 1')
+ ->where('gsf_id_organization = ?', $formValues['organization']);
+
+ $adapter->setIdentity($formValues['userlogin'])
+ ->setCredential($pwd_hash);
+
+ return $adapter;
+ }
+
+ /**
+ * Perform UserDefinition specific post-login logic
+ *
+ * @param Zend_Auth_Result $authResult
+ * @return void
+ */
+ public function afterLogin($authResult, $formValues)
+ {
+ if ($authResult->isValid()) {
+ $userData = $this->getUserData($formValues['userlogin'], $formValues['organization']);
+ $staff_id = $userData['user_id'];
+
+ $sql = 'SELECT gul_id_user FROM gems__user_logins WHERE gul_can_login = 1 AND gul_login = ? AND gul_id_organization = ?';
+
+ try {
+ $user_id = $this->db->fetchOne($sql, array($login_name, $organization));
+
+ $currentTimestamp = new Zend_Db_Expr('CURRENT_TIMESTAMP');
+
+ // Move to USER_STAFF
+ $values['gup_id_user'] = $user_id;
+ $values['gup_password'] = $this->project->getValueHash($password);
+ $values['gup_reset_key'] = null;
+ $values['gup_reset_requested'] = null;
+ $values['gup_reset_required'] = 0;
+ $values['gup_changed'] = $currentTimestamp ;
+ $values['gup_changed_by'] = $staff_id;
+ $values['gup_created'] = $currentTimestamp ;
+ $values['gup_created_by'] = $staff_id;
+
+ $this->db->insert('gems__user_passwords', $values);
+
+ // Update user class
+ $values = array();
+ $values['gul_user_class'] = Gems_User_UserLoader::USER_STAFF;
+ $values['gul_changed'] = $currentTimestamp ;
+ $values['gul_changed_by'] = $staff_id;
+ $this->db->update('gems__user_logins', $values, $this->db->quoteInto('gul_id_user = ?', $user_id));
+
+ // Remove old password
+ $values = array();
+ $values['gsf_password'] = null;
+ $values['gsf_changed'] = $currentTimestamp ;
+ $values['gsf_changed_by'] = $user_id;
+
+ $this->db->update('gems__staff', $values, $this->db->quoteInto('gsf_id_user = ?', $staff_id));
+
+ } catch (Zend_Db_Exception $e) {
+ // Fall through as this does not work if the database upgrade did not run
+ // MUtil_Echo::r($e);
+
+ }
+ }
+ }
}
Modified: trunk/library/classes/Gems/User/ProjectUserDefinition.php
===================================================================
--- trunk/library/classes/Gems/User/ProjectUserDefinition.php 2011-11-15 08:18:52 UTC (rev 214)
+++ trunk/library/classes/Gems/User/ProjectUserDefinition.php 2011-11-15 09:37:16 UTC (rev 215)
@@ -86,4 +86,10 @@
'allowedOrgs' => array($organization => 'SUPER ADMIN')
);
}
+
+ public function getAuthAdapter($formValues)
+ {
+ $adapter = new Gems_Auth_Adapter_Callback(array($this->project,'checkSuperAdminPassword'), $formValues['userlogin'], $formValues['password']);
+ return $adapter;
+ }
}
Modified: trunk/library/classes/Gems/User/StaffUserDefinition.php
===================================================================
--- trunk/library/classes/Gems/User/StaffUserDefinition.php 2011-11-15 08:18:52 UTC (rev 214)
+++ trunk/library/classes/Gems/User/StaffUserDefinition.php 2011-11-15 09:37:16 UTC (rev 215)
@@ -252,4 +252,21 @@
return $this;
}
+
+ public function getAuthAdapter($formValues)
+ {
+ $adapter = new Zend_Auth_Adapter_DbTable($this->db, 'gems__user_passwords', 'gul_login', 'gup_password');
+
+ $pwd_hash = $this->hashPassword($formValues['password']);
+
+ $select = $adapter->getDbSelect();
+ $select->join('gems__user_logins', 'gup_id_user = gul_id_user', array())
+ ->where('gul_can_login = 1')
+ ->where('gul_id_organization = ?', $formValues['organization']);
+
+ $adapter->setIdentity($formValues['userlogin'])
+ ->setCredential($pwd_hash);
+
+ return $adapter;
+ }
}
Modified: trunk/library/classes/Gems/User/User.php
===================================================================
--- trunk/library/classes/Gems/User/User.php 2011-11-15 08:18:52 UTC (rev 214)
+++ trunk/library/classes/Gems/User/User.php 2011-11-15 09:37:16 UTC (rev 215)
@@ -48,6 +48,12 @@
{
/**
*
+ * @var Zend_Auth_Result
+ */
+ private $_authResult;
+
+ /**
+ *
* @var ArrayObject or Zend_Session_Namespace
*/
private $_vars;
@@ -173,6 +179,34 @@
}
/**
+ * Perform project specific after login logic here, can also delegate to the user definition
+ *
+ * @return void
+ */
+ public function afterLogin($formValues) {
+ if (is_callable(array($this->definition, 'afterLogin'))) {
+ $this->definition->afterLogin($this->_authResult, $formValues);
+ }
+ }
+
+ /**
+ * Authenticate a users credentials using the submitted form
+ *
+ * @param array $formValues the array containing all formvalues from the login form
+ * @return boolean
+ */
+ public function authenticate($formValues)
+ {
+ $auth = Gems_Auth::getInstance();
+ $adapter = $this->definition->getAuthAdapter($formValues);
+ $authResult = $auth->authenticate($adapter, $formValues);
+
+ $this->_authResult = $authResult;
+
+ return $authResult;
+ }
+
+ /**
* Return true if a password reset key can be created.
*
* @return boolean
Modified: trunk/library/classes/Gems/User/UserDefinitionInterface.php
===================================================================
--- trunk/library/classes/Gems/User/UserDefinitionInterface.php 2011-11-15 08:18:52 UTC (rev 214)
+++ trunk/library/classes/Gems/User/UserDefinitionInterface.php 2011-11-15 09:37:16 UTC (rev 215)
@@ -88,6 +88,13 @@
public function checkPasswordResetKey(Gems_User_User $user, $key);
/**
+ * Returns an initialized Zend_Auth_Adapter_Interface
+ *
+ * @return Zend_Auth_Adapter_Interface
+ */
+ public function getAuthAdapter($formValues);
+
+ /**
* Return a password reset key
*
* @param Gems_User_User $user The user to create a key for.
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|