Passed
Push — master ( 67a56c...50d7c6 )
by
unknown
12:39
created

enrichResponseWithHeadersAndCookieInformation()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 16
rs 10
c 0
b 0
f 0
cc 3
nc 3
nop 2
1
<?php
2
3
declare(strict_types=1);
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
namespace TYPO3\CMS\Backend\Middleware;
19
20
use Psr\Http\Message\ResponseInterface;
21
use Psr\Http\Message\ServerRequestInterface;
22
use Psr\Http\Server\RequestHandlerInterface;
23
use TYPO3\CMS\Backend\Routing\Route;
24
use TYPO3\CMS\Backend\Routing\UriBuilder;
25
use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
26
use TYPO3\CMS\Core\Http\ImmediateResponseException;
27
use TYPO3\CMS\Core\Http\RedirectResponse;
28
use TYPO3\CMS\Core\Localization\LanguageService;
29
use TYPO3\CMS\Core\Utility\GeneralUtility;
30
31
/**
32
 * Initializes the backend user authentication object (BE_USER) and the global LANG object.
33
 *
34
 * @internal
35
 */
36
class BackendUserAuthenticator extends \TYPO3\CMS\Core\Middleware\BackendUserAuthenticator
37
{
38
    /**
39
     * List of requests that don't need a valid BE user
40
     *
41
     * @var array
42
     */
43
    protected $publicRoutes = [
44
        '/login',
45
        '/login/frame',
46
        '/login/password-reset/forget',
47
        '/login/password-reset/initiate-reset',
48
        '/login/password-reset/validate',
49
        '/login/password-reset/finish',
50
        '/ajax/login',
51
        '/ajax/logout',
52
        '/ajax/login/refresh',
53
        '/ajax/login/timedout',
54
        '/ajax/rsa/publickey',
55
        '/ajax/core/requirejs',
56
    ];
57
58
    /**
59
     * Calls the bootstrap process to set up $GLOBALS['BE_USER'] AND $GLOBALS['LANG']
60
     *
61
     * @param ServerRequestInterface $request
62
     * @param RequestHandlerInterface $handler
63
     * @return ResponseInterface
64
     */
65
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
66
    {
67
        $route = $request->getAttribute('route');
68
69
        // The global must be available very early, because methods below
70
        // might trigger code which relies on it. See: #45625
71
        $GLOBALS['BE_USER'] = GeneralUtility::makeInstance(BackendUserAuthentication::class);
72
        $GLOBALS['BE_USER']->start();
73
        // Register the backend user as aspect and initializing workspace once for TSconfig conditions
74
        $this->setBackendUserAspect($GLOBALS['BE_USER'], (int)$GLOBALS['BE_USER']->user['workspace_id']);
75
        if (!$this->isLoggedInBackendUserRequired($route) && !$this->context->getAspect('backend.user')->isLoggedIn()) {
0 ignored issues
show
Bug introduced by
The method isLoggedIn() does not exist on TYPO3\CMS\Core\Context\AspectInterface. It seems like you code against a sub-type of TYPO3\CMS\Core\Context\AspectInterface such as TYPO3\CMS\Core\Context\UserAspect. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

75
        if (!$this->isLoggedInBackendUserRequired($route) && !$this->context->getAspect('backend.user')->/** @scrutinizer ignore-call */ isLoggedIn()) {
Loading history...
76
            $uri = GeneralUtility::makeInstance(UriBuilder::class)->buildUriFromRoute('login');
77
            $response = new RedirectResponse($uri);
78
            return $this->enrichResponseWithHeadersAndCookieInformation($response, $GLOBALS['BE_USER']);
79
        }
80
        try {
81
            // @todo: Ensure that the runtime exceptions are caught
82
            $GLOBALS['BE_USER']->backendCheckLogin($this->isLoggedInBackendUserRequired($route));
83
            $GLOBALS['LANG'] = LanguageService::createFromUserPreferences($GLOBALS['BE_USER']);
84
            // Re-setting the user and take the workspace from the user object now
85
            $this->setBackendUserAspect($GLOBALS['BE_USER']);
86
            $response = $handler->handle($request);
87
        } catch (ImmediateResponseException $e) {
88
            $response = $this->enrichResponseWithHeadersAndCookieInformation(
89
                $e->getResponse(),
90
                $GLOBALS['BE_USER']
91
            );
92
            // Re-throw this exception
93
            throw new ImmediateResponseException($response, $e->getCode());
94
        }
95
        return $this->enrichResponseWithHeadersAndCookieInformation($response, $GLOBALS['BE_USER']);
96
    }
97
98
    /**
99
     * Backend requests should always apply Set-Cookie information and never be cacheable.
100
     * This is also needed if there is a redirect from somewhere in the code.
101
     *
102
     * @param ResponseInterface $response
103
     * @param BackendUserAuthentication|null $userAuthentication
104
     * @return ResponseInterface
105
     * @throws \TYPO3\CMS\Core\Context\Exception\AspectNotFoundException
106
     */
107
    protected function enrichResponseWithHeadersAndCookieInformation(
108
        ResponseInterface $response,
109
        ?BackendUserAuthentication $userAuthentication
110
    ): ResponseInterface {
111
        if ($userAuthentication) {
112
            // If no backend user is logged-in, the cookie should be removed
113
            if (!$this->context->getAspect('backend.user')->isLoggedIn()) {
114
                $userAuthentication->removeCookie();
115
            }
116
            // Ensure to always apply a cookie
117
            $response = $userAuthentication->appendCookieToResponse($response);
118
        }
119
        // Additional headers to never cache any PHP request should be sent at any time when
120
        // accessing the TYPO3 Backend
121
        $response = $this->applyHeadersToResponse($response);
122
        return $response;
123
    }
124
125
    /**
126
     * Check if the user is required for the request.
127
     * If we're trying to do a login or an ajax login, don't require a user.
128
     *
129
     * @param Route $route the Route path to check against, something like '
130
     * @return bool whether the request can proceed without a login required
131
     */
132
    protected function isLoggedInBackendUserRequired(Route $route): bool
133
    {
134
        return in_array($route->getPath(), $this->publicRoutes, true);
135
    }
136
}
137