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