[TASK] Re-work/simplify copyright header in PHP files - Part 3
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / FormProtection / BackendFormProtection.php
1 <?php
2 namespace TYPO3\CMS\Core\FormProtection;
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 * This class provides protection against cross-site request forgery (XSRF/CSRF)
19 * for forms in the BE.
20 *
21 * How to use:
22 *
23 * For each form in the BE (or link that changes some data), create a token and
24 * insert is as a hidden form element. The name of the form element does not
25 * matter; you only need it to get the form token for verifying it.
26 *
27 * <pre>
28 * $formToken = TYPO3\CMS\Core\FormProtection\BackendFormProtectionFactory::get()
29 * ->generateToken(
30 * 'BE user setup', 'edit'
31 * );
32 * $this->content .= '<input type="hidden" name="formToken" value="' .
33 * $formToken . '" />';
34 * </pre>
35 *
36 * The three parameters $formName, $action and $formInstanceName can be
37 * arbitrary strings, but they should make the form token as specific as
38 * possible. For different forms (e.g. BE user setup and editing a tt_content
39 * record) or different records (with different UIDs) from the same table,
40 * those values should be different.
41 *
42 * For editing a tt_content record, the call could look like this:
43 *
44 * <pre>
45 * $formToken = \TYPO3\CMS\Core\FormProtection\BackendFormProtectionFactory::get()
46 * ->getFormProtection()->generateToken(
47 * 'tt_content', 'edit', $uid
48 * );
49 * </pre>
50 *
51 *
52 * When processing the data that has been submitted by the form, you can check
53 * that the form token is valid like this:
54 *
55 * <pre>
56 * if ($dataHasBeenSubmitted && TYPO3\CMS\Core\FormProtection\BackendFormProtectionFactory::get()
57 * ->validateToken(
58 * \TYPO3\CMS\Core\Utility\GeneralUtility::_POST('formToken'),
59 * 'BE user setup', 'edit
60 * )
61 * ) {
62 * processes the data
63 * } else {
64 * no need to do anything here as the BE form protection will create a
65 * flash message for an invalid token
66 * }
67 * </pre>
68 */
69 /**
70 * Backend form protection
71 *
72 * @author Oliver Klee <typo3-coding@oliverklee.de>
73 * @author Helmut Hummel <helmut.hummel@typo3.org>
74 */
75 class BackendFormProtection extends \TYPO3\CMS\Core\FormProtection\AbstractFormProtection {
76
77 /**
78 * Keeps the instance of the user which existed during creation
79 * of the object.
80 *
81 * @var \TYPO3\CMS\Core\Authentication\BackendUserAuthentication
82 */
83 protected $backendUser;
84
85 /**
86 * Instance of the registry, which is used to permanently persist
87 * the session token so that it can be restored during re-login.
88 *
89 * @var \TYPO3\CMS\Core\Registry
90 */
91 protected $registry;
92
93 /**
94 * Only allow construction if we have a backend session
95 */
96 public function __construct() {
97 if (!$this->isAuthorizedBackendSession()) {
98 throw new \TYPO3\CMS\Core\Error\Exception('A back-end form protection may only be instantiated if there' . ' is an active back-end session.', 1285067843);
99 }
100 $this->backendUser = $GLOBALS['BE_USER'];
101 }
102
103 /**
104 * Creates or displays an error message telling the user that the submitted
105 * form token is invalid.
106 *
107 * @return void
108 */
109 protected function createValidationErrorMessage() {
110 $flashMessage = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
111 'TYPO3\\CMS\\Core\\Messaging\\FlashMessage',
112 $this->getLanguageService()->sL('LLL:EXT:lang/locallang_core.xlf:error.formProtection.tokenInvalid'),
113 '',
114 \TYPO3\CMS\Core\Messaging\FlashMessage::ERROR,
115 !$this->isAjaxRequest()
116 );
117 /** @var $flashMessageService \TYPO3\CMS\Core\Messaging\FlashMessageService */
118 $flashMessageService = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
119 'TYPO3\\CMS\\Core\\Messaging\\FlashMessageService'
120 );
121 /** @var $defaultFlashMessageQueue \TYPO3\CMS\Core\Messaging\FlashMessageQueue */
122 $defaultFlashMessageQueue = $flashMessageService->getMessageQueueByIdentifier();
123 $defaultFlashMessageQueue->enqueue($flashMessage);
124 }
125
126 /**
127 * Checks if the current request is an Ajax request
128 *
129 * @return bool
130 */
131 protected function isAjaxRequest() {
132 return (bool)(TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_AJAX);
133 }
134
135 /**
136 * Retrieves the saved session token or generates a new one.
137 *
138 * @return string
139 */
140 protected function retrieveSessionToken() {
141 $this->sessionToken = $this->backendUser->getSessionData('formSessionToken');
142 if (empty($this->sessionToken)) {
143 $this->sessionToken = $this->generateSessionToken();
144 $this->persistSessionToken();
145 }
146 return $this->sessionToken;
147 }
148
149 /**
150 * Saves the tokens so that they can be used by a later incarnation of this
151 * class.
152 *
153 * @access private
154 * @return void
155 */
156 public function persistSessionToken() {
157 $this->backendUser->setAndSaveSessionData('formSessionToken', $this->sessionToken);
158 }
159
160 /**
161 * Sets the session token for the user from the registry
162 * and returns it additionally.
163 *
164 * @access private
165 * @return string
166 * @throws \UnexpectedValueException
167 */
168 public function setSessionTokenFromRegistry() {
169 $this->sessionToken = $this->getRegistry()->get('core', 'formSessionToken:' . $this->backendUser->user['uid']);
170 if (empty($this->sessionToken)) {
171 throw new \UnexpectedValueException('Failed to restore the session token from the registry.', 1301827270);
172 }
173 return $this->sessionToken;
174 }
175
176 /**
177 * Stores the session token in the registry to have it
178 * available during re-login of the user.
179 *
180 * @access private
181 * @return void
182 */
183 public function storeSessionTokenInRegistry() {
184 $this->getRegistry()->set('core', 'formSessionToken:' . $this->backendUser->user['uid'], $this->getSessionToken());
185 }
186
187 /**
188 * Removes the session token for the user from the registry.
189 *
190 * @access private
191 */
192 public function removeSessionTokenFromRegistry() {
193 $this->getRegistry()->remove('core', 'formSessionToken:' . $this->backendUser->user['uid']);
194 }
195
196 /**
197 * Returns the instance of the registry.
198 *
199 * @return \TYPO3\CMS\Core\Registry
200 */
201 protected function getRegistry() {
202 if (!$this->registry instanceof \TYPO3\CMS\Core\Registry) {
203 $this->registry = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Registry');
204 }
205 return $this->registry;
206 }
207
208 /**
209 * Inject the registry. Currently only used in unit tests.
210 *
211 * @access private
212 * @param \TYPO3\CMS\Core\Registry $registry
213 * @return void
214 */
215 public function injectRegistry(\TYPO3\CMS\Core\Registry $registry) {
216 $this->registry = $registry;
217 }
218
219 /**
220 * Checks if a user is logged in and the session is active.
221 *
222 * @return boolean
223 */
224 protected function isAuthorizedBackendSession() {
225 return isset($GLOBALS['BE_USER']) && $GLOBALS['BE_USER'] instanceof \TYPO3\CMS\Core\Authentication\BackendUserAuthentication && isset($GLOBALS['BE_USER']->user['uid']);
226 }
227
228 /**
229 * Return language service instance
230 *
231 * @return \TYPO3\CMS\Lang\LanguageService
232 */
233 protected function getLanguageService() {
234 return $GLOBALS['LANG'];
235 }
236 }