[BUGFIX] Allow direct access to BE again while being logged in
[Packages/TYPO3.CMS.git] / typo3 / sysext / backend / Tests / Unit / Controller / LoginControllerTest.php
1 <?php
2
3 namespace TYPO3\CMS\Backend\Tests\Unit\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 TYPO3\CMS\Backend\Controller\LoginController;
19 use TYPO3\CMS\Backend\LoginProvider\UsernamePasswordLoginProvider;
20 use TYPO3\CMS\Backend\Template\DocumentTemplate;
21 use TYPO3\CMS\Core\Authentication\BackendUserAuthentication;
22 use TYPO3\CMS\Core\FormProtection\BackendFormProtection;
23 use TYPO3\CMS\Core\Http\ServerRequest;
24 use TYPO3\CMS\Core\Localization\LanguageService;
25 use TYPO3\CMS\Core\Utility\GeneralUtility;
26 use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
27
28 /**
29 * Class LoginControllerTest
30 */
31 class LoginControllerTest extends UnitTestCase
32 {
33 /**
34 * @var LoginController|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface
35 */
36 protected $loginControllerMock;
37
38 /**
39 * @var bool
40 * @see prophesizeFormProtection
41 */
42 protected static $alreadySetUp = false;
43
44 /**
45 * @throws \InvalidArgumentException
46 */
47 protected function setUp()
48 {
49 $this->loginControllerMock = $this->getAccessibleMock(LoginController::class, ['dummy'], [], '', false);
50 }
51
52 /**
53 * @test
54 */
55 public function validateAndSortLoginProvidersDetectsMissingProviderConfiguration()
56 {
57 $this->expectException(\RuntimeException::class);
58 $this->expectExceptionCode(1433417281);
59 unset($GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders']);
60 $this->loginControllerMock->_call('validateAndSortLoginProviders');
61 }
62
63 /**
64 * @test
65 */
66 public function validateAndSortLoginProvidersDetectsNonArrayProviderConfiguration()
67 {
68 $this->expectException(\RuntimeException::class);
69 $this->expectExceptionCode(1433417281);
70 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'] = 'foo';
71 $this->loginControllerMock->_call('validateAndSortLoginProviders');
72 }
73
74 /**
75 * @test
76 */
77 public function validateAndSortLoginProvidersDetectsIfNoProviderIsRegistered()
78 {
79 $this->expectException(\RuntimeException::class);
80 $this->expectExceptionCode(1433417281);
81 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'] = [];
82 $this->loginControllerMock->_call('validateAndSortLoginProviders');
83 }
84
85 /**
86 * @test
87 */
88 public function validateAndSortLoginProvidersDetectsMissingConfigurationForProvider()
89 {
90 $this->expectException(\RuntimeException::class);
91 $this->expectExceptionCode(1433416043);
92 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'] = [
93 1433419736 => [],
94 ];
95 $this->loginControllerMock->_call('validateAndSortLoginProviders');
96 }
97
98 /**
99 * @test
100 */
101 public function validateAndSortLoginProvidersDetectsWrongProvider()
102 {
103 $this->expectException(\RuntimeException::class);
104 $this->expectExceptionCode(1460977275);
105 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'] = [
106 1433419736 => [
107 'provider' => \stdClass::class,
108 ],
109 ];
110 $this->loginControllerMock->_call('validateAndSortLoginProviders');
111 }
112
113 /**
114 * @test
115 */
116 public function validateAndSortLoginProvidersDetectsMissingLabel()
117 {
118 $this->expectException(\RuntimeException::class);
119 $this->expectExceptionCode(1433416044);
120 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'] = [
121 1433419736 => [
122 'provider' => UsernamePasswordLoginProvider::class,
123 'sorting' => 30,
124 'icon-class' => 'foo',
125 ],
126 ];
127 $this->loginControllerMock->_call('validateAndSortLoginProviders');
128 }
129
130 /**
131 * @test
132 */
133 public function validateAndSortLoginProvidersDetectsMissingIconClass()
134 {
135 $this->expectException(\RuntimeException::class);
136 $this->expectExceptionCode(1433416045);
137 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'] = [
138 1433419736 => [
139 'provider' => UsernamePasswordLoginProvider::class,
140 'sorting' => 30,
141 'label' => 'foo',
142 ],
143 ];
144 $this->loginControllerMock->_call('validateAndSortLoginProviders');
145 }
146
147 /**
148 * @test
149 */
150 public function validateAndSortLoginProvidersDetectsMissingSorting()
151 {
152 $this->expectException(\RuntimeException::class);
153 $this->expectExceptionCode(1433416046);
154 $GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['backend']['loginProviders'] = [
155 1433419736 => [
156 'provider' => UsernamePasswordLoginProvider::class,
157 'label' => 'foo',
158 'icon-class' => 'foo',
159 ],
160 ];
161 $this->loginControllerMock->_call('validateAndSortLoginProviders');
162 }
163
164 /**
165 * @test
166 */
167 public function checkRedirectRedirectsIfLoginIsInProgressAndUserWasFound(): void
168 {
169 $GLOBALS['LANG'] = ($this->prophesize(LanguageService::class))->reveal();
170 $authenticationProphecy = $this->prophesize(BackendUserAuthentication::class);
171 $authenticationProphecy->getTSConfigVal('auth.BE.redirectToURL')->willReturn('http://example.com');
172 $authenticationProphecy->writeUC()->willReturn();
173 $authenticationProphecy->getSessionData('formProtectionSessionToken')->willReturn('foo');
174 $GLOBALS['BE_USER'] = $authenticationProphecy->reveal();
175 $this->prophesizeFormProtection();
176
177 $this->loginControllerMock = $this->getAccessibleMock(
178 LoginController::class,
179 ['isLoginInProgress', 'redirectToUrl'],
180 [],
181 '',
182 false
183 );
184
185 $GLOBALS['BE_USER']->user['uid'] = 1;
186 $this->loginControllerMock->method('isLoginInProgress')->willReturn(true);
187 $this->loginControllerMock->_set('loginRefresh', false);
188
189 $this->loginControllerMock->expects($this->once())->method('redirectToUrl');
190 $this->loginControllerMock->_call('checkRedirect', $this->prophesize(ServerRequest::class)->reveal());
191 }
192
193 /**
194 * @test
195 */
196 public function checkRedirectAddsJavaScriptForCaseLoginRefresh(): void
197 {
198 $GLOBALS['LANG'] = $this->prophesize(LanguageService::class)->reveal();
199 $authenticationProphecy = $this->prophesize(BackendUserAuthentication::class);
200 $authenticationProphecy->getTSConfigVal('auth.BE.redirectToURL')->willReturn('http://example.com');
201 $authenticationProphecy->writeUC()->willReturn();
202 $this->prophesizeFormProtection();
203 $GLOBALS['BE_USER'] = $authenticationProphecy->reveal();
204 $documentTemplateProphecy = $this->prophesize(DocumentTemplate::class);
205 $GLOBALS['TBE_TEMPLATE'] = $documentTemplateProphecy->reveal();
206
207 $this->loginControllerMock = $this->getAccessibleMock(
208 LoginController::class,
209 ['isLoginInProgress', 'redirectToUrl'],
210 [],
211 '',
212 false
213 );
214
215 $GLOBALS['BE_USER']->user['uid'] = 1;
216 $this->loginControllerMock->method('isLoginInProgress')->willReturn(false);
217 $this->loginControllerMock->_set('loginRefresh', true);
218
219 $this->loginControllerMock->_call('checkRedirect', $this->prophesize(ServerRequest::class)->reveal());
220
221 self::assertContains('window.opener.TYPO3.LoginRefresh.startTask();', $documentTemplateProphecy->JScode);
222 }
223
224 /**
225 * @test
226 */
227 public function checkRedirectAddsJavaScriptForCaseLoginRefreshWhileLoginIsInProgress(): void
228 {
229 $GLOBALS['LANG'] = $this->prophesize(LanguageService::class)->reveal();
230 $authenticationProphecy = $this->prophesize(BackendUserAuthentication::class);
231 $authenticationProphecy->getTSConfigVal('auth.BE.redirectToURL')->willReturn('http://example.com');
232 $authenticationProphecy->writeUC()->willReturn();
233 $GLOBALS['BE_USER'] = $authenticationProphecy->reveal();
234 $this->prophesizeFormProtection();
235 $documentTemplateProphecy = $this->prophesize(DocumentTemplate::class);
236 $GLOBALS['TBE_TEMPLATE'] = $documentTemplateProphecy->reveal();
237
238 $this->loginControllerMock = $this->getAccessibleMock(
239 LoginController::class,
240 ['isLoginInProgress', 'redirectToUrl'],
241 [],
242 '',
243 false
244 );
245
246 $GLOBALS['BE_USER']->user['uid'] = 1;
247 $this->loginControllerMock->method('isLoginInProgress')->willReturn(true);
248 $this->loginControllerMock->_set('loginRefresh', true);
249
250 $this->loginControllerMock->_call('checkRedirect', $this->prophesize(ServerRequest::class)->reveal());
251
252 self::assertContains('window.opener.TYPO3.LoginRefresh.startTask();', $documentTemplateProphecy->JScode);
253 }
254
255 /**
256 * @test
257 */
258 public function checkRedirectDoesNotRedirectIfNoUserIsFound(): void
259 {
260 $GLOBALS['BE_USER'] = $this->prophesize(BackendUserAuthentication::class)->reveal();
261 $this->loginControllerMock = $this->getAccessibleMock(
262 LoginController::class,
263 ['redirectToUrl'],
264 [],
265 '',
266 false
267 );
268
269 $GLOBALS['BE_USER']->user['uid'] = null;
270
271 $this->loginControllerMock->expects($this->never())->method('redirectToUrl');
272 $this->loginControllerMock->_call('checkRedirect', $this->prophesize(ServerRequest::class)->reveal());
273 }
274
275 /**
276 * FormProtectionFactory has an internal static instance cache we need to work around here
277 */
278 protected function prophesizeFormProtection(): void
279 {
280 if (!self::$alreadySetUp) {
281 $formProtectionProphecy = $this->prophesize(BackendFormProtection::class);
282 GeneralUtility::addInstance(BackendFormProtection::class, $formProtectionProphecy->reveal());
283 self::$alreadySetUp = true;
284 }
285 }
286 }