File indexing completed on 2024-12-22 05:36:17

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-2011 Zend Technologies USA Inc. (http://www.zend.com)
0019  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0020  * @version    $Id: DbTable.php 23775 2011-03-01 17:25:24Z ralph $
0021  */
0022 
0023 
0024 /**
0025  * @see Zend_Auth_Adapter_Interface
0026  */
0027 require_once 'Zend/Auth/Adapter/Interface.php';
0028 
0029 /**
0030  * @see Zend_Auth_Result
0031  */
0032 require_once 'Zend/Auth/Result.php';
0033 
0034 
0035 /**
0036  * @category   Zend
0037  * @package    Zend_Auth
0038  * @subpackage Adapter
0039  * @copyright  Copyright (c) 2011 Björn Schramke (http://www.schramke-online.de)
0040  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0041  */
0042 class CB_Auth_Adapter_Doctrine2 implements Zend_Auth_Adapter_Interface
0043 {
0044 
0045     /**
0046      * Doctrine2 EntityManager
0047      *
0048      * @var \Doctrine\ORM\EntityManager
0049      */
0050     protected $_em = null;
0051 
0052     /**
0053      * $_modelName - the Doctrine2 entity to check
0054      *
0055      * @var string
0056      */
0057     protected $_modelName = null;
0058 
0059     /**
0060      * $_identityColumn - the column to use as the identity
0061      *
0062      * @var string
0063      */
0064     protected $_identityColumn = null;
0065 
0066     /**
0067      * $_credentialColumns - columns to be used as the credentials
0068      *
0069      * @var string
0070      */
0071     protected $_credentialColumn = null;
0072 
0073     /**
0074      * $_identity - Identity value
0075      *
0076      * @var string
0077      */
0078     protected $_identity = null;
0079 
0080     /**
0081      * $_credential - Credential values
0082      *
0083      * @var string
0084      */
0085     protected $_credential = null;
0086 
0087     /**
0088      * $_credentialTreatment - Treatment applied to the credential, such as MD5() or PASSWORD()
0089      *
0090      * @var string
0091      */
0092     protected $_credentialTreatment = null;
0093 
0094     /**
0095      * $_authenticateResultInfo
0096      *
0097      * @var array
0098      */
0099     protected $_authenticateResultInfo = null;
0100 
0101     /**
0102      * $_resultRow - Results of database authentication query
0103      *
0104      * @var array
0105      */
0106     protected $_resultRow = null;
0107 
0108     /**
0109      * $_ambiguityIdentity - Flag to indicate same Identity can be used with
0110      * different credentials. Default is FALSE and need to be set to true to
0111      * allow ambiguity usage.
0112      *
0113      * @var boolean
0114      */
0115     protected $_ambiguityIdentity = false;
0116 
0117     /**
0118      * __construct() - Sets configuration options
0119      *
0120      * @param  \Doctrine\ORM\EntityManager $em If null, default database adapter assumed
0121      * @param  string                   $tableName
0122      * @param  string                   $identityColumn
0123      * @param  string                   $credentialColumn
0124      * @param  string                   $credentialTreatment
0125      * @return void
0126      */
0127     public function __construct(\Doctrine\ORM\EntityManager $em = null, $modelName = null, $identityColumn = null,
0128                                 $credentialColumn = null, $credentialTreatment = null)
0129     {
0130         $this->_setEntityManager($em);
0131 
0132         if (null !== $modelName) {
0133             $this->setModelName($modelName);
0134         }
0135 
0136         if (null !== $identityColumn) {
0137             $this->setIdentityColumn($identityColumn);
0138         }
0139 
0140         if (null !== $credentialColumn) {
0141             $this->setCredentialColumn($credentialColumn);
0142         }
0143 
0144         if (null !== $credentialTreatment) {
0145             $this->setCredentialTreatment($credentialTreatment);
0146         }
0147     }
0148 
0149     /**
0150      * _setEntityManager() - set the EntityManager to be used for quering
0151      *
0152      * @param \Doctrine\ORM\EntityManager
0153      * @throws Zend_Auth_Adapter_Exception
0154      * @return CB_Auth_Adapter_Doctrine2
0155      */
0156     protected function _setEntityManager(\Doctrine\ORM\EntityManager $em = null)
0157     {
0158         $this->_em = $em;
0159             
0160         /**
0161          * If no adapter is specified, fetch default database adapter.
0162          */
0163         if(null === $this->_em) {
0164             require_once 'Zend/Auth/Adapter/Exception.php';
0165             throw new Zend_Auth_Adapter_Exception('No Doctrine2 EntityManager present');
0166         }
0167 
0168         return $this;
0169     }
0170 
0171     /**
0172      * setTableName() - set the table name to be used in the select query
0173      *
0174      * @param  string $tableName
0175      * @return CB_Auth_Adapter_Doctrine2 Provides a fluent interface
0176      */
0177     public function setModelName($modelName)
0178     {
0179         $this->_modelName = $modelName;
0180         return $this;
0181     }
0182 
0183     /**
0184      * setIdentityColumn() - set the column name to be used as the identity column
0185      *
0186      * @param  string $identityColumn
0187      * @return CB_Auth_Adapter_Doctrine2 Provides a fluent interface
0188      */
0189     public function setIdentityColumn($identityColumn)
0190     {
0191         $this->_identityColumn = $identityColumn;
0192         return $this;
0193     }
0194 
0195     /**
0196      * setCredentialColumn() - set the column name to be used as the credential column
0197      *
0198      * @param  string $credentialColumn
0199      * @return CB_Auth_Adapter_Doctrine2 Provides a fluent interface
0200      */
0201     public function setCredentialColumn($credentialColumn)
0202     {
0203         $this->_credentialColumn = $credentialColumn;
0204         return $this;
0205     }
0206 
0207     /**
0208      * setCredentialTreatment() - allows the developer to pass a parameterized string that is
0209      * used to transform or treat the input credential data.
0210      *
0211      * In many cases, passwords and other sensitive data are encrypted, hashed, encoded,
0212      * obscured, or otherwise treated through some function or algorithm. By specifying a
0213      * parameterized treatment string with this method, a developer may apply arbitrary SQL
0214      * upon input credential data.
0215      *
0216      * Examples:
0217      *
0218      *  'PASSWORD(?)'
0219      *  'MD5(?)'
0220      *
0221      * @param  string $treatment
0222      * @return CB_Auth_Adapter_Doctrine2 Provides a fluent interface
0223      */
0224     public function setCredentialTreatment($treatment)
0225     {
0226         $this->_credentialTreatment = $treatment;
0227         return $this;
0228     }
0229 
0230     /**
0231      * setIdentity() - set the value to be used as the identity
0232      *
0233      * @param  string $value
0234      * @return CB_Auth_Adapter_Doctrine2 Provides a fluent interface
0235      */
0236     public function setIdentity($value)
0237     {
0238         $this->_identity = $value;
0239         return $this;
0240     }
0241 
0242     /**
0243      * setCredential() - set the credential value to be used, optionally can specify a treatment
0244      * to be used, should be supplied in parameterized form, such as 'MD5(?)' or 'PASSWORD(?)'
0245      *
0246      * @param  string $credential
0247      * @return CB_Auth_Adapter_Doctrine2 Provides a fluent interface
0248      */
0249     public function setCredential($credential)
0250     {
0251         $this->_credential = $credential;
0252         return $this;
0253     }
0254 
0255     /**
0256      * getResultRowObject() - Returns the result row as a stdClass object
0257      *
0258      * @param  string|array $returnColumns
0259      * @param  string|array $omitColumns
0260      * @return stdClass|boolean
0261      */
0262     public function getResultRowObject($returnColumns = null, $omitColumns = null)
0263     {
0264         if (!$this->_resultRow) {
0265             return false;
0266         }
0267         
0268         return $this->_resultRow;
0269     }
0270 
0271     /**
0272      * authenticate() - defined by Zend_Auth_Adapter_Interface.  This method is called to
0273      * attempt an authentication.  Previous to this call, this adapter would have already
0274      * been configured with all necessary information to successfully connect to a database
0275      * table and attempt to find a record matching the provided identity.
0276      *
0277      * @throws Zend_Auth_Adapter_Exception if answering the authentication query is impossible
0278      * @return Zend_Auth_Result
0279      */
0280     public function authenticate()
0281     {
0282         $this->_authenticateSetup();
0283         $query = $this->_authenticateCreateSelect();
0284         $resultIdentities = $this->_authenticateQuerySelect($query);
0285         $authResult = $this->_authenticateValidateResultSet($resultIdentities);
0286                 
0287         if ( $authResult instanceof Zend_Auth_Result) 
0288         {
0289             return $authResult;
0290         }
0291        
0292         return $this->_authenticateValidateResult(array_shift($resultIdentities));
0293     }
0294 
0295     /**
0296      * _authenticateSetup() - This method abstracts the steps involved with
0297      * making sure that this adapter was indeed setup properly with all
0298      * required pieces of information.
0299      *
0300      * @throws Zend_Auth_Adapter_Exception - in the event that setup was not done properly
0301      * @return true
0302      */
0303     protected function _authenticateSetup()
0304     {
0305         $exception = null;
0306 
0307         if ($this->_modelName == '') {
0308             $exception = 'A model must be supplied for the CB_Auth_Adapter_Doctrine2 authentication adapter.';
0309         } elseif ($this->_identityColumn == '') {
0310             $exception = 'An identity column must be supplied for the CB_Auth_Adapter_Doctrine2 authentication adapter.';
0311         } elseif ($this->_credentialColumn == '') {
0312             $exception = 'A credential column must be supplied for the CB_Auth_Adapter_Doctrine2 authentication adapter.';
0313         } elseif ($this->_identity == '') {
0314             $exception = 'A value for the identity was not provided prior to authentication with CB_Auth_Adapter_Doctrine2.';
0315         } elseif ($this->_credential === null) {
0316             $exception = 'A credential value was not provided prior to authentication with CB_Auth_Adapter_Doctrine2.';
0317         }
0318 
0319         if (null !== $exception) {
0320             /**
0321              * @see Zend_Auth_Adapter_Exception
0322              */
0323             require_once 'Zend/Auth/Adapter/Exception.php';
0324             throw new Zend_Auth_Adapter_Exception($exception);
0325         }
0326 
0327         $this->_authenticateResultInfo = array(
0328             'code'     => Zend_Auth_Result::FAILURE,
0329             'identity' => $this->_identity,
0330             'messages' => array()
0331             );
0332 
0333         return true;
0334     }
0335 
0336     /**
0337      * _authenticateCreateSelect() - This method creates a \Doctrine\ORM\Query object that
0338      * is completely configured to be queried against the database.
0339      *
0340      * @return \Doctrine\ORM\Query
0341      */
0342     protected function _authenticateCreateSelect()
0343     {
0344         // build credential expression
0345         if (empty($this->_credentialTreatment) || (strpos($this->_credentialTreatment, '?') === false)) {
0346             $this->_credentialTreatment = '?';
0347         }
0348 
0349         $idExpr = 'u.'.$this->_identityColumn.' = :id';
0350 //        $credExpr = 'u.'.$this->_credentialColumn.' = :cred';
0351 //        $query = $this->_em->createQuery('SELECT u from Application_Model_User u WHERE '.$idExpr.' AND '.$credExpr);
0352         $query = $this->_em->createQuery('SELECT u from Application_Model_User u WHERE '.$idExpr);
0353         $query->setParameters(array(
0354             'id' => $this->_identity,
0355 //            'cred' => $this->_credential,
0356         ));
0357 
0358         return $query;
0359     }
0360 
0361     /**
0362      * _authenticateQuerySelect() - This method accepts a Zend_Db_Select object and
0363      * performs a query against the database with that object.
0364      *
0365      * @param Zend_Db_Select $dbSelect
0366      * @throws Zend_Auth_Adapter_Exception - when an invalid select
0367      *                                       object is encountered
0368      * @return array
0369      */
0370     
0371     protected function _authenticateQuerySelect(\Doctrine\ORM\Query $query)
0372     {
0373         try {
0374             $resultIdentities = $query->getResult(); 
0375         } catch (Exception $e) {
0376             /**
0377              * @see Zend_Auth_Adapter_Exception
0378              */
0379             require_once 'Zend/Auth/Adapter/Exception.php';
0380             throw new Zend_Auth_Adapter_Exception('The supplied parameters to CB_Auth_Adapter_Doctrine2 failed to '
0381                                                 . 'produce a valid DQL statement, please check table and column names '
0382                                                 . 'for validity.', 0, $e);
0383         }
0384         return $resultIdentities;
0385     }
0386 
0387     /**
0388      * _authenticateValidateResultSet() - This method attempts to make
0389      * certain that only one record was returned in the resultset
0390      *
0391      * @param array $resultIdentities
0392      * @return true|Zend_Auth_Result
0393      */
0394     protected function _authenticateValidateResultSet(array $resultIdentities)
0395     {
0396 
0397         if (count($resultIdentities) < 1) {
0398             $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND;
0399             $this->_authenticateResultInfo['messages'][] = 'A record with the supplied identity could not be found.';
0400             return $this->_authenticateCreateAuthResult();
0401         } elseif (count($resultIdentities) > 1 && false === $this->getAmbiguityIdentity()) {
0402             $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS;
0403             $this->_authenticateResultInfo['messages'][] = 'More than one record matches the supplied identity.';
0404             return $this->_authenticateCreateAuthResult();
0405         }
0406 
0407         return true;
0408     }
0409 
0410     /**
0411      * _authenticateValidateResult() - This method attempts to validate that
0412      * the record in the resultset is indeed a record that matched the
0413      * identity provided to this adapter.
0414      *
0415      * @param array $resultIdentity
0416      * @return Zend_Auth_Result
0417      */
0418     protected function _authenticateValidateResult($resultIdentity)
0419     {
0420           $credColumnFunc = 'get'.ucfirst($this->_credentialColumn);
0421           
0422           if(!method_exists($resultIdentity,$credColumnFunc))
0423           {
0424             $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
0425             $this->_authenticateResultInfo['messages'][] = 'Error on validating supplied credential.';
0426             return $this->_authenticateCreateAuthResult();
0427           }
0428           
0429           $cred = $resultIdentity->{$credColumnFunc}();
0430         if ($cred !== $this->_credential) 
0431         {
0432             $this->_authenticateResultInfo['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
0433             $this->_authenticateResultInfo['messages'][] = 'Supplied credential is invalid.';
0434             return $this->_authenticateCreateAuthResult();
0435         }
0436           
0437         $this->_resultRow = $resultIdentity;
0438 
0439         $this->_authenticateResultInfo['code'] = Zend_Auth_Result::SUCCESS;
0440         $this->_authenticateResultInfo['messages'][] = 'Authentication successful.';
0441         return $this->_authenticateCreateAuthResult();
0442     }
0443 
0444     /**
0445      * _authenticateCreateAuthResult() - Creates a Zend_Auth_Result object from
0446      * the information that has been collected during the authenticate() attempt.
0447      *
0448      * @return Zend_Auth_Result
0449      */
0450     protected function _authenticateCreateAuthResult()
0451     {
0452         return new Zend_Auth_Result(
0453             $this->_authenticateResultInfo['code'],
0454             $this->_authenticateResultInfo['identity'],
0455             $this->_authenticateResultInfo['messages']
0456             );
0457     }
0458 
0459 }