Search moodle.org's
Developer Documentation

See Release Notes

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