TYPO3 CMS  TYPO3_8-7
LoginController.php
Go to the documentation of this file.
1 <?php
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 
32 
37 {
43  protected $redirectUrl;
44 
50  protected $redirectToURL;
51 
57  protected $loginProviderIdentifier = null;
58 
64  protected $loginProviders = [];
65 
73  protected $loginRefresh;
74 
80  protected $submitValue;
81 
85  protected $view;
86 
90  public function __construct()
91  {
93 
94  // We need a PHP session session for most login levels
95  session_start();
96  $this->redirectUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('redirect_url'));
97  $this->loginProviderIdentifier = $this->detectLoginProvider();
98 
99  $this->loginRefresh = (bool)GeneralUtility::_GP('loginRefresh');
100  // Value of "Login" button. If set, the login button was pressed.
101  $this->submitValue = GeneralUtility::_GP('commandLI');
102 
103  // Try to get the preferred browser language
105  $locales = GeneralUtility::makeInstance(Locales::class);
106  $preferredBrowserLanguage = $locales
107  ->getPreferredClientLanguage(GeneralUtility::getIndpEnv('HTTP_ACCEPT_LANGUAGE'));
108 
109  // If we found a $preferredBrowserLanguage and it is not the default language and no be_user is logged in
110  // initialize $this->getLanguageService() again with $preferredBrowserLanguage
111  if ($preferredBrowserLanguage !== 'default' && empty($this->getBackendUserAuthentication()->user['uid'])) {
112  $this->getLanguageService()->init($preferredBrowserLanguage);
113  GeneralUtility::makeInstance(PageRenderer::class)->setLanguage($preferredBrowserLanguage);
114  }
115 
116  $this->getLanguageService()->includeLLFile('EXT:lang/Resources/Private/Language/locallang_login.xlf');
117 
118  // Setting the redirect URL to "index.php?M=main" if no alternative input is given
119  $this->redirectToURL = $this->redirectUrl ?: BackendUtility::getModuleUrl('main');
120 
121  // If "L" is "OUT", then any logged in is logged out. If redirect_url is given, we redirect to it
122  if (GeneralUtility::_GP('L') === 'OUT' && is_object($this->getBackendUserAuthentication())) {
123  $this->getBackendUserAuthentication()->logoff();
124  HttpUtility::redirect($this->redirectUrl);
125  }
126 
127  $this->view = $this->getFluidTemplateObject();
128  }
129 
138  public function formAction(ServerRequestInterface $request, ResponseInterface $response)
139  {
140  $content = $this->main();
141  $response->getBody()->write($content);
142  return $response;
143  }
144 
151  public function main()
152  {
154  $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
155  $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Login');
156 
157  // Checking, if we should make a redirect.
158  // Might set JavaScript in the header to close window.
159  $this->checkRedirect();
160 
161  // Extension Configuration
162  $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['backend'], ['allowed_classes' => false]);
163 
164  // Background Image
165  if (!empty($extConf['loginBackgroundImage'])) {
166  $backgroundImage = $this->getUriForFileName($extConf['loginBackgroundImage']);
167  $this->getDocumentTemplate()->inDocStylesArray[] = '
168  @media (min-width: 768px){
169  .typo3-login-carousel-control.right,
170  .typo3-login-carousel-control.left,
171  .panel-login { border: 0; }
172  .typo3-login { background-image: url("' . $backgroundImage . '"); }
173  }
174  ';
175  }
176 
177  // Add additional css to use the highlight color in the login screen
178  if (!empty($extConf['loginHighlightColor'])) {
179  $this->getDocumentTemplate()->inDocStylesArray[] = '
180  .btn-login.disabled, .btn-login[disabled], fieldset[disabled] .btn-login,
181  .btn-login.disabled:hover, .btn-login[disabled]:hover, fieldset[disabled] .btn-login:hover,
182  .btn-login.disabled:focus, .btn-login[disabled]:focus, fieldset[disabled] .btn-login:focus,
183  .btn-login.disabled.focus, .btn-login[disabled].focus, fieldset[disabled] .btn-login.focus,
184  .btn-login.disabled:active, .btn-login[disabled]:active, fieldset[disabled] .btn-login:active,
185  .btn-login.disabled.active, .btn-login[disabled].active, fieldset[disabled] .btn-login.active,
186  .btn-login:hover, .btn-login:focus, .btn-login:active,
187  .btn-login:active:hover, .btn-login:active:focus,
188  .btn-login { background-color: ' . $extConf['loginHighlightColor'] . '; }
189  .panel-login .panel-body { border-color: ' . $extConf['loginHighlightColor'] . '; }
190  ';
191  }
192 
193  // Logo
194  if (!empty($extConf['loginLogo'])) {
195  $logo = $extConf['loginLogo'];
196  } else {
197  // Use TYPO3 logo depending on highlight color
198  if (!empty($extConf['loginHighlightColor'])) {
199  $logo = 'EXT:backend/Resources/Public/Images/typo3_black.svg';
200  } else {
201  $logo = 'EXT:backend/Resources/Public/Images/typo3_orange.svg';
202  }
203  $this->getDocumentTemplate()->inDocStylesArray[] = '
204  .typo3-login-logo .typo3-login-image { max-width: 150px; height:100%;}
205  ';
206  }
207  $logo = $this->getUriForFileName($logo);
208 
209  // Start form
210  $formType = empty($this->getBackendUserAuthentication()->user['uid']) ? 'LoginForm' : 'LogoutForm';
211  $this->view->assignMultiple([
212  'backendUser' => $this->getBackendUserAuthentication()->user,
213  'hasLoginError' => $this->isLoginInProgress(),
214  'formType' => $formType,
215  'logo' => $logo,
216  'images' => [
217  'capslock' => $this->getUriForFileName('EXT:backend/Resources/Public/Images/icon_capslock.svg'),
218  'typo3' => $this->getUriForFileName('EXT:backend/Resources/Public/Images/typo3_orange.svg'),
219  ],
220  'copyright' => BackendUtility::TYPO3_copyRightNotice(),
221  'redirectUrl' => $this->redirectUrl,
222  'loginNewsItems' => $this->getSystemNews(),
223  'loginProviderIdentifier' => $this->loginProviderIdentifier,
224  'loginProviders' => $this->loginProviders
225  ]);
226 
227  // Initialize interface selectors:
228  $this->makeInterfaceSelectorBox();
229 
231  $loginProvider = GeneralUtility::makeInstance($this->loginProviders[$this->loginProviderIdentifier]['provider']);
232  $loginProvider->render($this->view, $pageRenderer, $this);
233 
234  $content = $this->getDocumentTemplate()->startPage('TYPO3 CMS Login: ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
235  $content .= $this->view->render();
236  $content .= $this->getDocumentTemplate()->endPage();
237 
238  return $content;
239  }
240 
253  protected function checkRedirect()
254  {
255  if (
256  empty($this->getBackendUserAuthentication()->user['uid'])
257  && ($this->isLoginInProgress() || !$this->loginRefresh)
258  ) {
259  return;
260  }
261 
262  /*
263  * If no cookie has been set previously, we tell people that this is a problem.
264  * This assumes that a cookie-setting script (like this one) has been hit at
265  * least once prior to this instance.
266  */
267  if (!$_COOKIE[BackendUserAuthentication::getCookieName()]) {
268  if ($this->submitValue === 'setCookie') {
269  /*
270  * we tried it a second time but still no cookie
271  * 26/4 2005: This does not work anymore, because the saving of challenge values
272  * in $_SESSION means the system will act as if the password was wrong.
273  */
274  throw new \RuntimeException('Login-error: Yeah, that\'s a classic. No cookies, no TYPO3. ' .
275  'Please accept cookies from TYPO3 - otherwise you\'ll not be able to use the system.', 1294586846);
276  }
277  // try it once again - that might be needed for auto login
278  $this->redirectToURL = 'index.php?commandLI=setCookie';
279  }
280  $redirectToUrl = (string)$this->getBackendUserAuthentication()->getTSConfigVal('auth.BE.redirectToURL');
281  if (empty($redirectToUrl)) {
282  // Based on the interface we set the redirect script
283  switch (GeneralUtility::_GP('interface')) {
284  case 'frontend':
285  $interface = 'frontend';
286  $this->redirectToURL = '../';
287  break;
288  case 'backend':
289  $interface = 'backend';
290  $this->redirectToURL = BackendUtility::getModuleUrl('main');
291  break;
292  default:
293  $interface = '';
294  }
295  } else {
296  $this->redirectToURL = $redirectToUrl;
297  $interface = '';
298  }
299  // store interface
300  $this->getBackendUserAuthentication()->uc['interfaceSetup'] = $interface;
301  $this->getBackendUserAuthentication()->writeUC();
302 
303  $formProtection = FormProtectionFactory::get();
304  if (!$formProtection instanceof BackendFormProtection) {
305  throw new \RuntimeException('The Form Protection retrieved does not match the expected one.', 1432080411);
306  }
307  if ($this->loginRefresh) {
308  $formProtection->setSessionTokenFromRegistry();
309  $formProtection->persistSessionToken();
310  $this->getDocumentTemplate()->JScode .= GeneralUtility::wrapJS('
311  if (parent.opener && parent.opener.TYPO3 && parent.opener.TYPO3.LoginRefresh) {
312  parent.opener.TYPO3.LoginRefresh.startTask();
313  parent.close();
314  }
315  ');
316  } else {
317  $formProtection->storeSessionTokenInRegistry();
318  HttpUtility::redirect($this->redirectToURL);
319  }
320  }
321 
325  public function makeInterfaceSelectorBox()
326  {
327  // If interfaces are defined AND no input redirect URL in GET vars:
328  if ($GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces'] && ($this->isLoginInProgress() || !$this->redirectUrl)) {
329  $parts = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces']);
330  if (count($parts) > 1) {
331  // Only if more than one interface is defined we will show the selector
332  $interfaces = [
333  'backend' => [
334  'label' => $this->getLanguageService()->getLL('interface.backend'),
335  'jumpScript' => BackendUtility::getModuleUrl('main'),
336  'interface' => 'backend'
337  ],
338  'frontend' => [
339  'label' => $this->getLanguageService()->getLL('interface.frontend'),
340  'jumpScript' => '../',
341  'interface' => 'frontend'
342  ]
343  ];
344 
345  $this->view->assign('showInterfaceSelector', true);
346  $this->view->assign('interfaces', $interfaces);
347  } elseif (!$this->redirectUrl) {
348  // If there is only ONE interface value set and no redirect_url is present
349  $this->view->assign('showInterfaceSelector', false);
350  $this->view->assign('interface', $parts[0]);
351  }
352  }
353  }
354 
361  protected function getSystemNews()
362  {
363  $systemNewsTable = 'sys_news';
364  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
365  ->getQueryBuilderForTable($systemNewsTable);
366  $systemNews = [];
367  $systemNewsRecords = $queryBuilder
368  ->select('title', 'content', 'crdate')
369  ->from($systemNewsTable)
370  ->orderBy('crdate', 'DESC')
371  ->execute()
372  ->fetchAll();
373  foreach ($systemNewsRecords as $systemNewsRecord) {
374  $systemNews[] = [
375  'date' => date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], (int)$systemNewsRecord['crdate']),
376  'header' => $systemNewsRecord['title'],
377  'content' => $systemNewsRecord['content']
378  ];
379  }
380  return $systemNews;
381  }
382 
392  private function getUriForFileName($filename)
393  {
394  if (strpos($filename, '://')) {
395  return $filename;
396  }
397  $urlPrefix = '';
398  if (strpos($filename, 'EXT:') === 0) {
399  $absoluteFilename = GeneralUtility::getFileAbsFileName($filename);
400  $filename = '';
401  if ($absoluteFilename !== '') {
402  $filename = PathUtility::getAbsoluteWebPath($absoluteFilename);
403  }
404  } elseif (strpos($filename, '/') !== 0) {
405  $urlPrefix = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
406  }
407  return $urlPrefix . $filename;
408  }
409 
415  protected function isLoginInProgress()
416  {
417  $username = GeneralUtility::_GP('username');
418  return !empty($username) || !empty($this->submitValue);
419  }
420 
426  protected function getFluidTemplateObject()
427  {
429  $view = GeneralUtility::makeInstance(StandaloneView::class);
430  $view->setLayoutRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Layouts')]);
431  $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
432  $view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
433 
434  $view->getRequest()->setControllerExtensionName('Backend');
435  return $view;
436  }
437 
443  protected function validateAndSortLoginProviders()
444  {
445  if (
446  !isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'])
447  || !is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'])
448  || empty($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'])
449  ) {
450  throw new \RuntimeException('No login providers are registered in $GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'backend\'][\'loginProviders\'].', 1433417281);
451  }
452  $providers = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'];
453  foreach ($providers as $identifier => $configuration) {
454  if (empty($configuration) || !is_array($configuration)) {
455  throw new \RuntimeException('Missing configuration for login provider "' . $identifier . '".', 1433416043);
456  }
457  if (!is_string($configuration['provider']) || empty($configuration['provider']) || !class_exists($configuration['provider']) || !is_subclass_of($configuration['provider'], LoginProviderInterface::class)) {
458  throw new \RuntimeException('The login provider "' . $identifier . '" defines an invalid provider. Ensure the class exists and implements the "' . LoginProviderInterface::class . '".', 1460977275);
459  }
460  if (empty($configuration['label'])) {
461  throw new \RuntimeException('Missing label definition for login provider "' . $identifier . '".', 1433416044);
462  }
463  if (empty($configuration['icon-class'])) {
464  throw new \RuntimeException('Missing icon definition for login provider "' . $identifier . '".', 1433416045);
465  }
466  if (!isset($configuration['sorting'])) {
467  throw new \RuntimeException('Missing sorting definition for login provider "' . $identifier . '".', 1433416046);
468  }
469  }
470  // sort providers
471  uasort($providers, function ($a, $b) {
472  return $b['sorting'] - $a['sorting'];
473  });
474  $this->loginProviders = $providers;
475  }
476 
483  protected function detectLoginProvider()
484  {
485  $loginProvider = GeneralUtility::_GP('loginProvider');
486  if ((empty($loginProvider) || !isset($this->loginProviders[$loginProvider])) && !empty($_COOKIE['be_lastLoginProvider'])) {
487  $loginProvider = $_COOKIE['be_lastLoginProvider'];
488  }
489  if (empty($loginProvider) || !isset($this->loginProviders[$loginProvider])) {
490  reset($this->loginProviders);
491  $loginProvider = key($this->loginProviders);
492  }
493  // Use the secure option when the current request is served by a secure connection:
494  $cookieSecure = (bool)$GLOBALS['TYPO3_CONF_VARS']['SYS']['cookieSecure'] && GeneralUtility::getIndpEnv('TYPO3_SSL');
495  setcookie('be_lastLoginProvider', $loginProvider, $GLOBALS['EXEC_TIME'] + 7776000, null, null, $cookieSecure, true); // 90 days
496  return $loginProvider;
497  }
498 
502  public function getLoginProviderIdentifier()
503  {
505  }
506 
512  protected function getLanguageService()
513  {
514  return $GLOBALS['LANG'];
515  }
516 
520  protected function getBackendUserAuthentication()
521  {
522  return $GLOBALS['BE_USER'];
523  }
524 
530  protected function getDocumentTemplate()
531  {
532  return $GLOBALS['TBE_TEMPLATE'];
533  }
534 }
formAction(ServerRequestInterface $request, ResponseInterface $response)
static getAbsoluteWebPath($targetPath)
Definition: PathUtility.php:40
static getFileAbsFileName($filename, $_=null, $_2=null)
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static makeInstance($className,... $constructorArguments)
static get($classNameOrType='default',... $constructorArguments)
$extConf
static redirect($url, $httpStatus=self::HTTP_STATUS_303)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
$locales
Definition: be_users.php:6