[TASK] Set TYPO3 version to 9.5.0-dev
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / FrontendBackendUserAuthentication.php
1 <?php
2 namespace TYPO3\CMS\Backend;
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 use TYPO3\CMS\Backend\Utility\BackendUtility;
18 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
19 use TYPO3\CMS\Core\Compatibility\PublicPropertyDeprecationTrait;
20 use TYPO3\CMS\Core\Context\Context;
21 use TYPO3\CMS\Core\Context\LanguageAspect;
22 use TYPO3\CMS\Core\Database\ConnectionPool;
23 use TYPO3\CMS\Core\Database\Query\QueryBuilder;
24 use TYPO3\CMS\Core\Database\Query\QueryHelper;
25 use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
26 use TYPO3\CMS\Core\Localization\LanguageService;
27 use TYPO3\CMS\Core\Type\Bitmask\Permission;
28 use TYPO3\CMS\Core\Utility\GeneralUtility;
29
30 /**
31 * TYPO3 backend user authentication in the TSFE frontend.
32 * This includes mainly functions related to the Admin Panel
33 */
34 class FrontendBackendUserAuthentication extends BackendUserAuthentication
35 {
36 use PublicPropertyDeprecationTrait;
37
38 /**
39 * Properties which have been moved to protected status from public
40 *
41 * @var array
42 */
43 protected $deprecatedPublicProperties = [
44 'extAdmEnabled' => 'Using $extAdmEnabled of class FrontendBackendUserAuthentication from the outside is discouraged, as this variable is only used for internal storage.',
45 'adminPanel' => 'Using $adminPanel of class FrontendBackendUserAuthentication from the outside is discouraged, as this variable is only used for internal storage.',
46 'extAdminConfig' => 'Using $extAdminConfig of class FrontendBackendUserAuthentication from the outside is discouraged, as this variable is only used for internal storage.',
47 ];
48
49 /**
50 * Form field with login name.
51 *
52 * @var string
53 */
54 public $formfield_uname = '';
55
56 /**
57 * Form field with password.
58 *
59 * @var string
60 */
61 public $formfield_uident = '';
62
63 /**
64 * Formfield_status should be set to "". The value this->formfield_status is set to empty in order to
65 * disable login-attempts to the backend account through this script
66 *
67 * @var string
68 */
69 public $formfield_status = '';
70
71 /**
72 * Decides if the writelog() function is called at login and logout.
73 *
74 * @var bool
75 */
76 public $writeStdLog = false;
77
78 /**
79 * If the writelog() functions is called if a login-attempt has be tried without success.
80 *
81 * @var bool
82 */
83 public $writeAttemptLog = false;
84
85 /**
86 * General flag which is set if the adminpanel is enabled at all.
87 *
88 * @var bool
89 * @deprecated since TYPO3 v9, property will be removed in TYPO3 v10 - see extension "adminpanel" for new API
90 */
91 public $extAdmEnabled = false;
92
93 /**
94 * @var \TYPO3\CMS\Adminpanel\View\AdminPanelView Instance of admin panel
95 * @deprecated since TYPO3 v9, property will be removed in TYPO3 v10 - see extension "adminpanel" for new API
96 */
97 public $adminPanel;
98
99 /**
100 * @var \TYPO3\CMS\Core\FrontendEditing\FrontendEditingController
101 */
102 public $frontendEdit;
103
104 /**
105 * @var array
106 * @deprecated since TYPO3 v9, property will be removed in TYPO3 v10 - see extension "adminpanel" for new API
107 */
108 public $extAdminConfig = [];
109
110 /**
111 * Initializes the admin panel.
112 *
113 * @deprecated since TYPO3 v9 - rewritten as middleware
114 */
115 public function initializeAdminPanel()
116 {
117 trigger_error('Method will be removed in TYPO3 v10 - initialization is done via middleware.', E_USER_DEPRECATED);
118 }
119
120 /**
121 * Initializes frontend editing.
122 *
123 * @deprecated since TYPO3 v9 - rewritten as middleware
124 */
125 public function initializeFrontendEdit()
126 {
127 trigger_error('Method will be removed in TYPO3 v10 - initialization is done via middleware.', E_USER_DEPRECATED);
128 }
129
130 /**
131 * Determines whether frontend editing is currently active.
132 *
133 * @deprecated since TYPO3 v9 - see ext "feedit" for API
134 * @return bool Whether frontend editing is active
135 */
136 public function isFrontendEditingActive()
137 {
138 trigger_error('Method will be removed in TYPO3 v10 - use underlying TSFE directly.', E_USER_DEPRECATED);
139 return $this->extAdmEnabled && (
140 $this->adminPanel->isAdminModuleEnabled('edit') ||
141 (int)$GLOBALS['TSFE']->displayEditIcons === 1 ||
142 (int)$GLOBALS['TSFE']->displayFieldEditIcons === 1
143 );
144 }
145
146 /**
147 * Delegates to the appropriate view and renders the admin panel content.
148 *
149 * @deprecated since TYPO3 v9 - see ext "adminpanel" for new API
150 * @return string.
151 */
152 public function displayAdminPanel()
153 {
154 trigger_error('Method will be removed in TYPO3 v10 - use MainController of adminpanel extension.', E_USER_DEPRECATED);
155 return $this->adminPanel->display();
156 }
157
158 /**
159 * Determines whether the admin panel is enabled and visible.
160 *
161 * @deprecated since TYPO3 v9 - see ext "adminpanel" for new API
162 * @return bool true if the admin panel is enabled and visible
163 */
164 public function isAdminPanelVisible()
165 {
166 trigger_error('Method will be removed in TYPO3 v10 - use new adminpanel API instead.', E_USER_DEPRECATED);
167 return $this->extAdmEnabled && !$this->extAdminConfig['hide'] && $GLOBALS['TSFE']->config['config']['admPanel'];
168 }
169
170 /*****************************************************
171 *
172 * TSFE BE user Access Functions
173 *
174 ****************************************************/
175 /**
176 * Implementing the access checks that the TYPO3 CMS bootstrap script does before a user is ever logged in.
177 * Used in the frontend.
178 *
179 * @return bool Returns TRUE if access is OK
180 */
181 public function checkBackendAccessSettingsFromInitPhp()
182 {
183 // Check Hardcoded lock on BE
184 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['adminOnly'] < 0) {
185 return false;
186 }
187 // Check IP
188 if (trim($GLOBALS['TYPO3_CONF_VARS']['BE']['IPmaskList'])) {
189 if (!GeneralUtility::cmpIP(GeneralUtility::getIndpEnv('REMOTE_ADDR'), $GLOBALS['TYPO3_CONF_VARS']['BE']['IPmaskList'])) {
190 return false;
191 }
192 }
193 // Check IP mask based on TSconfig
194 if (!$this->checkLockToIP()) {
195 return false;
196 }
197 // Check SSL (https)
198 if ((bool)$GLOBALS['TYPO3_CONF_VARS']['BE']['lockSSL'] && !GeneralUtility::getIndpEnv('TYPO3_SSL')) {
199 return false;
200 }
201 // Finally a check as in BackendUserAuthentication::backendCheckLogin()
202 return $this->isUserAllowedToLogin();
203 }
204
205 /**
206 * Evaluates if the Backend User has read access to the input page record.
207 * The evaluation is based on both read-permission and whether the page is found in one of the users webmounts.
208 * Only if both conditions match, will the function return TRUE.
209 *
210 * Read access means that previewing is allowed etc.
211 *
212 * Used in \TYPO3\CMS\Frontend\Http\RequestHandler
213 *
214 * @param array $pageRec The page record to evaluate for
215 * @return bool TRUE if read access
216 */
217 public function extPageReadAccess($pageRec)
218 {
219 return $this->isInWebMount($pageRec['uid']) && $this->doesUserHaveAccess($pageRec, Permission::PAGE_SHOW);
220 }
221
222 /*****************************************************
223 *
224 * TSFE BE user Access Functions
225 *
226 ****************************************************/
227 /**
228 * Generates a list of Page-uid's from $id. List does not include $id itself
229 * The only pages excluded from the list are deleted pages.
230 *
231 * @param int $id Start page id
232 * @param int $depth Depth to traverse down the page tree.
233 * @param int $begin Is an optional integer that determines at which level in the tree to start collecting uid's. Zero means 'start right away', 1 = 'next level and out'
234 * @param string $perms_clause Perms clause
235 * @return string Returns the list with a comma in the end (if any pages selected!)
236 */
237 public function extGetTreeList($id, $depth, $begin = 0, $perms_clause)
238 {
239 /** @var QueryBuilder $queryBuilder */
240 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
241 ->getQueryBuilderForTable('pages');
242
243 $queryBuilder->getRestrictions()
244 ->removeAll()
245 ->add(GeneralUtility::makeInstance(DeletedRestriction::class));
246
247 $depth = (int)$depth;
248 $begin = (int)$begin;
249 $id = (int)$id;
250 $theList = '';
251 if ($id && $depth > 0) {
252 $result = $queryBuilder
253 ->select('uid', 'title')
254 ->from('pages')
255 ->where(
256 $queryBuilder->expr()->eq('pid', $queryBuilder->createNamedParameter($id, \PDO::PARAM_INT)),
257 QueryHelper::stripLogicalOperatorPrefix($perms_clause)
258 )
259 ->execute();
260 while ($row = $result->fetch()) {
261 if ($begin <= 0) {
262 $theList .= $row['uid'] . ',';
263 }
264 if ($depth > 1) {
265 $theList .= $this->extGetTreeList($row['uid'], $depth - 1, $begin - 1, $perms_clause);
266 }
267 }
268 }
269 return $theList;
270 }
271
272 /**
273 * Edit Access
274 */
275
276 /**
277 * Checks whether the user has access to edit the language for the
278 * requested record.
279 *
280 * @param string $table The name of the table.
281 * @param array $currentRecord The record.
282 * @return bool
283 */
284 public function allowedToEditLanguage($table, array $currentRecord): bool
285 {
286 // If no access right to record languages, return immediately
287 /** @var LanguageAspect $languageAspect */
288 $languageAspect = GeneralUtility::makeInstance(Context::class)->getAspect('language');
289 if ($table === 'pages') {
290 $languageId = $languageAspect->getId();
291 } elseif ($table === 'tt_content') {
292 $languageId = $languageAspect->getContentId();
293 } elseif ($GLOBALS['TCA'][$table]['ctrl']['languageField']) {
294 $languageId = $currentRecord[$GLOBALS['TCA'][$table]['ctrl']['languageField']];
295 } else {
296 $languageId = -1;
297 }
298 return $this->checkLanguageAccess($languageId);
299 }
300
301 /**
302 * Checks whether the user is allowed to edit the requested table.
303 *
304 * @param string $table The name of the table.
305 * @param array $dataArray The data array.
306 * @param array $conf The configuration array for the edit panel.
307 * @param bool $checkEditAccessInternals Boolean indicating whether recordEditAccessInternals should not be checked. Defaults
308 * @return bool
309 */
310 public function allowedToEdit(string $table, array $dataArray, array $conf, bool $checkEditAccessInternals): bool
311 {
312 // Unless permissions specifically allow it, editing is not allowed.
313 $mayEdit = false;
314 if ($checkEditAccessInternals) {
315 $editAccessInternals = $this->recordEditAccessInternals($table, $dataArray, false, false);
316 } else {
317 $editAccessInternals = true;
318 }
319 if ($editAccessInternals) {
320 if ($table === 'pages') {
321 if ($this->isAdmin() || $this->doesUserHaveAccess($dataArray, Permission::PAGE_EDIT)) {
322 $mayEdit = true;
323 }
324 } else {
325 if ($this->isAdmin() || $this->doesUserHaveAccess(BackendUtility::getRecord('pages', $dataArray['pid']), Permission::CONTENT_EDIT)) {
326 $mayEdit = true;
327 }
328 }
329 if (!$conf['onlyCurrentPid'] || $dataArray['pid'] == $GLOBALS['TSFE']->id) {
330 // Permissions:
331 $perms = $this->calcPerms($GLOBALS['TSFE']->page);
332 if ($table === 'pages') {
333 $allow = $this->getAllowedEditActions($table, $conf, $dataArray['pid']);
334 // Can only display editbox if there are options in the menu
335 if (!empty($allow)) {
336 $mayEdit = true;
337 }
338 } else {
339 $types = GeneralUtility::trimExplode(',', strtolower($conf['allow']), true);
340 $allow = array_flip($types);
341 $mayEdit = !empty($allow) && $perms & Permission::CONTENT_EDIT;
342 }
343 }
344 }
345 return $mayEdit;
346 }
347
348 /**
349 * Takes an array of generally allowed actions and filters that list based on page and content permissions.
350 *
351 * @param string $table The name of the table.
352 * @param array $conf The configuration array.
353 * @param int $pid The PID where editing will occur.
354 * @return array
355 */
356 public function getAllowedEditActions($table, array $conf, $pid): array
357 {
358 $types = GeneralUtility::trimExplode(',', strtolower($conf['allow']), true);
359 $allow = array_flip($types);
360 if (!$conf['onlyCurrentPid'] || $pid == $GLOBALS['TSFE']->id) {
361 // Permissions
362 $types = GeneralUtility::trimExplode(',', strtolower($conf['allow']), true);
363 $allow = array_flip($types);
364 $perms = $this->calcPerms($GLOBALS['TSFE']->page);
365 if ($table === 'pages') {
366 // Rootpage
367 if (count($GLOBALS['TSFE']->config['rootLine']) === 1) {
368 unset($allow['move']);
369 unset($allow['hide']);
370 unset($allow['delete']);
371 }
372 if (!($perms & Permission::PAGE_EDIT) || !$this->checkLanguageAccess(0)) {
373 unset($allow['edit']);
374 unset($allow['move']);
375 unset($allow['hide']);
376 }
377 if (!($perms & Permission::PAGE_DELETE)) {
378 unset($allow['delete']);
379 }
380 if (!($perms & Permission::PAGE_NEW)) {
381 unset($allow['new']);
382 }
383 }
384 }
385 return $allow;
386 }
387
388 /*****************************************************
389 *
390 * Localization handling
391 *
392 ****************************************************/
393 /**
394 * Returns the label for key. If a translation for the language set in $this->uc['lang']
395 * is found that is returned, otherwise the default value.
396 * If the global variable $LOCAL_LANG is NOT an array (yet) then this function loads
397 * the global $LOCAL_LANG array with the content of "EXT:core/Resources/Private/Language/locallang_tsfe.xlf"
398 * such that the values therein can be used for labels in the Admin Panel
399 *
400 * @param string $key Key for a label in the $GLOBALS['LOCAL_LANG'] array of "EXT:core/Resources/Private/Language/locallang_tsfe.xlf
401 * @return string The value for the $key
402 */
403 public function extGetLL($key)
404 {
405 if (!is_array($GLOBALS['LOCAL_LANG'])) {
406 $this->getLanguageService()->includeLLFile('EXT:core/Resources/Private/Language/locallang_tsfe.xlf');
407 if (!is_array($GLOBALS['LOCAL_LANG'])) {
408 $GLOBALS['LOCAL_LANG'] = [];
409 }
410 }
411 return htmlspecialchars($this->getLanguageService()->getLL($key));
412 }
413
414 /**
415 * @return LanguageService
416 */
417 protected function getLanguageService()
418 {
419 return $GLOBALS['LANG'];
420 }
421 }