PageRenderTime 50ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/library/GlassOnion/Auth/Adapter/Doctrine.php

https://github.com/cizar/glass_onion
PHP | 390 lines | 159 code | 42 blank | 189 comment | 26 complexity | c083bf710f5bf48b4c4ab6d633071bab MD5 | raw file
  1. <?php
  2. /**
  3. * Glass Onion
  4. *
  5. * Copyright (c) 2009 César Kästli (cesarkastli@gmail.com)
  6. *
  7. * Permission is hereby granted, free of charge, to any
  8. * person obtaining a copy of this software and associated
  9. * documentation files (the "Software"), to deal in the
  10. * Software without restriction, including without limitation
  11. * the rights to use, copy, modify, merge, publish,
  12. * distribute, sublicense, and/or sell copies of the
  13. * Software, and to permit persons to whom the Software is
  14. * furnished to do so, subject to the following conditions:
  15. *
  16. * The above copyright notice and this permission notice
  17. * shall be included in all copies or substantial portions of
  18. * the Software.
  19. *
  20. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
  21. * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  22. * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  23. * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
  24. * OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  25. * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  26. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  27. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. *
  29. * @copyright Copyright (c) 2009 César Kästli (cesarkastli@gmail.com)
  30. * @license MIT
  31. */
  32. /**
  33. * @see Zend_Auth_Result
  34. */
  35. require_once 'Zend/Auth/Result.php';
  36. /**
  37. * @see Zend_Auth_Adapter_Interface
  38. */
  39. require_once 'Zend/Auth/Adapter/Interface.php';
  40. /**
  41. * @category GlassOnion
  42. * @package GlassOnion_Auth
  43. */
  44. class GlassOnion_Auth_Adapter_Doctrine
  45. implements Zend_Auth_Adapter_Interface
  46. {
  47. /**
  48. * Doctrine connection
  49. *
  50. * @var Doctrine_Connection
  51. * @access private
  52. */
  53. private $_connection = null;
  54. /**
  55. * The table name to check
  56. *
  57. * @var string
  58. * @access private
  59. */
  60. private $_tableName = null;
  61. /**
  62. * The name of the column to be used as the identity
  63. *
  64. * @var string
  65. * @access private
  66. */
  67. private $_identityColumnName = null;
  68. /**
  69. * The name of the column to be used as the credential
  70. *
  71. * @var string
  72. * @access private
  73. */
  74. private $_credentialColumnName = null;
  75. /**
  76. * Treatment applied to the credential, such as MD5() or PASSWORD()
  77. *
  78. * @var string
  79. * @access private
  80. */
  81. private $_credentialTreatment = null;
  82. /**
  83. * Identity value
  84. *
  85. * @var string
  86. * @access private
  87. */
  88. private $_identity = null;
  89. /**
  90. * Credential value
  91. *
  92. * @var string
  93. * @access private
  94. */
  95. private $_credential = null;
  96. /**
  97. * Results of database authentication query
  98. *
  99. * @var string
  100. * @access private
  101. */
  102. private $_resultRow = null;
  103. /**
  104. * __construct() - Sets configuration options
  105. *
  106. * @param Doctrine_Connection $connection
  107. * @param string $tableName
  108. * @param string $identityColumnName
  109. * @param string $credentialColumnName
  110. * @param string $credentialTreatment
  111. * @return void
  112. */
  113. public function __construct(Doctrine_Connection $connection = null, $tableName = null,
  114. $identityColumnName = null, $credentialColumnName = null,
  115. $credentialTreatment = null)
  116. {
  117. if (null !== $connection) {
  118. $this->setConnection($connection);
  119. }
  120. if (null !== $tableName) {
  121. $this->setTableName($tableName);
  122. }
  123. if (null !== $identityColumnName) {
  124. $this->setIdentityColumnName($identityColumnName);
  125. }
  126. if (null !== $credentialColumnName) {
  127. $this->setCredentialColumnName($credentialColumnName);
  128. }
  129. if (null !== $credentialTreatment) {
  130. $this->setCredentialTreatment($credentialTreatment);
  131. }
  132. }
  133. /**
  134. * setConnection() - set the connection to the database
  135. *
  136. * @return GlassOnion_Auth_Adapter_Doctrine Provides a fluent interface
  137. */
  138. public function setConnection(Doctrine_Connection $connection)
  139. {
  140. $this->_connection = $connection;
  141. return $this;
  142. }
  143. /**
  144. * getConnection() - get the connection to the database
  145. *
  146. * @return Doctrine_Connection
  147. */
  148. public function getConnection()
  149. {
  150. if (null === $this->_connection && null !== $this->_tableName) {
  151. $this->_connection = Doctrine_Core::getConnectionByTableName($this->_tableName);
  152. }
  153. return $this->_connection;
  154. }
  155. /**
  156. * setTableName() - set the table name to be used in the select query
  157. *
  158. * @param string $tableName
  159. * @return GlassOnion_Auth_Adapter_Doctrine Provides a fluent interface
  160. */
  161. public function setTableName($tableName)
  162. {
  163. $this->_tableName = $tableName;
  164. return $this;
  165. }
  166. /**
  167. * setIdentityColumnName() - set the column name to be used as the identity column
  168. *
  169. * @param string $identityColumnName
  170. * @return GlassOnion_Auth_Adapter_Doctrine Provides a fluent interface
  171. */
  172. public function setIdentityColumnName($identityColumnName)
  173. {
  174. $this->_identityColumnName = $identityColumnName;
  175. return $this;
  176. }
  177. /**
  178. * setCredentialColumnName() - set the column name to be used as the credential column
  179. *
  180. * @param string $credentialColumnName
  181. * @return GlassOnion_Auth_Adapter_Doctrine Provides a fluent interface
  182. */
  183. public function setCredentialColumnName($credentialColumnName)
  184. {
  185. $this->_credentialColumnName = $credentialColumnName;
  186. return $this;
  187. }
  188. /**
  189. * setCredentialTreatment() - allows the developer to pass a parameterized string that is
  190. * used to transform or treat the input credential data.
  191. *
  192. * In many cases, passwords and other sensitive data are encrypted, hashed, encoded,
  193. * obscured, or otherwise treated through some function or algorithm. By specifying a
  194. * parameterized treatment string with this method, a developer may apply arbitrary SQL
  195. * upon input credential data.
  196. *
  197. * Examples:
  198. *
  199. * 'PASSWORD(?)'
  200. * 'MD5(?)'
  201. *
  202. * @param string $credentialTreatment
  203. * @return GlassOnion_Auth_Adapter_Doctrine Provides a fluent interface
  204. */
  205. public function setCredentialTreatment($credentialTreatment)
  206. {
  207. $this->_credentialTreatment = $credentialTreatment;
  208. return $this;
  209. }
  210. /**
  211. * setIdentity() - set the value to be used as the identity
  212. *
  213. * @param string $identity
  214. * @return GlassOnion_Auth_Adapter_Doctrine Provides a fluent interface
  215. */
  216. public function setIdentity($identity)
  217. {
  218. $this->_identity = $identity;
  219. return $this;
  220. }
  221. /**
  222. * setCredential() - set the value to be used as the credential
  223. *
  224. * @param string $credential
  225. * @return GlassOnion_Auth_Adapter_Doctrine Provides a fluent interface
  226. */
  227. public function setCredential($credential)
  228. {
  229. $this->_credential = $credential;
  230. return $this;
  231. }
  232. /**
  233. * getResultRowObject() - Returns the result row as a stdClass object
  234. *
  235. * @return stdClass|false
  236. */
  237. public function getResultRowObject()
  238. {
  239. if (!$this->_resultRow) {
  240. return false;
  241. }
  242. $returnObject = new stdClass();
  243. foreach ($this->_resultRow as $resultColumn => $resultValue) {
  244. $returnObject->{$resultColumn} = $resultValue;
  245. }
  246. return $returnObject;
  247. }
  248. /**
  249. * authenticate() - defined by Zend_Auth_Adapter_Interface. This method is called to
  250. * attempt an authentication. Previous to this call, this adapter would have already
  251. * been configured with all necessary information to successfully connect to a database
  252. * table and attempt to find a record matching the provided identity.
  253. *
  254. * @throws Zend_Auth_Adapter_Exception if answering the authentication query is impossible
  255. * @return Zend_Auth_Result
  256. */
  257. public function authenticate()
  258. {
  259. $this->_validatePrecondition();
  260. $identities = $this->_executeAuthenticationQuery();
  261. if (count($identities) < 1) {
  262. return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND,
  263. null, array('A record with the supplied identity could not be found.'));
  264. }
  265. if (count($identities) > 1) {
  266. return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS,
  267. null, array('More than one record matches the supplied identity.'));
  268. }
  269. if ($identities[0]['zend_auth_credential_match'] == 0) {
  270. return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID,
  271. null, array('Supplied credential is invalid.'));
  272. }
  273. $this->_resultRow = $identities[0];
  274. return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS,
  275. $this->_identity, array('Authentication sucessful.'));
  276. }
  277. private function _validatePrecondition()
  278. {
  279. $exception = null;
  280. if (null === $this->getConnection()) {
  281. $exception = 'A database connection was not set, nor could one be created.';
  282. }
  283. else if (empty($this->_tableName)) {
  284. $exception = 'A table must be supplied for the GlassOnion_Auth_Adapter_Doctrine authentication adapter.';
  285. }
  286. else if (empty($this->_identityColumnName)) {
  287. $exception = 'An identity column must be supplied for the GlassOnion_Auth_Adapter_Doctrine authentication adapter.';
  288. }
  289. else if (empty($this->_credentialColumnName)) {
  290. $exception = 'A credential column must be supplied for the GlassOnion_Auth_Adapter_Doctrine authentication adapter.';
  291. }
  292. else if (empty($this->_identity)) {
  293. $exception = 'A value for the identity was not provided prior to authentication with GlassOnion_Auth_Adapter_Doctrine.';
  294. }
  295. else if (empty($this->_credential)) {
  296. $exception = 'A credential value was not provided prior to authentication with GlassOnion_Auth_Adapter_Doctrine.';
  297. }
  298. if (null !== $exception) {
  299. /**
  300. * @see Zend_Auth_Adapter_Exception
  301. */
  302. require_once 'Zend/Auth/Adapter/Exception.php';
  303. throw new Zend_Auth_Adapter_Exception($exception);
  304. }
  305. }
  306. /**
  307. * _executeAuthenticationQuery() - This method executes the authentication query
  308. * against the database and returns the identities that matching identities
  309. *
  310. * @throws Zend_Auth_Adapter_Exception - when an invalid select object is encountered
  311. * @return array
  312. */
  313. private function _executeAuthenticationQuery()
  314. {
  315. try {
  316. return $this->_getAuthenticationQuery()->fetchArray();
  317. } catch (Exception $ex) {
  318. /**
  319. * @see Zend_Auth_Adapter_Exception
  320. */
  321. require_once 'Zend/Auth/Adapter/Exception.php';
  322. throw new Zend_Auth_Adapter_Exception('The supplied parameters to'
  323. . ' GlassOnion_Auth_Adapter_Doctrine failed to produce a valid sql statement,'
  324. . ' please check table and column names for validity.', 0, $ex);
  325. }
  326. }
  327. /**
  328. * _getAuthenticationQuery() - This method creates a Doctrine_Query object that
  329. * is completely configured to be queried against the database.
  330. *
  331. * @return Doctrine_Query
  332. */
  333. private function _getAuthenticationQuery()
  334. {
  335. // build credential expression
  336. if (empty($this->_credentialTreatment) || (strpos($this->_credentialTreatment, '?') === false)) {
  337. $this->_credentialTreatment = '?';
  338. }
  339. $select = sprintf('*, (%s = %s) AS zend_auth_credential_match',
  340. $this->getConnection()->quoteIdentifier($this->_credentialColumnName),
  341. str_replace('?', $this->getConnection()->quote($this->_credential), $this->_credentialTreatment)
  342. );
  343. return Doctrine_Query::create($this->getConnection())
  344. ->from($this->_tableName)
  345. ->select($select)
  346. ->where($this->_identityColumnName . ' = ?', $this->_identity);
  347. }
  348. }