622747c2f6897fee692cd07b2b8a509afcea3d48
[Packages/TYPO3.CMS.git] / t3lib / formprotection / class.t3lib_formprotection_backendformprotection.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2010-2011 Oliver Klee <typo3-coding@oliverklee.de>
6 * (c) 2010-2011 Helmut Hummel <helmut.hummel@typo3.org>
7 * All rights reserved
8 *
9 * This script is part of the TYPO3 project. The TYPO3 project is
10 * free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * The GNU General Public License can be found at
16 * http://www.gnu.org/copyleft/gpl.html.
17 *
18 * This script is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * This copyright notice MUST APPEAR in all copies of the script!
24 ***************************************************************/
25
26 /**
27 * Class t3lib_formprotection_BackendFormProtection.
28 *
29 * This class provides protection against cross-site request forgery (XSRF/CSRF)
30 * for forms in the BE.
31 *
32 * How to use:
33 *
34 * For each form in the BE (or link that changes some data), create a token and
35 * insert is as a hidden form element. The name of the form element does not
36 * matter; you only need it to get the form token for verifying it.
37 *
38 * <pre>
39 * $formToken = t3lib_formprotection_Factory::get()
40 * ->generateToken(
41 * 'BE user setup', 'edit'
42 * );
43 * $this->content .= '<input type="hidden" name="formToken" value="' .
44 * $formToken . '" />';
45 * </pre>
46 *
47 * The three parameters $formName, $action and $formInstanceName can be
48 * arbitrary strings, but they should make the form token as specific as
49 * possible. For different forms (e.g. BE user setup and editing a tt_content
50 * record) or different records (with different UIDs) from the same table,
51 * those values should be different.
52 *
53 * For editing a tt_content record, the call could look like this:
54 *
55 * <pre>
56 * $formToken = t3lib_formprotection_Factory::get()
57 * ->getFormProtection()->generateToken(
58 * 'tt_content', 'edit', $uid
59 * );
60 * </pre>
61 *
62 *
63 * When processing the data that has been submitted by the form, you can check
64 * that the form token is valid like this:
65 *
66 * <pre>
67 * if ($dataHasBeenSubmitted && t3lib_formprotection_Factory::get()
68 * ->validateToken(
69 * t3lib_div::_POST('formToken'),
70 * 'BE user setup', 'edit
71 * )
72 * ) {
73 * // processes the data
74 * } else {
75 * // no need to do anything here as the BE form protection will create a
76 * // flash message for an invalid token
77 * }
78 * </pre>
79 *
80 *
81 * @package TYPO3
82 * @subpackage t3lib
83 *
84 * @author Oliver Klee <typo3-coding@oliverklee.de>
85 * @author Helmut Hummel <helmut.hummel@typo3.org>
86 */
87 class t3lib_formprotection_BackendFormProtection extends t3lib_formprotection_Abstract {
88 /**
89 * Keeps the instance of the user which existed during creation
90 * of the object.
91 *
92 * @var t3lib_beUserAuth
93 */
94 protected $backendUser;
95
96 /**
97 * Instance of the registry, which is used to permanently persist
98 * the session token so that it can be restored during re-login.
99 *
100 * @var t3lib_Registry
101 */
102 protected $registry;
103
104 /**
105 * Only allow construction if we have a backend session
106 */
107 public function __construct() {
108 if (!$this->isAuthorizedBackendSession()) {
109 throw new t3lib_error_Exception(
110 'A back-end form protection may only be instantiated if there' .
111 ' is an active back-end session.',
112 1285067843
113 );
114 }
115 $this->backendUser = $GLOBALS['BE_USER'];
116 parent::__construct();
117 }
118
119 /**
120 * Creates or displays an error message telling the user that the submitted
121 * form token is invalid.
122 *
123 * @return void
124 */
125 protected function createValidationErrorMessage() {
126 $message = t3lib_div::makeInstance(
127 't3lib_FlashMessage',
128 $GLOBALS['LANG']->sL(
129 'LLL:EXT:lang/locallang_core.xml:error.formProtection.tokenInvalid'
130 ),
131 '',
132 t3lib_FlashMessage::ERROR,
133 TRUE
134 );
135 t3lib_FlashMessageQueue::addMessage($message);
136 }
137
138 /**
139 * Retrieves the saved session token or generates a new one.
140 *
141 * @return array<array>
142 * the saved tokens as, will be empty if no tokens have been saved
143 */
144 protected function retrieveSessionToken() {
145 $this->sessionToken = $this->backendUser->getSessionData('formSessionToken');
146 if (empty($this->sessionToken)) {
147 $this->sessionToken = $this->generateSessionToken();
148 $this->persistSessionToken();
149 }
150 }
151
152 /**
153 * Saves the tokens so that they can be used by a later incarnation of this
154 * class.
155 *
156 * @access private
157 * @return void
158 */
159 public function persistSessionToken() {
160 $this->backendUser->setAndSaveSessionData('formSessionToken', $this->sessionToken);
161 }
162
163 /**
164 * Sets the session token for the user from the registry
165 * and returns it additionally.
166 *
167 * @access private
168 * @return string
169 */
170 public function setSessionTokenFromRegistry() {
171 $this->sessionToken = $this->getRegistry()
172 ->get('core', 'formSessionToken:' . $this->backendUser->user['uid']);
173 if (empty($this->sessionToken)) {
174 throw new UnexpectedValueException('Failed to restore the session token from the registry.', 1301827270);
175 }
176 return $this->sessionToken;
177 }
178
179 /**
180 * Stores the session token in the registry to have it
181 * available during re-login of the user.
182 *
183 * @access private
184 * @return void
185 */
186 public function storeSessionTokenInRegistry() {
187 $this->getRegistry()
188 ->set('core', 'formSessionToken:' . $this->backendUser->user['uid'], $this->sessionToken);
189 }
190
191 /**
192 * Removes the session token for the user from the registry.
193 *
194 * @access private
195 * @return string
196 */
197 public function removeSessionTokenFromRegistry() {
198 return $this->getRegistry()
199 ->remove('core', 'formSessionToken:' . $this->backendUser->user['uid']);
200 }
201
202 /**
203 * Returns the instance of the registry.
204 *
205 * @return t3lib_Registry
206 */
207 protected function getRegistry() {
208 if (!$this->registry instanceof t3lib_Registry) {
209 $this->registry = t3lib_div::makeInstance('t3lib_Registry');
210 }
211 return $this->registry;
212 }
213
214 /**
215 * Inject the registry. Currently only used in unit tests.
216 *
217 * @access private
218 * @param t3lib_Registry $registry
219 * @return void
220 */
221 public function injectRegistry(t3lib_Registry $registry) {
222 $this->registry = $registry;
223 }
224
225 /**
226 * Checks if a user is logged in and the session is active.
227 *
228 * @return boolean
229 */
230 protected function isAuthorizedBackendSession() {
231 return (isset($GLOBALS['BE_USER']) && $GLOBALS['BE_USER'] instanceof t3lib_beUserAuth && isset($GLOBALS['BE_USER']->user['uid']));
232 }
233 }
234
235 if (defined('TYPO3_MODE') && isset($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/formprotection/class.t3lib_formprotection_backendformprotection.php'])) {
236 include_once($GLOBALS['TYPO3_CONF_VARS'][TYPO3_MODE]['XCLASS']['t3lib/formprotection/class.t3lib_formprotection_backendformprotection.php']);
237 }
238 ?>