From: <gem...@li...> - 2012-03-23 18:23:15
|
Revision: 564 http://gemstracker.svn.sourceforge.net/gemstracker/?rev=564&view=rev Author: matijsdejong Date: 2012-03-23 18:23:04 +0000 (Fri, 23 Mar 2012) Log Message: ----------- Password validated in login form OldStyle staff users are upgraded to new style staff users during login Authentication easier to extend / adapt Fixed temp fix in svn update 552 with callable (in project using it) Modified Paths: -------------- trunk/library/changelog.txt trunk/library/classes/Gems/Default/IndexAction.php trunk/library/classes/Gems/Project/ProjectSettings.php trunk/library/classes/Gems/User/DbUserDefinitionAbstract.php trunk/library/classes/Gems/User/Form/ChangePasswordForm.php trunk/library/classes/Gems/User/Form/LoginForm.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/RadiusUserDefinition.php trunk/library/classes/Gems/User/User.php trunk/library/classes/Gems/User/UserDefinitionInterface.php trunk/library/classes/Gems/User/UserLoader.php trunk/library/classes/MUtil/Model/DatabaseModelAbstract.php trunk/library/classes/MUtil/Model/TableBridgeAbstract.php trunk/library/configs/db/patches.sql trunk/library/configs/db/tables/gems__user_login_attempts.10.sql Added Paths: ----------- trunk/library/classes/Gems/User/Validate/ trunk/library/classes/Gems/User/Validate/GetUserInterface.php trunk/library/classes/Gems/User/Validate/GetUserPasswordValidator.php trunk/library/classes/Gems/User/Validate/NewPasswordValidator.php trunk/library/classes/Gems/User/Validate/PasswordValidatorAbstract.php trunk/library/classes/Gems/User/Validate/UserPasswordValidator.php Removed Paths: ------------- trunk/library/classes/Gems/User/UserNewPasswordValidator.php trunk/library/classes/Gems/User/UserPasswordValidator.php Modified: trunk/library/changelog.txt =================================================================== --- trunk/library/changelog.txt 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/changelog.txt 2012-03-23 18:23:04 UTC (rev 564) @@ -1,3 +1,12 @@ +Important changes from 1.5.2 => 1.5.3 +============================================================ +People can login using their e-amil address as user name. +Showing a list of organizations to choose during login happens except when 1) there is only one organization or 2) a url is used that is assigned to a specific organization. +Login & other password forms are now easy to customize on a per project basis. +Login and authorizaiton rules are easier to extend. +Alll password rules are reported during reset. + + Important changes from 1.5.1 => 1.5.2 ============================================================ Renamed project.ini setting concentRejected to consentRejected Modified: trunk/library/classes/Gems/Default/IndexAction.php =================================================================== --- trunk/library/classes/Gems/Default/IndexAction.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/Default/IndexAction.php 2012-03-23 18:23:04 UTC (rev 564) @@ -161,7 +161,7 @@ Gems_Html::init(); return $this->loader->getUserLoader()->getLoginForm($args); - + /* $form = $this->_getBasicForm(); $form->addElement($this->_getOrganizationElement()); $form->addElement($this->_getUserLoginElement()); @@ -175,7 +175,7 @@ $form->addElement($this->_getResetLinkElement()); } - return $form; + return $form; // */ } /** @@ -330,64 +330,54 @@ if ($request->isPost()) { if ($form->isValid($request->getPost(), false)) { + $user = $form->getUser(); - $user = $this->loader->getUser($request->getParam('userlogin'), $request->getParam('organization')); + $previousRequestParameters = $this->session->previousRequestParameters; - // NO!!! DO not test! Otherwise it is easy to test which users exist. - // if ($user->isActive()) { - $formValues = $form->getValues(); - $authResult = $user->authenticate($formValues); + $user->setAsCurrentUser(); - if ($authResult->isValid()) { - $previousRequestParameters = $this->session->previousRequestParameters; + if ($messages = $user->reportPasswordWeakness($request->getParam($form->passwordFieldName))) { + $user->setPasswordResetRequired(true); + $this->addMessage($this->_('Your password must be changed.')); + $this->addMessage($messages); + } - $user->setAsCurrentUser(); + /** + * Fix current locale in cookies + */ + Gems_Cookies::setLocale($user->getLocale(), $this->basepath->getBasePath()); - $user->afterLogin($form->getValues()); + /** + * Ready + */ + $this->addMessage(sprintf($this->_('Login successful, welcome %s.'), $user->getFullName())); - //* - if ($messages = $user->reportPasswordWeakness($request->getParam('password'))) { - $user->setPasswordResetRequired(true); - $this->addMessage($this->_('Your password must be changed.')); - $this->addMessage($messages); - } // */ + /** + * Log the login + */ + Gems_AccessLog::getLog($this->db)->log("index.login", $this->getRequest(), null, $user->getUserId(), true); - /** - * Fix current locale in cookies - */ - Gems_Cookies::setLocale($user->getLocale(), $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->_reroute(array('controller' => $previousRequestParameters['controller'], 'action' => $previousRequestParameters['action']), false); - } else { - // This reroutes to the first available menu page after login. - // - // Do not user $user->gotoStartPage() as the menu is still set - // for no login. - $this->_reroute(array('controller' => null, 'action' => null), true); - } - return; + if ($previousRequestParameters) { + $this->_reroute(array('controller' => $previousRequestParameters['controller'], 'action' => $previousRequestParameters['action']), false); } else { - //Now present the user with an error message - $errors = $authResult->getMessages(); - $this->addMessage($errors); - - //Also log the error to the log table - //when the project has logging enabled - $logErrors = join(' - ', $errors); - $log = Gems_AccessLog::getLog(); - $log->log('loginFail', $this->getRequest(), sprintf('Failed login for : %s (%s) - %s', $formValues['userlogin'], $formValues['organization'], $logErrors), null, true); + // This reroutes to the first available menu page after login. + // + // Do not user $user->gotoStartPage() as the menu is still set + // for no login. + $this->_reroute(array('controller' => null, 'action' => null), true); } + return; + } else { + //Now present the user with an error message + $errors = $form->getErrorMessages(); + $this->addMessage($errors); + + //Also log the error to the log table + //when the project has logging enabled + $logErrors = join(' - ', $errors); + $msg = sprintf('Failed login for : %s (%s) - %s', $request->getParam($form->usernameFieldName), $request->getParam($form->organizationFieldName), $logErrors); + $log = Gems_AccessLog::getLog(); + $log->log('loginFail', $this->getRequest(), $msg, null, true); } } $this->view->form = $form; Modified: trunk/library/classes/Gems/Project/ProjectSettings.php =================================================================== --- trunk/library/classes/Gems/Project/ProjectSettings.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/Project/ProjectSettings.php 2012-03-23 18:23:04 UTC (rev 564) @@ -187,20 +187,6 @@ } /** - * Returns the factor used to delay account reloading. - * - * @return int - */ - public function getAccountDelayFactor() - { - if ($this->offsetExists('account') && isset($this->account['delayFactor'])) { - return intval($this->account['delayFactor']); - } else { - return 4; - } - } - - /** * Returns an array with throttling settings for the ask * controller * Modified: trunk/library/classes/Gems/User/DbUserDefinitionAbstract.php =================================================================== --- trunk/library/classes/Gems/User/DbUserDefinitionAbstract.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/DbUserDefinitionAbstract.php 2012-03-23 18:23:04 UTC (rev 564) @@ -123,12 +123,11 @@ /** * Returns an initialized Zend_Auth_Adapter_Interface * - * @param string $username - * @param int $organizationId + * @param Gems_User_User $user * @param string $password * @return Zend_Auth_Adapter_Interface */ - public function getAuthAdapter($username, $organizationId, $password) + public function getAuthAdapter(Gems_User_User $user, $password) { $adapter = new Zend_Auth_Adapter_DbTable($this->db, 'gems__user_passwords', 'gul_login', 'gup_password'); @@ -137,9 +136,9 @@ $select = $adapter->getDbSelect(); $select->join('gems__user_logins', 'gup_id_user = gul_id_user', array()) ->where('gul_can_login = 1') - ->where('gul_id_organization = ?', $organizationId); + ->where('gul_id_organization = ?', $user->getBaseOrganizationId()); - $adapter->setIdentity($username) + $adapter->setIdentity($user->getLoginName()) ->setCredential($pwd_hash); return $adapter; Modified: trunk/library/classes/Gems/User/Form/ChangePasswordForm.php =================================================================== --- trunk/library/classes/Gems/User/Form/ChangePasswordForm.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/Form/ChangePasswordForm.php 2012-03-23 18:23:04 UTC (rev 564) @@ -168,7 +168,7 @@ $element->setAttrib('maxlength', 20); $element->setRequired(true); $element->setRenderPassword(true); - $element->addValidator(new Gems_User_UserNewPasswordValidator($this->user)); + $element->addValidator(new Gems_User_Validate_NewPasswordValidator($this->user)); $element->addValidator(new MUtil_Validate_IsConfirmed($this->_repeatPasswordFieldName, $this->translate->_('Repeat password'))); $this->addElement($element); @@ -194,7 +194,7 @@ $element->setAttrib('maxlength', 20); $element->setRenderPassword(true); $element->setRequired(true); - $element->addValidator(new Gems_User_UserPasswordValidator($this->user, $this->translate)); + $element->addValidator(new Gems_User_Validate_UserPasswordValidator($this->user, $this->translate->_('Wrong password.'))); $this->addElement($element); } Modified: trunk/library/classes/Gems/User/Form/LoginForm.php =================================================================== --- trunk/library/classes/Gems/User/Form/LoginForm.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/Form/LoginForm.php 2012-03-23 18:23:04 UTC (rev 564) @@ -44,7 +44,7 @@ * @license New BSD License * @since Class available since version 1.5 */ -class Gems_User_Form_LoginForm extends Gems_Form_AutoLoadFormAbstract +class Gems_User_Form_LoginForm extends Gems_Form_AutoLoadFormAbstract implements Gems_User_Validate_GetUserInterface { /** * The field name for the lost password element. @@ -54,14 +54,6 @@ protected $_lostPasswordFieldName = 'lost_password'; /** - * The field name for the organization element. - * - * @var string - */ - protected $_organizationFieldName = 'organization'; - - - /** * When true the organization was derived from the the url * * @var boolean @@ -69,13 +61,6 @@ protected $_organizationFromUrl = false; /** - * The field name for the password element. - * - * @var string - */ - protected $_passwordFieldName = 'password'; - - /** * The field name for the submit element. * * @var string @@ -90,11 +75,10 @@ protected $_tokenFieldName = 'token_link'; /** - * The field name for the username element. * - * @var string + * @var Gems_User_User */ - protected $_usernameFieldName = 'userlogin'; + protected $_user; /** * @@ -103,6 +87,13 @@ protected $loader; /** + * The field name for the organization element. + * + * @var string + */ + public $organizationFieldName = 'organization'; + + /** * For small numbers of organizations a multiline selectbox will be nice. This * setting handles how many lines will display at once. Use 1 for the normal * dropdown selectbox @@ -112,7 +103,14 @@ protected $organizationMaxLines = 6; /** + * The field name for the password element. * + * @var string + */ + public $passwordFieldName = 'password'; + + /** + * * @var Zend_Controller_Request_Abstract */ protected $request; @@ -138,7 +136,14 @@ protected $translate; /** + * The field name for the username element. * + * @var string + */ + public $usernameFieldName = 'userlogin'; + + /** + * * @var Zend_Util */ protected $util; @@ -161,7 +166,7 @@ } $request = $this->getRequest(); - if ($request->isPost() && ($orgId = $request->getParam($this->_organizationFieldName))) { + if ($request->isPost() && ($orgId = $request->getParam($this->organizationFieldName))) { return $orgId; } @@ -216,14 +221,14 @@ */ public function getOrganizationElement() { - $element = $this->getElement($this->_organizationFieldName); + $element = $this->getElement($this->organizationFieldName); $orgId = $this->getCurrentOrganizationId(); $orgs = $this->getLoginOrganizations(); $hidden = $this->_organizationFromUrl || (count($orgs) < 2); if ($hidden) { if (! $element instanceof Zend_Form_Element_Hidden) { - $element = new Zend_Form_Element_Hidden($this->_organizationFieldName); + $element = new Zend_Form_Element_Hidden($this->organizationFieldName); $this->addElement($element); } @@ -234,7 +239,7 @@ } } elseif (! $element instanceof Zend_Form_Element_Select) { - $element = new Zend_Form_Element_Select($this->_organizationFieldName); + $element = new Zend_Form_Element_Select($this->organizationFieldName); $element->setLabel($this->translate->_('Organization')); $element->setRequired(true); $element->setMultiOptions($orgs); @@ -257,16 +262,23 @@ */ public function getPasswordElement() { - $element = $this->getElement($this->_passwordFieldName); + $element = $this->getElement($this->passwordFieldName); if (! $element) { // Veld password - $element = new Zend_Form_Element_Password($this->_passwordFieldName); + $element = new Zend_Form_Element_Password($this->passwordFieldName); $element->setLabel($this->translate->_('Password')); $element->setAttrib('size', 10); $element->setAttrib('maxlength', 20); $element->setRequired(true); + if ($this->getOrganizationElement() instanceof Zend_Form_Element_Hidden) { + $explain = $this->translate->_('Combination of user and password not found.'); + } else { + $explain = $this->translate->_('Combination of user and password not found for this organization.'); + } + $element->addValidator(new Gems_User_Validate_GetUserPasswordValidator($this, $explain)); + $this->addElement($element); } @@ -338,18 +350,29 @@ { return MUtil_Html::create('a', array('controller' => 'ask', 'action' => 'token'), $this->translate->_('Enter your token...'), array('class' => 'actionlink')); } + /** + * Returns a user + * + * @return Gems_User_User + */ + public function getUser() + { + return $this->_user; + } + + /** * Returns/sets a login name element. * * @return Zend_Form_Element_Text */ public function getUserNameElement() { - $element = $this->getElement($this->_usernameFieldName); + $element = $this->getElement($this->usernameFieldName); if (! $element) { // Veld inlognaam - $element = new Zend_Form_Element_Text($this->_usernameFieldName); + $element = new Zend_Form_Element_Text($this->usernameFieldName); $element->setLabel($this->translate->_('Username')); $element->setAttrib('size', 10); $element->setAttrib('maxlength', 20); @@ -362,6 +385,26 @@ } /** + * Validate the form + * + * As it is better for translation utilities to set the labels etc. translated, + * the MUtil default is to disable translation. + * + * However, this also disables the translation of validation messages, which we + * cannot set translated. The MUtil form is extended so it can make this switch. + * + * @param array $data + * @param boolean $disableTranslateValidators Extra switch + * @return boolean + */ + public function isValid($data, $disableTranslateValidators = null) + { + $this->_user = $this->loader->getUser($data[$this->usernameFieldName], $data[$this->organizationFieldName]); + + return parent::isValid($data, $disableTranslateValidators); + } + + /** * The function that determines the element load order * * @return Gems_User_Form_LoginForm (continuation pattern) Modified: trunk/library/classes/Gems/User/NoLoginDefinition.php =================================================================== --- trunk/library/classes/Gems/User/NoLoginDefinition.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/NoLoginDefinition.php 2012-03-23 18:23:04 UTC (rev 564) @@ -47,27 +47,15 @@ class Gems_User_NoLoginDefinition extends Gems_User_UserDefinitionAbstract { /** - * Helper method for the case a user tries to authenticate while he is inactive - * - * @return boolean - */ - public function alwaysFalse() - { - return false; - } - - /** * Returns an initialized Zend_Auth_Adapter_Interface * - * @param string $username - * @param int $organizationId + * @param Gems_User_User $user * @param string $password * @return Zend_Auth_Adapter_Interface */ - public function getAuthAdapter($username, $organizationId, $password) + public function getAuthAdapter(Gems_User_User $user, $password) { - $adapter = new Gems_Auth_Adapter_Callback(array($this,'alwaysFalse'), $username); - return $adapter; + return false; } /** @@ -80,8 +68,11 @@ public function getUserData($login_name, $organization) { return array( - 'user_active' => false, - 'user_role' => 'nologin', + 'user_login' => $login_name, + 'user_name' => $login_name, + 'user_base_org_id' => $organization, + 'user_active' => false, + 'user_role' => 'nologin', ); } } Modified: trunk/library/classes/Gems/User/OldStaffUserDefinition.php =================================================================== --- trunk/library/classes/Gems/User/OldStaffUserDefinition.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/OldStaffUserDefinition.php 2012-03-23 18:23:04 UTC (rev 564) @@ -60,23 +60,6 @@ protected $project; /** - * Perform UserDefinition specific post-login logic - * - * @param Zend_Auth_Result $authResult - * @return void - */ - public function afterLogin(Zend_Auth_Result $authResult, $formValues) - { - // MUtil_Echo::track($authResult->isValid(), $formValues); - if ($authResult->isValid()) { - $login_name = $formValues['userlogin']; - $organization = $formValues['organization']; - $password = $formValues['password']; - $this->makeNewStaffUser($login_name, $organization, $password); - } - } - - /** * Return true if the password can be set. * * Returns the setting for the definition whan no user is passed, otherwise @@ -93,13 +76,25 @@ /** * Returns an initialized Zend_Auth_Adapter_Interface * - * @param string $username - * @param int $organizationId + * @param Gems_User_User $user * @param string $password * @return Zend_Auth_Adapter_Interface */ - public function getAuthAdapter($username, $organizationId, $password) + public function getAuthAdapter(Gems_User_User $user, $password) { + $pwd_hash = $this->hashPassword($password); + + $sql = "SELECT gsf_id_user FROM gems__staff WHERE gsf_active = 1 AND gsf_login = ? AND gsf_id_organization = ? AND gsf_password = ?"; + + if ($this->db->fetchOne($sql, array($user->getLoginName(), $user->getBaseOrganizationId(), $pwd_hash))) { + $this->makeNewStaffUser($user, $password); + + return true; + } else { + return false; + } + + /* $adapter = new Zend_Auth_Adapter_DbTable(null, 'gems__staff', 'gsf_login', 'gsf_password'); $pwd_hash = $this->hashPassword($password); @@ -112,6 +107,7 @@ ->setCredential($pwd_hash); return $adapter; + // */ } /** @@ -200,15 +196,19 @@ return md5($password); } - protected function makeNewStaffUser($login_name, $organization, $password) + /** + * Sets the user up as a new staff user + * + * @param Gems_User_User $user + * @param string $password + */ + protected function makeNewStaffUser(Gems_User_User $user, $password) { - $userData = $this->getUserData($login_name, $organization); - $staff_id = $userData['user_id']; + $staff_id = $user->getUserId(); + $sql = 'SELECT gul_id_user FROM gems__user_logins WHERE gul_can_login = 1 AND gul_login = ? AND gul_id_organization = ?'; - $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)); + $user_id = $this->db->fetchOne($sql, array($user->getLoginName(), $user->getBaseOrganizationId())); $currentTimestamp = new Zend_Db_Expr('CURRENT_TIMESTAMP'); @@ -240,6 +240,8 @@ $this->db->update('gems__staff', $values, $this->db->quoteInto('gsf_id_user = ?', $staff_id)); + $user->refresh(Gems_User_UserLoader::USER_STAFF); + } catch (Zend_Db_Exception $e) { GemsEscort::getInstance()->logger->log($e->getMessage(), Zend_Log::ERR); // Fall through as this does not work if the database upgrade did not run @@ -257,7 +259,7 @@ */ public function setPassword(Gems_User_User $user, $password) { - $this->makeNewStaffUser($user->getLoginName(), $user->getBaseOrganizationId(), $password); + $this->makeNewStaffUser($user, $password); return $this; } Modified: trunk/library/classes/Gems/User/ProjectUserDefinition.php =================================================================== --- trunk/library/classes/Gems/User/ProjectUserDefinition.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/ProjectUserDefinition.php 2012-03-23 18:23:04 UTC (rev 564) @@ -55,14 +55,13 @@ /** * Returns an initialized Zend_Auth_Adapter_Interface * - * @param string $username - * @param int $organizationId + * @param Gems_User_User $user * @param string $password * @return Zend_Auth_Adapter_Interface */ - public function getAuthAdapter($username, $organizationId, $password) + public function getAuthAdapter(Gems_User_User $user, $password) { - $adapter = new Gems_Auth_Adapter_Callback(array($this->project,'checkSuperAdminPassword'), $username, array($password)); + $adapter = new Gems_Auth_Adapter_Callback(array($this->project, 'checkSuperAdminPassword'), $user->getLoginName(), array($password)); return $adapter; } @@ -76,14 +75,15 @@ public function getUserData($login_name, $organization) { return array( - 'user_id' => 1, - 'user_login' => $login_name, - 'user_name' => $login_name, - 'user_group' => 800, - 'user_role' => 'master', - 'user_style' => 'gems', - 'user_base_org_id' => $organization, + 'user_id' => 1, + 'user_login' => $login_name, + 'user_name' => $login_name, + 'user_group' => 800, + 'user_role' => 'master', + 'user_style' => 'gems', + 'user_base_org_id' => $organization, 'user_allowed_ip_ranges' => $this->project->getSuperAdminIPRanges(), + 'user_blockable' => false, ); } } \ No newline at end of file Modified: trunk/library/classes/Gems/User/RadiusUserDefinition.php =================================================================== --- trunk/library/classes/Gems/User/RadiusUserDefinition.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/RadiusUserDefinition.php 2012-03-23 18:23:04 UTC (rev 564) @@ -128,15 +128,14 @@ /** * Returns an initialized Zend_Auth_Adapter_Interface * - * @param string $username - * @param int $organizationId + * @param Gems_User_User $user * @param string $password * @return Zend_Auth_Adapter_Interface */ - public function getAuthAdapter($username, $organizationId, $password) + public function getAuthAdapter(Gems_User_User $user, $password) { //Ok hardcoded for now this needs to be read from the userdefinition - $configData = $this->loadConfig(array('gor_id_organization' => $organizationId)); + $configData = $this->loadConfig(array('gor_id_organization' => $user->getBaseOrganizationId())); $config = array('ip' => $configData['grcfg_ip'], 'authenticationport' => $configData['grcfg_port'], @@ -150,7 +149,7 @@ } $adapter = new Gems_User_Adapter_Radius($config); - $adapter->setIdentity($username) + $adapter->setIdentity($user->getLoginName()) ->setCredential($password); return $adapter; Modified: trunk/library/classes/Gems/User/User.php =================================================================== --- trunk/library/classes/Gems/User/User.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/User.php 2012-03-23 18:23:04 UTC (rev 564) @@ -87,7 +87,21 @@ protected $definition; /** + * Sets number failed accounts that trigger a block * + * @var int + */ + protected $failureBlockCount = 6; + + /** + * Sets number of seconds until a previous failed login can be ignored + * + * @var int + */ + protected $failureIgnoreTime = 600; + + /** + * * @var Zend_Controller_Request_Abstract */ protected $request; @@ -113,7 +127,16 @@ protected $userLoader; /** + * Use Zend_Auth for authentication * + * Warning: Zend_Auth contains only a partial ID of the current user, the base organization is missing + * + * @var boolean + */ + protected $useZendAuth = false; + + /** + * * @var Gems_Util */ protected $util; @@ -221,56 +244,205 @@ } /** - * Perform project specific after login logic here, can also delegate to the user definition + * Process everything after authentication. * - * @return void + * @param Zend_Auth_Result $result */ - public function afterLogin($formValues) { - if (is_callable(array($this->definition, 'afterLogin'))) { - // Use the USERS organization, not the one he or she is using currently - $formValues['organization'] = $this->getBaseOrganizationId(); - $this->definition->afterLogin($this->_authResult, $formValues); + protected function afterAuthorization(Zend_Auth_Result $result) + { + try { + $select = $this->db->select(); + $select->from('gems__user_login_attempts', array('gula_failed_logins', 'gula_last_failed', 'gula_block_until', 'UNIX_TIMESTAMP() - UNIX_TIMESTAMP(gula_last_failed) AS since_last')) + ->where('gula_login = ?', $this->getLoginName()) + ->where('gula_id_organization = ?', $this->getCurrentOrganizationId()) + ->limit(1); + + $values = $this->db->fetchRow($select); + + // The first login attempt + if (! $values) { + $values['gula_login'] = $this->getLoginName(); + $values['gula_id_organization'] = $this->getCurrentOrganizationId(); + $values['gula_failed_logins'] = 0; + $values['gula_last_failed'] = null; + $values['gula_block_until'] = null; + $values['since_last'] = $this->failureBlockCount + 1; + } + + if ($result->isValid()) { + // Reset login failures + $values['gula_failed_logins'] = 0; + $values['gula_last_failed'] = null; + $values['gula_block_until'] = null; + + } else { + + // Reset the counters when the last login was longer ago than the delay factor + if ($values['since_last'] > $this->failureIgnoreTime) { + $values['gula_failed_logins'] = 1; + } else { + $values['gula_failed_logins'] += 1; + } + + // If block is already set + if ($values['gula_block_until']) { + // Do not change it anymore + unset($values['gula_block_until']); + + } else { + // Only set the block when needed + if ($this->failureBlockCount <= $values['gula_failed_logins']) { + $values['gula_block_until'] = new Zend_Db_Expr('DATE_ADD(CURRENT_TIMESTAMP, INTERVAL ' . $this->failureIgnoreTime . ' SECOND)'); + } + } + + // Always record the last fail + $values['gula_last_failed'] = new Zend_Db_Expr('CURRENT_TIMESTAMP'); + + // Response gets slowly slower + $sleepTime = min($values['gula_failed_logins'] - 1, 10) * 2; + sleep($sleepTime); + // MUtil_Echo::track($sleepTime, $values, $result->getMessages()); + } + + // Value not saveable + unset($values['since_last']); + + if (isset($values['gula_login'])) { + $this->db->insert('gems__user_login_attempts', $values); + } else { + $where = $this->db->quoteInto('gula_login = ? AND ', $this->getLoginName()); + $where .= $this->db->quoteInto('gula_id_organization = ?', $this->getCurrentOrganizationId()); + $this->db->update('gems__user_login_attempts', $values, $where); + } + + } catch (Zend_Db_Exception $e) { + // Fall through as this does not work if the database upgrade did not yet run + // MUtil_Echo::r($e); } + } /** - * Helper method for the case a user tries to authenticate while he is inactive + * Authenticate a users credentials using the submitted form * - * @return boolean + * @param string $password The password to test + * @return Zend_Auth_Result */ - public function alwaysFalse() + public function authenticate($password) { - return false; + if ($this->useZendAuth) { + $zendAuth = Zend_Auth::getInstance(); + } + $auths = $this->loadAuthorizers($password); + + foreach ($auths as $result) { + if (is_callable($result)) { + $result = call_user_func($result); + } + + if ($result instanceof Zend_Auth_Adapter_Interface) { + if ($this->useZendAuth) { + $result = $zendAuth->authenticate($result); + } else { + $result = $result->authenticate(); + } + } + + if ($result instanceof Zend_Auth_Result) { + if (! $result->isValid()) { + break; + } + } else { + if (true === $result) { + $result = new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $this->getLoginName()); + + } else { + // Always a fail when not true + if ($result === false) { + $code = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID; + $result = array(); + } else { + $code = Zend_Auth_Result::FAILURE_UNCATEGORIZED; + if (is_string($result)) { + $result = array($result); + } + } + $result = new Zend_Auth_Result($code, $this->getLoginName(), $result); + break; + } + } + } + + $this->afterAuthorization($result); + + // MUtil_Echo::track($result); + $this->_authResult = $result; + + return $result; } /** - * Authenticate a users credentials using the submitted form + * Checks if the user is allowed to login or is blocked * - * @param array $formValues the array containing all formvalues from the login form - * @return Zend_Auth_Result + * An adapter authorizes and if the end resultis boolean, string or array + * it is converted into a Zend_Auth_Result. + * + * @return mixed Zend_Auth_Adapter_Interface|Zend_Auth_Result|boolean|string|array */ - public function authenticate($formValues) + protected function authorizeBlock() { - // Check if the client IP address is within allowed IP ranges - if (! $this->util->isAllowedIP($_SERVER['REMOTE_ADDR'], $this->getAllowedIPRanges())) { - return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_UNCATEGORIZED, $this->getLoginName(), array($this->translate->_('You are not allowed to login from this location.'))); - } + try { + $select = $this->db->select(); + $select->from('gems__user_login_attempts', array('UNIX_TIMESTAMP(gula_block_until) - UNIX_TIMESTAMP() AS wait')) + ->where('gula_block_until is not null') + ->where('gula_login = ?', $this->getLoginName()) + ->where('gula_id_organization = ?', $this->getCurrentOrganizationId()) + ->limit(1); - $auth = Gems_Auth::getInstance(); + // Not the first login + if ($block = $this->db->fetchOne($select)) { + if ($block > 0) { + $minutes = intval($block / 60) + 1; - $formValues['organization'] = $this->getBaseOrganizationId(); - $formValues['userlogin'] = $this->getLoginName(); + // Report all is not well + return sprintf($this->translate->plural('Your account is temporarily blocked, please wait a minute.', 'Your account is temporarily blocked, please wait %d minutes.', $minutes), $minutes); - if ($this->isActive()) { - $adapter = $this->definition->getAuthAdapter($formValues['userlogin'], $formValues['organization'], $formValues['password']); - } else { - $adapter = new Gems_Auth_Adapter_Callback(array($this,'alwaysFalse'), $formValues['userlogin']); + } else { + // Clean the block once it's past + $values['gula_failed_logins'] = 0; + $values['gula_last_failed'] = null; + $values['gula_block_until'] = null; + $where = $this->db->quoteInto('gula_login = ? AND ', $this->getLoginName()); + $where .= $this->db->quoteInto('gula_id_organization = ?', $this->getCurrentOrganizationId()); + + $this->db->update('gems__user_login_attempts', $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); } - $authResult = $auth->authenticate($adapter, $formValues); - $this->_authResult = $authResult; + return true; + } - return $authResult; + /** + * Checks if the user is allowed to login using the current IP address + * + * An adapter authorizes and if the end resultis boolean, string or array + * it is converted into a Zend_Auth_Result. + * + * @return mixed Zend_Auth_Adapter_Interface|Zend_Auth_Result|boolean|string|array + */ + protected function authorizeIp() + { + if ($this->util->isAllowedIP($_SERVER['REMOTE_ADDR'], $this->getAllowedIPRanges())) { + return true; + } else { + return $this->translate->_('You are not allowed to login from this location.'); + } } /** @@ -439,20 +611,6 @@ } /** - * Get the array to use for authenticate() - * - * @param string $password - * @return array - */ - public function getFormValuesForPassword($password) - { - return array( - 'userlogin' => $this->getLoginName(), - 'password' => $password, - 'organization' => $this->getCurrentOrganizationId()); - } - - /** * Returns the full user name (first, prefix, last). * * @return string @@ -704,6 +862,20 @@ } /** + * True when this user must enter a new password. + * + * @return boolean + */ + public function isBlockable() + { + if ($this->_hasVar('user_blockable')) { + return (boolean) $this->_getVar('user_blockable'); + } else { + return true; + } + } + + /** * Checks if this user is the current user * * @return boolean @@ -744,6 +916,53 @@ } /** + * Load the callables | results needed to authenticate/authorize this user + * + * A callable will be called, then an adapter authorizes and if the end result + * is boolean, string or array it is converted into a Zend_Auth_Result. + * + * @param string $password + * @return array Of Callable|Zend_Auth_Adapter_Interface|Zend_Auth_Result|boolean|string|array + */ + protected function loadAuthorizers($password) + { + $auths['ip'] = array($this, 'authorizeIp'); + + if ($this->isBlockable()) { + $auths['block'] = array($this, 'authorizeBlock'); + } + + if ($this->isActive()) { + $auths['pwd'] = $this->definition->getAuthAdapter($this, $password); + } else { + $auths['pwd'] = false; + } + + return $auths; + } + + /** + * + * @param string $defName Optional + * @return Gems_User_User (continuation pattern) + */ + public function refresh($defName = null) + { + if ($defName) { + $this->definition = $this->userLoader->getUserDefinition($defName); + } + + $newData = $this->definition->getUserData($this->getLoginName(), $this->getBaseOrganizationId()); + $newData = $this->userLoader->ensureDefaultUserValues($newData, $this->definition, $defName); + + foreach ($newData as $key => $value) { + $this->_setVar($key, $value); + } + + return $this; + } + + /** * Allowes a refresh of the existing list of organizations * for this user. * Modified: trunk/library/classes/Gems/User/UserDefinitionInterface.php =================================================================== --- trunk/library/classes/Gems/User/UserDefinitionInterface.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/UserDefinitionInterface.php 2012-03-23 18:23:04 UTC (rev 564) @@ -80,12 +80,10 @@ /** * Returns an initialized Zend_Auth_Adapter_Interface * - * @param string $username - * @param int $organizationId - * @param string $password + * @param Gems_User_User $user * @return Zend_Auth_Adapter_Interface */ - public function getAuthAdapter($username, $organizationId, $password); + public function getAuthAdapter(Gems_User_User $user, $password); /** * Return a password reset key Modified: trunk/library/classes/Gems/User/UserLoader.php =================================================================== --- trunk/library/classes/Gems/User/UserLoader.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/UserLoader.php 2012-03-23 18:23:04 UTC (rev 564) @@ -171,6 +171,30 @@ } /** + * Makes sure default values are set for a user + * + * @param array $values + * @param Gems_User_UserDefinitionInterface $definition + * @param string $defName Optional + * @return array + */ + public function ensureDefaultUserValues(array $values, Gems_User_UserDefinitionInterface $definition, $defName = null) + { + if (! isset($values['user_active'])) { + $values['user_active'] = true; + } + if (! isset($values['user_staff'])) { + $values['user_staff'] = $definition->isStaff(); + } + + if ($defName) { + $values['__user_definition'] = $defName; + } + + return $values; + } + + /** * Get userclass / description array of available UserDefinitions for respondents * * @return array @@ -464,15 +488,8 @@ $values = $definition->getUserData($userName, $userOrganization); // MUtil_Echo::track($defName, $login_name, $userOrganization, $values); - if (! isset($values['user_active'])) { - $values['user_active'] = true; - } - if (! isset($values['user_staff'])) { - $values['user_staff'] = $definition->isStaff(); - } + $values = $this->ensureDefaultUserValues($values, $definition, $defName); - $values['__user_definition'] = $defName; - return $this->_loadClass('User', true, array($values, $definition)); } Deleted: trunk/library/classes/Gems/User/UserNewPasswordValidator.php =================================================================== --- trunk/library/classes/Gems/User/UserNewPasswordValidator.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/UserNewPasswordValidator.php 2012-03-23 18:23:04 UTC (rev 564) @@ -1,117 +0,0 @@ -<?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. - * - * - * @package Gems - * @subpackage User - * @author Matijs de Jong <mj...@ma...> - * @copyright Copyright (c) 2011 Erasmus MC - * @license New BSD License - * @version $Id$ - */ - -/** - * - * - * @package Gems - * @subpackage User - * @copyright Copyright (c) 2011 Erasmus MC - * @license New BSD License - * @since Class available since version 1.5 - */ -class Gems_User_UserNewPasswordValidator implements Zend_Validate_Interface -{ - /** - * The reported problems with the password. - * - * @var array or null - */ - private $_report; - - /** - * - * @var Gems_User_User - */ - private $_user; - - /** - * - * @param Gems_User_User $user The user to check - */ - public function __construct(Gems_User_User $user) - { - $this->_user = $user; - } - - /** - * Returns true if and only if $value meets the validation requirements - * - * If $value fails validation, then this method returns false, and - * getMessages() will return an array of messages that explain why the - * validation failed. - * - * @param mixed $value - * @param mixed $content - * @return boolean - * @throws Zend_Validate_Exception If validation of $value is impossible - */ - public function isValid($value, $context = array()) - { - $this->_report = $this->_user->reportPasswordWeakness($value); - - foreach ($this->_report as &$report) { - $report = ucfirst($report) . '.'; - } - - // MUtil_Echo::track($value, $this->_report); - - return ! (boolean) $this->_report; - } - - /** - * Returns an array of messages that explain why the most recent isValid() - * call returned false. The array keys are validation failure message identifiers, - * and the array values are the corresponding human-readable message strings. - * - * If isValid() was never called or if the most recent isValid() call - * returned true, then this method returns an empty array. - * - * @return array - */ - public function getMessages() - { - if ($this->_report) { - return $this->_report; - - } else { - return array(); - } - - - } -} Deleted: trunk/library/classes/Gems/User/UserPasswordValidator.php =================================================================== --- trunk/library/classes/Gems/User/UserPasswordValidator.php 2012-03-22 17:05:18 UTC (rev 563) +++ trunk/library/classes/Gems/User/UserPasswordValidator.php 2012-03-23 18:23:04 UTC (rev 564) @@ -1,120 +0,0 @@ -<?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. - * - * - * @package Gems - * @subpackage User - * @author Matijs de Jong <mj...@ma...> - * @copyright Copyright (c) 2011 Erasmus MC - * @license New BSD License - * @version $Id$ - */ - -/** - * - * - * @package Gems - * @subpackage User - * @copyright Copyright (c) 2011 Erasmus MC - * @license New BSD License - * @since Class available since version 1.5 - */ -class Gems_User_UserPasswordValidator implements Zend_Validate_Interface -{ - /** - * - * @var Gems_User_User - */ - private $_user; - - /** - * - * @var Zend_Translate - */ - private $_translate; - - /** - * - * @var boolean - */ - private $_valid = false; - - /** - * - * @param Gems_User_User $user The user to check - * @param Zend_Translate $translate Optional translator - */ - public function __construct(Gems_User_User $user, Zend_Translate $translate = null) - { - $this->_user = $user; - $this->_translate = $translate ? $translate : new MUtil_Translate_Adapter_Potemkin(); - } - - /** - * Returns true if and only if $value meets the validation requirements - * - * If $value fails validation, then this method returns false, and - * getMessages() will return an array of messages that explain why the - * validation failed. - * - * @param mixed $value - * @param mixed $content - * @return boolean - * @throws Zend_Validate_Exception If validation of $value is impossible - */ - public function isValid($value, $context = array()) - { - $authResult = $this->_user->authenticate($this->_user->getFormValuesForPassword($value)); - - $this->_valid = $authResult->isValid(); - - return $this->_valid; - } - - /** - * Returns an array of messages that explain why the most recent isValid() - * call returned false. The array keys are validation failure message identifiers, - * and the array values are the corresponding human-readable message strings. - * - * If isValid() was never called or if the most recent isValid() call - * returned true, then this method returns an empty array. - * - * @return array - */ - public function getMessages() - { - if ($this->_valid) { - return array(); - - } else { - return array($this->_translate->_('Wrong password.')); - } - - - } -} Property changes on: trunk/library/classes/Gems/User/Validate ___________________________________________________________________ Added: bugtraq:url + http://survey.erasmusmc.nl/support/mantis/view.php?id=%BUGID% Added: bugtraq:logregex + #(\d+) Added: trunk/library/classes/Gems/User/Validate/GetUserInterface.php =================================================================== --- trunk/library/classes/Gems/User/Validate/GetUserInterface.php (rev 0) +++ trunk/library/classes/Gems/User/Validate/GetUserInterface.php 2012-03-23 18:23:04 UTC (rev 564) @@ -0,0 +1,55 @@ +<?php + +/** + * Copyright (c) 2012, 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. + * + * + * @package Gems + * @subpackage User + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @version $id: GetUserInterface.php 203 2012-01-01 12:51:32Z matijs $ + */ + +/** + * + * + * @package Gems + * @subpackage User + * @copyright Copyright (c) 2012 Erasmus MC + * @license New BSD License + * @since Class available since version 1.5.3 + */ +interface Gems_User_Validate_GetUserInterface +{ + /** + * Returns a user + * + * @return Gems_User_User + */ + public function getUser(); +} Added: trunk/library/classes/Gems/User/Validate/GetUserPasswordValidator.php =================================================================== --- trunk/library/classes/Gems/User/Validate/GetUserPasswordValidator.php (rev 0) +++ trunk/library/classes/Gems/User/Validate/GetUserPasswordValidator.php 2012-03-23 18:23:04 UTC (rev 564) @@ -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. + * + * + * @package Gems + * @subpackage User + * @author Matijs de Jong <mj...@ma...> + * @copyright Copyright (c) 2011 Erasmus MC + * @license New BSD License + * @version $Id: UserPasswordValidator.php 370 2011-12-19 09:27:19Z mennodekker $ + */ + +/** + * + * + * @package Gems + * @subpackage User + * @copyright Copyright (c) 2011 Erasmus MC + * @license New BSD License + * @since Class available since version 1.5 + */ +class Gems_User_Validate_GetUserPasswordValidator extends Gems_User_Validate_PasswordValidatorAbstract +{ + /** + * + * @var Gems_User_Validate_GetUserInterface + */ + private $_userSource; + + /** + * + * @param Gems_User_Validate_GetUserInterface $userSource The source for the user + * @param string $message Default message for standard login fail. + */ + public function __construct(Gems_User_Validate_GetUserInterface $userSource, $message) + { + $this->_userSource = $userSource; + + parent::__construct($message); + } + + /** + * Returns true if and only if $value meets the validation requirements + * + * If $value fails validation, then this method returns false, and + * getMessages() will return an array of messages that explain why the + * validation failed. + * + * @param mixed $value + * @param mixed $content + * @return boolean + * @throws Zend_Validate_Exception If validation of $value is impossible + */ + public function isValid($value, $context = array()) + { + $user = $this->_userSource->getUser(); + if ($user instanceof Gems_User_User) { + $result = $user->authenticate($value); + } else { + $result = new Zend_Auth_Result(Zend_Auth_Result::FAILURE_UNCATEGORIZED, null); + } + + return $this->setAuthResult($result); + } +} Added: trunk/library/classes/Gems/User/Validate/NewPassword... [truncated message content] |