TYPO3 v15 dev-main snapshot ()
This commit is contained in:
@@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* This file is part of the TYPO3 CMS project.
|
||||
*
|
||||
* It is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, either version 2
|
||||
* of the License, or any later version.
|
||||
*
|
||||
* For the full copyright and license information, please read the
|
||||
* LICENSE.txt file that was distributed with this source code.
|
||||
*
|
||||
* The TYPO3 project - inspiring people to share!
|
||||
*/
|
||||
|
||||
namespace TYPO3\CMS\Backend\Controller;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use TYPO3\CMS\Backend\Attribute\AsController;
|
||||
use TYPO3\CMS\Backend\Authentication\PasswordReset;
|
||||
use TYPO3\CMS\Backend\Routing\RouteRedirect;
|
||||
use TYPO3\CMS\Backend\Routing\UriBuilder;
|
||||
use TYPO3\CMS\Backend\Template\PageRendererBackendSetupTrait;
|
||||
use TYPO3\CMS\Backend\View\AuthenticationStyleInformation;
|
||||
use TYPO3\CMS\Backend\View\BackendViewFactory;
|
||||
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
|
||||
use TYPO3\CMS\Core\Configuration\ExtensionConfiguration;
|
||||
use TYPO3\CMS\Core\Configuration\Features;
|
||||
use TYPO3\CMS\Core\Context\Context;
|
||||
use TYPO3\CMS\Core\Http\PropagateResponseException;
|
||||
use TYPO3\CMS\Core\Http\RedirectResponse;
|
||||
use TYPO3\CMS\Core\Information\Typo3Information;
|
||||
use TYPO3\CMS\Core\Localization\LanguageService;
|
||||
use TYPO3\CMS\Core\Localization\Locales;
|
||||
use TYPO3\CMS\Core\Page\PageRenderer;
|
||||
use TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyAction;
|
||||
use TYPO3\CMS\Core\PasswordPolicy\PasswordPolicyValidator;
|
||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||
use TYPO3\CMS\Core\View\ViewInterface;
|
||||
|
||||
/**
|
||||
* Controller responsible for rendering and processing backend user password reset requests.
|
||||
*
|
||||
* @internal This class is a specific Backend controller implementation and is not considered part of the Public TYPO3 API.
|
||||
*/
|
||||
#[AsController]
|
||||
class ResetPasswordController
|
||||
{
|
||||
use PageRendererBackendSetupTrait;
|
||||
|
||||
protected string $loginProvider = '';
|
||||
protected ViewInterface $view;
|
||||
|
||||
public function __construct(
|
||||
protected readonly Context $context,
|
||||
protected readonly Locales $locales,
|
||||
protected readonly Features $features,
|
||||
protected readonly UriBuilder $uriBuilder,
|
||||
protected readonly PageRenderer $pageRenderer,
|
||||
protected readonly PasswordReset $passwordReset,
|
||||
protected readonly Typo3Information $typo3Information,
|
||||
protected readonly AuthenticationStyleInformation $authenticationStyleInformation,
|
||||
protected readonly ExtensionConfiguration $extensionConfiguration,
|
||||
protected readonly BackendViewFactory $backendViewFactory,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Show a form to enter an email address to request a password reset email.
|
||||
*/
|
||||
public function forgetPasswordFormAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
if (!$this->passwordReset->isEnabled()) {
|
||||
return $this->redirectToLoginForm($request);
|
||||
}
|
||||
$this->initialize($request);
|
||||
$this->initializeForgetPasswordView($request);
|
||||
$this->pageRenderer->setBodyContent('<body>' . $this->view->render('Login/ForgetPasswordForm'));
|
||||
return $this->pageRenderer->renderResponse($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the email address.
|
||||
*
|
||||
* Restricted to POST method in Configuration/Backend/Routes.php
|
||||
*/
|
||||
public function initiatePasswordResetAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
if (!$this->passwordReset->isEnabled()) {
|
||||
return $this->redirectToLoginForm($request);
|
||||
}
|
||||
$this->initialize($request);
|
||||
$this->initializeForgetPasswordView($request);
|
||||
$emailAddress = $request->getParsedBody()['email'] ?? '';
|
||||
if (!is_string($emailAddress)) {
|
||||
$emailAddress = '';
|
||||
}
|
||||
$this->view->assign('email', $emailAddress);
|
||||
if (!GeneralUtility::validEmail($emailAddress)) {
|
||||
$this->view->assign('invalidEmail', true);
|
||||
} else {
|
||||
$this->passwordReset->initiateReset($request, $this->context, $emailAddress);
|
||||
$this->view->assign('resetInitiated', true);
|
||||
}
|
||||
$this->pageRenderer->setBodyContent('<body>' . $this->view->render('Login/ForgetPasswordForm'));
|
||||
// Prevent time based information disclosure by waiting a random time
|
||||
// before sending a response. This prevents that the response time
|
||||
// can be an indicator if the used email exists or not. Wait a random
|
||||
// time between 200 milliseconds and 3 seconds.
|
||||
usleep(random_int(200000, 3000000));
|
||||
return $this->pageRenderer->renderResponse($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the link and show a form to enter the new password.
|
||||
*/
|
||||
public function passwordResetAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
if (!$this->passwordReset->isEnabled()) {
|
||||
return $this->redirectToLoginForm($request);
|
||||
}
|
||||
$this->initialize($request);
|
||||
$this->initializeResetPasswordView($request);
|
||||
if (!$this->passwordReset->isValidResetTokenFromRequest($request)) {
|
||||
$this->view->assign('invalidToken', true);
|
||||
}
|
||||
$this->pageRenderer->setBodyContent('<body>' . $this->view->render('Login/ResetPasswordForm'));
|
||||
return $this->pageRenderer->renderResponse($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the password in the database.
|
||||
*
|
||||
* Restricted to POST method in Configuration/Backend/Routes.php
|
||||
*/
|
||||
public function passwordResetFinishAction(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
if (!$this->passwordReset->isEnabled()) {
|
||||
return $this->redirectToLoginForm($request);
|
||||
}
|
||||
// Token is invalid
|
||||
if (!$this->passwordReset->isValidResetTokenFromRequest($request)) {
|
||||
return $this->passwordResetAction($request);
|
||||
}
|
||||
$this->initialize($request);
|
||||
$this->initializeResetPasswordView($request);
|
||||
if ($this->passwordReset->resetPassword($request, $this->context)) {
|
||||
$this->view->assign('resetExecuted', true);
|
||||
} else {
|
||||
$this->view->assign('error', true);
|
||||
}
|
||||
$this->pageRenderer->setBodyContent('<body>' . $this->view->render('Login/ResetPasswordForm'));
|
||||
return $this->pageRenderer->renderResponse($request);
|
||||
}
|
||||
|
||||
private function redirectToLoginForm(ServerRequestInterface $request): ResponseInterface
|
||||
{
|
||||
return new RedirectResponse(
|
||||
$this->uriBuilder->buildUriWithRedirect('login', [], RouteRedirect::createFromRequest($request)),
|
||||
303
|
||||
);
|
||||
}
|
||||
|
||||
protected function initializeForgetPasswordView(ServerRequestInterface $request): void
|
||||
{
|
||||
$parameters = array_filter(['loginProvider' => $this->loginProvider]);
|
||||
$this->view->assignMultiple([
|
||||
'formUrl' => $this->uriBuilder->buildUriWithRedirect('password_forget_initiate_reset', $parameters, RouteRedirect::createFromRequest($request)),
|
||||
'returnUrl' => $this->uriBuilder->buildUriWithRedirect('login', $parameters, RouteRedirect::createFromRequest($request)),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function initializeResetPasswordView(ServerRequestInterface $request): void
|
||||
{
|
||||
$token = $request->getQueryParams()['t'] ?? '';
|
||||
$identity = $request->getQueryParams()['i'] ?? '';
|
||||
$expirationDate = $request->getQueryParams()['e'] ?? '';
|
||||
$parameters = array_filter(['loginProvider' => $this->loginProvider]);
|
||||
$formUrl = $this->uriBuilder->buildUriWithRedirect(
|
||||
'password_reset_finish',
|
||||
array_filter(array_merge($parameters, [
|
||||
't' => $token,
|
||||
'i' => $identity,
|
||||
'e' => $expirationDate,
|
||||
])),
|
||||
RouteRedirect::createFromRequest($request)
|
||||
);
|
||||
$this->view->assignMultiple([
|
||||
'token' => $token,
|
||||
'identity' => $identity,
|
||||
'expirationDate' => $expirationDate,
|
||||
'formUrl' => $formUrl,
|
||||
'restartUrl' => $this->uriBuilder->buildUriWithRedirect('password_forget', $parameters, RouteRedirect::createFromRequest($request)),
|
||||
'passwordRequirements' => $this->getPasswordRequirements(),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function initialize(ServerRequestInterface $request): void
|
||||
{
|
||||
$languageService = $this->getLanguageService();
|
||||
|
||||
// Only allow to execute this if not logged in as a user right now
|
||||
if ($this->context->getAspect('backend.user')->isLoggedIn()) {
|
||||
throw new PropagateResponseException(
|
||||
new RedirectResponse($this->uriBuilder->buildUriFromRoute('login'), 303),
|
||||
1618342858
|
||||
);
|
||||
}
|
||||
|
||||
// Fetch login provider from the request
|
||||
$this->loginProvider = $request->getQueryParams()['loginProvider'] ?? '';
|
||||
|
||||
// Try to get the preferred browser language
|
||||
$httpAcceptLanguage = $request->getServerParams()['HTTP_ACCEPT_LANGUAGE'] ?? '';
|
||||
$preferredBrowserLanguage = $this->locales->getPreferredClientLanguage($httpAcceptLanguage);
|
||||
|
||||
// If we found a $preferredBrowserLanguage, which is not the default language
|
||||
// initialize $this->getLanguageService() again with $preferredBrowserLanguage.
|
||||
// Additionally, set the language to the backend user object, so labels in fluid views are translated
|
||||
if ($preferredBrowserLanguage !== 'default') {
|
||||
$languageService->init($preferredBrowserLanguage);
|
||||
$this->getBackendUserAuthentication()->user['lang'] = $preferredBrowserLanguage;
|
||||
}
|
||||
|
||||
$this->setUpBasicPageRendererForBackend($this->pageRenderer, $this->extensionConfiguration, $request, $languageService);
|
||||
$this->pageRenderer->setTitle('TYPO3 CMS Login: ' . ($GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'] ?? ''));
|
||||
$this->pageRenderer->loadJavaScriptModule('bootstrap');
|
||||
$this->pageRenderer->loadJavaScriptModule('@typo3/backend/login.js');
|
||||
|
||||
$this->view = $this->backendViewFactory->create($request);
|
||||
$this->view->assignMultiple([
|
||||
'enablePasswordReset' => $this->passwordReset->isEnabled(),
|
||||
'referrerCheckEnabled' => $this->features->isFeatureEnabled('security.backend.enforceReferrer'),
|
||||
'loginUrl' => (string)$request->getUri(),
|
||||
]);
|
||||
|
||||
$this->provideCustomLoginStyling($request);
|
||||
}
|
||||
|
||||
protected function provideCustomLoginStyling(ServerRequestInterface $request): void
|
||||
{
|
||||
if (($backgroundImageStyles = $this->authenticationStyleInformation->getBackgroundImageStyles($request)) !== '') {
|
||||
$this->pageRenderer->addCssInlineBlock('loginBackgroundImage', $backgroundImageStyles, null, false, true);
|
||||
}
|
||||
if (($footerNote = $this->authenticationStyleInformation->getFooterNote()) !== '') {
|
||||
$this->view->assign('loginFootnote', $footerNote);
|
||||
}
|
||||
if (($highlightColorStyles = $this->authenticationStyleInformation->getHighlightColorStyles()) !== '') {
|
||||
$this->pageRenderer->addCssInlineBlock('loginHighlightColor', $highlightColorStyles, null, false, true);
|
||||
}
|
||||
$this->view->assignMultiple([
|
||||
'copyright' => $this->typo3Information->getCopyrightNotice(),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function getPasswordRequirements(): array
|
||||
{
|
||||
$passwordPolicy = $GLOBALS['TYPO3_CONF_VARS']['BE']['passwordPolicy'] ?? 'default';
|
||||
$passwordPolicyValidator = GeneralUtility::makeInstance(
|
||||
PasswordPolicyValidator::class,
|
||||
PasswordPolicyAction::UPDATE_USER_PASSWORD,
|
||||
is_string($passwordPolicy) ? $passwordPolicy : ''
|
||||
);
|
||||
return $passwordPolicyValidator->getRequirements();
|
||||
}
|
||||
|
||||
protected function getLanguageService(): LanguageService
|
||||
{
|
||||
return $GLOBALS['LANG'];
|
||||
}
|
||||
|
||||
protected function getBackendUserAuthentication(): BackendUserAuthentication
|
||||
{
|
||||
return $GLOBALS['BE_USER'];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user