PageRenderTime 51ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/www/libs/Zend/Authentication/Adapter/DbTable.php

https://bitbucket.org/Ppito/kawaiviewmodel2
PHP | 491 lines | 226 code | 58 blank | 207 comment | 25 complexity | 49ba4d8e0b9a2218135d4a38c3c3aeb2 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. * @package Zend_Authentication
  9. */
  10. namespace Zend\Authentication\Adapter;
  11. use stdClass;
  12. use Zend\Authentication\Result as AuthenticationResult;
  13. use Zend\Db\Adapter\Adapter as DbAdapter;
  14. use Zend\Db\ResultSet\ResultSet;
  15. use Zend\Db\Sql\Expression;
  16. use Zend\Db\Sql\Select as DbSelect;
  17. /**
  18. * @category Zend
  19. * @package Zend_Authentication
  20. * @subpackage Adapter
  21. */
  22. class DbTable implements AdapterInterface
  23. {
  24. /**
  25. * Database Connection
  26. *
  27. * @var DbAdapter
  28. */
  29. protected $zendDb = null;
  30. /**
  31. * @var DbSelect
  32. */
  33. protected $dbSelect = null;
  34. /**
  35. * $tableName - the table name to check
  36. *
  37. * @var string
  38. */
  39. protected $tableName = null;
  40. /**
  41. * $identityColumn - the column to use as the identity
  42. *
  43. * @var string
  44. */
  45. protected $identityColumn = null;
  46. /**
  47. * $credentialColumns - columns to be used as the credentials
  48. *
  49. * @var string
  50. */
  51. protected $credentialColumn = null;
  52. /**
  53. * $identity - Identity value
  54. *
  55. * @var string
  56. */
  57. protected $identity = null;
  58. /**
  59. * $credential - Credential values
  60. *
  61. * @var string
  62. */
  63. protected $credential = null;
  64. /**
  65. * $credentialTreatment - Treatment applied to the credential, such as MD5() or PASSWORD()
  66. *
  67. * @var string
  68. */
  69. protected $credentialTreatment = null;
  70. /**
  71. * $authenticateResultInfo
  72. *
  73. * @var array
  74. */
  75. protected $authenticateResultInfo = null;
  76. /**
  77. * $resultRow - Results of database authentication query
  78. *
  79. * @var array
  80. */
  81. protected $resultRow = null;
  82. /**
  83. * $ambiguityIdentity - Flag to indicate same Identity can be used with
  84. * different credentials. Default is FALSE and need to be set to true to
  85. * allow ambiguity usage.
  86. *
  87. * @var boolean
  88. */
  89. protected $ambiguityIdentity = false;
  90. /**
  91. * __construct() - Sets configuration options
  92. *
  93. * @param DbAdapter $zendDb
  94. * @param string $tableName Optional
  95. * @param string $identityColumn Optional
  96. * @param string $credentialColumn Optional
  97. * @param string $credentialTreatment Optional
  98. * @return \Zend\Authentication\Adapter\DbTable
  99. */
  100. public function __construct(DbAdapter $zendDb, $tableName = null, $identityColumn = null,
  101. $credentialColumn = null, $credentialTreatment = null)
  102. {
  103. $this->zendDb = $zendDb;
  104. if (null !== $tableName) {
  105. $this->setTableName($tableName);
  106. }
  107. if (null !== $identityColumn) {
  108. $this->setIdentityColumn($identityColumn);
  109. }
  110. if (null !== $credentialColumn) {
  111. $this->setCredentialColumn($credentialColumn);
  112. }
  113. if (null !== $credentialTreatment) {
  114. $this->setCredentialTreatment($credentialTreatment);
  115. }
  116. }
  117. /**
  118. * setTableName() - set the table name to be used in the select query
  119. *
  120. * @param string $tableName
  121. * @return DbTable Provides a fluent interface
  122. */
  123. public function setTableName($tableName)
  124. {
  125. $this->tableName = $tableName;
  126. return $this;
  127. }
  128. /**
  129. * setIdentityColumn() - set the column name to be used as the identity column
  130. *
  131. * @param string $identityColumn
  132. * @return DbTable Provides a fluent interface
  133. */
  134. public function setIdentityColumn($identityColumn)
  135. {
  136. $this->identityColumn = $identityColumn;
  137. return $this;
  138. }
  139. /**
  140. * setCredentialColumn() - set the column name to be used as the credential column
  141. *
  142. * @param string $credentialColumn
  143. * @return DbTable Provides a fluent interface
  144. */
  145. public function setCredentialColumn($credentialColumn)
  146. {
  147. $this->credentialColumn = $credentialColumn;
  148. return $this;
  149. }
  150. /**
  151. * setCredentialTreatment() - allows the developer to pass a parametrized string that is
  152. * used to transform or treat the input credential data.
  153. *
  154. * In many cases, passwords and other sensitive data are encrypted, hashed, encoded,
  155. * obscured, or otherwise treated through some function or algorithm. By specifying a
  156. * parametrized treatment string with this method, a developer may apply arbitrary SQL
  157. * upon input credential data.
  158. *
  159. * Examples:
  160. *
  161. * 'PASSWORD(?)'
  162. * 'MD5(?)'
  163. *
  164. * @param string $treatment
  165. * @return DbTable Provides a fluent interface
  166. */
  167. public function setCredentialTreatment($treatment)
  168. {
  169. $this->credentialTreatment = $treatment;
  170. return $this;
  171. }
  172. /**
  173. * setIdentity() - set the value to be used as the identity
  174. *
  175. * @param string $value
  176. * @return DbTable Provides a fluent interface
  177. */
  178. public function setIdentity($value)
  179. {
  180. $this->identity = $value;
  181. return $this;
  182. }
  183. /**
  184. * setCredential() - set the credential value to be used, optionally can specify a treatment
  185. * to be used, should be supplied in parametrized form, such as 'MD5(?)' or 'PASSWORD(?)'
  186. *
  187. * @param string $credential
  188. * @return DbTable Provides a fluent interface
  189. */
  190. public function setCredential($credential)
  191. {
  192. $this->credential = $credential;
  193. return $this;
  194. }
  195. /**
  196. * setAmbiguityIdentity() - sets a flag for usage of identical identities
  197. * with unique credentials. It accepts integers (0, 1) or boolean (true,
  198. * false) parameters. Default is false.
  199. *
  200. * @param int|bool $flag
  201. * @return DbTable Provides a fluent interface
  202. */
  203. public function setAmbiguityIdentity($flag)
  204. {
  205. if (is_integer($flag)) {
  206. $this->ambiguityIdentity = (1 === $flag ? true : false);
  207. } elseif (is_bool($flag)) {
  208. $this->ambiguityIdentity = $flag;
  209. }
  210. return $this;
  211. }
  212. /**
  213. * getAmbiguityIdentity() - returns TRUE for usage of multiple identical
  214. * identities with different credentials, FALSE if not used.
  215. *
  216. * @return bool
  217. */
  218. public function getAmbiguityIdentity()
  219. {
  220. return $this->ambiguityIdentity;
  221. }
  222. /**
  223. * getDbSelect() - Return the preauthentication Db Select object for userland select query modification
  224. *
  225. * @return DbSelect
  226. */
  227. public function getDbSelect()
  228. {
  229. if ($this->dbSelect == null) {
  230. $this->dbSelect = new DbSelect();
  231. }
  232. return $this->dbSelect;
  233. }
  234. /**
  235. * getResultRowObject() - Returns the result row as a stdClass object
  236. *
  237. * @param string|array $returnColumns
  238. * @param string|array $omitColumns
  239. * @return stdClass|boolean
  240. */
  241. public function getResultRowObject($returnColumns = null, $omitColumns = null)
  242. {
  243. if (!$this->resultRow) {
  244. return false;
  245. }
  246. $returnObject = new stdClass();
  247. if (null !== $returnColumns) {
  248. $availableColumns = array_keys($this->resultRow);
  249. foreach ((array) $returnColumns as $returnColumn) {
  250. if (in_array($returnColumn, $availableColumns)) {
  251. $returnObject->{$returnColumn} = $this->resultRow[$returnColumn];
  252. }
  253. }
  254. return $returnObject;
  255. } elseif (null !== $omitColumns) {
  256. $omitColumns = (array) $omitColumns;
  257. foreach ($this->resultRow as $resultColumn => $resultValue) {
  258. if (!in_array($resultColumn, $omitColumns)) {
  259. $returnObject->{$resultColumn} = $resultValue;
  260. }
  261. }
  262. return $returnObject;
  263. }
  264. foreach ($this->resultRow as $resultColumn => $resultValue) {
  265. $returnObject->{$resultColumn} = $resultValue;
  266. }
  267. return $returnObject;
  268. }
  269. /**
  270. * This method is called to attempt an authentication. Previous to this
  271. * call, this adapter would have already been configured with all
  272. * necessary information to successfully connect to a database table and
  273. * attempt to find a record matching the provided identity.
  274. *
  275. * @throws Exception\RuntimeException if answering the authentication query is impossible
  276. * @return AuthenticationResult
  277. */
  278. public function authenticate()
  279. {
  280. $this->_authenticateSetup();
  281. $dbSelect = $this->_authenticateCreateSelect();
  282. $resultIdentities = $this->_authenticateQuerySelect($dbSelect);
  283. if (($authResult = $this->_authenticateValidateResultSet($resultIdentities)) instanceof AuthenticationResult) {
  284. return $authResult;
  285. }
  286. // At this point, ambiguity is already done. Loop, check and break on success.
  287. foreach ($resultIdentities as $identity) {
  288. $authResult = $this->_authenticateValidateResult($identity);
  289. if ($authResult->isValid()) {
  290. break;
  291. }
  292. }
  293. return $authResult;
  294. }
  295. /**
  296. * _authenticateSetup() - This method abstracts the steps involved with
  297. * making sure that this adapter was indeed setup properly with all
  298. * required pieces of information.
  299. *
  300. * @throws Exception\RuntimeException in the event that setup was not done properly
  301. * @return boolean
  302. */
  303. protected function _authenticateSetup()
  304. {
  305. $exception = null;
  306. if ($this->tableName == '') {
  307. $exception = 'A table must be supplied for the DbTable authentication adapter.';
  308. } elseif ($this->identityColumn == '') {
  309. $exception = 'An identity column must be supplied for the DbTable authentication adapter.';
  310. } elseif ($this->credentialColumn == '') {
  311. $exception = 'A credential column must be supplied for the DbTable authentication adapter.';
  312. } elseif ($this->identity == '') {
  313. $exception = 'A value for the identity was not provided prior to authentication with DbTable.';
  314. } elseif ($this->credential === null) {
  315. $exception = 'A credential value was not provided prior to authentication with DbTable.';
  316. }
  317. if (null !== $exception) {
  318. throw new Exception\RuntimeException($exception);
  319. }
  320. $this->authenticateResultInfo = array(
  321. 'code' => AuthenticationResult::FAILURE,
  322. 'identity' => $this->identity,
  323. 'messages' => array()
  324. );
  325. return true;
  326. }
  327. /**
  328. * _authenticateCreateSelect() - This method creates a Zend\Db\Sql\Select object that
  329. * is completely configured to be queried against the database.
  330. *
  331. * @return DbSelect
  332. */
  333. protected function _authenticateCreateSelect()
  334. {
  335. // build credential expression
  336. if (empty($this->credentialTreatment) || (strpos($this->credentialTreatment, '?') === false)) {
  337. $this->credentialTreatment = '?';
  338. }
  339. $credentialExpression = new Expression(
  340. '(CASE WHEN '
  341. . $this->zendDb->getPlatform()->quoteIdentifier($this->credentialColumn)
  342. . ' = ' . $this->credentialTreatment
  343. . ' THEN 1 ELSE 0 END) AS '
  344. . $this->zendDb->getPlatform()->quoteIdentifier('zend_auth_credential_match')
  345. );
  346. // get select
  347. $dbSelect = clone $this->getDbSelect();
  348. $dbSelect->from($this->tableName)
  349. ->columns(array('*', $credentialExpression))
  350. ->where($this->zendDb->getPlatform()->quoteIdentifier($this->identityColumn) . ' = ?');
  351. return $dbSelect;
  352. }
  353. /**
  354. * _authenticateQuerySelect() - This method accepts a Zend\Db\Sql\Select object and
  355. * performs a query against the database with that object.
  356. *
  357. * @param DbSelect $dbSelect
  358. * @throws Exception\RuntimeException when an invalid select object is encountered
  359. * @return array
  360. */
  361. protected function _authenticateQuerySelect(DbSelect $dbSelect)
  362. {
  363. $statement = $this->zendDb->createStatement();
  364. $dbSelect->prepareStatement($this->zendDb, $statement);
  365. $resultSet = new ResultSet();
  366. try {
  367. $resultSet->initialize($statement->execute(array($this->credential, $this->identity)));
  368. $resultIdentities = $resultSet->toArray();
  369. } catch (\Exception $e) {
  370. throw new Exception\RuntimeException(
  371. 'The supplied parameters to DbTable failed to '
  372. . 'produce a valid sql statement, please check table and column names '
  373. . 'for validity.', 0, $e
  374. );
  375. }
  376. return $resultIdentities;
  377. }
  378. /**
  379. * _authenticateValidateResultSet() - This method attempts to make
  380. * certain that only one record was returned in the resultset
  381. *
  382. * @param array $resultIdentities
  383. * @return boolean|\Zend\Authentication\Result
  384. */
  385. protected function _authenticateValidateResultSet(array $resultIdentities)
  386. {
  387. if (count($resultIdentities) < 1) {
  388. $this->authenticateResultInfo['code'] = AuthenticationResult::FAILURE_IDENTITY_NOT_FOUND;
  389. $this->authenticateResultInfo['messages'][] = 'A record with the supplied identity could not be found.';
  390. return $this->_authenticateCreateAuthResult();
  391. } elseif (count($resultIdentities) > 1 && false === $this->getAmbiguityIdentity()) {
  392. $this->authenticateResultInfo['code'] = AuthenticationResult::FAILURE_IDENTITY_AMBIGUOUS;
  393. $this->authenticateResultInfo['messages'][] = 'More than one record matches the supplied identity.';
  394. return $this->_authenticateCreateAuthResult();
  395. }
  396. return true;
  397. }
  398. /**
  399. * _authenticateValidateResult() - This method attempts to validate that
  400. * the record in the resultset is indeed a record that matched the
  401. * identity provided to this adapter.
  402. *
  403. * @param array $resultIdentity
  404. * @return AuthenticationResult
  405. */
  406. protected function _authenticateValidateResult($resultIdentity)
  407. {
  408. if ($resultIdentity['zend_auth_credential_match'] != '1') {
  409. $this->authenticateResultInfo['code'] = AuthenticationResult::FAILURE_CREDENTIAL_INVALID;
  410. $this->authenticateResultInfo['messages'][] = 'Supplied credential is invalid.';
  411. return $this->_authenticateCreateAuthResult();
  412. }
  413. unset($resultIdentity['zend_auth_credential_match']);
  414. $this->resultRow = $resultIdentity;
  415. $this->authenticateResultInfo['code'] = AuthenticationResult::SUCCESS;
  416. $this->authenticateResultInfo['messages'][] = 'Authentication successful.';
  417. return $this->_authenticateCreateAuthResult();
  418. }
  419. /**
  420. * Creates a Zend\Authentication\Result object from the information that
  421. * has been collected during the authenticate() attempt.
  422. *
  423. * @return AuthenticationResult
  424. */
  425. protected function _authenticateCreateAuthResult()
  426. {
  427. return new AuthenticationResult(
  428. $this->authenticateResultInfo['code'],
  429. $this->authenticateResultInfo['identity'],
  430. $this->authenticateResultInfo['messages']
  431. );
  432. }
  433. }