* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 * @link https://wiki.jasig.org/display/CASC/phpCAS */ define('CAS_PGT_STORAGE_DB_DEFAULT_TABLE', 'cas_pgts'); /** * Basic class for PGT database storage * The CAS_PGTStorage_Db class is a class for PGT database storage. * * @class CAS_PGTStorage_Db * @category Authentication * @package PhpCAS * @author Daniel Frett * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 * @link https://wiki.jasig.org/display/CASC/phpCAS * * @ingroup internalPGTStorageDb */ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage { /** * @addtogroup internalCAS_PGTStorageDb * @{ */ /** * the PDO object to use for database interactions */ private $_pdo; /** * This method returns the PDO object to use for database interactions. * * @return the PDO object */ private function _getPdo() { return $this->_pdo; } /** * database connection options to use when creating a new PDO object */ private $_dsn; private $_username; private $_password; private $_table_options; /** * the table to use for storing/retrieving pgt's */ private $_table; /** * This method returns the table to use when storing/retrieving PGT's * * @return the name of the pgt storage table. */ private function _getTable() { return $this->_table; } // ######################################################################## // DEBUGGING // ######################################################################## /** * This method returns an informational string giving the type of storage * used by the object (used for debugging purposes). * * @return an informational string. */ public function getStorageType() { return "db"; } /** * This method returns an informational string giving informations on the * parameters of the storage.(used for debugging purposes). * * @return an informational string. * @public */ public function getStorageInfo() { return 'table=`'.$this->_getTable().'\''; } // ######################################################################## // CONSTRUCTOR // ######################################################################## /** * The class constructor. * * @param CAS_Client $cas_parent the CAS_Client instance that creates * the object. * @param string $dsn_or_pdo a dsn string to use for creating a PDO * object or a PDO object * @param string $username the username to use when connecting to * the database * @param string $password the password to use when connecting to * the database * @param string $table the table to use for storing and * retrieving PGT's * @param string $driver_options any driver options to use when * connecting to the database */ public function __construct( $cas_parent, $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null ) { phpCAS::traceBegin(); // call the ancestor's constructor parent::__construct($cas_parent); // set default values if ( empty($table) ) { $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE; } if ( !is_array($driver_options) ) { $driver_options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); } // store the specified parameters if ($dsn_or_pdo instanceof PDO) { $this->_pdo = $dsn_or_pdo; } else { $this->_dsn = $dsn_or_pdo; $this->_username = $username; $this->_password = $password; $this->_driver_options = $driver_options; } // store the table name $this->_table = $table; phpCAS::traceEnd(); } // ######################################################################## // INITIALIZATION // ######################################################################## /** * This method is used to initialize the storage. Halts on error. * * @return void */ public function init() { phpCAS::traceBegin(); // if the storage has already been initialized, return immediatly if ($this->isInitialized()) { return; } // initialize the base object parent::init(); // create the PDO object if it doesn't exist already if (!($this->_pdo instanceof PDO)) { try { $this->_pdo = new PDO( $this->_dsn, $this->_username, $this->_password, $this->_driver_options ); } catch(PDOException $e) { phpCAS::error('Database connection error: ' . $e->getMessage()); } } phpCAS::traceEnd(); } // ######################################################################## // PDO database interaction // ######################################################################## /** * attribute that stores the previous error mode for the PDO handle while * processing a transaction */ private $_errMode; /** * This method will enable the Exception error mode on the PDO object * * @return void */ private function _setErrorMode() { // get PDO object and enable exception error mode $pdo = $this->_getPdo(); $this->_errMode = $pdo->getAttribute(PDO::ATTR_ERRMODE); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } /** * this method will reset the error mode on the PDO object * * @return void */ private function _resetErrorMode() { // get PDO object and reset the error mode to what it was originally $pdo = $this->_getPdo(); $pdo->setAttribute(PDO::ATTR_ERRMODE, $this->_errMode); } // ######################################################################## // database queries // ######################################################################## // these queries are potentially unsafe because the person using this library // can set the table to use, but there is no reliable way to escape SQL // fieldnames in PDO yet /** * This method returns the query used to create a pgt storage table * * @return the create table SQL, no bind params in query */ protected function createTableSql() { return 'CREATE TABLE ' . $this->_getTable() . ' (pgt_iou VARCHAR(255) NOT NULL PRIMARY KEY, pgt VARCHAR(255) NOT NULL)'; } /** * This method returns the query used to store a pgt * * @return the store PGT SQL, :pgt and :pgt_iou are the bind params contained * in the query */ protected function storePgtSql() { return 'INSERT INTO ' . $this->_getTable() . ' (pgt_iou, pgt) VALUES (:pgt_iou, :pgt)'; } /** * This method returns the query used to retrieve a pgt. the first column * of the first row should contain the pgt * * @return the retrieve PGT SQL, :pgt_iou is the only bind param contained * in the query */ protected function retrievePgtSql() { return 'SELECT pgt FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou'; } /** * This method returns the query used to delete a pgt. * * @return the delete PGT SQL, :pgt_iou is the only bind param contained in * the query */ protected function deletePgtSql() { return 'DELETE FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou'; } // ######################################################################## // PGT I/O // ######################################################################## /** * This method creates the database table used to store pgt's and pgtiou's * * @return void */ public function createTable() { phpCAS::traceBegin(); // initialize this PGTStorage object if it hasn't been initialized yet if ( !$this->isInitialized() ) { $this->init(); } // initialize the PDO object for this method $pdo = $this->_getPdo(); $this->_setErrorMode(); try { $pdo->beginTransaction(); $query = $pdo->query($this->createTableSQL()); $query->closeCursor(); $pdo->commit(); } catch(PDOException $e) { // attempt rolling back the transaction before throwing a phpCAS error try { $pdo->rollBack(); } catch(PDOException $e) { } phpCAS::error('error creating PGT storage table: ' . $e->getMessage()); } // reset the PDO object $this->_resetErrorMode(); phpCAS::traceEnd(); } /** * This method stores a PGT and its corresponding PGT Iou in the database. * Echoes a warning on error. * * @param string $pgt the PGT * @param string $pgt_iou the PGT iou * * @return void */ public function write($pgt, $pgt_iou) { phpCAS::traceBegin(); // initialize the PDO object for this method $pdo = $this->_getPdo(); $this->_setErrorMode(); try { $pdo->beginTransaction(); $query = $pdo->prepare($this->storePgtSql()); $query->bindValue(':pgt', $pgt, PDO::PARAM_STR); $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR); $query->execute(); $query->closeCursor(); $pdo->commit(); } catch(PDOException $e) { // attempt rolling back the transaction before throwing a phpCAS error try { $pdo->rollBack(); } catch(PDOException $e) { } phpCAS::error('error writing PGT to database: ' . $e->getMessage()); } // reset the PDO object $this->_resetErrorMode(); phpCAS::traceEnd(); } /** * This method reads a PGT corresponding to a PGT Iou and deletes the * corresponding db entry. * * @param string $pgt_iou the PGT iou * * @return the corresponding PGT, or FALSE on error */ public function read($pgt_iou) { phpCAS::traceBegin(); $pgt = false; // initialize the PDO object for this method $pdo = $this->_getPdo(); $this->_setErrorMode(); try { $pdo->beginTransaction(); // fetch the pgt for the specified pgt_iou $query = $pdo->prepare($this->retrievePgtSql()); $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR); $query->execute(); $pgt = $query->fetchColumn(0); $query->closeCursor(); // delete the specified pgt_iou from the database $query = $pdo->prepare($this->deletePgtSql()); $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR); $query->execute(); $query->closeCursor(); $pdo->commit(); } catch(PDOException $e) { // attempt rolling back the transaction before throwing a phpCAS error try { $pdo->rollBack(); } catch(PDOException $e) { } phpCAS::trace('error reading PGT from database: ' . $e->getMessage()); } // reset the PDO object $this->_resetErrorMode(); phpCAS::traceEnd(); return $pgt; } /** @} */ } ?>