[BUGFIX] Fixing login logo height in IE
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Classes / Controller / LoginController.php
1 <?php
2 declare(strict_types = 1);
3 namespace TYPO3\CMS\Backend\Controller;
4
5 /*
6 * This file is part of the TYPO3 CMS project.
7 *
8 * It is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, either version 2
10 * of the License, or any later version.
11 *
12 * For the full copyright and license information, please read the
13 * LICENSE.txt file that was distributed with this source code.
14 *
15 * The TYPO3 project - inspiring people to share!
16 */
17
18 use Psr\Http\Message\ResponseInterface;
19 use Psr\Http\Message\ServerRequestInterface;
20 use Psr\Log\LoggerAwareInterface;
21 use Psr\Log\LoggerAwareTrait;
22 use TYPO3\CMS\Backend\Exception;
23 use TYPO3\CMS\Backend\LoginProvider\LoginProviderInterface;
24 use TYPO3\CMS\Backend\Routing\UriBuilder;
25 use TYPO3\CMS\Backend\Template\DocumentTemplate;
26 use TYPO3\CMS\Backend\Utility\BackendUtility;
27 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
28 use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
29 use TYPO3\CMS\Core\Database\ConnectionPool;
30 use TYPO3\CMS\Core\FormProtection\BackendFormProtection;
31 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
32 use TYPO3\CMS\Core\Http\HtmlResponse;
33 use TYPO3\CMS\Core\Localization\LanguageService;
34 use TYPO3\CMS\Core\Localization\Locales;
35 use TYPO3\CMS\Core\Page\PageRenderer;
36 use TYPO3\CMS\Core\Utility\GeneralUtility;
37 use TYPO3\CMS\Core\Utility\HttpUtility;
38 use TYPO3\CMS\Core\Utility\PathUtility;
39 use TYPO3\CMS\Fluid\View\StandaloneView;
40
41 /**
42 * Script Class for rendering the login form
43 */
44 class LoginController implements LoggerAwareInterface
45 {
46 use LoggerAwareTrait;
47
48 /**
49 * The URL to redirect to after login.
50 *
51 * @var string
52 */
53 protected $redirectUrl;
54
55 /**
56 * Set to the redirect URL of the form (may be redirect_url or "index.php?M=main")
57 *
58 * @var string
59 */
60 protected $redirectToURL;
61
62 /**
63 * the active login provider identifier
64 *
65 * @var string
66 */
67 protected $loginProviderIdentifier;
68
69 /**
70 * List of registered and sorted login providers
71 *
72 * @var array
73 */
74 protected $loginProviders = [];
75
76 /**
77 * Login-refresh bool; The backend will call this script
78 * with this value set when the login is close to being expired
79 * and the form needs to be redrawn.
80 *
81 * @var bool
82 */
83 protected $loginRefresh;
84
85 /**
86 * Value of forms submit button for login.
87 *
88 * @var string
89 */
90 protected $submitValue;
91
92 /**
93 * @var StandaloneView
94 */
95 protected $view;
96
97 /**
98 * Initialize the login box. Will also react on a &L=OUT flag and exit.
99 */
100 public function __construct()
101 {
102 // @deprecated since v9, will be obsolete in v10
103 $request = $GLOBALS['TYPO3_REQUEST'];
104 $parsedBody = $request->getParsedBody();
105 $queryParams = $request->getQueryParams();
106 $this->validateAndSortLoginProviders();
107
108 // We need a PHP session session for most login levels
109 session_start();
110 $this->redirectUrl = GeneralUtility::sanitizeLocalUrl($parsedBody['redirect_url'] ?? $queryParams['redirect_url'] ?? null);
111 $this->loginProviderIdentifier = $this->detectLoginProvider($request);
112
113 $this->loginRefresh = (bool)($parsedBody['loginRefresh'] ?? $queryParams['loginRefresh'] ?? false);
114 // Value of "Login" button. If set, the login button was pressed.
115 $this->submitValue = $parsedBody['commandLI'] ?? $queryParams['commandLI'] ?? null;
116 // Try to get the preferred browser language
117 /** @var Locales $locales */
118 $locales = GeneralUtility::makeInstance(Locales::class);
119 $httpAcceptLanguage = $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'];
120 $preferredBrowserLanguage = $locales
121 ->getPreferredClientLanguage($httpAcceptLanguage);
122
123 // If we found a $preferredBrowserLanguage and it is not the default language and no be_user is logged in
124 // initialize $this->getLanguageService() again with $preferredBrowserLanguage
125 if ($preferredBrowserLanguage !== 'default' && empty($this->getBackendUserAuthentication()->user['uid'])) {
126 $this->getLanguageService()->init($preferredBrowserLanguage);
127 GeneralUtility::makeInstance(PageRenderer::class)->setLanguage($preferredBrowserLanguage);
128 }
129
130 $this->getLanguageService()->includeLLFile('EXT:backend/Resources/Private/Language/locallang_login.xlf');
131
132 // Setting the redirect URL to "index.php?M=main" if no alternative input is given
133 if ($this->redirectUrl) {
134 $this->redirectToURL = $this->redirectUrl;
135 } else {
136 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
137 $this->redirectToURL = (string)$uriBuilder->buildUriFromRoute('main');
138 }
139
140 // If "L" is "OUT", then any logged in is logged out. If redirect_url is given, we redirect to it
141 if (($parsedBody['L'] ?? $queryParams['L'] ?? null) === 'OUT' && is_object($this->getBackendUserAuthentication())) {
142 $this->getBackendUserAuthentication()->logoff();
143 $this->redirectToUrl();
144 }
145
146 $this->view = $this->getFluidTemplateObject();
147 }
148
149 /**
150 * Injects the request and response objects for the current request or subrequest
151 * As this controller goes only through the main() method, it is rather simple for now
152 *
153 * @param ServerRequestInterface $request the current request
154 * @return ResponseInterface the finished response with the content
155 */
156 public function formAction(ServerRequestInterface $request): ResponseInterface
157 {
158 return new HtmlResponse($this->createLoginLogoutForm($request));
159 }
160
161 /**
162 * Calls the main function but with loginRefresh enabled at any time
163 *
164 * @param ServerRequestInterface $request the current request
165 * @return ResponseInterface the finished response with the content
166 */
167 public function refreshAction(ServerRequestInterface $request): ResponseInterface
168 {
169 $this->loginRefresh = true;
170 return new HtmlResponse($this->createLoginLogoutForm($request));
171 }
172
173 /**
174 * Main function - creating the login/logout form
175 *
176 * @throws Exception
177 * @return string The content to output
178 * @deprecated since v9, will be removed in v10
179 */
180 public function main(): string
181 {
182 trigger_error('Method main() will be replaced by protected method createLoginLogoutForm() in v10. Do not call from other extension', E_USER_DEPRECATED);
183 return $this->createLoginLogoutForm($GLOBALS['TYPO3_REQUEST']);
184 }
185
186 /**
187 * Main function - creating the login/logout form
188 *
189 * @param ServerRequestInterface $request
190 * @return string $content
191 * @throws Exception
192 */
193 protected function createLoginLogoutForm(ServerRequestInterface $request): string
194 {
195 /** @var $pageRenderer PageRenderer */
196 $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
197 $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Login');
198
199 // Checking, if we should make a redirect.
200 // Might set JavaScript in the header to close window.
201 $this->checkRedirect($request);
202
203 // Extension Configuration
204 $extConf = GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('backend');
205
206 // Background Image
207 if (!empty($extConf['loginBackgroundImage'])) {
208 $backgroundImage = $this->getUriForFileName($extConf['loginBackgroundImage']);
209 if ($backgroundImage === '') {
210 $this->logger->warning(
211 'The configured TYPO3 backend login background image "' . htmlspecialchars($extConf['loginBackgroundImage']) .
212 '" can\'t be resolved. Please check if the file exists and the extension is activated.'
213 );
214 }
215 $this->getDocumentTemplate()->inDocStylesArray[] = '
216 .typo3-login-carousel-control.right,
217 .typo3-login-carousel-control.left,
218 .panel-login { border: 0; }
219 .typo3-login { background-image: url("' . $backgroundImage . '"); }
220 .typo3-login-footnote { background-color: #000000; color: #ffffff; opacity: 0.5; }
221 ';
222 }
223
224 // Login Footnote
225 if (!empty($extConf['loginFootnote'])) {
226 $this->view->assign('loginFootnote', strip_tags(trim($extConf['loginFootnote'])));
227 }
228
229 // Add additional css to use the highlight color in the login screen
230 if (!empty($extConf['loginHighlightColor'])) {
231 $this->getDocumentTemplate()->inDocStylesArray[] = '
232 .btn-login.disabled, .btn-login[disabled], fieldset[disabled] .btn-login,
233 .btn-login.disabled:hover, .btn-login[disabled]:hover, fieldset[disabled] .btn-login:hover,
234 .btn-login.disabled:focus, .btn-login[disabled]:focus, fieldset[disabled] .btn-login:focus,
235 .btn-login.disabled.focus, .btn-login[disabled].focus, fieldset[disabled] .btn-login.focus,
236 .btn-login.disabled:active, .btn-login[disabled]:active, fieldset[disabled] .btn-login:active,
237 .btn-login.disabled.active, .btn-login[disabled].active, fieldset[disabled] .btn-login.active,
238 .btn-login:hover, .btn-login:focus, .btn-login:active,
239 .btn-login:active:hover, .btn-login:active:focus,
240 .btn-login { background-color: ' . $extConf['loginHighlightColor'] . '; }
241 .panel-login .panel-body { border-color: ' . $extConf['loginHighlightColor'] . '; }
242 ';
243 }
244
245 // Logo
246 if (!empty($extConf['loginLogo'])) {
247 if ($this->getUriForFileName($extConf['loginLogo']) === '') {
248 $this->logger->warning(
249 'The configured TYPO3 backend login logo "' . htmlspecialchars($extConf['loginLogo']) .
250 '" can\'t be resolved. Please check if the file exists and the extension is activated.'
251 );
252 }
253 $logo = $extConf['loginLogo'];
254 } else {
255 // Use TYPO3 logo depending on highlight color
256 if (!empty($extConf['loginHighlightColor'])) {
257 $logo = 'EXT:backend/Resources/Public/Images/typo3_black.svg';
258 } else {
259 $logo = 'EXT:backend/Resources/Public/Images/typo3_orange.svg';
260 }
261 $this->getDocumentTemplate()->inDocStylesArray[] = '
262 .typo3-login-logo .typo3-login-image { max-width: 150px; height:100%;}
263 ';
264 }
265 $logo = $this->getUriForFileName($logo);
266
267 // Start form
268 $formType = empty($this->getBackendUserAuthentication()->user['uid']) ? 'LoginForm' : 'LogoutForm';
269 $this->view->assignMultiple([
270 'backendUser' => $this->getBackendUserAuthentication()->user,
271 'hasLoginError' => $this->isLoginInProgress($request),
272 'formType' => $formType,
273 'logo' => $logo,
274 'images' => [
275 'capslock' => $this->getUriForFileName('EXT:backend/Resources/Public/Images/icon_capslock.svg'),
276 'typo3' => $this->getUriForFileName('EXT:backend/Resources/Public/Images/typo3_orange.svg'),
277 ],
278 'copyright' => BackendUtility::TYPO3_copyRightNotice(),
279 'redirectUrl' => $this->redirectUrl,
280 'loginRefresh' => $this->loginRefresh,
281 'loginNewsItems' => $this->getSystemNews(),
282 'loginProviderIdentifier' => $this->loginProviderIdentifier,
283 'loginProviders' => $this->loginProviders
284 ]);
285
286 // Initialize interface selectors:
287 $this->makeInterfaceSelector($request);
288
289 /** @var LoginProviderInterface $loginProvider */
290 $loginProvider = GeneralUtility::makeInstance($this->loginProviders[$this->loginProviderIdentifier]['provider']);
291 $loginProvider->render($this->view, $pageRenderer, $this);
292
293 $content = $this->getDocumentTemplate()->startPage('TYPO3 CMS Login: ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
294 $content .= $this->view->render();
295 $content .= $this->getDocumentTemplate()->endPage();
296
297 return $content;
298 }
299
300 /**
301 * Checking, if we should perform some sort of redirection OR closing of windows.
302 *
303 * Do a redirect if a user is logged in
304 *
305 * @param ServerRequestInterface $request
306 * @throws \RuntimeException
307 * @throws \UnexpectedValueException
308 * @throws \TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException
309 */
310 protected function checkRedirect(ServerRequestInterface $request): void
311 {
312 $backendUser = $this->getBackendUserAuthentication();
313 if (empty($backendUser->user['uid'])) {
314 return;
315 }
316
317 /*
318 * If no cookie has been set previously, we tell people that this is a problem.
319 * This assumes that a cookie-setting script (like this one) has been hit at
320 * least once prior to this instance.
321 */
322 if (!isset($_COOKIE[BackendUserAuthentication::getCookieName()])) {
323 if ($this->submitValue === 'setCookie') {
324 /*
325 * we tried it a second time but still no cookie
326 * 26/4 2005: This does not work anymore, because the saving of challenge values
327 * in $_SESSION means the system will act as if the password was wrong.
328 */
329 throw new \RuntimeException('Login-error: Yeah, that\'s a classic. No cookies, no TYPO3. ' .
330 'Please accept cookies from TYPO3 - otherwise you\'ll not be able to use the system.', 1294586846);
331 }
332 // try it once again - that might be needed for auto login
333 $this->redirectToURL = 'index.php?commandLI=setCookie';
334 }
335 $redirectToUrl = (string)($backendUser->getTSConfig()['auth.']['BE.']['redirectToURL'] ?? '');
336 if (empty($redirectToUrl)) {
337 // Based on the interface we set the redirect script
338 $parsedBody = $request->getParsedBody();
339 $queryParams = $request->getQueryParams();
340 $interface = $parsedBody['interface'] ?? $queryParams['interface'] ?? '';
341 switch ($interface) {
342 case 'frontend':
343 $this->redirectToURL = '../';
344 break;
345 case 'backend':
346 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
347 $this->redirectToURL = (string)$uriBuilder->buildUriFromRoute('main');
348 break;
349 }
350 } else {
351 $this->redirectToURL = $redirectToUrl;
352 $interface = '';
353 }
354 // store interface
355 $backendUser->uc['interfaceSetup'] = $interface;
356 $backendUser->writeUC();
357
358 $formProtection = FormProtectionFactory::get();
359 if (!$formProtection instanceof BackendFormProtection) {
360 throw new \RuntimeException('The Form Protection retrieved does not match the expected one.', 1432080411);
361 }
362 if ($this->loginRefresh) {
363 $formProtection->setSessionTokenFromRegistry();
364 $formProtection->persistSessionToken();
365 $this->getDocumentTemplate()->JScode .= GeneralUtility::wrapJS('
366 if (window.opener && window.opener.TYPO3 && window.opener.TYPO3.LoginRefresh) {
367 window.opener.TYPO3.LoginRefresh.startTask();
368 window.close();
369 }
370 ');
371 } else {
372 $formProtection->storeSessionTokenInRegistry();
373 $this->redirectToUrl();
374 }
375 }
376
377 /**
378 * Making interface selector
379 *
380 * @deprecated since v9, will be removed in v10
381 */
382 public function makeInterfaceSelectorBox(): void
383 {
384 trigger_error('Method makeInterfaceSelectorBox() will be replaced by protected method makeInterfaceSelector() in v10. Do not call from other extension', E_USER_DEPRECATED);
385 $this->makeInterfaceSelector($GLOBALS['TYPO3_REQUEST']);
386 }
387
388 /**
389 * Making interface selector
390 * @param ServerRequestInterface $request
391 */
392 protected function makeInterfaceSelector(ServerRequestInterface $request): void
393 {
394 // If interfaces are defined AND no input redirect URL in GET vars:
395 if ($GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces'] && ($this->isLoginInProgress($request) || !$this->redirectUrl)) {
396 $parts = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces']);
397 if (count($parts) > 1) {
398 // Only if more than one interface is defined we will show the selector
399 $uriBuilder = GeneralUtility::makeInstance(UriBuilder::class);
400 $interfaces = [
401 'backend' => [
402 'label' => $this->getLanguageService()->getLL('interface.backend'),
403 'jumpScript' => (string)$uriBuilder->buildUriFromRoute('main'),
404 'interface' => 'backend'
405 ],
406 'frontend' => [
407 'label' => $this->getLanguageService()->getLL('interface.frontend'),
408 'jumpScript' => '../',
409 'interface' => 'frontend'
410 ]
411 ];
412
413 $this->view->assign('showInterfaceSelector', true);
414 $this->view->assign('interfaces', $interfaces);
415 } elseif (!$this->redirectUrl) {
416 // If there is only ONE interface value set and no redirect_url is present
417 $this->view->assign('showInterfaceSelector', false);
418 $this->view->assign('interface', $parts[0]);
419 }
420 }
421 }
422
423 /**
424 * Gets news from sys_news and converts them into a format suitable for
425 * showing them at the login screen.
426 *
427 * @return array An array of login news.
428 */
429 protected function getSystemNews(): array
430 {
431 $systemNewsTable = 'sys_news';
432 $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
433 ->getQueryBuilderForTable($systemNewsTable);
434 $systemNews = [];
435 $systemNewsRecords = $queryBuilder
436 ->select('title', 'content', 'crdate')
437 ->from($systemNewsTable)
438 ->orderBy('crdate', 'DESC')
439 ->execute()
440 ->fetchAll();
441 foreach ($systemNewsRecords as $systemNewsRecord) {
442 $systemNews[] = [
443 'date' => date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], (int)$systemNewsRecord['crdate']),
444 'header' => $systemNewsRecord['title'],
445 'content' => $systemNewsRecord['content']
446 ];
447 }
448 return $systemNews;
449 }
450
451 /**
452 * Returns the uri of a relative reference, resolves the "EXT:" prefix
453 * (way of referring to files inside extensions) and checks that the file is inside
454 * the project root of the TYPO3 installation
455 *
456 * @param string $filename The input filename/filepath to evaluate
457 * @return string Returns the filename of $filename if valid, otherwise blank string.
458 * @internal
459 */
460 private function getUriForFileName($filename): string
461 {
462 // Check if it's already a URL
463 if (preg_match('/^(https?:)?\/\//', $filename)) {
464 return $filename;
465 }
466 $absoluteFilename = GeneralUtility::getFileAbsFileName(ltrim($filename, '/'));
467 $filename = '';
468 if ($absoluteFilename !== '' && @is_file($absoluteFilename)) {
469 $filename = PathUtility::getAbsoluteWebPath($absoluteFilename);
470 }
471 return $filename;
472 }
473
474 /**
475 * Checks if login credentials are currently submitted
476 *
477 * @param ServerRequestInterface $request
478 * @return bool
479 */
480 protected function isLoginInProgress(ServerRequestInterface $request): bool
481 {
482 $parsedBody = $request->getParsedBody();
483 $queryParams = $request->getQueryParams();
484 $username = $parsedBody['username'] ?? $queryParams['username'] ?? null;
485 return !empty($username) || !empty($this->submitValue);
486 }
487
488 /**
489 * returns a new standalone view, shorthand function
490 *
491 * @return StandaloneView
492 */
493 protected function getFluidTemplateObject()
494 {
495 /** @var StandaloneView $view */
496 $view = GeneralUtility::makeInstance(StandaloneView::class);
497 $view->setLayoutRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Layouts')]);
498 $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
499 $view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
500
501 $view->getRequest()->setControllerExtensionName('Backend');
502 return $view;
503 }
504
505 /**
506 * Wrapper method to redirect to configured redirect URL
507 */
508 protected function redirectToUrl(): void
509 {
510 HttpUtility::redirect($this->redirectToURL);
511 }
512
513 /**
514 * Validates the registered login providers
515 *
516 * @throws \RuntimeException
517 */
518 protected function validateAndSortLoginProviders()
519 {
520 $providers = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'] ?? [];
521 if (empty($providers) || !is_array($providers)) {
522 throw new \RuntimeException('No login providers are registered in $GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'backend\'][\'loginProviders\'].', 1433417281);
523 }
524 foreach ($providers as $identifier => $configuration) {
525 if (empty($configuration) || !is_array($configuration)) {
526 throw new \RuntimeException('Missing configuration for login provider "' . $identifier . '".', 1433416043);
527 }
528 if (!is_string($configuration['provider']) || empty($configuration['provider']) || !class_exists($configuration['provider']) || !is_subclass_of($configuration['provider'], LoginProviderInterface::class)) {
529 throw new \RuntimeException('The login provider "' . $identifier . '" defines an invalid provider. Ensure the class exists and implements the "' . LoginProviderInterface::class . '".', 1460977275);
530 }
531 if (empty($configuration['label'])) {
532 throw new \RuntimeException('Missing label definition for login provider "' . $identifier . '".', 1433416044);
533 }
534 if (empty($configuration['icon-class'])) {
535 throw new \RuntimeException('Missing icon definition for login provider "' . $identifier . '".', 1433416045);
536 }
537 if (!isset($configuration['sorting'])) {
538 throw new \RuntimeException('Missing sorting definition for login provider "' . $identifier . '".', 1433416046);
539 }
540 }
541 // sort providers
542 uasort($providers, function ($a, $b) {
543 return $b['sorting'] - $a['sorting'];
544 });
545 $this->loginProviders = $providers;
546 }
547
548 /**
549 * Detect the login provider, get from request or choose the
550 * first one as default
551 *
552 * @param ServerRequestInterface $request
553 * @return string
554 */
555 protected function detectLoginProvider(ServerRequestInterface $request): string
556 {
557 $parsedBody = $request->getParsedBody();
558 $queryParams = $request->getQueryParams();
559 $loginProvider = $parsedBody['loginProvider'] ?? $queryParams['loginProvider'] ?? '';
560 if ((empty($loginProvider) || !isset($this->loginProviders[$loginProvider])) && !empty($_COOKIE['be_lastLoginProvider'])) {
561 $loginProvider = $_COOKIE['be_lastLoginProvider'];
562 }
563 if (empty($loginProvider) || !isset($this->loginProviders[$loginProvider])) {
564 reset($this->loginProviders);
565 $loginProvider = key($this->loginProviders);
566 }
567 // Use the secure option when the current request is served by a secure connection:
568 $normalizedParams = $request->getAttribute('normalizedParams');
569 $isHttps = $normalizedParams->isHttps();
570 $cookieSecure = (bool)$GLOBALS['TYPO3_CONF_VARS']['SYS']['cookieSecure'] && $isHttps;
571 setcookie('be_lastLoginProvider', (string)$loginProvider, $GLOBALS['EXEC_TIME'] + 7776000, '', '', $cookieSecure, true); // 90 days
572 return (string)$loginProvider;
573 }
574
575 /**
576 * @return string
577 */
578 public function getLoginProviderIdentifier()
579 {
580 return $this->loginProviderIdentifier;
581 }
582
583 /**
584 * Returns LanguageService
585 *
586 * @return LanguageService
587 */
588 protected function getLanguageService(): LanguageService
589 {
590 return $GLOBALS['LANG'];
591 }
592
593 /**
594 * @return BackendUserAuthentication
595 */
596 protected function getBackendUserAuthentication(): BackendUserAuthentication
597 {
598 return $GLOBALS['BE_USER'];
599 }
600
601 /**
602 * Returns an instance of DocumentTemplate
603 *
604 * @return DocumentTemplate
605 */
606 protected function getDocumentTemplate(): DocumentTemplate
607 {
608 return $GLOBALS['TBE_TEMPLATE'];
609 }
610 }