xref: /plugin/authssocas/vendor/apereo/phpcas/source/CAS/PGTStorage/Db.php (revision d10b5556242e78d8a430c323b91984ec16415a46)
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