File indexing completed on 2025-01-19 05:20:55
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_Auth 0017 * @subpackage Adapter 0018 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0019 * @license http://framework.zend.com/license/new-bsd New BSD License 0020 * @version $Id$ 0021 */ 0022 0023 0024 /** 0025 * @see Zend_Auth_Adapter_Interface 0026 */ 0027 // require_once 'Zend/Auth/Adapter/Interface.php'; 0028 0029 /** 0030 * @see Zend_Db_Adapter_Abstract 0031 */ 0032 // require_once 'Zend/Db/Adapter/Abstract.php'; 0033 0034 /** 0035 * @see Zend_Auth_Result 0036 */ 0037 // require_once 'Zend/Auth/Result.php'; 0038 0039 0040 /** 0041 * @category Zend 0042 * @package Zend_Auth 0043 * @subpackage Adapter 0044 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0045 * @license http://framework.zend.com/license/new-bsd New BSD License 0046 */ 0047 class Zend_Auth_Adapter_DbTable implements Zend_Auth_Adapter_Interface 0048 { 0049 0050 /** 0051 * Database Connection 0052 * 0053 * @var Zend_Db_Adapter_Abstract 0054 */ 0055 protected $_zendDb = null; 0056 0057 /** 0058 * @var Zend_Db_Select 0059 */ 0060 protected $_dbSelect = null; 0061 0062 /** 0063 * $_tableName - the table name to check 0064 * 0065 * @var string 0066 */ 0067 protected $_tableName = null; 0068 0069 /** 0070 * $_identityColumn - the column to use as the identity 0071 * 0072 * @var string 0073 */ 0074 protected $_identityColumn = null; 0075 0076 /** 0077 * $_credentialColumns - columns to be used as the credentials 0078 * 0079 * @var string 0080 */ 0081 protected $_credentialColumn = null; 0082 0083 /** 0084 * $_identity - Identity value 0085 * 0086 * @var string 0087 */ 0088 protected $_identity = null; 0089 0090 /** 0091 * $_credential - Credential values 0092 * 0093 * @var string 0094 */ 0095 protected $_credential = null; 0096 0097 /** 0098 * $_credentialTreatment - Treatment applied to the credential, such as MD5() or PASSWORD() 0099 * 0100 * @var string 0101 */ 0102 protected $_credentialTreatment = null; 0103 0104 /** 0105 * $_authenticateResultInfo 0106 * 0107 * @var array 0108 */ 0109 protected $_authenticateResultInfo = null; 0110 0111 /** 0112 * $_resultRow - Results of database authentication query 0113 * 0114 * @var array 0115 */ 0116 protected $_resultRow = null; 0117 0118 /** 0119 * $_ambiguityIdentity - Flag to indicate same Identity can be used with 0120 * different credentials. Default is FALSE and need to be set to true to 0121 * allow ambiguity usage. 0122 * 0123 * @var boolean 0124 */ 0125 protected $_ambiguityIdentity = false; 0126 0127 /** 0128 * __construct() - Sets configuration options 0129 * 0130 * @param Zend_Db_Adapter_Abstract $zendDb If null, default database adapter assumed 0131 * @param string $tableName 0132 * @param string $identityColumn 0133 * @param string $credentialColumn 0134 * @param string $credentialTreatment 0135 */ 0136 public function __construct(Zend_Db_Adapter_Abstract $zendDb = null, $tableName = null, $identityColumn = null, 0137 $credentialColumn = null, $credentialTreatment = null) 0138 { 0139 $this->_setDbAdapter($zendDb); 0140 0141 if (null !== $tableName) { 0142 $this->setTableName($tableName); 0143 } 0144 0145 if (null !== $identityColumn) { 0146 $this->setIdentityColumn($identityColumn); 0147 } 0148 0149 if (null !== $credentialColumn) { 0150 $this->setCredentialColumn($credentialColumn); 0151 } 0152 0153 if (null !== $credentialTreatment) { 0154 $this->setCredentialTreatment($credentialTreatment); 0155 } 0156 } 0157 0158 /** 0159 * _setDbAdapter() - set the database adapter to be used for quering 0160 * 0161 * @param Zend_Db_Adapter_Abstract 0162 * @throws Zend_Auth_Adapter_Exception 0163 * @return Zend_Auth_Adapter_DbTable 0164 */ 0165 protected function _setDbAdapter(Zend_Db_Adapter_Abstract $zendDb = null) 0166 { 0167 $this->_zendDb = $zendDb; 0168 0169 /** 0170 * If no adapter is specified, fetch default database adapter. 0171 */ 0172 if(null === $this->_zendDb) { 0173 // require_once 'Zend/Db/Table/Abstract.php'; 0174 $this->_zendDb = Zend_Db_Table_Abstract::getDefaultAdapter(); 0175 if (null === $this->_zendDb) { 0176 // require_once 'Zend/Auth/Adapter/Exception.php'; 0177 throw new Zend_Auth_Adapter_Exception('No database adapter present'); 0178 } 0179 } 0180 0181 return $this; 0182 } 0183 0184 /** 0185 * setTableName() - set the table name to be used in the select query 0186 * 0187 * @param string $tableName 0188 * @return Zend_Auth_Adapter_DbTable Provides a fluent interface 0189 */ 0190 public function setTableName($tableName) 0191 { 0192 $this->_tableName = $tableName; 0193 return $this; 0194 } 0195 0196 /** 0197 * setIdentityColumn() - set the column name to be used as the identity column 0198 * 0199 * @param string $identityColumn 0200 * @return Zend_Auth_Adapter_DbTable Provides a fluent interface 0201 */ 0202 public function setIdentityColumn($identityColumn) 0203 { 0204 $this->_identityColumn = $identityColumn; 0205 return $this; 0206 } 0207 0208 /** 0209 * setCredentialColumn() - set the column name to be used as the credential column 0210 * 0211 * @param string $credentialColumn 0212 * @return Zend_Auth_Adapter_DbTable Provides a fluent interface 0213 */ 0214 public function setCredentialColumn($credentialColumn) 0215 { 0216 $this->_credentialColumn = $credentialColumn; 0217 return $this; 0218 } 0219 0220 /** 0221 * setCredentialTreatment() - allows the developer to pass a parameterized string that is 0222 * used to transform or treat the input credential data. 0223 * 0224 * In many cases, passwords and other sensitive data are encrypted, hashed, encoded, 0225 * obscured, or otherwise treated through some function or algorithm. By specifying a 0226 * parameterized treatment string with this method, a developer may apply arbitrary SQL 0227 * upon input credential data. 0228 * 0229 * Examples: 0230 * 0231 * 'PASSWORD(?)' 0232 * 'MD5(?)' 0233 * 0234 * @param string $treatment 0235 * @return Zend_Auth_Adapter_DbTable Provides a fluent interface 0236 */ 0237 public function setCredentialTreatment($treatment) 0238 { 0239 $this->_credentialTreatment = $treatment; 0240 return $this; 0241 } 0242 0243 /** 0244 * setIdentity() - set the value to be used as the identity 0245 * 0246 * @param string $value 0247 * @return Zend_Auth_Adapter_DbTable Provides a fluent interface 0248 */ 0249 public function setIdentity($value) 0250 { 0251 $this->_identity = $value; 0252 return $this; 0253 } 0254 0255 /** 0256 * setCredential() - set the credential value to be used, optionally can specify a treatment 0257 * to be used, should be supplied in parameterized form, such as 'MD5(?)' or 'PASSWORD(?)' 0258 * 0259 * @param string $credential 0260 * @return Zend_Auth_Adapter_DbTable Provides a fluent interface 0261 */ 0262 public function setCredential($credential) 0263 { 0264 $this->_credential = $credential; 0265 return $this; 0266 } 0267 0268 /** 0269 * setAmbiguityIdentity() - sets a flag for usage of identical identities 0270 * with unique credentials. It accepts integers (0, 1) or boolean (true, 0271 * false) parameters. Default is false. 0272 * 0273 * @param int|bool $flag 0274 * @return Zend_Auth_Adapter_DbTable 0275 */ 0276 public function setAmbiguityIdentity($flag) 0277 { 0278 if (is_integer($flag)) { 0279 $this->_ambiguityIdentity = (1 === $flag ? true : false); 0280 } elseif (is_bool($flag)) { 0281 $this->_ambiguityIdentity = $flag; 0282 } 0283 return $this; 0284 } 0285 /** 0286 * getAmbiguityIdentity() - returns TRUE for usage of multiple identical 0287 * identies with different credentials, FALSE if not used. 0288 * 0289 * @return bool 0290 */ 0291 public function getAmbiguityIdentity() 0292 { 0293 return $this->_ambiguityIdentity; 0294 } 0295 0296 /** 0297 * getDbSelect() - Return the preauthentication Db Select object for userland select query modification 0298 * 0299 * @return Zend_Db_Select 0300 */ 0301 public function getDbSelect() 0302 { 0303 if ($this->_dbSelect == null) { 0304 $this->_dbSelect = $this->_zendDb->select(); 0305 } 0306 0307 return $this->_dbSelect; 0308 } 0309 0310 /** 0311 * getResultRowObject() - Returns the result row as a stdClass object 0312 * 0313 * @param string|array $returnColumns 0314 * @param string|array $omitColumns 0315 * @return stdClass|boolean 0316 */ 0317 public function getResultRowObject($returnColumns = null, $omitColumns = null) 0318 { 0319 if (!$this->_resultRow) { 0320 return false; 0321 } 0322 0323 $returnObject = new stdClass(); 0324 0325 if (null !== $returnColumns) { 0326 0327 $availableColumns = array_keys($this->_resultRow); 0328 foreach ( (array) $returnColumns as $returnColumn) { 0329 if (in_array($returnColumn, $availableColumns)) { 0330 $returnObject->{$returnColumn} = $this->_resultRow[$returnColumn]; 0331 } 0332 } 0333 return $returnObject; 0334 0335 } elseif (null !== $omitColumns) { 0336 0337 $omitColumns = (array) $omitColumns; 0338 foreach ($this->_resultRow as $resultColumn => $resultValue) { 0339 if (!in_array($resultColumn, $omitColumns)) { 0340 $returnObject->{$resultColumn} = $resultValue; 0341 } 0342 } 0343 return $returnObject; 0344 0345 } else { 0346 0347 foreach ($this->_resultRow as $resultColumn => $resultValue) { 0348 $returnObject->{$resultColumn} = $resultValue; 0349 } 0350 return $returnObject; 0351 0352 } 0353 } 0354 0355 /** 0356 * authenticate() - defined by Zend_Auth_Adapter_Interface. This method is called to 0357 * attempt an authentication. Previous to this call, this adapter would have already 0358 * been configured with all necessary information to successfully connect to a database 0359 * table and attempt to find a record matching the provided identity. 0360 * 0361 * @throws Zend_Auth_Adapter_Exception if answering the authentication query is impossible 0362 * @return Zend_Auth_Result 0363 */ 0364 public function authenticate() 0365 { 0366 $this->_authenticateSetup(); 0367 $dbSelect = $this->_authenticateCreateSelect(); 0368 $resultIdentities = $this->_authenticateQuerySelect($dbSelect); 0369 0370 if ( ($authResult = $this->_authenticateValidateResultSet($resultIdentities)) instanceof Zend_Auth_Result) { 0371 return $authResult; 0372 } 0373 0374 if (true === $this->getAmbiguityIdentity()) { 0375 $validIdentities = array (); 0376 $zendAuthCredentialMatchColumn = $this->_zendDb->foldCase('zend_auth_credential_match'); 0377 foreach ($resultIdentities as $identity) { 0378 if (1 === (int) $identity[$zendAuthCredentialMatchColumn]) { 0379 $validIdentities[] = $identity; 0380 } 0381 } 0382 $resultIdentities = $validIdentities; 0383 } 0384 0385 $authResult = $this->_authenticateValidateResult(array_shift($resultIdentities)); 0386 return $authResult; 0387 } 0388 0389 /** 0390 * _authenticateSetup() - This method abstracts the steps involved with 0391 * making sure that this adapter was indeed setup properly with all 0392 * required pieces of information. 0393 * 0394 * @throws Zend_Auth_Adapter_Exception - in the event that setup was not done properly 0395 * @return true 0396 */ 0397 protected function _authenticateSetup() 0398 { 0399 $exception = null; 0400 0401 if ($this->_tableName == '') { 0402 $exception = 'A table must be supplied for the Zend_Auth_Adapter_DbTable authentication adapter.'; 0403 } elseif ($this->_identityColumn == '') { 0404 $exception = 'An identity column must be supplied for the Zend_Auth_Adapter_DbTable authentication adapter.'; 0405 } elseif ($this->_credentialColumn == '') { 0406 $exception = 'A credential column must be supplied for the Zend_Auth_Adapter_DbTable authentication adapter.'; 0407 } elseif ($this->_identity == '') { 0408 $exception = 'A value for the identity was not provided prior to authentication with Zend_Auth_Adapter_DbTable.'; 0409 } elseif ($this->_credential === null) { 0410 $exception = 'A credential value was not provided prior to authentication with Zend_Auth_Adapter_DbTable.'; 0411 } 0412 0413 if (null !== $exception) { 0414 /** 0415 * @see Zend_Auth_Adapter_Exception 0416 */ 0417 // require_once 'Zend/Auth/Adapter/Exception.php'; 0418 throw new Zend_Auth_Adapter_Exception($exception); 0419 } 0420 0421 $this->_authenticateResultInfo = array( 0422 'code' => Zend_Auth_Result::FAILURE, 0423 'identity' => $this->_identity, 0424 'messages' => array() 0425 ); 0426 0427 return true; 0428 } 0429 0430 /** 0431 * _authenticateCreateSelect() - This method creates a Zend_Db_Select object that 0432 * is completely configured to be queried against the database. 0433 * 0434 * @return Zend_Db_Select 0435 */ 0436 protected function _authenticateCreateSelect() 0437 { 0438 // build credential expression 0439 if (empty($this->_credentialTreatment) || (strpos($this->_credentialTreatment, '?') === false)) { 0440 $this->_credentialTreatment = '?'; 0441 } 0442 0443 $credentialExpression = new Zend_Db_Expr( 0444 '(CASE WHEN ' . 0445 $this->_zendDb->quoteInto( 0446 $this->_zendDb->quoteIdentifier($this->_credentialColumn, true) 0447 . ' = ' . $this->_credentialTreatment, $this->_credential 0448 ) 0449 . ' THEN 1 ELSE 0 END) AS ' 0450 . $this->_zendDb->quoteIdentifier( 0451 $this->_zendDb->foldCase('zend_auth_credential_match') 0452 ) 0453 ); 0454 0455 // get select 0456 $dbSelect = clone $this->getDbSelect(); 0457 $dbSelect->from($this->_tableName, array('*', $credentialExpression)) 0458 ->where($this->_zendDb->quoteIdentifier($this->_identityColumn, true) . ' = ?', $this->_identity); 0459 0460 return $dbSelect; 0461 } 0462 0463 /** 0464 * _authenticateQuerySelect() - This method accepts a Zend_Db_Select object and 0465 * performs a query against the database with that object. 0466 * 0467 * @param Zend_Db_Select $dbSelect 0468 * @throws Zend_Auth_Adapter_Exception - when an invalid select 0469 * object is encountered 0470 * @return array 0471 */ 0472 protected function _authenticateQuerySelect(Zend_Db_Select $dbSelect) 0473 { 0474 try { 0475 if ($this->_zendDb->getFetchMode() != Zend_DB::FETCH_ASSOC) { 0476 $origDbFetchMode = $this->_zendDb->getFetchMode(); 0477 $this->_zendDb->setFetchMode(Zend_DB::FETCH_ASSOC); 0478 } 0479 $resultIdentities = $this->_zendDb->fetchAll($dbSelect); 0480 if (isset($origDbFetchMode)) { 0481 $this->_zendDb->setFetchMode($origDbFetchMode); 0482 unset($origDbFetchMode); 0483 } 0484 } catch (Exception $e) { 0485 /** 0486 * @see Zend_Auth_Adapter_Exception 0487 */ 0488 // require_once 'Zend/Auth/Adapter/Exception.php'; 0489 throw new Zend_Auth_Adapter_Exception('The supplied parameters to Zend_Auth_Adapter_DbTable failed to ' 0490 . 'produce a valid sql statement, please check table and column names ' 0491 . 'for validity.', 0, $e); 0492 } 0493 return $resultIdentities; 0494 } 0495 0496 /** 0497 * _authenticateValidateResultSet() - This method attempts to make 0498 * certain that only one record was returned in the resultset 0499 * 0500 * @param array $resultIdentities 0501 * @return true|Zend_Auth_Result 0502 */ 0503 protected function _authenticateValidateResultSet(array $resultIdentities) 0504 { 0505 0506 if (count($resultIdentities) < 1) { 0507 $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND; 0508 $this->_authenticateResultInfo['messages'][] = 'A record with the supplied identity could not be found.'; 0509 return $this->_authenticateCreateAuthResult(); 0510 } elseif (count($resultIdentities) > 1 && false === $this->getAmbiguityIdentity()) { 0511 $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS; 0512 $this->_authenticateResultInfo['messages'][] = 'More than one record matches the supplied identity.'; 0513 return $this->_authenticateCreateAuthResult(); 0514 } 0515 0516 return true; 0517 } 0518 0519 /** 0520 * _authenticateValidateResult() - This method attempts to validate that 0521 * the record in the resultset is indeed a record that matched the 0522 * identity provided to this adapter. 0523 * 0524 * @param array $resultIdentity 0525 * @return Zend_Auth_Result 0526 */ 0527 protected function _authenticateValidateResult($resultIdentity) 0528 { 0529 $zendAuthCredentialMatchColumn = $this->_zendDb->foldCase('zend_auth_credential_match'); 0530 0531 if ($resultIdentity[$zendAuthCredentialMatchColumn] != '1') { 0532 $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID; 0533 $this->_authenticateResultInfo['messages'][] = 'Supplied credential is invalid.'; 0534 return $this->_authenticateCreateAuthResult(); 0535 } 0536 0537 unset($resultIdentity[$zendAuthCredentialMatchColumn]); 0538 $this->_resultRow = $resultIdentity; 0539 0540 $this->_authenticateResultInfo['code'] = Zend_Auth_Result::SUCCESS; 0541 $this->_authenticateResultInfo['messages'][] = 'Authentication successful.'; 0542 return $this->_authenticateCreateAuthResult(); 0543 } 0544 0545 /** 0546 * _authenticateCreateAuthResult() - Creates a Zend_Auth_Result object from 0547 * the information that has been collected during the authenticate() attempt. 0548 * 0549 * @return Zend_Auth_Result 0550 */ 0551 protected function _authenticateCreateAuthResult() 0552 { 0553 return new Zend_Auth_Result( 0554 $this->_authenticateResultInfo['code'], 0555 $this->_authenticateResultInfo['identity'], 0556 $this->_authenticateResultInfo['messages'] 0557 ); 0558 } 0559 0560 }