[TASK] EXT:felogin unit tests
[Packages/TYPO3.CMS.git] / typo3 / sysext / felogin / Tests / Unit / Controller / FrontendLoginControllerTest.php
1 <?php
2 namespace TYPO3\CMS\Felogin\Tests\Unit\Controller;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2012 Helmut Hummel <helmut@typo3.org>
8 *
9 * All rights reserved
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 *
20 * This script is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * This copyright notice MUST APPEAR in all copies of the script!
26 *
27 * The code was adapted from newloginbox, see manual for detailed description
28 ***************************************************************/
29
30 /**
31 * Testcase for URL validation in class FrontendLoginController
32 *
33 * @author Helmut Hummel <helmut@typo3.org>
34 * @package TYPO3
35 * @subpackage felogin
36 */
37 class FrontendLoginTest extends \tx_phpunit_testcase {
38
39 /**
40 * Enable backup of global and system variables
41 *
42 * @var boolean
43 */
44 protected $backupGlobals = TRUE;
45
46 /**
47 * Exclude TYPO3_DB from backup/ restore of $GLOBALS
48 * because resource types cannot be handled during serializing
49 *
50 * @var array
51 */
52 protected $backupGlobalsBlacklist = array('TYPO3_DB');
53
54 /**
55 * @var \TYPO3\CMS\Core\Database\DatabaseConnection
56 */
57 protected $typo3DbBackup;
58
59 /**
60 * @var \TYPO3\CMS\Felogin\Controller\FrontendLoginController|\Tx_Phpunit_Interface_AccessibleObject
61 */
62 protected $accessibleFixture;
63
64 /**
65 * @var string
66 */
67 protected $testHostName;
68
69 /**
70 * @var string
71 */
72 protected $testSitePath;
73
74 /**
75 * @var string
76 */
77 private $testTableName;
78
79 /**
80 * Set up
81 */
82 public function setUp() {
83 $this->typo3DbBackup = $GLOBALS['TYPO3_DB'];
84 $this->testTableName = 'sys_domain';
85 $this->testHostName = 'hostname.tld';
86 $this->testSitePath = '/';
87 $this->accessibleFixture = $this->getAccessibleMock('TYPO3\\CMS\\Felogin\\Controller\\FrontendLoginController', array('dummy'));
88 $this->accessibleFixture->cObj = $this->getMock('TYPO3\\CMS\\Frontend\\ContentObject\\ContentObjectRenderer');
89 $GLOBALS['TSFE'] = $this->getMock('TYPO3\\CMS\\Frontend\\Controller\\TypoScriptFrontendController', array(), array(), '', FALSE);
90 $this->setUpFakeSitePathAndHost();
91 }
92
93 /**
94 * Tear down
95 */
96 public function tearDown() {
97 $GLOBALS['TYPO3_DB'] = $this->typo3DbBackup;
98 $this->accessibleFixture = NULL;
99 }
100
101 /**
102 * Set up a fake site path and host
103 */
104 protected function setUpFakeSitePathAndHost() {
105 $_SERVER['ORIG_PATH_INFO'] = $_SERVER['PATH_INFO'] = $_SERVER['ORIG_SCRIPT_NAME'] = $_SERVER['SCRIPT_NAME'] = $this->testSitePath . TYPO3_mainDir;
106 $_SERVER['HTTP_HOST'] = $this->testHostName;
107 }
108
109 /**
110 * Mock database
111 */
112 protected function setUpDatabaseMock() {
113 $GLOBALS['TYPO3_DB'] = $this->getMock('TYPO3\\CMS\\Core\\Database\\DatabaseConnection', array('exec_SELECTgetRows'));
114 $GLOBALS['TYPO3_DB']
115 ->expects($this->any())
116 ->method('exec_SELECTgetRows')
117 ->will($this->returnCallback(array($this, 'getDomainRecordsCallback')));
118 }
119
120 /**
121 * Callback method for pageIdCanBeDetermined test cases.
122 * Simulates TYPO3_DB->exec_SELECTgetRows().
123 *
124 * @param string $fields
125 * @param string $table
126 * @param string $where
127 * @return mixed
128 * @see setUpDatabaseMock
129 */
130 public function getDomainRecordsCallback($fields, $table, $where) {
131 if ($table !== $this->testTableName) {
132 return FALSE;
133 }
134 return array(
135 array('domainName' => 'domainhostname.tld'),
136 array('domainName' => 'otherhostname.tld/path'),
137 array('domainName' => 'sub.domainhostname.tld/path/')
138 );
139 }
140
141 /**
142 * @test
143 */
144 public function typo3SitePathEqualsStubSitePath() {
145 $this->assertEquals(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'), $this->testSitePath);
146 }
147
148 /**
149 * @test
150 */
151 public function typo3SiteUrlEqualsStubSiteUrl() {
152 $this->assertEquals(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_URL'), ('http://' . $this->testHostName) . $this->testSitePath);
153 }
154
155 /**
156 * @test
157 */
158 public function typo3SitePathEqualsStubSitePathAfterChangingInTest() {
159 $this->testHostName = 'somenewhostname.com';
160 $this->testSitePath = '/somenewpath/';
161 $this->setUpFakeSitePathAndHost();
162 $this->assertEquals(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_PATH'), $this->testSitePath);
163 }
164
165 /**
166 * @test
167 */
168 public function typo3SiteUrlEqualsStubSiteUrlAfterChangingInTest() {
169 $this->testHostName = 'somenewhostname.com';
170 $this->testSitePath = '/somenewpath/';
171 $this->setUpFakeSitePathAndHost();
172 $this->assertEquals(\TYPO3\CMS\Core\Utility\GeneralUtility::getIndpEnv('TYPO3_SITE_URL'), ('http://' . $this->testHostName) . $this->testSitePath);
173 }
174
175 /**
176 * Data provider for validateRedirectUrlClearsUrl
177 *
178 * @return array
179 */
180 public function validateRedirectUrlClearsUrlDataProvider() {
181 return array(
182 'absolute URL, hostname not in sys_domain, trailing slash' => array('http://badhost.tld/'),
183 'absolute URL, hostname not in sys_domain, no trailing slash' => array('http://badhost.tld'),
184 'absolute URL, subdomain in sys_domain, but main domain not, trailing slash' => array('http://domainhostname.tld.badhost.tld/'),
185 'absolute URL, subdomain in sys_domain, but main domain not, no trailing slash' => array('http://domainhostname.tld.badhost.tld'),
186 'non http absolute URL 1' => array('its://domainhostname.tld/itunes/'),
187 'non http absolute URL 2' => array('ftp://domainhostname.tld/download/'),
188 'XSS attempt 1' => array('javascript:alert(123)'),
189 'XSS attempt 2' => array('" onmouseover="alert(123)"'),
190 'invalid URL, HTML break out attempt' => array('" >blabuubb'),
191 'invalid URL, UNC path' => array('\\\\foo\\bar\\'),
192 'invalid URL, backslashes in path' => array('http://domainhostname.tld\\bla\\blupp'),
193 'invalid URL, linefeed in path' => array('http://domainhostname.tld/bla/blupp' . LF),
194 'invalid URL, only one slash after scheme' => array('http:/domainhostname.tld/bla/blupp'),
195 'invalid URL, illegal chars' => array('http://(<>domainhostname).tld/bla/blupp'),
196 );
197 }
198
199 /**
200 * @test
201 * @dataProvider validateRedirectUrlClearsUrlDataProvider
202 * @param string $url Invalid Url
203 */
204 public function validateRedirectUrlClearsUrl($url) {
205 $this->setUpDatabaseMock();
206 $this->assertEquals('', $this->accessibleFixture->_call('validateRedirectUrl', $url));
207 }
208
209 /**
210 * Data provider for validateRedirectUrlKeepsCleanUrl
211 *
212 * @return array
213 */
214 public function validateRedirectUrlKeepsCleanUrlDataProvider() {
215 return array(
216 'sane absolute URL' => array('http://domainhostname.tld/'),
217 'sane absolute URL with script' => array('http://domainhostname.tld/index.php?id=1'),
218 'sane absolute URL with realurl' => array('http://domainhostname.tld/foo/bar/foo.html'),
219 'sane absolute URL with homedir' => array('http://domainhostname.tld/~user/'),
220 'sane absolute URL with some strange chars encoded' => array('http://domainhostname.tld/~user/a%cc%88o%cc%88%c3%9fa%cc%82/foo.html'),
221 'sane absolute URL (domain record with path)' => array('http://otherhostname.tld/path/'),
222 'sane absolute URL with script (domain record with path)' => array('http://otherhostname.tld/path/index.php?id=1'),
223 'sane absolute URL with realurl (domain record with path)' => array('http://otherhostname.tld/path/foo/bar/foo.html'),
224 'sane absolute URL (domain record with path and slash)' => array('http://sub.domainhostname.tld/path/'),
225 'sane absolute URL with script (domain record with path slash)' => array('http://sub.domainhostname.tld/path/index.php?id=1'),
226 'sane absolute URL with realurl (domain record with path slash)' => array('http://sub.domainhostname.tld/path/foo/bar/foo.html'),
227 'relative URL, no leading slash 1' => array('index.php?id=1'),
228 'relative URL, no leading slash 2' => array('foo/bar/index.php?id=2'),
229 'relative URL, leading slash, no realurl' => array('/index.php?id=1'),
230 'relative URL, leading slash, realurl' => array('/de/service/imprint.html'),
231 );
232 }
233
234 /**
235 * @test
236 * @dataProvider validateRedirectUrlKeepsCleanUrlDataProvider
237 * @param string $url Clean URL to test
238 */
239 public function validateRedirectUrlKeepsCleanUrl($url) {
240 $this->setUpDatabaseMock();
241 $this->assertEquals($url, $this->accessibleFixture->_call('validateRedirectUrl', $url));
242 }
243
244 /**
245 * Data provider for validateRedirectUrlClearsInvalidUrlInSubdirectory
246 *
247 * @return array
248 */
249 public function validateRedirectUrlClearsInvalidUrlInSubdirectoryDataProvider() {
250 return array(
251 'absolute URL, missing subdirectory' => array('http://hostname.tld/'),
252 'absolute URL, wrong subdirectory' => array('http://hostname.tld/hacker/index.php'),
253 'absolute URL, correct subdirectory, no trailing slash' => array('http://hostname.tld/subdir'),
254 'absolute URL, correct subdirectory of sys_domain record, no trailing slash' => array('http://otherhostname.tld/path'),
255 'absolute URL, correct subdirectory of sys_domain record, no trailing slash, subdomain' => array('http://sub.domainhostname.tld/path'),
256 'relative URL, leading slash, no path' => array('/index.php?id=1'),
257 'relative URL, leading slash, wrong path' => array('/de/sub/site.html'),
258 'relative URL, leading slash, slash only' => array('/'),
259 );
260 }
261
262 /**
263 * @test
264 * @dataProvider validateRedirectUrlClearsInvalidUrlInSubdirectoryDataProvider
265 * @param string $url Invalid Url
266 */
267 public function validateRedirectUrlClearsInvalidUrlInSubdirectory($url) {
268 $this->testSitePath = '/subdir/';
269 $this->setUpFakeSitePathAndHost();
270 $this->setUpDatabaseMock();
271 $this->assertEquals('', $this->accessibleFixture->_call('validateRedirectUrl', $url));
272 }
273
274 /**
275 * Data provider for validateRedirectUrlKeepsCleanUrlInSubdirectory
276 *
277 * @return array
278 */
279 public function validateRedirectUrlKeepsCleanUrlInSubdirectoryDataProvider() {
280 return array(
281 'absolute URL, correct subdirectory' => array('http://hostname.tld/subdir/'),
282 'absolute URL, correct subdirectory, realurl' => array('http://hostname.tld/subdir/de/imprint.html'),
283 'absolute URL, correct subdirectory, no realurl' => array('http://hostname.tld/subdir/index.php?id=10'),
284 'absolute URL, correct subdirectory of sys_domain record' => array('http://otherhostname.tld/path/'),
285 'absolute URL, correct subdirectory of sys_domain record, subdomain' => array('http://sub.domainhostname.tld/path/'),
286 'relative URL, no leading slash, realurl' => array('de/service/imprint.html'),
287 'relative URL, no leading slash, no realurl' => array('index.php?id=1'),
288 'relative nested URL, no leading slash, no realurl' => array('foo/bar/index.php?id=2')
289 );
290 }
291
292 /**
293 * @test
294 * @dataProvider validateRedirectUrlKeepsCleanUrlInSubdirectoryDataProvider
295 * @param string $url Invalid Url
296 */
297 public function validateRedirectUrlKeepsCleanUrlInSubdirectory($url) {
298 $this->testSitePath = '/subdir/';
299 $this->setUpFakeSitePathAndHost();
300 $this->setUpDatabaseMock();
301 $this->assertEquals($url, $this->accessibleFixture->_call('validateRedirectUrl', $url));
302 }
303
304 }
305
306 ?>