TYPO3 CMS  TYPO3_7-6
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 
30 
35 {
41  protected $redirectUrl;
42 
48  protected $redirectToURL;
49 
55  protected $loginProviderIdentifier = null;
56 
62  protected $loginProviders = [];
63 
71  protected $loginRefresh;
72 
78  protected $submitValue;
79 
83  protected $view;
84 
88  public function __construct()
89  {
91 
92  // We need a PHP session session for most login levels
93  session_start();
94  $this->redirectUrl = GeneralUtility::sanitizeLocalUrl(GeneralUtility::_GP('redirect_url'));
95  $this->loginProviderIdentifier = $this->detectLoginProvider();
96 
97  $this->loginRefresh = (bool)GeneralUtility::_GP('loginRefresh');
98  // Value of "Login" button. If set, the login button was pressed.
99  $this->submitValue = GeneralUtility::_GP('commandLI');
100 
101  // Try to get the preferred browser language
102  $preferredBrowserLanguage = $this->getLanguageService()->csConvObj
103  ->getPreferredClientLanguage(GeneralUtility::getIndpEnv('HTTP_ACCEPT_LANGUAGE'));
104 
105  // If we found a $preferredBrowserLanguage and it is not the default language and no be_user is logged in
106  // initialize $this->getLanguageService() again with $preferredBrowserLanguage
107  if ($preferredBrowserLanguage !== 'default' && empty($this->getBackendUserAuthentication()->user['uid'])) {
108  $this->getLanguageService()->init($preferredBrowserLanguage);
109  GeneralUtility::makeInstance(PageRenderer::class)->setLanguage($preferredBrowserLanguage);
110  }
111 
112  $this->getLanguageService()->includeLLFile('EXT:lang/locallang_login.xlf');
113 
114  // Setting the redirect URL to "index.php?M=main" if no alternative input is given
115  $this->redirectToURL = $this->redirectUrl ?: BackendUtility::getModuleUrl('main');
116 
117  // If "L" is "OUT", then any logged in is logged out. If redirect_url is given, we redirect to it
118  if (GeneralUtility::_GP('L') === 'OUT' && is_object($this->getBackendUserAuthentication())) {
119  $this->getBackendUserAuthentication()->logoff();
120  HttpUtility::redirect($this->redirectUrl);
121  }
122 
123  $this->view = $this->getFluidTemplateObject();
124  }
125 
134  public function formAction(ServerRequestInterface $request, ResponseInterface $response)
135  {
136  $content = $this->main();
137  $response->getBody()->write($content);
138  return $response;
139  }
140 
147  public function main()
148  {
150  $pageRenderer = GeneralUtility::makeInstance(PageRenderer::class);
151  $pageRenderer->loadRequireJsModule('TYPO3/CMS/Backend/Login');
152 
153  // support placeholders for IE9 and lower
154  $clientInfo = GeneralUtility::clientInfo();
155  if ($clientInfo['BROWSER'] === 'msie' && $clientInfo['VERSION'] <= 9) {
156  $pageRenderer->addJsLibrary('placeholders', 'sysext/core/Resources/Public/JavaScript/Contrib/placeholders.min.js');
157  }
158 
159  // Checking, if we should make a redirect.
160  // Might set JavaScript in the header to close window.
161  $this->checkRedirect();
162 
163  // Extension Configuration
164  $extConf = unserialize($GLOBALS['TYPO3_CONF_VARS']['EXT']['extConf']['backend']);
165 
166  // Background Image
167  if (!empty($extConf['loginBackgroundImage'])) {
168  $backgroundImage = $this->getUriForFileName($extConf['loginBackgroundImage']);
169  $this->getDocumentTemplate()->inDocStylesArray[] = '
170  @media (min-width: 768px){
171  .typo3-login-carousel-control.right,
172  .typo3-login-carousel-control.left,
173  .panel-login { border: 0; }
174  .typo3-login { background-image: url("' . $backgroundImage . '"); }
175  }
176  ';
177  }
178 
179  // Add additional css to use the highlight color in the login screen
180  if (!empty($extConf['loginHighlightColor'])) {
181  $this->getDocumentTemplate()->inDocStylesArray[] = '
182  .btn-login.disabled, .btn-login[disabled], fieldset[disabled] .btn-login,
183  .btn-login.disabled:hover, .btn-login[disabled]:hover, fieldset[disabled] .btn-login:hover,
184  .btn-login.disabled:focus, .btn-login[disabled]:focus, fieldset[disabled] .btn-login:focus,
185  .btn-login.disabled.focus, .btn-login[disabled].focus, fieldset[disabled] .btn-login.focus,
186  .btn-login.disabled:active, .btn-login[disabled]:active, fieldset[disabled] .btn-login:active,
187  .btn-login.disabled.active, .btn-login[disabled].active, fieldset[disabled] .btn-login.active,
188  .btn-login:hover, .btn-login:focus, .btn-login:active,
189  .btn-login:active:hover, .btn-login:active:focus,
190  .btn-login { background-color: ' . $extConf['loginHighlightColor'] . '; }
191  .panel-login .panel-body { border-color: ' . $extConf['loginHighlightColor'] . '; }
192  ';
193  }
194 
195  // Logo
196  if (!empty($extConf['loginLogo'])) {
197  $logo = $extConf['loginLogo'];
198  } elseif (!empty($GLOBALS['TBE_STYLES']['logo_login'])) {
199  // Fallback to old TBE_STYLES login logo
200  $logo = $GLOBALS['TBE_STYLES']['logo_login'];
201  GeneralUtility::deprecationLog('$GLOBALS["TBE_STYLES"]["logo_login"] is deprecated since TYPO3 CMS 7 and will be removed in TYPO3 CMS 8, please use the backend extension\'s configuration instead.');
202  } else {
203  // Use TYPO3 logo depending on highlight color
204  if (!empty($extConf['loginHighlightColor'])) {
205  $logo = 'EXT:backend/Resources/Public/Images/typo3_black.svg';
206  } else {
207  $logo = 'EXT:backend/Resources/Public/Images/typo3_orange.svg';
208  }
209  $this->getDocumentTemplate()->inDocStylesArray[] = '
210  .typo3-login-logo .typo3-login-image { max-width: 150px; }
211  ';
212  }
213  $logo = $this->getUriForFileName($logo);
214 
215  // Start form
216  $formType = empty($this->getBackendUserAuthentication()->user['uid']) ? 'LoginForm' : 'LogoutForm';
217  $this->view->assignMultiple([
218  'backendUser' => $this->getBackendUserAuthentication()->user,
219  'hasLoginError' => $this->isLoginInProgress(),
220  'formType' => $formType,
221  'logo' => $logo,
222  'images' => [
223  'capslock' => $this->getUriForFileName('EXT:backend/Resources/Public/Images/icon_capslock.svg'),
224  'typo3' => $this->getUriForFileName('EXT:backend/Resources/Public/Images/typo3_orange.svg'),
225  ],
226  'copyright' => BackendUtility::TYPO3_copyRightNotice(),
227  'redirectUrl' => $this->redirectUrl,
228  'loginNewsItems' => $this->getSystemNews(),
229  'loginProviderIdentifier' => $this->loginProviderIdentifier,
230  'loginProviders' => $this->loginProviders
231  ]);
232 
233  // Initialize interface selectors:
234  $this->makeInterfaceSelectorBox();
235 
237  $loginProvider = GeneralUtility::makeInstance($this->loginProviders[$this->loginProviderIdentifier]['provider']);
238  $loginProvider->render($this->view, $pageRenderer, $this);
239 
240  $content = $this->getDocumentTemplate()->startPage('TYPO3 CMS Login: ' . $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename']);
241  $content .= $this->view->render();
242  $content .= $this->getDocumentTemplate()->endPage();
243 
244  return $content;
245  }
246 
259  protected function checkRedirect()
260  {
261  if (
262  empty($this->getBackendUserAuthentication()->user['uid'])
263  && ($this->isLoginInProgress() || !$this->loginRefresh)
264  ) {
265  return;
266  }
267 
268  /*
269  * If no cookie has been set previously, we tell people that this is a problem.
270  * This assumes that a cookie-setting script (like this one) has been hit at
271  * least once prior to this instance.
272  */
273  if (!$_COOKIE[BackendUserAuthentication::getCookieName()]) {
274  if ($this->submitValue === 'setCookie') {
275  /*
276  * we tried it a second time but still no cookie
277  * 26/4 2005: This does not work anymore, because the saving of challenge values
278  * in $_SESSION means the system will act as if the password was wrong.
279  */
280  throw new \RuntimeException('Login-error: Yeah, that\'s a classic. No cookies, no TYPO3. ' .
281  'Please accept cookies from TYPO3 - otherwise you\'ll not be able to use the system.', 1294586846);
282  } else {
283  // try it once again - that might be needed for auto login
284  $this->redirectToURL = 'index.php?commandLI=setCookie';
285  }
286  }
287  $redirectToUrl = (string)$this->getBackendUserAuthentication()->getTSConfigVal('auth.BE.redirectToURL');
288  if (empty($redirectToUrl)) {
289  // Based on the interface we set the redirect script
290  switch (GeneralUtility::_GP('interface')) {
291  case 'frontend':
292  $interface = 'frontend';
293  $this->redirectToURL = '../';
294  break;
295  case 'backend':
296  $interface = 'backend';
297  $this->redirectToURL = BackendUtility::getModuleUrl('main');
298  break;
299  default:
300  $interface = '';
301  }
302  } else {
303  $this->redirectToURL = $redirectToUrl;
304  $interface = '';
305  }
306  // store interface
307  $this->getBackendUserAuthentication()->uc['interfaceSetup'] = $interface;
308  $this->getBackendUserAuthentication()->writeUC();
309 
310  $formProtection = FormProtectionFactory::get();
311  if (!$formProtection instanceof BackendFormProtection) {
312  throw new \RuntimeException('The Form Protection retrieved does not match the expected one.', 1432080411);
313  }
314  if ($this->loginRefresh) {
315  $formProtection->setSessionTokenFromRegistry();
316  $formProtection->persistSessionToken();
317  $this->getDocumentTemplate()->JScode .= $this->getDocumentTemplate()->wrapScriptTags('
318  if (parent.opener && parent.opener.TYPO3 && parent.opener.TYPO3.LoginRefresh) {
319  parent.opener.TYPO3.LoginRefresh.startTask();
320  parent.close();
321  }
322  ');
323  } else {
324  $formProtection->storeSessionTokenInRegistry();
325  HttpUtility::redirect($this->redirectToURL);
326  }
327  }
328 
334  public function makeInterfaceSelectorBox()
335  {
336  // If interfaces are defined AND no input redirect URL in GET vars:
337  if ($GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces'] && ($this->isLoginInProgress() || !$this->redirectUrl)) {
338  $parts = GeneralUtility::trimExplode(',', $GLOBALS['TYPO3_CONF_VARS']['BE']['interfaces']);
339  if (count($parts) > 1) {
340  // Only if more than one interface is defined we will show the selector
341  $interfaces = [
342  'backend' => [
343  'label' => $this->getLanguageService()->getLL('interface.backend'),
344  'jumpScript' => BackendUtility::getModuleUrl('main'),
345  'interface' => 'backend'
346  ],
347  'frontend' => [
348  'label' => $this->getLanguageService()->getLL('interface.frontend'),
349  'jumpScript' => '../',
350  'interface' => 'frontend'
351  ]
352  ];
353 
354  $this->view->assign('showInterfaceSelector', true);
355  $this->view->assign('interfaces', $interfaces);
356  } elseif (!$this->redirectUrl) {
357  // If there is only ONE interface value set and no redirect_url is present
358  $this->view->assign('showInterfaceSelector', false);
359  $this->view->assign('interface', $parts[0]);
360  }
361  }
362  }
363 
370  protected function getSystemNews()
371  {
372  $systemNewsTable = 'sys_news';
373  $systemNews = [];
374  $systemNewsRecords = $this->getDatabaseConnection()->exec_SELECTgetRows('title, content, crdate', $systemNewsTable, '1=1' . BackendUtility::BEenableFields($systemNewsTable) . BackendUtility::deleteClause($systemNewsTable), '', 'crdate DESC');
375  foreach ($systemNewsRecords as $systemNewsRecord) {
376  $systemNews[] = [
377  'date' => date($GLOBALS['TYPO3_CONF_VARS']['SYS']['ddmmyy'], $systemNewsRecord['crdate']),
378  'header' => $systemNewsRecord['title'],
379  'content' => $systemNewsRecord['content']
380  ];
381  }
382  return $systemNews;
383  }
384 
394  private function getUriForFileName($filename)
395  {
396  if (strpos($filename, '://')) {
397  return $filename;
398  }
399  $urlPrefix = '';
400  if (strpos($filename, 'EXT:') === 0) {
401  $absoluteFilename = GeneralUtility::getFileAbsFileName($filename);
402  $filename = '';
403  if ($absoluteFilename !== '') {
404  $filename = PathUtility::getAbsoluteWebPath($absoluteFilename);
405  }
406  } elseif (strpos($filename, '/') !== 0) {
407  $urlPrefix = GeneralUtility::getIndpEnv('TYPO3_SITE_PATH');
408  }
409  return $urlPrefix . $filename;
410  }
411 
417  protected function isLoginInProgress()
418  {
419  $username = GeneralUtility::_GP('username');
420  return !empty($username) || !empty($this->submitValue);
421  }
422 
428  protected function getFluidTemplateObject()
429  {
431  $view = GeneralUtility::makeInstance(StandaloneView::class);
432  $view->setLayoutRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Layouts')]);
433  $view->setPartialRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Partials')]);
434  $view->setTemplateRootPaths([GeneralUtility::getFileAbsFileName('EXT:backend/Resources/Private/Templates')]);
435 
436  $view->getRequest()->setControllerExtensionName('Backend');
437  return $view;
438  }
439 
445  protected function validateAndSortLoginProviders()
446  {
447  if (
448  !isset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'])
449  || !is_array($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'])
450  || empty($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'])
451  ) {
452  throw new \RuntimeException('No login providers are registered in $GLOBALS[\'TYPO3_CONF_VARS\'][\'EXTCONF\'][\'backend\'][\'loginProviders\'].', 1433417281);
453  }
454  $providers = $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'];
455  foreach ($providers as $identifier => $configuration) {
456  if (empty($configuration) || !is_array($configuration)) {
457  throw new \RuntimeException('Missing configuration for login provider "' . $identifier . '".', 1433416043);
458  }
459  if (!is_string($configuration['provider']) || empty($configuration['provider']) || !class_exists($configuration['provider']) || !is_subclass_of($configuration['provider'], LoginProviderInterface::class)) {
460  throw new \RuntimeException('The login provider "' . $identifier . '" defines an invalid provider. Ensure the class exists and implements the "' . LoginProviderInterface::class . '".', 1433416043);
461  }
462  if (empty($configuration['label'])) {
463  throw new \RuntimeException('Missing label definition for login provider "' . $identifier . '".', 1433416044);
464  }
465  if (empty($configuration['icon-class'])) {
466  throw new \RuntimeException('Missing icon definition for login provider "' . $identifier . '".', 1433416045);
467  }
468  if (!isset($configuration['sorting'])) {
469  throw new \RuntimeException('Missing sorting definition for login provider "' . $identifier . '".', 1433416046);
470  }
471  }
472  // sort providers
473  uasort($providers, function ($a, $b) {
474  return $b['sorting'] - $a['sorting'];
475  });
476  $this->loginProviders = $providers;
477  }
478 
485  protected function detectLoginProvider()
486  {
487  $loginProvider = GeneralUtility::_GP('loginProvider');
488  if ((empty($loginProvider) || !isset($this->loginProviders[$loginProvider])) && !empty($_COOKIE['be_lastLoginProvider'])) {
489  $loginProvider = $_COOKIE['be_lastLoginProvider'];
490  }
491  if (empty($loginProvider) || !isset($this->loginProviders[$loginProvider])) {
492  reset($this->loginProviders);
493  $loginProvider = key($this->loginProviders);
494  }
495  setcookie('be_lastLoginProvider', $loginProvider, $GLOBALS['EXEC_TIME'] + 7776000); // 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 getDatabaseConnection()
531  {
532  return $GLOBALS['TYPO3_DB'];
533  }
534 
540  protected function getDocumentTemplate()
541  {
542  return $GLOBALS['TBE_TEMPLATE'];
543  }
544 }
formAction(ServerRequestInterface $request, ResponseInterface $response)
static BEenableFields($table, $inv=false)
static getAbsoluteWebPath($targetPath)
Definition: PathUtility.php:40
static trimExplode($delim, $string, $removeEmptyValues=false, $limit=0)
static redirect($url, $httpStatus=self::HTTP_STATUS_303)
Definition: HttpUtility.php:76
static getFileAbsFileName($filename, $onlyRelative=true, $relToTYPO3_mainDir=false)
if(TYPO3_MODE==='BE') $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tsfebeuserauth.php']['frontendEditingController']['default']
$extConf
static deleteClause($table, $tableAlias='')