2 namespace TYPO3\CMS\Openid
;
4 /***************************************************************
7 * (c) 2009-2013 Dmitry Dulepov (dmitry.dulepov@gmail.com)
10 * This script is part of the Typo3 project. The Typo3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
19 * This script is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
28 * This class is a TYPO3-specific OpenID store.
30 * @author Dmitry Dulepov <dmitry.dulepov@gmail.com>
32 class OpenidStore
extends \Auth_OpenID_OpenIDStore
{
34 const ASSOCIATION_TABLE_NAME
= 'tx_openid_assoc_store';
35 const NONCE_TABLE_NAME
= 'tx_openid_nonce_store';
37 const ASSOCIATION_EXPIRATION_SAFETY_INTERVAL
= 120;
39 const NONCE_STORAGE_TIME
= 864000;
42 * @var \TYPO3\CMS\Core\Database\DatabaseConnection
44 protected $databaseConnection;
47 * @param null|\TYPO3\CMS\Core\Database\DatabaseConnection $databaseConnection
49 public function __construct($databaseConnection = NULL) {
50 $this->databaseConnection
= $databaseConnection ?
: $GLOBALS['TYPO3_DB'];
54 * Sores the association for future use
56 * @param string $serverUrl Server URL
57 * @param \Auth_OpenID_Association $association OpenID association
60 public function storeAssociation($serverUrl, $association) {
61 /* @var $association \Auth_OpenID_Association */
62 $this->databaseConnection
->sql_query('START TRANSACTION');
63 if ($this->doesAssociationExist($serverUrl, $association->handle
)) {
64 $this->updateExistingAssociation($serverUrl, $association);
66 $this->storeNewAssociation($serverUrl, $association);
68 $this->databaseConnection
->sql_query('COMMIT');
72 * Removes all expired associations.
74 * @return integer A number of removed associations
76 public function cleanupAssociations() {
77 $where = sprintf('expires<=%d', time());
78 $this->databaseConnection
->exec_DELETEquery(self
::ASSOCIATION_TABLE_NAME
, $where);
79 return $this->databaseConnection
->sql_affected_rows();
83 * Obtains the association to the server
85 * @param string $serverUrl Server URL
86 * @param string $handle Association handle (optional)
87 * @return \Auth_OpenID_Association
89 public function getAssociation($serverUrl, $handle = NULL) {
90 $this->cleanupAssociations();
91 $where = sprintf('server_url=%s AND expires>%d', $this->databaseConnection
->fullQuoteStr($serverUrl, self
::ASSOCIATION_TABLE_NAME
), time());
92 if ($handle != NULL) {
93 $where .= sprintf(' AND assoc_handle=%s', $this->databaseConnection
->fullQuoteStr($handle, self
::ASSOCIATION_TABLE_NAME
));
96 $sort = 'tstamp DESC';
98 $row = $this->databaseConnection
->exec_SELECTgetSingleRow('uid, content', self
::ASSOCIATION_TABLE_NAME
, $where, '', $sort);
100 if (is_array($row)) {
101 $result = @unserialize
(base64_decode($row['content']));
102 if ($result === FALSE) {
105 $this->updateAssociationTimeStamp($row['tstamp']);
112 * Removes the association
114 * @param string $serverUrl Server URL
115 * @param string $handle Association handle (optional)
116 * @return boolean TRUE if the association existed
118 public function removeAssociation($serverUrl, $handle) {
119 $where = sprintf('server_url=%s AND assoc_handle=%s', $this->databaseConnection
->fullQuoteStr($serverUrl, self
::ASSOCIATION_TABLE_NAME
), $this->databaseConnection
->fullQuoteStr($handle, self
::ASSOCIATION_TABLE_NAME
));
120 $this->databaseConnection
->exec_DELETEquery(self
::ASSOCIATION_TABLE_NAME
, $where);
121 $deletedCount = $this->databaseConnection
->sql_affected_rows();
122 return $deletedCount > 0;
130 public function cleanupNonces() {
131 $where = sprintf('crdate<%d', time() - self
::NONCE_STORAGE_TIME
);
132 $this->databaseConnection
->exec_DELETEquery(self
::NONCE_TABLE_NAME
, $where);
136 * Checks if this nonce was already used
138 * @param string $serverUrl Server URL
139 * @param integer $timestamp Time stamp
140 * @param string $salt Nonce value
141 * @return boolean TRUE if nonce was not used before anc can be used now
143 public function useNonce($serverUrl, $timestamp, $salt) {
145 if (abs($timestamp - time()) < $GLOBALS['Auth_OpenID_SKEW']) {
149 'server_url' => $serverUrl,
150 'tstamp' => $timestamp
152 $this->databaseConnection
->exec_INSERTquery(self
::NONCE_TABLE_NAME
, $values);
153 $affectedRows = $this->databaseConnection
->sql_affected_rows();
154 $result = $affectedRows > 0;
160 * Resets the store by removing all data in it
164 public function reset() {
165 $this->databaseConnection
->exec_TRUNCATEquery(self
::ASSOCIATION_TABLE_NAME
);
166 $this->databaseConnection
->exec_TRUNCATEquery(self
::NONCE_TABLE_NAME
);
170 * Checks if such association exists.
172 * @param string $serverUrl Server URL
173 * @param \Auth_OpenID_Association $association OpenID association
176 protected function doesAssociationExist($serverUrl, $association) {
177 $where = sprintf('server_url=%s AND assoc_handle=%s AND expires>%d', $this->databaseConnection
->fullQuoteStr($serverUrl, self
::ASSOCIATION_TABLE_NAME
), $this->databaseConnection
->fullQuoteStr($association->handle
, self
::ASSOCIATION_TABLE_NAME
), time());
178 $row = $this->databaseConnection
->exec_SELECTgetSingleRow('COUNT(*) as assocCount', self
::ASSOCIATION_TABLE_NAME
, $where);
179 return $row['assocCount'] > 0;
183 * Updates existing association.
185 * @param string $serverUrl Server URL
186 * @param \Auth_OpenID_Association $association OpenID association
189 protected function updateExistingAssociation($serverUrl, \Auth_OpenID_Association
$association) {
190 $where = sprintf('server_url=%s AND assoc_handle=%s AND expires>%d', $this->databaseConnection
->fullQuoteStr($serverUrl, self
::ASSOCIATION_TABLE_NAME
), $this->databaseConnection
->fullQuoteStr($association->handle
, self
::ASSOCIATION_TABLE_NAME
), time());
191 $serializedAssociation = serialize($association);
193 'content' => base64_encode($serializedAssociation),
196 $this->databaseConnection
->exec_UPDATEquery(self
::ASSOCIATION_TABLE_NAME
, $where, $values);
200 * Stores new association to the database.
202 * @param string $serverUrl Server URL
203 * @param \Auth_OpenID_Association $association OpenID association
206 protected function storeNewAssociation($serverUrl, $association) {
207 $serializedAssociation = serialize($association);
209 'assoc_handle' => $association->handle
,
210 'content' => base64_encode($serializedAssociation),
211 'crdate' => $association->issued
,
213 'expires' => $association->issued +
$association->lifetime
- self
::ASSOCIATION_EXPIRATION_SAFETY_INTERVAL
,
214 'server_url' => $serverUrl
216 // In the next query we can get race conditions. sha1_hash prevents many
217 // asociations from being stored for one server
218 $this->databaseConnection
->exec_INSERTquery(self
::ASSOCIATION_TABLE_NAME
, $values);
222 * Updates association time stamp.
224 * @param integer $recordId Association record id in the database
227 protected function updateAssociationTimeStamp($recordId) {
228 $where = sprintf('uid=%d', $recordId);
232 $this->databaseConnection
->exec_UPDATEquery(self
::ASSOCIATION_TABLE_NAME
, $where, $values);