1*d10b5556SXylle<?php 2*d10b5556SXylle 3*d10b5556SXylle/** 4*d10b5556SXylle * Licensed to Jasig under one or more contributor license 5*d10b5556SXylle * agreements. See the NOTICE file distributed with this work for 6*d10b5556SXylle * additional information regarding copyright ownership. 7*d10b5556SXylle * 8*d10b5556SXylle * Jasig licenses this file to you under the Apache License, 9*d10b5556SXylle * Version 2.0 (the "License"); you may not use this file except in 10*d10b5556SXylle * compliance with the License. You may obtain a copy of the License at: 11*d10b5556SXylle * 12*d10b5556SXylle * http://www.apache.org/licenses/LICENSE-2.0 13*d10b5556SXylle * 14*d10b5556SXylle * Unless required by applicable law or agreed to in writing, software 15*d10b5556SXylle * distributed under the License is distributed on an "AS IS" BASIS, 16*d10b5556SXylle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17*d10b5556SXylle * See the License for the specific language governing permissions and 18*d10b5556SXylle * limitations under the License. 19*d10b5556SXylle * 20*d10b5556SXylle * PHP Version 7 21*d10b5556SXylle * 22*d10b5556SXylle * @file CAS/PGTStorage/Db.php 23*d10b5556SXylle * @category Authentication 24*d10b5556SXylle * @package PhpCAS 25*d10b5556SXylle * @author Daniel Frett <daniel.frett@gmail.com> 26*d10b5556SXylle * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 27*d10b5556SXylle * @link https://wiki.jasig.org/display/CASC/phpCAS 28*d10b5556SXylle */ 29*d10b5556SXylle 30*d10b5556SXylledefine('CAS_PGT_STORAGE_DB_DEFAULT_TABLE', 'cas_pgts'); 31*d10b5556SXylle 32*d10b5556SXylle/** 33*d10b5556SXylle * Basic class for PGT database storage 34*d10b5556SXylle * The CAS_PGTStorage_Db class is a class for PGT database storage. 35*d10b5556SXylle * 36*d10b5556SXylle * @class CAS_PGTStorage_Db 37*d10b5556SXylle * @category Authentication 38*d10b5556SXylle * @package PhpCAS 39*d10b5556SXylle * @author Daniel Frett <daniel.frett@gmail.com> 40*d10b5556SXylle * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 41*d10b5556SXylle * @link https://wiki.jasig.org/display/CASC/phpCAS 42*d10b5556SXylle * 43*d10b5556SXylle * @ingroup internalPGTStorageDb 44*d10b5556SXylle */ 45*d10b5556SXylle 46*d10b5556SXylleclass CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage 47*d10b5556SXylle{ 48*d10b5556SXylle /** 49*d10b5556SXylle * @addtogroup internalCAS_PGTStorageDb 50*d10b5556SXylle * @{ 51*d10b5556SXylle */ 52*d10b5556SXylle 53*d10b5556SXylle /** 54*d10b5556SXylle * the PDO object to use for database interactions 55*d10b5556SXylle */ 56*d10b5556SXylle private $_pdo; 57*d10b5556SXylle 58*d10b5556SXylle /** 59*d10b5556SXylle * This method returns the PDO object to use for database interactions. 60*d10b5556SXylle * 61*d10b5556SXylle * @return PDO object 62*d10b5556SXylle */ 63*d10b5556SXylle private function _getPdo() 64*d10b5556SXylle { 65*d10b5556SXylle return $this->_pdo; 66*d10b5556SXylle } 67*d10b5556SXylle 68*d10b5556SXylle /** 69*d10b5556SXylle * database connection options to use when creating a new PDO object 70*d10b5556SXylle */ 71*d10b5556SXylle private $_dsn; 72*d10b5556SXylle private $_username; 73*d10b5556SXylle private $_password; 74*d10b5556SXylle private $_driver_options; 75*d10b5556SXylle 76*d10b5556SXylle /** 77*d10b5556SXylle * @var string the table to use for storing/retrieving pgt's 78*d10b5556SXylle */ 79*d10b5556SXylle private $_table; 80*d10b5556SXylle 81*d10b5556SXylle /** 82*d10b5556SXylle * This method returns the table to use when storing/retrieving PGT's 83*d10b5556SXylle * 84*d10b5556SXylle * @return string the name of the pgt storage table. 85*d10b5556SXylle */ 86*d10b5556SXylle private function _getTable() 87*d10b5556SXylle { 88*d10b5556SXylle return $this->_table; 89*d10b5556SXylle } 90*d10b5556SXylle 91*d10b5556SXylle // ######################################################################## 92*d10b5556SXylle // DEBUGGING 93*d10b5556SXylle // ######################################################################## 94*d10b5556SXylle 95*d10b5556SXylle /** 96*d10b5556SXylle * This method returns an informational string giving the type of storage 97*d10b5556SXylle * used by the object (used for debugging purposes). 98*d10b5556SXylle * 99*d10b5556SXylle * @return string an informational string. 100*d10b5556SXylle */ 101*d10b5556SXylle public function getStorageType() 102*d10b5556SXylle { 103*d10b5556SXylle return "db"; 104*d10b5556SXylle } 105*d10b5556SXylle 106*d10b5556SXylle /** 107*d10b5556SXylle * This method returns an informational string giving informations on the 108*d10b5556SXylle * parameters of the storage.(used for debugging purposes). 109*d10b5556SXylle * 110*d10b5556SXylle * @return string an informational string. 111*d10b5556SXylle * @public 112*d10b5556SXylle */ 113*d10b5556SXylle public function getStorageInfo() 114*d10b5556SXylle { 115*d10b5556SXylle return 'table=`'.$this->_getTable().'\''; 116*d10b5556SXylle } 117*d10b5556SXylle 118*d10b5556SXylle // ######################################################################## 119*d10b5556SXylle // CONSTRUCTOR 120*d10b5556SXylle // ######################################################################## 121*d10b5556SXylle 122*d10b5556SXylle /** 123*d10b5556SXylle * The class constructor. 124*d10b5556SXylle * 125*d10b5556SXylle * @param CAS_Client $cas_parent the CAS_Client instance that creates 126*d10b5556SXylle * the object. 127*d10b5556SXylle * @param string $dsn_or_pdo a dsn string to use for creating a PDO 128*d10b5556SXylle * object or a PDO object 129*d10b5556SXylle * @param string $username the username to use when connecting to 130*d10b5556SXylle * the database 131*d10b5556SXylle * @param string $password the password to use when connecting to 132*d10b5556SXylle * the database 133*d10b5556SXylle * @param string $table the table to use for storing and 134*d10b5556SXylle * retrieving PGT's 135*d10b5556SXylle * @param string $driver_options any driver options to use when 136*d10b5556SXylle * connecting to the database 137*d10b5556SXylle */ 138*d10b5556SXylle public function __construct( 139*d10b5556SXylle $cas_parent, $dsn_or_pdo, $username='', $password='', $table='', 140*d10b5556SXylle $driver_options=null 141*d10b5556SXylle ) { 142*d10b5556SXylle phpCAS::traceBegin(); 143*d10b5556SXylle // call the ancestor's constructor 144*d10b5556SXylle parent::__construct($cas_parent); 145*d10b5556SXylle 146*d10b5556SXylle // set default values 147*d10b5556SXylle if ( empty($table) ) { 148*d10b5556SXylle $table = CAS_PGT_STORAGE_DB_DEFAULT_TABLE; 149*d10b5556SXylle } 150*d10b5556SXylle if ( !is_array($driver_options) ) { 151*d10b5556SXylle $driver_options = array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION); 152*d10b5556SXylle } 153*d10b5556SXylle 154*d10b5556SXylle // store the specified parameters 155*d10b5556SXylle if ($dsn_or_pdo instanceof PDO) { 156*d10b5556SXylle $this->_pdo = $dsn_or_pdo; 157*d10b5556SXylle } else { 158*d10b5556SXylle $this->_dsn = $dsn_or_pdo; 159*d10b5556SXylle $this->_username = $username; 160*d10b5556SXylle $this->_password = $password; 161*d10b5556SXylle $this->_driver_options = $driver_options; 162*d10b5556SXylle } 163*d10b5556SXylle 164*d10b5556SXylle // store the table name 165*d10b5556SXylle $this->_table = $table; 166*d10b5556SXylle 167*d10b5556SXylle phpCAS::traceEnd(); 168*d10b5556SXylle } 169*d10b5556SXylle 170*d10b5556SXylle // ######################################################################## 171*d10b5556SXylle // INITIALIZATION 172*d10b5556SXylle // ######################################################################## 173*d10b5556SXylle 174*d10b5556SXylle /** 175*d10b5556SXylle * This method is used to initialize the storage. Halts on error. 176*d10b5556SXylle * 177*d10b5556SXylle * @return void 178*d10b5556SXylle */ 179*d10b5556SXylle public function init() 180*d10b5556SXylle { 181*d10b5556SXylle phpCAS::traceBegin(); 182*d10b5556SXylle // if the storage has already been initialized, return immediatly 183*d10b5556SXylle if ($this->isInitialized()) { 184*d10b5556SXylle return; 185*d10b5556SXylle } 186*d10b5556SXylle 187*d10b5556SXylle // initialize the base object 188*d10b5556SXylle parent::init(); 189*d10b5556SXylle 190*d10b5556SXylle // create the PDO object if it doesn't exist already 191*d10b5556SXylle if (!($this->_pdo instanceof PDO)) { 192*d10b5556SXylle try { 193*d10b5556SXylle $this->_pdo = new PDO( 194*d10b5556SXylle $this->_dsn, $this->_username, $this->_password, 195*d10b5556SXylle $this->_driver_options 196*d10b5556SXylle ); 197*d10b5556SXylle } 198*d10b5556SXylle catch(PDOException $e) { 199*d10b5556SXylle phpCAS::error('Database connection error: ' . $e->getMessage()); 200*d10b5556SXylle } 201*d10b5556SXylle } 202*d10b5556SXylle 203*d10b5556SXylle phpCAS::traceEnd(); 204*d10b5556SXylle } 205*d10b5556SXylle 206*d10b5556SXylle // ######################################################################## 207*d10b5556SXylle // PDO database interaction 208*d10b5556SXylle // ######################################################################## 209*d10b5556SXylle 210*d10b5556SXylle /** 211*d10b5556SXylle * attribute that stores the previous error mode for the PDO handle while 212*d10b5556SXylle * processing a transaction 213*d10b5556SXylle */ 214*d10b5556SXylle private $_errMode; 215*d10b5556SXylle 216*d10b5556SXylle /** 217*d10b5556SXylle * This method will enable the Exception error mode on the PDO object 218*d10b5556SXylle * 219*d10b5556SXylle * @return void 220*d10b5556SXylle */ 221*d10b5556SXylle private function _setErrorMode() 222*d10b5556SXylle { 223*d10b5556SXylle // get PDO object and enable exception error mode 224*d10b5556SXylle $pdo = $this->_getPdo(); 225*d10b5556SXylle $this->_errMode = $pdo->getAttribute(PDO::ATTR_ERRMODE); 226*d10b5556SXylle $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 227*d10b5556SXylle } 228*d10b5556SXylle 229*d10b5556SXylle /** 230*d10b5556SXylle * this method will reset the error mode on the PDO object 231*d10b5556SXylle * 232*d10b5556SXylle * @return void 233*d10b5556SXylle */ 234*d10b5556SXylle private function _resetErrorMode() 235*d10b5556SXylle { 236*d10b5556SXylle // get PDO object and reset the error mode to what it was originally 237*d10b5556SXylle $pdo = $this->_getPdo(); 238*d10b5556SXylle $pdo->setAttribute(PDO::ATTR_ERRMODE, $this->_errMode); 239*d10b5556SXylle } 240*d10b5556SXylle 241*d10b5556SXylle // ######################################################################## 242*d10b5556SXylle // database queries 243*d10b5556SXylle // ######################################################################## 244*d10b5556SXylle // these queries are potentially unsafe because the person using this library 245*d10b5556SXylle // can set the table to use, but there is no reliable way to escape SQL 246*d10b5556SXylle // fieldnames in PDO yet 247*d10b5556SXylle 248*d10b5556SXylle /** 249*d10b5556SXylle * This method returns the query used to create a pgt storage table 250*d10b5556SXylle * 251*d10b5556SXylle * @return string the create table SQL, no bind params in query 252*d10b5556SXylle */ 253*d10b5556SXylle protected function createTableSql() 254*d10b5556SXylle { 255*d10b5556SXylle return 'CREATE TABLE ' . $this->_getTable() 256*d10b5556SXylle . ' (pgt_iou VARCHAR(255) NOT NULL PRIMARY KEY, pgt VARCHAR(255) NOT NULL)'; 257*d10b5556SXylle } 258*d10b5556SXylle 259*d10b5556SXylle /** 260*d10b5556SXylle * This method returns the query used to store a pgt 261*d10b5556SXylle * 262*d10b5556SXylle * @return string the store PGT SQL, :pgt and :pgt_iou are the bind params contained 263*d10b5556SXylle * in the query 264*d10b5556SXylle */ 265*d10b5556SXylle protected function storePgtSql() 266*d10b5556SXylle { 267*d10b5556SXylle return 'INSERT INTO ' . $this->_getTable() 268*d10b5556SXylle . ' (pgt_iou, pgt) VALUES (:pgt_iou, :pgt)'; 269*d10b5556SXylle } 270*d10b5556SXylle 271*d10b5556SXylle /** 272*d10b5556SXylle * This method returns the query used to retrieve a pgt. the first column 273*d10b5556SXylle * of the first row should contain the pgt 274*d10b5556SXylle * 275*d10b5556SXylle * @return string the retrieve PGT SQL, :pgt_iou is the only bind param contained 276*d10b5556SXylle * in the query 277*d10b5556SXylle */ 278*d10b5556SXylle protected function retrievePgtSql() 279*d10b5556SXylle { 280*d10b5556SXylle return 'SELECT pgt FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou'; 281*d10b5556SXylle } 282*d10b5556SXylle 283*d10b5556SXylle /** 284*d10b5556SXylle * This method returns the query used to delete a pgt. 285*d10b5556SXylle * 286*d10b5556SXylle * @return string the delete PGT SQL, :pgt_iou is the only bind param contained in 287*d10b5556SXylle * the query 288*d10b5556SXylle */ 289*d10b5556SXylle protected function deletePgtSql() 290*d10b5556SXylle { 291*d10b5556SXylle return 'DELETE FROM ' . $this->_getTable() . ' WHERE pgt_iou = :pgt_iou'; 292*d10b5556SXylle } 293*d10b5556SXylle 294*d10b5556SXylle // ######################################################################## 295*d10b5556SXylle // PGT I/O 296*d10b5556SXylle // ######################################################################## 297*d10b5556SXylle 298*d10b5556SXylle /** 299*d10b5556SXylle * This method creates the database table used to store pgt's and pgtiou's 300*d10b5556SXylle * 301*d10b5556SXylle * @return void 302*d10b5556SXylle */ 303*d10b5556SXylle public function createTable() 304*d10b5556SXylle { 305*d10b5556SXylle phpCAS::traceBegin(); 306*d10b5556SXylle 307*d10b5556SXylle // initialize this PGTStorage object if it hasn't been initialized yet 308*d10b5556SXylle if ( !$this->isInitialized() ) { 309*d10b5556SXylle $this->init(); 310*d10b5556SXylle } 311*d10b5556SXylle 312*d10b5556SXylle // initialize the PDO object for this method 313*d10b5556SXylle $pdo = $this->_getPdo(); 314*d10b5556SXylle $this->_setErrorMode(); 315*d10b5556SXylle 316*d10b5556SXylle try { 317*d10b5556SXylle $pdo->beginTransaction(); 318*d10b5556SXylle 319*d10b5556SXylle $query = $pdo->query($this->createTableSQL()); 320*d10b5556SXylle $query->closeCursor(); 321*d10b5556SXylle 322*d10b5556SXylle $pdo->commit(); 323*d10b5556SXylle } 324*d10b5556SXylle catch(PDOException $e) { 325*d10b5556SXylle // attempt rolling back the transaction before throwing a phpCAS error 326*d10b5556SXylle try { 327*d10b5556SXylle $pdo->rollBack(); 328*d10b5556SXylle } 329*d10b5556SXylle catch(PDOException $e) { 330*d10b5556SXylle } 331*d10b5556SXylle phpCAS::error('error creating PGT storage table: ' . $e->getMessage()); 332*d10b5556SXylle } 333*d10b5556SXylle 334*d10b5556SXylle // reset the PDO object 335*d10b5556SXylle $this->_resetErrorMode(); 336*d10b5556SXylle 337*d10b5556SXylle phpCAS::traceEnd(); 338*d10b5556SXylle } 339*d10b5556SXylle 340*d10b5556SXylle /** 341*d10b5556SXylle * This method stores a PGT and its corresponding PGT Iou in the database. 342*d10b5556SXylle * Echoes a warning on error. 343*d10b5556SXylle * 344*d10b5556SXylle * @param string $pgt the PGT 345*d10b5556SXylle * @param string $pgt_iou the PGT iou 346*d10b5556SXylle * 347*d10b5556SXylle * @return void 348*d10b5556SXylle */ 349*d10b5556SXylle public function write($pgt, $pgt_iou) 350*d10b5556SXylle { 351*d10b5556SXylle phpCAS::traceBegin(); 352*d10b5556SXylle 353*d10b5556SXylle // initialize the PDO object for this method 354*d10b5556SXylle $pdo = $this->_getPdo(); 355*d10b5556SXylle $this->_setErrorMode(); 356*d10b5556SXylle 357*d10b5556SXylle try { 358*d10b5556SXylle $pdo->beginTransaction(); 359*d10b5556SXylle 360*d10b5556SXylle $query = $pdo->prepare($this->storePgtSql()); 361*d10b5556SXylle $query->bindValue(':pgt', $pgt, PDO::PARAM_STR); 362*d10b5556SXylle $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR); 363*d10b5556SXylle $query->execute(); 364*d10b5556SXylle $query->closeCursor(); 365*d10b5556SXylle 366*d10b5556SXylle $pdo->commit(); 367*d10b5556SXylle } 368*d10b5556SXylle catch(PDOException $e) { 369*d10b5556SXylle // attempt rolling back the transaction before throwing a phpCAS error 370*d10b5556SXylle try { 371*d10b5556SXylle $pdo->rollBack(); 372*d10b5556SXylle } 373*d10b5556SXylle catch(PDOException $e) { 374*d10b5556SXylle } 375*d10b5556SXylle phpCAS::error('error writing PGT to database: ' . $e->getMessage()); 376*d10b5556SXylle } 377*d10b5556SXylle 378*d10b5556SXylle // reset the PDO object 379*d10b5556SXylle $this->_resetErrorMode(); 380*d10b5556SXylle 381*d10b5556SXylle phpCAS::traceEnd(); 382*d10b5556SXylle } 383*d10b5556SXylle 384*d10b5556SXylle /** 385*d10b5556SXylle * This method reads a PGT corresponding to a PGT Iou and deletes the 386*d10b5556SXylle * corresponding db entry. 387*d10b5556SXylle * 388*d10b5556SXylle * @param string $pgt_iou the PGT iou 389*d10b5556SXylle * 390*d10b5556SXylle * @return string|false the corresponding PGT, or FALSE on error 391*d10b5556SXylle */ 392*d10b5556SXylle public function read($pgt_iou) 393*d10b5556SXylle { 394*d10b5556SXylle phpCAS::traceBegin(); 395*d10b5556SXylle $pgt = false; 396*d10b5556SXylle 397*d10b5556SXylle // initialize the PDO object for this method 398*d10b5556SXylle $pdo = $this->_getPdo(); 399*d10b5556SXylle $this->_setErrorMode(); 400*d10b5556SXylle 401*d10b5556SXylle try { 402*d10b5556SXylle $pdo->beginTransaction(); 403*d10b5556SXylle 404*d10b5556SXylle // fetch the pgt for the specified pgt_iou 405*d10b5556SXylle $query = $pdo->prepare($this->retrievePgtSql()); 406*d10b5556SXylle $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR); 407*d10b5556SXylle $query->execute(); 408*d10b5556SXylle $pgt = $query->fetchColumn(0); 409*d10b5556SXylle $query->closeCursor(); 410*d10b5556SXylle 411*d10b5556SXylle // delete the specified pgt_iou from the database 412*d10b5556SXylle $query = $pdo->prepare($this->deletePgtSql()); 413*d10b5556SXylle $query->bindValue(':pgt_iou', $pgt_iou, PDO::PARAM_STR); 414*d10b5556SXylle $query->execute(); 415*d10b5556SXylle $query->closeCursor(); 416*d10b5556SXylle 417*d10b5556SXylle $pdo->commit(); 418*d10b5556SXylle } 419*d10b5556SXylle catch(PDOException $e) { 420*d10b5556SXylle // attempt rolling back the transaction before throwing a phpCAS error 421*d10b5556SXylle try { 422*d10b5556SXylle $pdo->rollBack(); 423*d10b5556SXylle } 424*d10b5556SXylle catch(PDOException $e) { 425*d10b5556SXylle } 426*d10b5556SXylle phpCAS::trace('error reading PGT from database: ' . $e->getMessage()); 427*d10b5556SXylle } 428*d10b5556SXylle 429*d10b5556SXylle // reset the PDO object 430*d10b5556SXylle $this->_resetErrorMode(); 431*d10b5556SXylle 432*d10b5556SXylle phpCAS::traceEnd(); 433*d10b5556SXylle return $pgt; 434*d10b5556SXylle } 435*d10b5556SXylle 436*d10b5556SXylle /** @} */ 437*d10b5556SXylle 438*d10b5556SXylle} 439*d10b5556SXylle 440*d10b5556SXylle?> 441