PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/monica/monica/vendor/zendframework/zendframework/library/Zend/Authentication/Adapter/DbTable.php

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