Db.php 13 KB

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