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