[TASK] Cleanup phpDoc to match CGL
[Packages/TYPO3.CMS.git] / typo3 / sysext / openid / Classes / OpenidStore.php
1 <?php
2 namespace TYPO3\CMS\Openid;
3
4 /**
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 require_once \TYPO3\CMS\Core\Utility\ExtensionManagementUtility::extPath('openid') . 'lib/php-openid/Auth/OpenID/Interface.php';
18
19 /**
20 * This class is a TYPO3-specific OpenID store.
21 *
22 * @author Dmitry Dulepov <dmitry.dulepov@gmail.com>
23 */
24 class OpenidStore extends \Auth_OpenID_OpenIDStore {
25
26 const ASSOCIATION_TABLE_NAME = 'tx_openid_assoc_store';
27 const NONCE_TABLE_NAME = 'tx_openid_nonce_store';
28 /* 2 minutes */
29 const ASSOCIATION_EXPIRATION_SAFETY_INTERVAL = 120;
30 /* 10 days */
31 const NONCE_STORAGE_TIME = 864000;
32
33 /**
34 * @var \TYPO3\CMS\Core\Database\DatabaseConnection
35 */
36 protected $databaseConnection;
37
38 /**
39 * @param null|\TYPO3\CMS\Core\Database\DatabaseConnection $databaseConnection
40 */
41 public function __construct($databaseConnection = NULL) {
42 $this->databaseConnection = $databaseConnection ?: $GLOBALS['TYPO3_DB'];
43 }
44
45 /**
46 * Sores the association for future use
47 *
48 * @param string $serverUrl Server URL
49 * @param \Auth_OpenID_Association $association OpenID association
50 * @return void
51 */
52 public function storeAssociation($serverUrl, $association) {
53 /* @var $association \Auth_OpenID_Association */
54 $this->databaseConnection->sql_query('START TRANSACTION');
55 if ($this->doesAssociationExist($serverUrl, $association->handle)) {
56 $this->updateExistingAssociation($serverUrl, $association);
57 } else {
58 $this->storeNewAssociation($serverUrl, $association);
59 }
60 $this->databaseConnection->sql_query('COMMIT');
61 }
62
63 /**
64 * Removes all expired associations.
65 *
66 * @return int A number of removed associations
67 */
68 public function cleanupAssociations() {
69 $where = sprintf('expires<=%d', time());
70 $this->databaseConnection->exec_DELETEquery(self::ASSOCIATION_TABLE_NAME, $where);
71 return $this->databaseConnection->sql_affected_rows();
72 }
73
74 /**
75 * Obtains the association to the server
76 *
77 * @param string $serverUrl Server URL
78 * @param string $handle Association handle (optional)
79 * @return \Auth_OpenID_Association
80 */
81 public function getAssociation($serverUrl, $handle = NULL) {
82 $this->cleanupAssociations();
83 $where = sprintf('server_url=%s AND expires>%d', $this->databaseConnection->fullQuoteStr($serverUrl, self::ASSOCIATION_TABLE_NAME), time());
84 if ($handle != NULL) {
85 $where .= sprintf(' AND assoc_handle=%s', $this->databaseConnection->fullQuoteStr($handle, self::ASSOCIATION_TABLE_NAME));
86 $sort = '';
87 } else {
88 $sort = 'tstamp DESC';
89 }
90 $row = $this->databaseConnection->exec_SELECTgetSingleRow('uid, content', self::ASSOCIATION_TABLE_NAME, $where, '', $sort);
91 $result = NULL;
92 if (is_array($row)) {
93 $result = @unserialize(base64_decode($row['content']));
94 if ($result === FALSE) {
95 $result = NULL;
96 } else {
97 $this->updateAssociationTimeStamp($row['tstamp']);
98 }
99 }
100 return $result;
101 }
102
103 /**
104 * Removes the association
105 *
106 * @param string $serverUrl Server URL
107 * @param string $handle Association handle (optional)
108 * @return bool TRUE if the association existed
109 */
110 public function removeAssociation($serverUrl, $handle) {
111 $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));
112 $this->databaseConnection->exec_DELETEquery(self::ASSOCIATION_TABLE_NAME, $where);
113 $deletedCount = $this->databaseConnection->sql_affected_rows();
114 return $deletedCount > 0;
115 }
116
117 /**
118 * Removes old nonces
119 *
120 * @return void
121 */
122 public function cleanupNonces() {
123 $where = sprintf('crdate<%d', time() - self::NONCE_STORAGE_TIME);
124 $this->databaseConnection->exec_DELETEquery(self::NONCE_TABLE_NAME, $where);
125 }
126
127 /**
128 * Checks if this nonce was already used
129 *
130 * @param string $serverUrl Server URL
131 * @param int $timestamp Time stamp
132 * @param string $salt Nonce value
133 * @return bool TRUE if nonce was not used before anc can be used now
134 */
135 public function useNonce($serverUrl, $timestamp, $salt) {
136 $result = FALSE;
137 if (abs($timestamp - time()) < $GLOBALS['Auth_OpenID_SKEW']) {
138 $values = array(
139 'crdate' => time(),
140 'salt' => $salt,
141 'server_url' => $serverUrl,
142 'tstamp' => $timestamp
143 );
144 $this->databaseConnection->exec_INSERTquery(self::NONCE_TABLE_NAME, $values);
145 $affectedRows = $this->databaseConnection->sql_affected_rows();
146 $result = $affectedRows > 0;
147 }
148 return $result;
149 }
150
151 /**
152 * Resets the store by removing all data in it
153 *
154 * @return void
155 */
156 public function reset() {
157 $this->databaseConnection->exec_TRUNCATEquery(self::ASSOCIATION_TABLE_NAME);
158 $this->databaseConnection->exec_TRUNCATEquery(self::NONCE_TABLE_NAME);
159 }
160
161 /**
162 * Checks if such association exists.
163 *
164 * @param string $serverUrl Server URL
165 * @param \Auth_OpenID_Association $association OpenID association
166 * @return bool
167 */
168 protected function doesAssociationExist($serverUrl, $association) {
169 $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());
170 $row = $this->databaseConnection->exec_SELECTgetSingleRow('COUNT(*) as assocCount', self::ASSOCIATION_TABLE_NAME, $where);
171 return $row['assocCount'] > 0;
172 }
173
174 /**
175 * Updates existing association.
176 *
177 * @param string $serverUrl Server URL
178 * @param \Auth_OpenID_Association $association OpenID association
179 * @return void
180 */
181 protected function updateExistingAssociation($serverUrl, \Auth_OpenID_Association $association) {
182 $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());
183 $serializedAssociation = serialize($association);
184 $values = array(
185 'content' => base64_encode($serializedAssociation),
186 'tstamp' => time()
187 );
188 $this->databaseConnection->exec_UPDATEquery(self::ASSOCIATION_TABLE_NAME, $where, $values);
189 }
190
191 /**
192 * Stores new association to the database.
193 *
194 * @param string $serverUrl Server URL
195 * @param \Auth_OpenID_Association $association OpenID association
196 * @return void
197 */
198 protected function storeNewAssociation($serverUrl, $association) {
199 $serializedAssociation = serialize($association);
200 $values = array(
201 'assoc_handle' => $association->handle,
202 'content' => base64_encode($serializedAssociation),
203 'crdate' => $association->issued,
204 'tstamp' => time(),
205 'expires' => $association->issued + $association->lifetime - self::ASSOCIATION_EXPIRATION_SAFETY_INTERVAL,
206 'server_url' => $serverUrl
207 );
208 // In the next query we can get race conditions. sha1_hash prevents many
209 // asociations from being stored for one server
210 $this->databaseConnection->exec_INSERTquery(self::ASSOCIATION_TABLE_NAME, $values);
211 }
212
213 /**
214 * Updates association time stamp.
215 *
216 * @param int $recordId Association record id in the database
217 * @return void
218 */
219 protected function updateAssociationTimeStamp($recordId) {
220 $where = sprintf('uid=%d', $recordId);
221 $values = array(
222 'tstamp' => time()
223 );
224 $this->databaseConnection->exec_UPDATEquery(self::ASSOCIATION_TABLE_NAME, $where, $values);
225 }
226
227 }