[TASK] Remove closing PHP tags
[Packages/TYPO3.CMS.git] / typo3 / sysext / openid / Classes / OpenidStore.php
1 <?php
2 namespace TYPO3\CMS\Openid;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2009-2013 Dmitry Dulepov (dmitry.dulepov@gmail.com)
8 * All rights reserved
9 *
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.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 *
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.
23 *
24 * This copyright notice MUST APPEAR in all copies of the script!
25 ***************************************************************/
26
27 /**
28 * This class is a TYPO3-specific OpenID store.
29 *
30 * @author Dmitry Dulepov <dmitry.dulepov@gmail.com>
31 */
32 class OpenidStore extends \Auth_OpenID_OpenIDStore {
33
34 const ASSOCIATION_TABLE_NAME = 'tx_openid_assoc_store';
35 const NONCE_TABLE_NAME = 'tx_openid_nonce_store';
36 /* 2 minutes */
37 const ASSOCIATION_EXPIRATION_SAFETY_INTERVAL = 120;
38 /* 10 days */
39 const NONCE_STORAGE_TIME = 864000;
40
41 /**
42 * @var \TYPO3\CMS\Core\Database\DatabaseConnection
43 */
44 protected $databaseConnection;
45
46 /**
47 * @param null|\TYPO3\CMS\Core\Database\DatabaseConnection $databaseConnection
48 */
49 public function __construct($databaseConnection = NULL) {
50 $this->databaseConnection = $databaseConnection ?: $GLOBALS['TYPO3_DB'];
51 }
52
53 /**
54 * Sores the association for future use
55 *
56 * @param string $serverUrl Server URL
57 * @param \Auth_OpenID_Association $association OpenID association
58 * @return void
59 */
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);
65 } else {
66 $this->storeNewAssociation($serverUrl, $association);
67 }
68 $this->databaseConnection->sql_query('COMMIT');
69 }
70
71 /**
72 * Removes all expired associations.
73 *
74 * @return integer A number of removed associations
75 */
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();
80 }
81
82 /**
83 * Obtains the association to the server
84 *
85 * @param string $serverUrl Server URL
86 * @param string $handle Association handle (optional)
87 * @return \Auth_OpenID_Association
88 */
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));
94 $sort = '';
95 } else {
96 $sort = 'tstamp DESC';
97 }
98 $row = $this->databaseConnection->exec_SELECTgetSingleRow('uid, content', self::ASSOCIATION_TABLE_NAME, $where, '', $sort);
99 $result = NULL;
100 if (is_array($row)) {
101 $result = @unserialize(base64_decode($row['content']));
102 if ($result === FALSE) {
103 $result = NULL;
104 } else {
105 $this->updateAssociationTimeStamp($row['tstamp']);
106 }
107 }
108 return $result;
109 }
110
111 /**
112 * Removes the association
113 *
114 * @param string $serverUrl Server URL
115 * @param string $handle Association handle (optional)
116 * @return boolean TRUE if the association existed
117 */
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;
123 }
124
125 /**
126 * Removes old nonces
127 *
128 * @return void
129 */
130 public function cleanupNonces() {
131 $where = sprintf('crdate<%d', time() - self::NONCE_STORAGE_TIME);
132 $this->databaseConnection->exec_DELETEquery(self::NONCE_TABLE_NAME, $where);
133 }
134
135 /**
136 * Checks if this nonce was already used
137 *
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
142 */
143 public function useNonce($serverUrl, $timestamp, $salt) {
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 $this->databaseConnection->exec_TRUNCATEquery(self::ASSOCIATION_TABLE_NAME);
166 $this->databaseConnection->exec_TRUNCATEquery(self::NONCE_TABLE_NAME);
167 }
168
169 /**
170 * Checks if such association exists.
171 *
172 * @param string $serverUrl Server URL
173 * @param \Auth_OpenID_Association $association OpenID association
174 * @return boolean
175 */
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;
180 }
181
182 /**
183 * Updates existing association.
184 *
185 * @param string $serverUrl Server URL
186 * @param \Auth_OpenID_Association $association OpenID association
187 * @return void
188 */
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);
192 $values = array(
193 'content' => base64_encode($serializedAssociation),
194 'tstamp' => time()
195 );
196 $this->databaseConnection->exec_UPDATEquery(self::ASSOCIATION_TABLE_NAME, $where, $values);
197 }
198
199 /**
200 * Stores new association to the database.
201 *
202 * @param string $serverUrl Server URL
203 * @param \Auth_OpenID_Association $association OpenID association
204 * @return void
205 */
206 protected function storeNewAssociation($serverUrl, $association) {
207 $serializedAssociation = serialize($association);
208 $values = array(
209 'assoc_handle' => $association->handle,
210 'content' => base64_encode($serializedAssociation),
211 'crdate' => $association->issued,
212 'tstamp' => time(),
213 'expires' => $association->issued + $association->lifetime - self::ASSOCIATION_EXPIRATION_SAFETY_INTERVAL,
214 'server_url' => $serverUrl
215 );
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);
219 }
220
221 /**
222 * Updates association time stamp.
223 *
224 * @param integer $recordId Association record id in the database
225 * @return void
226 */
227 protected function updateAssociationTimeStamp($recordId) {
228 $where = sprintf('uid=%d', $recordId);
229 $values = array(
230 'tstamp' => time()
231 );
232 $this->databaseConnection->exec_UPDATEquery(self::ASSOCIATION_TABLE_NAME, $where, $values);
233 }
234
235 }