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