Upgrade phpCAS
[piwik-CASLogin.git] / CAS / CAS / PGTStorage / Db.php
diff --git a/CAS/CAS/PGTStorage/Db.php b/CAS/CAS/PGTStorage/Db.php
new file mode 100644 (file)
index 0000000..1f635f8
--- /dev/null
@@ -0,0 +1,429 @@
+<?php
+
+/**
+ * Licensed to Jasig under one or more contributor license
+ * agreements. See the NOTICE file distributed with this work for
+ * additional information regarding copyright ownership.
+ *
+ * Jasig licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * PHP Version 5
+ *
+ * @file     CAS/PGTStorage/Db.php
+ * @category Authentication
+ * @package  PhpCAS
+ * @author   Daniel Frett <daniel.frett@gmail.com>
+ * @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 <daniel.frett@gmail.com>
+ * @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;
+    }
+
+    /** @} */
+
+}
+
+?>