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