File indexing completed on 2024-12-22 05:36:23
0001 <?php 0002 0003 /** 0004 * ocs-webserver 0005 * 0006 * Copyright 2016 by pling GmbH. 0007 * 0008 * This file is part of ocs-webserver. 0009 * 0010 * This program is free software: you can redistribute it and/or modify 0011 * it under the terms of the GNU Affero General Public License as 0012 * published by the Free Software Foundation, either version 3 of the 0013 * License, or (at your option) any later version. 0014 * 0015 * This program is distributed in the hope that it will be useful, 0016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0018 * GNU Affero General Public License for more details. 0019 * 0020 * You should have received a copy of the GNU Affero General Public License 0021 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0022 **/ 0023 class Local_Auth_Adapter_Ocs implements Local_Auth_Adapter_Interface 0024 { 0025 0026 const MD5 = 'enc01'; 0027 const SHA = 'enc02'; 0028 const PASSWORDSALT = 'ghdfklsdfgjkldfghdklgioerjgiogkldfgndfohgfhhgfhgfhgfhgfhfghfgnndf'; 0029 const USER_DEACTIVATED = '_double'; 0030 const EMAIL_DEACTIVATED = '_double'; 0031 0032 protected $_db; 0033 protected $_tableName; 0034 protected $_identity; 0035 protected $_credential; 0036 protected $_encryption; 0037 protected $_resultRow; 0038 0039 /** 0040 * __construct() - Sets configuration options 0041 * 0042 * @param Zend_Db_Adapter_Abstract $dbAdapter If null, default database adapter assumed 0043 * @param string $tableName 0044 * 0045 * @throws Zend_Auth_Adapter_Exception 0046 */ 0047 public function __construct(Zend_Db_Adapter_Abstract $dbAdapter = null, $tableName = null) 0048 { 0049 $this->_db = $dbAdapter; 0050 if (empty($this->_db)) { 0051 $this->_db = Zend_Db_Table_Abstract::getDefaultAdapter(); 0052 if (empty($this->_db)) { 0053 throw new Zend_Auth_Adapter_Exception('No database adapter present'); 0054 } 0055 } 0056 0057 $this->_tableName = $tableName; 0058 } 0059 0060 /** 0061 * @param string $password 0062 * @param int $passwordType 0063 * @return string 0064 */ 0065 public static function getEncryptedPassword($password, $passwordType) 0066 { 0067 return $passwordType == Default_Model_DbTable_Member::PASSWORD_TYPE_HIVE 0068 ? sha1((self::PASSWORDSALT . $password . self::PASSWORDSALT)) 0069 : md5($password); 0070 } 0071 0072 /** 0073 * @param string $password 0074 * @return string 0075 */ 0076 public static function getEncryptedLdapPass($password) 0077 { 0078 return '{MD5}' . base64_encode(md5($password, true)); 0079 } 0080 0081 /** 0082 * Performs an authentication attempt 0083 * 0084 * @return Zend_Auth_Result 0085 * @throws Zend_Exception 0086 */ 0087 public function authenticate() 0088 { 0089 $validator = new Zend_Validate_EmailAddress(); 0090 if ($validator->isValid($this->_identity)) { 0091 $resultSet = $this->fetchUserByEmail(); 0092 } else { 0093 $resultSet = $this->fetchUserByUsername(); 0094 } 0095 0096 if (count($resultSet) == 0) { 0097 return $this->createAuthResult(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND, $this->_identity, 0098 array('A record with the supplied identity could not be found.')); 0099 } 0100 0101 if (count($resultSet) > 1) { 0102 return $this->createAuthResult(Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS, $this->_identity, 0103 array('More than one record matches the supplied identity.')); 0104 } 0105 0106 if (empty($resultSet[0]['email_checked'])) { 0107 return $this->createAuthResult(Local_Auth_Result::MAIL_ADDRESS_NOT_VALIDATED, $resultSet[0]['member_id'], 0108 array('Mail address not validated.')); 0109 } 0110 0111 if ($resultSet[0]['is_active'] == 0) { 0112 return $this->createAuthResult(Local_Auth_Result::ACCOUNT_INACTIVE, $this->_identity, 0113 array('User account is inactive.')); 0114 } 0115 0116 $this->_resultRow = array_shift($resultSet); 0117 0118 return $this->createAuthResult(Zend_Auth_Result::SUCCESS, $this->_identity, 0119 array('Authentication successful.')); 0120 } 0121 0122 /** 0123 * @return array 0124 * @throws Zend_Exception 0125 */ 0126 private function fetchUserByEmail() 0127 { 0128 $sql = " 0129 SELECT `m`.*, `member_email`.`email_verification_value`, `member_email`.`email_checked`, `mei`.`external_id` 0130 FROM `member` AS `m` 0131 JOIN `member_email` ON `m`.`member_id` = `member_email`.`email_member_id` AND `member_email`.`email_primary` = 1 AND `member_email`.`email_deleted` = 0 0132 LEFT JOIN `member_external_id` AS `mei` ON `mei`.`member_id` = `m`.`member_id` 0133 WHERE 0134 `m`.`is_active` = :active AND 0135 `m`.`is_deleted` = :deleted AND 0136 `m`.`login_method` = :login AND 0137 (LOWER(`m`.`mail`) = LOWER(:mail) OR 0138 LOWER(`m`.`mail`) = CONCAT(LOWER(:mail),:user_deactivated) 0139 ) AND 0140 `m`.`password` = :pwd"; 0141 0142 $this->_db->getProfiler()->setEnabled(true); 0143 $resultSet = $this->_db->fetchAll($sql, array( 0144 'active' => Default_Model_DbTable_Member::MEMBER_ACTIVE, 0145 'deleted' => Default_Model_DbTable_Member::MEMBER_NOT_DELETED, 0146 'login' => Default_Model_DbTable_Member::MEMBER_LOGIN_LOCAL, 0147 'mail' => $this->_identity, 0148 'user_deactivated' => $this::EMAIL_DEACTIVATED, 0149 'pwd' => $this->_credential 0150 )); 0151 0152 $sql = str_replace(':active', Default_Model_DbTable_Member::MEMBER_ACTIVE, $sql); 0153 $sql = str_replace(':deleted', Default_Model_DbTable_Member::MEMBER_NOT_DELETED, $sql); 0154 $sql = str_replace(':login', "'" . Default_Model_DbTable_Member::MEMBER_LOGIN_LOCAL . "'", $sql); 0155 $sql = str_replace(':mail', "'" . $this->_identity . "'", $sql); 0156 $sql = str_replace(':pwd', "'" . $this->_credential . "'", $sql); 0157 0158 Zend_Registry::get('logger')->debug(__METHOD__ . ' - SQL: ' . $sql . ' - sql take seconds: ' . $this->_db->getProfiler() 0159 ->getLastQueryProfile() 0160 ->getElapsedSecs()); 0161 $this->_db->getProfiler()->setEnabled(false); 0162 0163 return $resultSet; 0164 } 0165 0166 /** 0167 * Fetches a user by username, username ist not case sensitve 0168 * 0169 * @return array 0170 * @throws Zend_Exception 0171 */ 0172 private function fetchUserByUsername() 0173 { 0174 $sql = " 0175 SELECT `m`.*, `member_email`.`email_verification_value`, `member_email`.`email_checked`, `mei`.`external_id` 0176 FROM `member` AS `m` 0177 JOIN `member_email` ON `m`.`member_id` = `member_email`.`email_member_id` AND `member_email`.`email_primary` = 1 AND `member_email`.`email_deleted` = 0 0178 LEFT JOIN `member_external_id` AS `mei` ON `mei`.`member_id` = `m`.`member_id` 0179 WHERE 0180 `m`.`is_active` = :active AND 0181 `m`.`is_deleted` = :deleted AND 0182 `m`.`login_method` = :login AND 0183 (LOWER(`m`.`username`) = LOWER(:username) OR 0184 LOWER(`m`.`username`) = CONCAT(LOWER(:username),:user_deactivated) 0185 ) 0186 AND 0187 `m`.`password` = :pwd"; 0188 0189 $this->_db->getProfiler()->setEnabled(true); 0190 $resultSet = $this->_db->fetchAll($sql, array( 0191 'active' => Default_Model_DbTable_Member::MEMBER_ACTIVE, 0192 'deleted' => Default_Model_DbTable_Member::MEMBER_NOT_DELETED, 0193 'login' => Default_Model_DbTable_Member::MEMBER_LOGIN_LOCAL, 0194 'username' => $this->_identity, 0195 'user_deactivated' => $this::USER_DEACTIVATED, 0196 'pwd' => $this->_credential 0197 )); 0198 0199 $sql = str_replace(':active', Default_Model_DbTable_Member::MEMBER_ACTIVE, $sql); 0200 $sql = str_replace(':deleted', Default_Model_DbTable_Member::MEMBER_NOT_DELETED, $sql); 0201 $sql = str_replace(':login', "'" . Default_Model_DbTable_Member::MEMBER_LOGIN_LOCAL . "'", $sql); 0202 $sql = str_replace(':username', "'" . $this->_identity . "'", $sql); 0203 $sql = str_replace(':user_deactivated', "'" . $this::USER_DEACTIVATED . "'", $sql); 0204 $sql = str_replace(':pwd', "'" . $this->_credential . "'", $sql); 0205 0206 Zend_Registry::get('logger')->debug(__METHOD__ . ' - SQL: ' . $sql . ' - sql take seconds: ' . $this->_db->getProfiler() 0207 ->getLastQueryProfile() 0208 ->getElapsedSecs()); 0209 $this->_db->getProfiler()->setEnabled(false); 0210 0211 return $resultSet; 0212 } 0213 0214 protected function createAuthResult($code, $identity, $messages) 0215 { 0216 return new Local_Auth_Result($code, $identity, $messages); 0217 } 0218 0219 /** 0220 * @param string $identity 0221 * 0222 * @return Local_Auth_Adapter_Ocs 0223 */ 0224 public function setIdentity($identity) 0225 { 0226 $this->_identity = $identity; 0227 0228 return $this; 0229 } 0230 0231 /** 0232 * @param string $credential 0233 * 0234 * @return Local_Auth_Adapter_Ocs 0235 * @throws Zend_Exception 0236 */ 0237 public function setCredential($credential) 0238 { 0239 switch ($this->_encryption) { 0240 case self::MD5 : 0241 $this->_credential = md5($credential); 0242 break; 0243 case self::SHA : 0244 $this->_credential = sha1((self::PASSWORDSALT . $credential . self::PASSWORDSALT)); 0245 break; 0246 default: 0247 throw new Zend_Exception('There is no default case for credential encryption.'); 0248 } 0249 0250 return $this; 0251 } 0252 0253 /** 0254 * @param mixed $encryption 0255 * 0256 * @return Local_Auth_Adapter_Ocs 0257 */ 0258 public function setEncryption($encryption) 0259 { 0260 $this->_encryption = $encryption; 0261 0262 return $this; 0263 } 0264 0265 /** 0266 * getResultRowObject() - Returns the result row as a stdClass object 0267 * 0268 * @param string|array $returnColumns 0269 * @param string|array $omitColumns 0270 * 0271 * @return stdClass|boolean 0272 */ 0273 public function getResultRowObject($returnColumns = null, $omitColumns = null) 0274 { 0275 if (!$this->_resultRow) { 0276 return false; 0277 } 0278 0279 $returnObject = new stdClass(); 0280 0281 if (null !== $returnColumns) { 0282 0283 $availableColumns = array_keys($this->_resultRow); 0284 foreach ((array)$returnColumns as $returnColumn) { 0285 if (in_array($returnColumn, $availableColumns)) { 0286 $returnObject->{$returnColumn} = $this->_resultRow[$returnColumn]; 0287 } 0288 } 0289 0290 return $returnObject; 0291 } else { 0292 if (null !== $omitColumns) { 0293 0294 $omitColumns = (array)$omitColumns; 0295 foreach ($this->_resultRow as $resultColumn => $resultValue) { 0296 if (!in_array($resultColumn, $omitColumns)) { 0297 $returnObject->{$resultColumn} = $resultValue; 0298 } 0299 } 0300 0301 return $returnObject; 0302 } else { 0303 0304 foreach ($this->_resultRow as $resultColumn => $resultValue) { 0305 $returnObject->{$resultColumn} = $resultValue; 0306 } 0307 0308 return $returnObject; 0309 } 0310 } 0311 } 0312 0313 }