TYPO3 CMS  TYPO3_7-6
FrontendLoginControllerTest.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 
22 
27 {
31  protected $accessibleFixture;
32 
36  protected $testHostName;
37 
41  protected $testSitePath;
42 
46  protected $testTableName;
47 
51  protected function setUp()
52  {
53  $this->testTableName = 'sys_domain';
54  $this->testHostName = 'hostname.tld';
55  $this->testSitePath = '/';
56  $this->accessibleFixture = $this->getAccessibleMock(\TYPO3\CMS\Felogin\Controller\FrontendLoginController::class, ['dummy']);
57  $this->accessibleFixture->cObj = $this->getMock(\TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer::class);
58  $this->accessibleFixture->_set('frontendController', $this->getMock(\TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController::class, [], [], '', false));
59  $this->setUpFakeSitePathAndHost();
60  }
61 
65  protected function setUpFakeSitePathAndHost()
66  {
68  $_SERVER['ORIG_PATH_INFO'] = $_SERVER['PATH_INFO'] = $_SERVER['ORIG_SCRIPT_NAME'] = $_SERVER['SCRIPT_NAME'] = $this->testSitePath . TYPO3_mainDir;
69  $_SERVER['HTTP_HOST'] = $this->testHostName;
70  }
71 
75  protected function setUpDatabaseMock()
76  {
77  $db = $this->getMock(\TYPO3\CMS\Core\Database\DatabaseConnection::class, ['exec_SELECTgetRows']);
78  $db
79  ->expects($this->any())
80  ->method('exec_SELECTgetRows')
81  ->will($this->returnCallback([$this, 'getDomainRecordsCallback']));
82  $this->accessibleFixture->_set('databaseConnection', $db);
83  }
84 
95  public function getDomainRecordsCallback($fields, $table, $where)
96  {
97  if ($table !== $this->testTableName) {
98  return false;
99  }
100  return [
101  ['domainName' => 'domainhostname.tld'],
102  ['domainName' => 'otherhostname.tld/path'],
103  ['domainName' => 'sub.domainhostname.tld/path/']
104  ];
105  }
106 
111  {
112  $this->assertEquals(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'), $this->testSitePath);
113  }
114 
119  {
120  $this->assertEquals(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_URL'), ('http://' . $this->testHostName) . $this->testSitePath);
121  }
122 
127  {
128  $this->testHostName = 'somenewhostname.com';
129  $this->testSitePath = '/somenewpath/';
130  $this->setUpFakeSitePathAndHost();
131  $this->assertEquals(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'), $this->testSitePath);
132  }
133 
138  {
139  $this->testHostName = 'somenewhostname.com';
140  $this->testSitePath = '/somenewpath/';
141  $this->setUpFakeSitePathAndHost();
142  $this->assertEquals(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_URL'), ('http://' . $this->testHostName) . $this->testSitePath);
143  }
144 
151  {
152  return [
153  'absolute URL, hostname not in sys_domain, trailing slash' => ['http://badhost.tld/'],
154  'absolute URL, hostname not in sys_domain, no trailing slash' => ['http://badhost.tld'],
155  'absolute URL, subdomain in sys_domain, but main domain not, trailing slash' => ['http://domainhostname.tld.badhost.tld/'],
156  'absolute URL, subdomain in sys_domain, but main domain not, no trailing slash' => ['http://domainhostname.tld.badhost.tld'],
157  'non http absolute URL 1' => ['its://domainhostname.tld/itunes/'],
158  'non http absolute URL 2' => ['ftp://domainhostname.tld/download/'],
159  'XSS attempt 1' => ['javascript:alert(123)'],
160  'XSS attempt 2' => ['" onmouseover="alert(123)"'],
161  'invalid URL, HTML break out attempt' => ['" >blabuubb'],
162  'invalid URL, UNC path' => ['\\\\foo\\bar\\'],
163  'invalid URL, backslashes in path' => ['http://domainhostname.tld\\bla\\blupp'],
164  'invalid URL, linefeed in path' => ['http://domainhostname.tld/bla/blupp' . LF],
165  'invalid URL, only one slash after scheme' => ['http:/domainhostname.tld/bla/blupp'],
166  'invalid URL, illegal chars' => ['http://(<>domainhostname).tld/bla/blupp'],
167  ];
168  }
169 
175  public function validateRedirectUrlClearsUrl($url)
176  {
177  $this->setUpDatabaseMock();
178  $this->assertEquals('', $this->accessibleFixture->_call('validateRedirectUrl', $url));
179  }
180 
187  {
188  return [
189  'sane absolute URL' => ['http://domainhostname.tld/'],
190  'sane absolute URL with script' => ['http://domainhostname.tld/index.php?id=1'],
191  'sane absolute URL with realurl' => ['http://domainhostname.tld/foo/bar/foo.html'],
192  'sane absolute URL with homedir' => ['http://domainhostname.tld/~user/'],
193  'sane absolute URL with some strange chars encoded' => ['http://domainhostname.tld/~user/a%cc%88o%cc%88%c3%9fa%cc%82/foo.html'],
194  'sane absolute URL (domain record with path)' => ['http://otherhostname.tld/path/'],
195  'sane absolute URL with script (domain record with path)' => ['http://otherhostname.tld/path/index.php?id=1'],
196  'sane absolute URL with realurl (domain record with path)' => ['http://otherhostname.tld/path/foo/bar/foo.html'],
197  'sane absolute URL (domain record with path and slash)' => ['http://sub.domainhostname.tld/path/'],
198  'sane absolute URL with script (domain record with path slash)' => ['http://sub.domainhostname.tld/path/index.php?id=1'],
199  'sane absolute URL with realurl (domain record with path slash)' => ['http://sub.domainhostname.tld/path/foo/bar/foo.html'],
200  'relative URL, no leading slash 1' => ['index.php?id=1'],
201  'relative URL, no leading slash 2' => ['foo/bar/index.php?id=2'],
202  'relative URL, leading slash, no realurl' => ['/index.php?id=1'],
203  'relative URL, leading slash, realurl' => ['/de/service/imprint.html'],
204  ];
205  }
206 
212  public function validateRedirectUrlKeepsCleanUrl($url)
213  {
214  $this->setUpDatabaseMock();
215  $this->assertEquals($url, $this->accessibleFixture->_call('validateRedirectUrl', $url));
216  }
217 
224  {
225  return [
226  'absolute URL, missing subdirectory' => ['http://hostname.tld/'],
227  'absolute URL, wrong subdirectory' => ['http://hostname.tld/hacker/index.php'],
228  'absolute URL, correct subdirectory, no trailing slash' => ['http://hostname.tld/subdir'],
229  'absolute URL, correct subdirectory of sys_domain record, no trailing slash' => ['http://otherhostname.tld/path'],
230  'absolute URL, correct subdirectory of sys_domain record, no trailing slash, subdomain' => ['http://sub.domainhostname.tld/path'],
231  'relative URL, leading slash, no path' => ['/index.php?id=1'],
232  'relative URL, leading slash, wrong path' => ['/de/sub/site.html'],
233  'relative URL, leading slash, slash only' => ['/'],
234  ];
235  }
236 
243  {
244  $this->testSitePath = '/subdir/';
245  $this->setUpFakeSitePathAndHost();
246  $this->setUpDatabaseMock();
247  $this->assertEquals('', $this->accessibleFixture->_call('validateRedirectUrl', $url));
248  }
249 
256  {
257  return [
258  'absolute URL, correct subdirectory' => ['http://hostname.tld/subdir/'],
259  'absolute URL, correct subdirectory, realurl' => ['http://hostname.tld/subdir/de/imprint.html'],
260  'absolute URL, correct subdirectory, no realurl' => ['http://hostname.tld/subdir/index.php?id=10'],
261  'absolute URL, correct subdirectory of sys_domain record' => ['http://otherhostname.tld/path/'],
262  'absolute URL, correct subdirectory of sys_domain record, subdomain' => ['http://sub.domainhostname.tld/path/'],
263  'relative URL, no leading slash, realurl' => ['de/service/imprint.html'],
264  'relative URL, no leading slash, no realurl' => ['index.php?id=1'],
265  'relative nested URL, no leading slash, no realurl' => ['foo/bar/index.php?id=2']
266  ];
267  }
268 
275  {
276  $this->testSitePath = '/subdir/';
277  $this->setUpFakeSitePathAndHost();
278  $this->setUpDatabaseMock();
279  $this->assertEquals($url, $this->accessibleFixture->_call('validateRedirectUrl', $url));
280  }
281 
282  /*************************
283  * Test concerning getPreverveGetVars
284  *************************/
285 
290  {
291  return [
292  'special get var id is not preserved' => [
293  [
294  'id' => 42,
295  ],
296  '',
297  '',
298  ],
299  'simple additional parameter is not preserved if not specified in preservedGETvars' => [
300  [
301  'id' => 42,
302  'special' => 23,
303  ],
304  '',
305  '',
306  ],
307  'all params except ignored ones are preserved if preservedGETvars is set to "all"' => [
308  [
309  'id' => 42,
310  'special1' => 23,
311  'special2' => [
312  'foo' => 'bar',
313  ],
314  'tx_felogin_pi1' => [
315  'forgot' => 1,
316  ],
317  ],
318  'all',
319  '&special1=23&special2[foo]=bar',
320  ],
321  'preserve single parameter' => [
322  [
323  'L' => 42,
324  ],
325  'L',
326  '&L=42'
327  ],
328  'preserve whole parameter array' => [
329  [
330  'L' => 3,
331  'tx_someext' => [
332  'foo' => 'simple',
333  'bar' => [
334  'baz' => 'simple',
335  ],
336  ],
337  ],
338  'L,tx_someext',
339  '&L=3&tx_someext[foo]=simple&tx_someext[bar][baz]=simple',
340  ],
341  'preserve part of sub array' => [
342  [
343  'L' => 3,
344  'tx_someext' => [
345  'foo' => 'simple',
346  'bar' => [
347  'baz' => 'simple',
348  ],
349  ],
350  ],
351  'L,tx_someext[bar]',
352  '&L=3&tx_someext[bar][baz]=simple',
353  ],
354  'preserve keys on different levels' => [
355  [
356  'L' => 3,
357  'no-preserve' => 'whatever',
358  'tx_ext2' => [
359  'foo' => 'simple',
360  ],
361  'tx_ext3' => [
362  'bar' => [
363  'baz' => 'simple',
364  ],
365  'go-away' => '',
366  ],
367  ],
368  'L,tx_ext2,tx_ext3[bar]',
369  '&L=3&tx_ext2[foo]=simple&tx_ext3[bar][baz]=simple',
370  ],
371  'preserved value that does not exist in get' => [
372  [],
373  'L,foo[bar]',
374  ''
375  ],
376  'url params are encoded' => [
377  ['tx_ext1' => 'param with spaces and \\ %<>& /'],
378  'L,tx_ext1',
379  '&tx_ext1=param%20with%20spaces%20and%20%5C%20%25%3C%3E%26%20%2F'
380  ],
381  ];
382  }
383 
392  public function getPreserveGetVarsReturnsCorrectResult(array $getArray, $preserveVars, $expected)
393  {
394  $_GET = $getArray;
395  $this->accessibleFixture->conf['preserveGETvars'] = $preserveVars;
396  $this->assertSame($expected, $this->accessibleFixture->_call('getPreserveGetVars'));
397  }
398 
399  /**************************************************
400  * Tests concerning isInLocalDomain
401  **************************************************/
402 
409  {
410  return [
411  'url https, current host http' => [
412  'example.com', // HTTP_HOST
413  '0', // HTTPS
414  'https://example.com/foo.html' // URL
415  ],
416  'url http, current host https' => [
417  'example.com',
418  '1',
419  'http://example.com/foo.html'
420  ],
421  'url https, current host https' => [
422  'example.com',
423  '1',
424  'https://example.com/foo.html'
425  ],
426  'url http, current host http' => [
427  'example.com',
428  '0',
429  'http://example.com/foo.html'
430  ]
431  ];
432  }
433 
441  public function isInCurrentDomainIgnoresScheme($host, $https, $url)
442  {
443  $_SERVER['HTTP_HOST'] = $host;
444  $_SERVER['HTTPS'] = $https;
445  $this->assertTrue($this->accessibleFixture->_call('isInCurrentDomain', $url));
446  }
447 
452  {
453  return [
454  'simple difference' => [
455  'example.com', // HTTP_HOST
456  'http://typo3.org/foo.html' // URL
457  ],
458  'subdomain different' => [
459  'example.com',
460  'http://foo.example.com/bar.html'
461  ]
462  ];
463  }
464 
472  {
473  $_SERVER['HTTP_HOST'] = $host;
474  $this->assertFalse($this->accessibleFixture->_call('isInCurrentDomain', $url));
475  }
476 
480  public function processRedirectReferrerDomainsMatchesDomains()
481  {
482  $conf = [
483  'redirectMode' => 'refererDomains',
484  'domains' => 'example.com'
485  ];
486 
487  $this->accessibleFixture->_set('conf', $conf);
488  $this->accessibleFixture->_set('logintype', 'login');
489  $this->accessibleFixture->_set('referer', 'http://www.example.com/snafu');
491  $tsfe = $this->accessibleFixture->_get('frontendController');
492  $tsfe->loginUser = true;
493  $this->assertSame(['http://www.example.com/snafu'], $this->accessibleFixture->_call('processRedirect'));
494  }
495 
500  {
501  return [
502  'Simple casing' => [
503  [
504  'username' => 'Holy',
505  'lastname' => 'Wood',
506  ],
507  [
508  'username.' => [
509  'case' => 'upper'
510  ]
511  ],
512  [
513  '###FEUSER_USERNAME###' => 'HOLY',
514  '###FEUSER_LASTNAME###' => 'Wood',
515  '###USER###' => 'HOLY'
516  ]
517  ],
518  'Default config applies' => [
519  [
520  'username' => 'Holy',
521  'lastname' => 'O" Mally',
522  ],
523  [
524  'username.' => [
525  'case' => 'upper'
526  ]
527  ],
528  [
529  '###FEUSER_USERNAME###' => 'HOLY',
530  '###FEUSER_LASTNAME###' => 'O&quot; Mally',
531  '###USER###' => 'HOLY'
532  ]
533  ],
534  'Specific config overrides default config' => [
535  [
536  'username' => 'Holy',
537  'lastname' => 'O" Mally',
538  ],
539  [
540  'username.' => [
541  'case' => 'upper'
542  ],
543  'lastname.' => [
544  'htmlSpecialChars' => '0'
545  ]
546  ],
547  [
548  '###FEUSER_USERNAME###' => 'HOLY',
549  '###FEUSER_LASTNAME###' => 'O" Mally',
550  '###USER###' => 'HOLY'
551  ]
552  ],
553  'No given user returns empty array' => [
554  null,
555  [
556  'username.' => [
557  'case' => 'upper'
558  ],
559  'lastname.' => [
560  'htmlSpecialChars' => '0'
561  ]
562  ],
563  []
564  ],
565  ];
566  }
567 
572  public function processUserFieldsRespectsDefaultConfigurationForStdWrap($userRecord, $fieldConf, $expectedMarkers)
573  {
574  $charsetConverter = $this->prophesize(CharsetConverter::class);
575  $charsetConverter->conv_case('utf-8', Argument::any(), 'toUpper')
576  ->will(function(array $args) {
577  return mb_strtoupper($args[1]);
578  });
580  $tsfe = $this->getMock(
581  TypoScriptFrontendController::class,
582  [],
583  [],
584  '',
585  false
586  );
587  $tsfe->csConvObj = $charsetConverter->reveal();
588  $tsfe->fe_user = new \stdClass();
589  $tsfe->fe_user->user = $userRecord;
590  $conf = ['userfields.' => $fieldConf];
591  $this->accessibleFixture->_set('cObj', new ContentObjectRenderer($tsfe));
592  $this->accessibleFixture->_set('frontendController', $tsfe);
593  $this->accessibleFixture->_set('conf', $conf);
594  $actualResult = $this->accessibleFixture->_call('getUserFieldMarkers');
595  $this->assertEquals($expectedMarkers, $actualResult);
596  }
597 }
getAccessibleMock( $originalClassName, $methods=[], array $arguments=[], $mockClassName='', $callOriginalConstructor=true, $callOriginalClone=true, $callAutoload=true)
$host
Definition: server.php:37