RequestTest.php 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051
  1. <?php
  2. /**
  3. * @copyright 2013 Thomas Tanghus (thomas@tanghus.net)
  4. * @copyright 2016 Lukas Reschke lukas@owncloud.com
  5. *
  6. * This file is licensed under the Affero General Public License version 3 or
  7. * later.
  8. * See the COPYING-README file.
  9. */
  10. namespace Test\AppFramework\Http;
  11. use OC\AppFramework\Http\Request;
  12. use OC\Security\CSRF\CsrfToken;
  13. use OC\Security\CSRF\CsrfTokenManager;
  14. use OCP\Security\ISecureRandom;
  15. use OCP\IConfig;
  16. /**
  17. * Class RequestTest
  18. *
  19. * @package OC\AppFramework\Http
  20. */
  21. class RequestTest extends \Test\TestCase {
  22. /** @var string */
  23. protected $stream = 'fakeinput://data';
  24. /** @var ISecureRandom */
  25. protected $secureRandom;
  26. /** @var IConfig */
  27. protected $config;
  28. /** @var CsrfTokenManager */
  29. protected $csrfTokenManager;
  30. protected function setUp() {
  31. parent::setUp();
  32. if (in_array('fakeinput', stream_get_wrappers())) {
  33. stream_wrapper_unregister('fakeinput');
  34. }
  35. stream_wrapper_register('fakeinput', 'Test\AppFramework\Http\RequestStream');
  36. $this->secureRandom = $this->getMockBuilder('\OCP\Security\ISecureRandom')->getMock();
  37. $this->config = $this->getMockBuilder(IConfig::class)->getMock();
  38. $this->csrfTokenManager = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenManager')
  39. ->disableOriginalConstructor()->getMock();
  40. }
  41. protected function tearDown() {
  42. stream_wrapper_unregister('fakeinput');
  43. parent::tearDown();
  44. }
  45. public function testRequestAccessors() {
  46. $vars = array(
  47. 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
  48. 'method' => 'GET',
  49. );
  50. $request = new Request(
  51. $vars,
  52. $this->secureRandom,
  53. $this->config,
  54. $this->csrfTokenManager,
  55. $this->stream
  56. );
  57. // Countable
  58. $this->assertSame(2, count($request));
  59. // Array access
  60. $this->assertSame('Joey', $request['nickname']);
  61. // "Magic" accessors
  62. $this->assertSame('Joey', $request->{'nickname'});
  63. $this->assertTrue(isset($request['nickname']));
  64. $this->assertTrue(isset($request->{'nickname'}));
  65. $this->assertFalse(isset($request->{'flickname'}));
  66. // Only testing 'get', but same approach for post, files etc.
  67. $this->assertSame('Joey', $request->get['nickname']);
  68. // Always returns null if variable not set.
  69. $this->assertSame(null, $request->{'flickname'});
  70. }
  71. // urlParams has precedence over POST which has precedence over GET
  72. public function testPrecedence() {
  73. $vars = array(
  74. 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
  75. 'post' => array('name' => 'Jane Doe', 'nickname' => 'Janey'),
  76. 'urlParams' => array('user' => 'jw', 'name' => 'Johnny Weissmüller'),
  77. 'method' => 'GET'
  78. );
  79. $request = new Request(
  80. $vars,
  81. $this->secureRandom,
  82. $this->config,
  83. $this->csrfTokenManager,
  84. $this->stream
  85. );
  86. $this->assertSame(3, count($request));
  87. $this->assertSame('Janey', $request->{'nickname'});
  88. $this->assertSame('Johnny Weissmüller', $request->{'name'});
  89. }
  90. /**
  91. * @expectedException \RuntimeException
  92. */
  93. public function testImmutableArrayAccess() {
  94. $vars = array(
  95. 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
  96. 'method' => 'GET'
  97. );
  98. $request = new Request(
  99. $vars,
  100. $this->secureRandom,
  101. $this->config,
  102. $this->csrfTokenManager,
  103. $this->stream
  104. );
  105. $request['nickname'] = 'Janey';
  106. }
  107. /**
  108. * @expectedException \RuntimeException
  109. */
  110. public function testImmutableMagicAccess() {
  111. $vars = array(
  112. 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
  113. 'method' => 'GET'
  114. );
  115. $request = new Request(
  116. $vars,
  117. $this->secureRandom,
  118. $this->config,
  119. $this->csrfTokenManager,
  120. $this->stream
  121. );
  122. $request->{'nickname'} = 'Janey';
  123. }
  124. /**
  125. * @expectedException \LogicException
  126. */
  127. public function testGetTheMethodRight() {
  128. $vars = array(
  129. 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
  130. 'method' => 'GET',
  131. );
  132. $request = new Request(
  133. $vars,
  134. $this->secureRandom,
  135. $this->config,
  136. $this->csrfTokenManager,
  137. $this->stream
  138. );
  139. $request->post;
  140. }
  141. public function testTheMethodIsRight() {
  142. $vars = array(
  143. 'get' => array('name' => 'John Q. Public', 'nickname' => 'Joey'),
  144. 'method' => 'GET',
  145. );
  146. $request = new Request(
  147. $vars,
  148. $this->secureRandom,
  149. $this->config,
  150. $this->csrfTokenManager,
  151. $this->stream
  152. );
  153. $this->assertSame('GET', $request->method);
  154. $result = $request->get;
  155. $this->assertSame('John Q. Public', $result['name']);
  156. $this->assertSame('Joey', $result['nickname']);
  157. }
  158. public function testJsonPost() {
  159. global $data;
  160. $data = '{"name": "John Q. Public", "nickname": "Joey"}';
  161. $vars = array(
  162. 'method' => 'POST',
  163. 'server' => array('CONTENT_TYPE' => 'application/json; utf-8')
  164. );
  165. $request = new Request(
  166. $vars,
  167. $this->secureRandom,
  168. $this->config,
  169. $this->csrfTokenManager,
  170. $this->stream
  171. );
  172. $this->assertSame('POST', $request->method);
  173. $result = $request->post;
  174. $this->assertSame('John Q. Public', $result['name']);
  175. $this->assertSame('Joey', $result['nickname']);
  176. $this->assertSame('Joey', $request->params['nickname']);
  177. $this->assertSame('Joey', $request['nickname']);
  178. }
  179. public function testNotJsonPost() {
  180. global $data;
  181. $data = 'this is not valid json';
  182. $vars = array(
  183. 'method' => 'POST',
  184. 'server' => array('CONTENT_TYPE' => 'application/json; utf-8')
  185. );
  186. $request = new Request(
  187. $vars,
  188. $this->secureRandom,
  189. $this->config,
  190. $this->csrfTokenManager,
  191. $this->stream
  192. );
  193. $this->assertEquals('POST', $request->method);
  194. $result = $request->post;
  195. // ensure there's no error attempting to decode the content
  196. }
  197. public function testPatch() {
  198. global $data;
  199. $data = http_build_query(array('name' => 'John Q. Public', 'nickname' => 'Joey'), '', '&');
  200. $vars = array(
  201. 'method' => 'PATCH',
  202. 'server' => array('CONTENT_TYPE' => 'application/x-www-form-urlencoded'),
  203. );
  204. $request = new Request(
  205. $vars,
  206. $this->secureRandom,
  207. $this->config,
  208. $this->csrfTokenManager,
  209. $this->stream
  210. );
  211. $this->assertSame('PATCH', $request->method);
  212. $result = $request->patch;
  213. $this->assertSame('John Q. Public', $result['name']);
  214. $this->assertSame('Joey', $result['nickname']);
  215. }
  216. public function testJsonPatchAndPut() {
  217. global $data;
  218. // PUT content
  219. $data = '{"name": "John Q. Public", "nickname": "Joey"}';
  220. $vars = array(
  221. 'method' => 'PUT',
  222. 'server' => array('CONTENT_TYPE' => 'application/json; utf-8'),
  223. );
  224. $request = new Request(
  225. $vars,
  226. $this->secureRandom,
  227. $this->config,
  228. $this->csrfTokenManager,
  229. $this->stream
  230. );
  231. $this->assertSame('PUT', $request->method);
  232. $result = $request->put;
  233. $this->assertSame('John Q. Public', $result['name']);
  234. $this->assertSame('Joey', $result['nickname']);
  235. // PATCH content
  236. $data = '{"name": "John Q. Public", "nickname": null}';
  237. $vars = array(
  238. 'method' => 'PATCH',
  239. 'server' => array('CONTENT_TYPE' => 'application/json; utf-8'),
  240. );
  241. $request = new Request(
  242. $vars,
  243. $this->secureRandom,
  244. $this->config,
  245. $this->csrfTokenManager,
  246. $this->stream
  247. );
  248. $this->assertSame('PATCH', $request->method);
  249. $result = $request->patch;
  250. $this->assertSame('John Q. Public', $result['name']);
  251. $this->assertSame(null, $result['nickname']);
  252. }
  253. public function testPutStream() {
  254. global $data;
  255. $data = file_get_contents(__DIR__ . '/../../../data/testimage.png');
  256. $vars = array(
  257. 'put' => $data,
  258. 'method' => 'PUT',
  259. 'server' => [
  260. 'CONTENT_TYPE' => 'image/png',
  261. 'CONTENT_LENGTH' => (string)strlen($data)
  262. ],
  263. );
  264. $request = new Request(
  265. $vars,
  266. $this->secureRandom,
  267. $this->config,
  268. $this->csrfTokenManager,
  269. $this->stream
  270. );
  271. $this->assertSame('PUT', $request->method);
  272. $resource = $request->put;
  273. $contents = stream_get_contents($resource);
  274. $this->assertSame($data, $contents);
  275. try {
  276. $resource = $request->put;
  277. } catch(\LogicException $e) {
  278. return;
  279. }
  280. $this->fail('Expected LogicException.');
  281. }
  282. public function testSetUrlParameters() {
  283. $vars = array(
  284. 'post' => array(),
  285. 'method' => 'POST',
  286. 'urlParams' => array('id' => '2'),
  287. );
  288. $request = new Request(
  289. $vars,
  290. $this->secureRandom,
  291. $this->config,
  292. $this->csrfTokenManager,
  293. $this->stream
  294. );
  295. $newParams = array('id' => '3', 'test' => 'test2');
  296. $request->setUrlParameters($newParams);
  297. $this->assertSame('test2', $request->getParam('test'));
  298. $this->assertEquals('3', $request->getParam('id'));
  299. $this->assertEquals('3', $request->getParams()['id']);
  300. }
  301. public function testGetIdWithModUnique() {
  302. $vars = [
  303. 'server' => [
  304. 'UNIQUE_ID' => 'GeneratedUniqueIdByModUnique'
  305. ],
  306. ];
  307. $request = new Request(
  308. $vars,
  309. $this->secureRandom,
  310. $this->config,
  311. $this->csrfTokenManager,
  312. $this->stream
  313. );
  314. $this->assertSame('GeneratedUniqueIdByModUnique', $request->getId());
  315. }
  316. public function testGetIdWithoutModUnique() {
  317. $this->secureRandom->expects($this->once())
  318. ->method('generate')
  319. ->with('20')
  320. ->will($this->returnValue('GeneratedByOwnCloudItself'));
  321. $request = new Request(
  322. [],
  323. $this->secureRandom,
  324. $this->config,
  325. $this->csrfTokenManager,
  326. $this->stream
  327. );
  328. $this->assertSame('GeneratedByOwnCloudItself', $request->getId());
  329. }
  330. public function testGetIdWithoutModUniqueStable() {
  331. $request = new Request(
  332. [],
  333. \OC::$server->getSecureRandom(),
  334. $this->config,
  335. $this->csrfTokenManager,
  336. $this->stream
  337. );
  338. $firstId = $request->getId();
  339. $secondId = $request->getId();
  340. $this->assertSame($firstId, $secondId);
  341. }
  342. public function testGetRemoteAddressWithoutTrustedRemote() {
  343. $this->config
  344. ->expects($this->once())
  345. ->method('getSystemValue')
  346. ->with('trusted_proxies')
  347. ->will($this->returnValue([]));
  348. $request = new Request(
  349. [
  350. 'server' => [
  351. 'REMOTE_ADDR' => '10.0.0.2',
  352. 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4',
  353. 'HTTP_X_FORWARDED_FOR' => '192.168.0.233'
  354. ],
  355. ],
  356. $this->secureRandom,
  357. $this->config,
  358. $this->csrfTokenManager,
  359. $this->stream
  360. );
  361. $this->assertSame('10.0.0.2', $request->getRemoteAddress());
  362. }
  363. public function testGetRemoteAddressWithNoTrustedHeader() {
  364. $this->config
  365. ->expects($this->at(0))
  366. ->method('getSystemValue')
  367. ->with('trusted_proxies')
  368. ->will($this->returnValue(['10.0.0.2']));
  369. $this->config
  370. ->expects($this->at(1))
  371. ->method('getSystemValue')
  372. ->with('forwarded_for_headers')
  373. ->will($this->returnValue([]));
  374. $request = new Request(
  375. [
  376. 'server' => [
  377. 'REMOTE_ADDR' => '10.0.0.2',
  378. 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4',
  379. 'HTTP_X_FORWARDED_FOR' => '192.168.0.233'
  380. ],
  381. ],
  382. $this->secureRandom,
  383. $this->config,
  384. $this->csrfTokenManager,
  385. $this->stream
  386. );
  387. $this->assertSame('10.0.0.2', $request->getRemoteAddress());
  388. }
  389. public function testGetRemoteAddressWithSingleTrustedRemote() {
  390. $this->config
  391. ->expects($this->at(0))
  392. ->method('getSystemValue')
  393. ->with('trusted_proxies')
  394. ->will($this->returnValue(['10.0.0.2']));
  395. $this->config
  396. ->expects($this->at(1))
  397. ->method('getSystemValue')
  398. ->with('forwarded_for_headers')
  399. ->will($this->returnValue(['HTTP_X_FORWARDED']));
  400. $request = new Request(
  401. [
  402. 'server' => [
  403. 'REMOTE_ADDR' => '10.0.0.2',
  404. 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4',
  405. 'HTTP_X_FORWARDED_FOR' => '192.168.0.233'
  406. ],
  407. ],
  408. $this->secureRandom,
  409. $this->config,
  410. $this->csrfTokenManager,
  411. $this->stream
  412. );
  413. $this->assertSame('10.4.0.5', $request->getRemoteAddress());
  414. }
  415. public function testGetRemoteAddressIPv6WithSingleTrustedRemote() {
  416. $this->config
  417. ->expects($this->at(0))
  418. ->method('getSystemValue')
  419. ->with('trusted_proxies')
  420. ->will($this->returnValue(['2001:db8:85a3:8d3:1319:8a2e:370:7348']));
  421. $this->config
  422. ->expects($this->at(1))
  423. ->method('getSystemValue')
  424. ->with('forwarded_for_headers')
  425. ->will($this->returnValue(['HTTP_X_FORWARDED']));
  426. $request = new Request(
  427. [
  428. 'server' => [
  429. 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348',
  430. 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4',
  431. 'HTTP_X_FORWARDED_FOR' => '192.168.0.233'
  432. ],
  433. ],
  434. $this->secureRandom,
  435. $this->config,
  436. $this->csrfTokenManager,
  437. $this->stream
  438. );
  439. $this->assertSame('10.4.0.5', $request->getRemoteAddress());
  440. }
  441. public function testGetRemoteAddressVerifyPriorityHeader() {
  442. $this->config
  443. ->expects($this->at(0))
  444. ->method('getSystemValue')
  445. ->with('trusted_proxies')
  446. ->will($this->returnValue(['10.0.0.2']));
  447. $this->config
  448. ->expects($this->at(1))
  449. ->method('getSystemValue')
  450. ->with('forwarded_for_headers')
  451. ->will($this->returnValue([
  452. 'HTTP_CLIENT_IP',
  453. 'HTTP_X_FORWARDED_FOR',
  454. 'HTTP_X_FORWARDED'
  455. ]));
  456. $request = new Request(
  457. [
  458. 'server' => [
  459. 'REMOTE_ADDR' => '10.0.0.2',
  460. 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4',
  461. 'HTTP_X_FORWARDED_FOR' => '192.168.0.233'
  462. ],
  463. ],
  464. $this->secureRandom,
  465. $this->config,
  466. $this->csrfTokenManager,
  467. $this->stream
  468. );
  469. $this->assertSame('192.168.0.233', $request->getRemoteAddress());
  470. }
  471. public function testGetRemoteAddressIPv6VerifyPriorityHeader() {
  472. $this->config
  473. ->expects($this->at(0))
  474. ->method('getSystemValue')
  475. ->with('trusted_proxies')
  476. ->will($this->returnValue(['2001:db8:85a3:8d3:1319:8a2e:370:7348']));
  477. $this->config
  478. ->expects($this->at(1))
  479. ->method('getSystemValue')
  480. ->with('forwarded_for_headers')
  481. ->will($this->returnValue([
  482. 'HTTP_CLIENT_IP',
  483. 'HTTP_X_FORWARDED_FOR',
  484. 'HTTP_X_FORWARDED'
  485. ]));
  486. $request = new Request(
  487. [
  488. 'server' => [
  489. 'REMOTE_ADDR' => '2001:db8:85a3:8d3:1319:8a2e:370:7348',
  490. 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4',
  491. 'HTTP_X_FORWARDED_FOR' => '192.168.0.233'
  492. ],
  493. ],
  494. $this->secureRandom,
  495. $this->config,
  496. $this->csrfTokenManager,
  497. $this->stream
  498. );
  499. $this->assertSame('192.168.0.233', $request->getRemoteAddress());
  500. }
  501. public function testGetRemoteAddressWithMatchingCidrTrustedRemote() {
  502. $this->config
  503. ->expects($this->at(0))
  504. ->method('getSystemValue')
  505. ->with('trusted_proxies')
  506. ->will($this->returnValue(['192.168.2.0/24']));
  507. $this->config
  508. ->expects($this->at(1))
  509. ->method('getSystemValue')
  510. ->with('forwarded_for_headers')
  511. ->will($this->returnValue(['HTTP_X_FORWARDED_FOR']));
  512. $request = new Request(
  513. [
  514. 'server' => [
  515. 'REMOTE_ADDR' => '192.168.2.99',
  516. 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4',
  517. 'HTTP_X_FORWARDED_FOR' => '192.168.0.233'
  518. ],
  519. ],
  520. $this->secureRandom,
  521. $this->config,
  522. $this->csrfTokenManager,
  523. $this->stream
  524. );
  525. $this->assertSame('192.168.0.233', $request->getRemoteAddress());
  526. }
  527. public function testGetRemoteAddressWithNotMatchingCidrTrustedRemote() {
  528. $this->config
  529. ->expects($this->once())
  530. ->method('getSystemValue')
  531. ->with('trusted_proxies')
  532. ->will($this->returnValue(['192.168.2.0/24']));
  533. $request = new Request(
  534. [
  535. 'server' => [
  536. 'REMOTE_ADDR' => '192.168.3.99',
  537. 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4',
  538. 'HTTP_X_FORWARDED_FOR' => '192.168.0.233'
  539. ],
  540. ],
  541. $this->secureRandom,
  542. $this->config,
  543. $this->csrfTokenManager,
  544. $this->stream
  545. );
  546. $this->assertSame('192.168.3.99', $request->getRemoteAddress());
  547. }
  548. /**
  549. * @return array
  550. */
  551. public function httpProtocolProvider() {
  552. return [
  553. // Valid HTTP 1.0
  554. ['HTTP/1.0', 'HTTP/1.0'],
  555. ['http/1.0', 'HTTP/1.0'],
  556. ['HTTp/1.0', 'HTTP/1.0'],
  557. // Valid HTTP 1.1
  558. ['HTTP/1.1', 'HTTP/1.1'],
  559. ['http/1.1', 'HTTP/1.1'],
  560. ['HTTp/1.1', 'HTTP/1.1'],
  561. // Valid HTTP 2.0
  562. ['HTTP/2', 'HTTP/2'],
  563. ['http/2', 'HTTP/2'],
  564. ['HTTp/2', 'HTTP/2'],
  565. // Invalid
  566. ['HTTp/394', 'HTTP/1.1'],
  567. ['InvalidProvider/1.1', 'HTTP/1.1'],
  568. [null, 'HTTP/1.1'],
  569. ['', 'HTTP/1.1'],
  570. ];
  571. }
  572. /**
  573. * @dataProvider httpProtocolProvider
  574. *
  575. * @param mixed $input
  576. * @param string $expected
  577. */
  578. public function testGetHttpProtocol($input, $expected) {
  579. $request = new Request(
  580. [
  581. 'server' => [
  582. 'SERVER_PROTOCOL' => $input,
  583. ],
  584. ],
  585. $this->secureRandom,
  586. $this->config,
  587. $this->csrfTokenManager,
  588. $this->stream
  589. );
  590. $this->assertSame($expected, $request->getHttpProtocol());
  591. }
  592. public function testGetServerProtocolWithOverride() {
  593. $this->config
  594. ->expects($this->at(0))
  595. ->method('getSystemValue')
  596. ->with('overwriteprotocol')
  597. ->will($this->returnValue('customProtocol'));
  598. $this->config
  599. ->expects($this->at(1))
  600. ->method('getSystemValue')
  601. ->with('overwritecondaddr')
  602. ->will($this->returnValue(''));
  603. $this->config
  604. ->expects($this->at(2))
  605. ->method('getSystemValue')
  606. ->with('overwriteprotocol')
  607. ->will($this->returnValue('customProtocol'));
  608. $request = new Request(
  609. [],
  610. $this->secureRandom,
  611. $this->config,
  612. $this->csrfTokenManager,
  613. $this->stream
  614. );
  615. $this->assertSame('customProtocol', $request->getServerProtocol());
  616. }
  617. public function testGetServerProtocolWithProtoValid() {
  618. $this->config
  619. ->method('getSystemValue')
  620. ->will($this->returnCallback(function($key, $default) {
  621. if ($key === 'trusted_proxies') {
  622. return ['1.2.3.4'];
  623. }
  624. return $default;
  625. }));
  626. $requestHttps = new Request(
  627. [
  628. 'server' => [
  629. 'HTTP_X_FORWARDED_PROTO' => 'HtTpS',
  630. 'REMOTE_ADDR' => '1.2.3.4',
  631. ],
  632. ],
  633. $this->secureRandom,
  634. $this->config,
  635. $this->csrfTokenManager,
  636. $this->stream
  637. );
  638. $requestHttp = new Request(
  639. [
  640. 'server' => [
  641. 'HTTP_X_FORWARDED_PROTO' => 'HTTp',
  642. 'REMOTE_ADDR' => '1.2.3.4',
  643. ],
  644. ],
  645. $this->secureRandom,
  646. $this->config,
  647. $this->csrfTokenManager,
  648. $this->stream
  649. );
  650. $this->assertSame('https', $requestHttps->getServerProtocol());
  651. $this->assertSame('http', $requestHttp->getServerProtocol());
  652. }
  653. public function testGetServerProtocolWithHttpsServerValueOn() {
  654. $this->config
  655. ->method('getSystemValue')
  656. ->will($this->returnCallback(function($key, $default) {
  657. return $default;
  658. }));
  659. $request = new Request(
  660. [
  661. 'server' => [
  662. 'HTTPS' => 'on'
  663. ],
  664. ],
  665. $this->secureRandom,
  666. $this->config,
  667. $this->csrfTokenManager,
  668. $this->stream
  669. );
  670. $this->assertSame('https', $request->getServerProtocol());
  671. }
  672. public function testGetServerProtocolWithHttpsServerValueOff() {
  673. $this->config
  674. ->method('getSystemValue')
  675. ->will($this->returnCallback(function($key, $default) {
  676. return $default;
  677. }));
  678. $request = new Request(
  679. [
  680. 'server' => [
  681. 'HTTPS' => 'off'
  682. ],
  683. ],
  684. $this->secureRandom,
  685. $this->config,
  686. $this->csrfTokenManager,
  687. $this->stream
  688. );
  689. $this->assertSame('http', $request->getServerProtocol());
  690. }
  691. public function testGetServerProtocolWithHttpsServerValueEmpty() {
  692. $this->config
  693. ->method('getSystemValue')
  694. ->will($this->returnCallback(function($key, $default) {
  695. return $default;
  696. }));
  697. $request = new Request(
  698. [
  699. 'server' => [
  700. 'HTTPS' => ''
  701. ],
  702. ],
  703. $this->secureRandom,
  704. $this->config,
  705. $this->csrfTokenManager,
  706. $this->stream
  707. );
  708. $this->assertSame('http', $request->getServerProtocol());
  709. }
  710. public function testGetServerProtocolDefault() {
  711. $this->config
  712. ->method('getSystemValue')
  713. ->will($this->returnCallback(function($key, $default) {
  714. return $default;
  715. }));
  716. $request = new Request(
  717. [],
  718. $this->secureRandom,
  719. $this->config,
  720. $this->csrfTokenManager,
  721. $this->stream
  722. );
  723. $this->assertSame('http', $request->getServerProtocol());
  724. }
  725. public function testGetServerProtocolBehindLoadBalancers() {
  726. $this->config
  727. ->method('getSystemValue')
  728. ->will($this->returnCallback(function($key, $default) {
  729. if ($key === 'trusted_proxies') {
  730. return ['1.2.3.4'];
  731. }
  732. return $default;
  733. }));
  734. $request = new Request(
  735. [
  736. 'server' => [
  737. 'HTTP_X_FORWARDED_PROTO' => 'https,http,http',
  738. 'REMOTE_ADDR' => '1.2.3.4',
  739. ],
  740. ],
  741. $this->secureRandom,
  742. $this->config,
  743. $this->csrfTokenManager,
  744. $this->stream
  745. );
  746. $this->assertSame('https', $request->getServerProtocol());
  747. }
  748. /**
  749. * @dataProvider userAgentProvider
  750. * @param string $testAgent
  751. * @param array $userAgent
  752. * @param bool $matches
  753. */
  754. public function testUserAgent($testAgent, $userAgent, $matches) {
  755. $request = new Request(
  756. [
  757. 'server' => [
  758. 'HTTP_USER_AGENT' => $testAgent,
  759. ]
  760. ],
  761. $this->secureRandom,
  762. $this->config,
  763. $this->csrfTokenManager,
  764. $this->stream
  765. );
  766. $this->assertSame($matches, $request->isUserAgent($userAgent));
  767. }
  768. /**
  769. * @dataProvider userAgentProvider
  770. * @param string $testAgent
  771. * @param array $userAgent
  772. * @param bool $matches
  773. */
  774. public function testUndefinedUserAgent($testAgent, $userAgent, $matches) {
  775. $request = new Request(
  776. [],
  777. $this->secureRandom,
  778. $this->config,
  779. $this->csrfTokenManager,
  780. $this->stream
  781. );
  782. $this->assertFalse($request->isUserAgent($userAgent));
  783. }
  784. /**
  785. * @return array
  786. */
  787. function userAgentProvider() {
  788. return [
  789. [
  790. 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
  791. [
  792. Request::USER_AGENT_IE
  793. ],
  794. true,
  795. ],
  796. [
  797. 'Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Firefox/24.0',
  798. [
  799. Request::USER_AGENT_IE
  800. ],
  801. false,
  802. ],
  803. [
  804. 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
  805. [
  806. Request::USER_AGENT_CHROME
  807. ],
  808. true,
  809. ],
  810. [
  811. 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/53.0.2785.143 Chrome/53.0.2785.143 Safari/537.36',
  812. [
  813. Request::USER_AGENT_CHROME
  814. ],
  815. true,
  816. ],
  817. [
  818. 'Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36',
  819. [
  820. Request::USER_AGENT_ANDROID_MOBILE_CHROME
  821. ],
  822. true,
  823. ],
  824. [
  825. 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
  826. [
  827. Request::USER_AGENT_ANDROID_MOBILE_CHROME
  828. ],
  829. false,
  830. ],
  831. [
  832. 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
  833. [
  834. Request::USER_AGENT_IE,
  835. Request::USER_AGENT_ANDROID_MOBILE_CHROME,
  836. ],
  837. true,
  838. ],
  839. [
  840. 'Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16S) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36',
  841. [
  842. Request::USER_AGENT_IE,
  843. Request::USER_AGENT_ANDROID_MOBILE_CHROME,
  844. ],
  845. true,
  846. ],
  847. [
  848. 'Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Firefox/24.0',
  849. [
  850. Request::USER_AGENT_FREEBOX
  851. ],
  852. false,
  853. ],
  854. [
  855. 'Mozilla/5.0',
  856. [
  857. Request::USER_AGENT_FREEBOX
  858. ],
  859. true,
  860. ],
  861. [
  862. 'Fake Mozilla/5.0',
  863. [
  864. Request::USER_AGENT_FREEBOX
  865. ],
  866. false,
  867. ],
  868. [
  869. 'Mozilla/5.0 (Android) ownCloud-android/2.0.0',
  870. [
  871. Request::USER_AGENT_CLIENT_ANDROID
  872. ],
  873. true,
  874. ],
  875. [
  876. 'Mozilla/5.0 (Android) Nextcloud-android/2.0.0',
  877. [
  878. Request::USER_AGENT_CLIENT_ANDROID
  879. ],
  880. true,
  881. ],
  882. ];
  883. }
  884. public function testInsecureServerHostServerNameHeader() {
  885. $request = new Request(
  886. [
  887. 'server' => [
  888. 'SERVER_NAME' => 'from.server.name:8080',
  889. ]
  890. ],
  891. $this->secureRandom,
  892. $this->config,
  893. $this->csrfTokenManager,
  894. $this->stream
  895. );
  896. $this->assertSame('from.server.name:8080', $request->getInsecureServerHost());
  897. }
  898. public function testInsecureServerHostHttpHostHeader() {
  899. $request = new Request(
  900. [
  901. 'server' => [
  902. 'SERVER_NAME' => 'from.server.name:8080',
  903. 'HTTP_HOST' => 'from.host.header:8080',
  904. ]
  905. ],
  906. $this->secureRandom,
  907. $this->config,
  908. $this->csrfTokenManager,
  909. $this->stream
  910. );
  911. $this->assertSame('from.host.header:8080', $request->getInsecureServerHost());
  912. }
  913. public function testInsecureServerHostHttpFromForwardedHeaderSingle() {
  914. $this->config
  915. ->method('getSystemValue')
  916. ->will($this->returnCallback(function($key, $default) {
  917. if ($key === 'trusted_proxies') {
  918. return ['1.2.3.4'];
  919. }
  920. return $default;
  921. }));
  922. $request = new Request(
  923. [
  924. 'server' => [
  925. 'SERVER_NAME' => 'from.server.name:8080',
  926. 'HTTP_HOST' => 'from.host.header:8080',
  927. 'HTTP_X_FORWARDED_HOST' => 'from.forwarded.host:8080',
  928. 'REMOTE_ADDR' => '1.2.3.4',
  929. ]
  930. ],
  931. $this->secureRandom,
  932. $this->config,
  933. $this->csrfTokenManager,
  934. $this->stream
  935. );
  936. $this->assertSame('from.forwarded.host:8080', $request->getInsecureServerHost());
  937. }
  938. public function testInsecureServerHostHttpFromForwardedHeaderStacked() {
  939. $this->config
  940. ->method('getSystemValue')
  941. ->will($this->returnCallback(function($key, $default) {
  942. if ($key === 'trusted_proxies') {
  943. return ['1.2.3.4'];
  944. }
  945. return $default;
  946. }));
  947. $request = new Request(
  948. [
  949. 'server' => [
  950. 'SERVER_NAME' => 'from.server.name:8080',
  951. 'HTTP_HOST' => 'from.host.header:8080',
  952. 'HTTP_X_FORWARDED_HOST' => 'from.forwarded.host2:8080,another.one:9000',
  953. 'REMOTE_ADDR' => '1.2.3.4',
  954. ]
  955. ],
  956. $this->secureRandom,
  957. $this->config,
  958. $this->csrfTokenManager,
  959. $this->stream
  960. );
  961. $this->assertSame('from.forwarded.host2:8080', $request->getInsecureServerHost());
  962. }
  963. public function testGetServerHostWithOverwriteHost() {
  964. $this->config
  965. ->method('getSystemValue')
  966. ->will($this->returnCallback(function($key, $default) {
  967. if ($key === 'overwritecondaddr') {
  968. return '';
  969. } else if ($key === 'overwritehost') {
  970. return 'my.overwritten.host';
  971. }
  972. return $default;
  973. }));
  974. $request = new Request(
  975. [],
  976. $this->secureRandom,
  977. $this->config,
  978. $this->csrfTokenManager,
  979. $this->stream
  980. );
  981. $this->assertSame('my.overwritten.host', $request->getServerHost());
  982. }
  983. public function testGetServerHostWithTrustedDomain() {
  984. $this->config
  985. ->method('getSystemValue')
  986. ->will($this->returnCallback(function($key, $default) {
  987. if ($key === 'trusted_proxies') {
  988. return ['1.2.3.4'];
  989. } else if ($key === 'trusted_domains') {
  990. return ['my.trusted.host'];
  991. }
  992. return $default;
  993. }));
  994. $request = new Request(
  995. [
  996. 'server' => [
  997. 'HTTP_X_FORWARDED_HOST' => 'my.trusted.host',
  998. 'REMOTE_ADDR' => '1.2.3.4',
  999. ],
  1000. ],
  1001. $this->secureRandom,
  1002. $this->config,
  1003. $this->csrfTokenManager,
  1004. $this->stream
  1005. );
  1006. $this->assertSame('my.trusted.host', $request->getServerHost());
  1007. }
  1008. public function testGetServerHostWithUntrustedDomain() {
  1009. $this->config
  1010. ->method('getSystemValue')
  1011. ->will($this->returnCallback(function($key, $default) {
  1012. if ($key === 'trusted_proxies') {
  1013. return ['1.2.3.4'];
  1014. } else if ($key === 'trusted_domains') {
  1015. return ['my.trusted.host'];
  1016. }
  1017. return $default;
  1018. }));
  1019. $request = new Request(
  1020. [
  1021. 'server' => [
  1022. 'HTTP_X_FORWARDED_HOST' => 'my.untrusted.host',
  1023. 'REMOTE_ADDR' => '1.2.3.4',
  1024. ],
  1025. ],
  1026. $this->secureRandom,
  1027. $this->config,
  1028. $this->csrfTokenManager,
  1029. $this->stream
  1030. );
  1031. $this->assertSame('my.trusted.host', $request->getServerHost());
  1032. }
  1033. public function testGetServerHostWithNoTrustedDomain() {
  1034. $this->config
  1035. ->method('getSystemValue')
  1036. ->will($this->returnCallback(function($key, $default) {
  1037. if ($key === 'trusted_proxies') {
  1038. return ['1.2.3.4'];
  1039. }
  1040. return $default;
  1041. }));
  1042. $request = new Request(
  1043. [
  1044. 'server' => [
  1045. 'HTTP_X_FORWARDED_HOST' => 'my.untrusted.host',
  1046. 'REMOTE_ADDR' => '1.2.3.4',
  1047. ],
  1048. ],
  1049. $this->secureRandom,
  1050. $this->config,
  1051. $this->csrfTokenManager,
  1052. $this->stream
  1053. );
  1054. $this->assertSame('', $request->getServerHost());
  1055. }
  1056. public function testGetOverwriteHostDefaultNull() {
  1057. $this->config
  1058. ->expects($this->once())
  1059. ->method('getSystemValue')
  1060. ->with('overwritehost')
  1061. ->will($this->returnValue(''));
  1062. $request = new Request(
  1063. [],
  1064. $this->secureRandom,
  1065. $this->config,
  1066. $this->csrfTokenManager,
  1067. $this->stream
  1068. );
  1069. $this->assertNull(self::invokePrivate($request, 'getOverwriteHost'));
  1070. }
  1071. public function testGetOverwriteHostWithOverwrite() {
  1072. $this->config
  1073. ->expects($this->at(0))
  1074. ->method('getSystemValue')
  1075. ->with('overwritehost')
  1076. ->will($this->returnValue('www.owncloud.org'));
  1077. $this->config
  1078. ->expects($this->at(1))
  1079. ->method('getSystemValue')
  1080. ->with('overwritecondaddr')
  1081. ->will($this->returnValue(''));
  1082. $this->config
  1083. ->expects($this->at(2))
  1084. ->method('getSystemValue')
  1085. ->with('overwritehost')
  1086. ->will($this->returnValue('www.owncloud.org'));
  1087. $request = new Request(
  1088. [],
  1089. $this->secureRandom,
  1090. $this->config,
  1091. $this->csrfTokenManager,
  1092. $this->stream
  1093. );
  1094. $this->assertSame('www.owncloud.org', self::invokePrivate($request, 'getOverwriteHost'));
  1095. }
  1096. /**
  1097. * @expectedException \Exception
  1098. * @expectedExceptionMessage The requested uri(/foo.php) cannot be processed by the script '/var/www/index.php')
  1099. */
  1100. public function testGetPathInfoNotProcessible() {
  1101. $request = new Request(
  1102. [
  1103. 'server' => [
  1104. 'REQUEST_URI' => '/foo.php',
  1105. 'SCRIPT_NAME' => '/var/www/index.php',
  1106. ]
  1107. ],
  1108. $this->secureRandom,
  1109. $this->config,
  1110. $this->csrfTokenManager,
  1111. $this->stream
  1112. );
  1113. $request->getPathInfo();
  1114. }
  1115. /**
  1116. * @expectedException \Exception
  1117. * @expectedExceptionMessage The requested uri(/foo.php) cannot be processed by the script '/var/www/index.php')
  1118. */
  1119. public function testGetRawPathInfoNotProcessible() {
  1120. $request = new Request(
  1121. [
  1122. 'server' => [
  1123. 'REQUEST_URI' => '/foo.php',
  1124. 'SCRIPT_NAME' => '/var/www/index.php',
  1125. ]
  1126. ],
  1127. $this->secureRandom,
  1128. $this->config,
  1129. $this->csrfTokenManager,
  1130. $this->stream
  1131. );
  1132. $request->getRawPathInfo();
  1133. }
  1134. /**
  1135. * @dataProvider genericPathInfoProvider
  1136. * @param string $requestUri
  1137. * @param string $scriptName
  1138. * @param string $expected
  1139. */
  1140. public function testGetPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected) {
  1141. $request = new Request(
  1142. [
  1143. 'server' => [
  1144. 'REQUEST_URI' => $requestUri,
  1145. 'SCRIPT_NAME' => $scriptName,
  1146. ]
  1147. ],
  1148. $this->secureRandom,
  1149. $this->config,
  1150. $this->csrfTokenManager,
  1151. $this->stream
  1152. );
  1153. $this->assertSame($expected, $request->getPathInfo());
  1154. }
  1155. /**
  1156. * @dataProvider genericPathInfoProvider
  1157. * @param string $requestUri
  1158. * @param string $scriptName
  1159. * @param string $expected
  1160. */
  1161. public function testGetRawPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected) {
  1162. $request = new Request(
  1163. [
  1164. 'server' => [
  1165. 'REQUEST_URI' => $requestUri,
  1166. 'SCRIPT_NAME' => $scriptName,
  1167. ]
  1168. ],
  1169. $this->secureRandom,
  1170. $this->config,
  1171. $this->csrfTokenManager,
  1172. $this->stream
  1173. );
  1174. $this->assertSame($expected, $request->getRawPathInfo());
  1175. }
  1176. /**
  1177. * @dataProvider rawPathInfoProvider
  1178. * @param string $requestUri
  1179. * @param string $scriptName
  1180. * @param string $expected
  1181. */
  1182. public function testGetRawPathInfoWithoutSetEnv($requestUri, $scriptName, $expected) {
  1183. $request = new Request(
  1184. [
  1185. 'server' => [
  1186. 'REQUEST_URI' => $requestUri,
  1187. 'SCRIPT_NAME' => $scriptName,
  1188. ]
  1189. ],
  1190. $this->secureRandom,
  1191. $this->config,
  1192. $this->csrfTokenManager,
  1193. $this->stream
  1194. );
  1195. $this->assertSame($expected, $request->getRawPathInfo());
  1196. }
  1197. /**
  1198. * @dataProvider pathInfoProvider
  1199. * @param string $requestUri
  1200. * @param string $scriptName
  1201. * @param string $expected
  1202. */
  1203. public function testGetPathInfoWithoutSetEnv($requestUri, $scriptName, $expected) {
  1204. $request = new Request(
  1205. [
  1206. 'server' => [
  1207. 'REQUEST_URI' => $requestUri,
  1208. 'SCRIPT_NAME' => $scriptName,
  1209. ]
  1210. ],
  1211. $this->secureRandom,
  1212. $this->config,
  1213. $this->csrfTokenManager,
  1214. $this->stream
  1215. );
  1216. $this->assertSame($expected, $request->getPathInfo());
  1217. }
  1218. /**
  1219. * @return array
  1220. */
  1221. public function genericPathInfoProvider() {
  1222. return [
  1223. ['/core/index.php?XDEBUG_SESSION_START=14600', '/core/index.php', ''],
  1224. ['/index.php/apps/files/', 'index.php', '/apps/files/'],
  1225. ['/index.php/apps/files/../&amp;/&?someQueryParameter=QueryParam', 'index.php', '/apps/files/../&amp;/&'],
  1226. ['/remote.php/漢字編碼方法 / 汉字编码方法', 'remote.php', '/漢字編碼方法 / 汉字编码方法'],
  1227. ['///removeTrailin//gSlashes///', 'remote.php', '/removeTrailin/gSlashes/'],
  1228. ['/', '/', ''],
  1229. ['', '', ''],
  1230. ];
  1231. }
  1232. /**
  1233. * @return array
  1234. */
  1235. public function rawPathInfoProvider() {
  1236. return [
  1237. ['/foo%2Fbar/subfolder', '', 'foo%2Fbar/subfolder'],
  1238. ];
  1239. }
  1240. /**
  1241. * @return array
  1242. */
  1243. public function pathInfoProvider() {
  1244. return [
  1245. ['/foo%2Fbar/subfolder', '', 'foo/bar/subfolder'],
  1246. ];
  1247. }
  1248. public function testGetRequestUriWithoutOverwrite() {
  1249. $this->config
  1250. ->expects($this->once())
  1251. ->method('getSystemValue')
  1252. ->with('overwritewebroot')
  1253. ->will($this->returnValue(''));
  1254. $request = new Request(
  1255. [
  1256. 'server' => [
  1257. 'REQUEST_URI' => '/test.php'
  1258. ]
  1259. ],
  1260. $this->secureRandom,
  1261. $this->config,
  1262. $this->csrfTokenManager,
  1263. $this->stream
  1264. );
  1265. $this->assertSame('/test.php', $request->getRequestUri());
  1266. }
  1267. public function providesGetRequestUriWithOverwriteData() {
  1268. return [
  1269. ['/scriptname.php/some/PathInfo', '/owncloud/', ''],
  1270. ['/scriptname.php/some/PathInfo', '/owncloud/', '123'],
  1271. ];
  1272. }
  1273. /**
  1274. * @dataProvider providesGetRequestUriWithOverwriteData
  1275. */
  1276. public function testGetRequestUriWithOverwrite($expectedUri, $overwriteWebRoot, $overwriteCondAddr) {
  1277. $this->config
  1278. ->expects($this->at(0))
  1279. ->method('getSystemValue')
  1280. ->with('overwritewebroot')
  1281. ->will($this->returnValue($overwriteWebRoot));
  1282. $this->config
  1283. ->expects($this->at(1))
  1284. ->method('getSystemValue')
  1285. ->with('overwritecondaddr')
  1286. ->will($this->returnValue($overwriteCondAddr));
  1287. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1288. ->setMethods(['getScriptName'])
  1289. ->setConstructorArgs([
  1290. [
  1291. 'server' => [
  1292. 'REQUEST_URI' => '/test.php/some/PathInfo',
  1293. 'SCRIPT_NAME' => '/test.php',
  1294. ]
  1295. ],
  1296. $this->secureRandom,
  1297. $this->config,
  1298. $this->csrfTokenManager,
  1299. $this->stream
  1300. ])
  1301. ->getMock();
  1302. $request
  1303. ->expects($this->once())
  1304. ->method('getScriptName')
  1305. ->will($this->returnValue('/scriptname.php'));
  1306. $this->assertSame($expectedUri, $request->getRequestUri());
  1307. }
  1308. public function testPassesCSRFCheckWithGet() {
  1309. /** @var Request $request */
  1310. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1311. ->setMethods(['getScriptName'])
  1312. ->setConstructorArgs([
  1313. [
  1314. 'get' => [
  1315. 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1316. ],
  1317. 'cookies' => [
  1318. 'nc_sameSiteCookiestrict' => 'true',
  1319. 'nc_sameSiteCookielax' => 'true',
  1320. ],
  1321. ],
  1322. $this->secureRandom,
  1323. $this->config,
  1324. $this->csrfTokenManager,
  1325. $this->stream
  1326. ])
  1327. ->getMock();
  1328. $token = new CsrfToken('AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds');
  1329. $this->csrfTokenManager
  1330. ->expects($this->once())
  1331. ->method('isTokenValid')
  1332. ->with($token)
  1333. ->willReturn(true);
  1334. $this->assertTrue($request->passesCSRFCheck());
  1335. }
  1336. public function testPassesCSRFCheckWithPost() {
  1337. /** @var Request $request */
  1338. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1339. ->setMethods(['getScriptName'])
  1340. ->setConstructorArgs([
  1341. [
  1342. 'post' => [
  1343. 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1344. ],
  1345. 'cookies' => [
  1346. 'nc_sameSiteCookiestrict' => 'true',
  1347. 'nc_sameSiteCookielax' => 'true',
  1348. ],
  1349. ],
  1350. $this->secureRandom,
  1351. $this->config,
  1352. $this->csrfTokenManager,
  1353. $this->stream
  1354. ])
  1355. ->getMock();
  1356. $token = new CsrfToken('AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds');
  1357. $this->csrfTokenManager
  1358. ->expects($this->once())
  1359. ->method('isTokenValid')
  1360. ->with($token)
  1361. ->willReturn(true);
  1362. $this->assertTrue($request->passesCSRFCheck());
  1363. }
  1364. public function testPassesCSRFCheckWithHeader() {
  1365. /** @var Request $request */
  1366. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1367. ->setMethods(['getScriptName'])
  1368. ->setConstructorArgs([
  1369. [
  1370. 'server' => [
  1371. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1372. ],
  1373. 'cookies' => [
  1374. 'nc_sameSiteCookiestrict' => 'true',
  1375. 'nc_sameSiteCookielax' => 'true',
  1376. ],
  1377. ],
  1378. $this->secureRandom,
  1379. $this->config,
  1380. $this->csrfTokenManager,
  1381. $this->stream
  1382. ])
  1383. ->getMock();
  1384. $token = new CsrfToken('AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds');
  1385. $this->csrfTokenManager
  1386. ->expects($this->once())
  1387. ->method('isTokenValid')
  1388. ->with($token)
  1389. ->willReturn(true);
  1390. $this->assertTrue($request->passesCSRFCheck());
  1391. }
  1392. public function testPassesCSRFCheckWithGetAndWithoutCookies() {
  1393. /** @var Request $request */
  1394. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1395. ->setMethods(['getScriptName'])
  1396. ->setConstructorArgs([
  1397. [
  1398. 'get' => [
  1399. 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1400. ],
  1401. ],
  1402. $this->secureRandom,
  1403. $this->config,
  1404. $this->csrfTokenManager,
  1405. $this->stream
  1406. ])
  1407. ->getMock();
  1408. $this->csrfTokenManager
  1409. ->expects($this->once())
  1410. ->method('isTokenValid')
  1411. ->willReturn(true);
  1412. $this->assertTrue($request->passesCSRFCheck());
  1413. }
  1414. public function testPassesCSRFCheckWithPostAndWithoutCookies() {
  1415. /** @var Request $request */
  1416. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1417. ->setMethods(['getScriptName'])
  1418. ->setConstructorArgs([
  1419. [
  1420. 'post' => [
  1421. 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1422. ],
  1423. ],
  1424. $this->secureRandom,
  1425. $this->config,
  1426. $this->csrfTokenManager,
  1427. $this->stream
  1428. ])
  1429. ->getMock();
  1430. $this->csrfTokenManager
  1431. ->expects($this->once())
  1432. ->method('isTokenValid')
  1433. ->willReturn(true);
  1434. $this->assertTrue($request->passesCSRFCheck());
  1435. }
  1436. public function testPassesCSRFCheckWithHeaderAndWithoutCookies() {
  1437. /** @var Request $request */
  1438. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1439. ->setMethods(['getScriptName'])
  1440. ->setConstructorArgs([
  1441. [
  1442. 'server' => [
  1443. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1444. ],
  1445. ],
  1446. $this->secureRandom,
  1447. $this->config,
  1448. $this->csrfTokenManager,
  1449. $this->stream
  1450. ])
  1451. ->getMock();
  1452. $this->csrfTokenManager
  1453. ->expects($this->once())
  1454. ->method('isTokenValid')
  1455. ->willReturn(true);
  1456. $this->assertTrue($request->passesCSRFCheck());
  1457. }
  1458. public function testFailsCSRFCheckWithHeaderAndNotAllChecksPassing() {
  1459. /** @var Request $request */
  1460. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1461. ->setMethods(['getScriptName'])
  1462. ->setConstructorArgs([
  1463. [
  1464. 'server' => [
  1465. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1466. ],
  1467. 'cookies' => [
  1468. session_name() => 'asdf',
  1469. 'nc_sameSiteCookiestrict' => 'true',
  1470. ],
  1471. ],
  1472. $this->secureRandom,
  1473. $this->config,
  1474. $this->csrfTokenManager,
  1475. $this->stream
  1476. ])
  1477. ->getMock();
  1478. $this->csrfTokenManager
  1479. ->expects($this->never())
  1480. ->method('isTokenValid');
  1481. $this->assertFalse($request->passesCSRFCheck());
  1482. }
  1483. public function testPassesStrictCookieCheckWithAllCookiesAndStrict() {
  1484. /** @var Request $request */
  1485. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1486. ->setMethods(['getScriptName', 'getCookieParams'])
  1487. ->setConstructorArgs([
  1488. [
  1489. 'server' => [
  1490. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1491. ],
  1492. 'cookies' => [
  1493. session_name() => 'asdf',
  1494. '__Host-nc_sameSiteCookiestrict' => 'true',
  1495. '__Host-nc_sameSiteCookielax' => 'true',
  1496. ],
  1497. ],
  1498. $this->secureRandom,
  1499. $this->config,
  1500. $this->csrfTokenManager,
  1501. $this->stream
  1502. ])
  1503. ->getMock();
  1504. $request
  1505. ->expects($this->any())
  1506. ->method('getCookieParams')
  1507. ->willReturn([
  1508. 'secure' => true,
  1509. 'path' => '/',
  1510. ]);
  1511. $this->assertTrue($request->passesStrictCookieCheck());
  1512. }
  1513. public function testFailsStrictCookieCheckWithAllCookiesAndMissingStrict() {
  1514. /** @var Request $request */
  1515. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1516. ->setMethods(['getScriptName', 'getCookieParams'])
  1517. ->setConstructorArgs([
  1518. [
  1519. 'server' => [
  1520. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1521. ],
  1522. 'cookies' => [
  1523. session_name() => 'asdf',
  1524. 'nc_sameSiteCookiestrict' => 'true',
  1525. 'nc_sameSiteCookielax' => 'true',
  1526. ],
  1527. ],
  1528. $this->secureRandom,
  1529. $this->config,
  1530. $this->csrfTokenManager,
  1531. $this->stream
  1532. ])
  1533. ->getMock();
  1534. $request
  1535. ->expects($this->any())
  1536. ->method('getCookieParams')
  1537. ->willReturn([
  1538. 'secure' => true,
  1539. 'path' => '/',
  1540. ]);
  1541. $this->assertFalse($request->passesStrictCookieCheck());
  1542. }
  1543. public function testGetCookieParams() {
  1544. /** @var Request $request */
  1545. $request = $this->getMockBuilder(Request::class)
  1546. ->setMethods(['getScriptName'])
  1547. ->setConstructorArgs([
  1548. [],
  1549. $this->secureRandom,
  1550. $this->config,
  1551. $this->csrfTokenManager,
  1552. $this->stream
  1553. ])
  1554. ->getMock();
  1555. $actual = $request->getCookieParams();
  1556. $this->assertSame(session_get_cookie_params(), $actual);
  1557. }
  1558. public function testPassesStrictCookieCheckWithAllCookies() {
  1559. /** @var Request $request */
  1560. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1561. ->setMethods(['getScriptName'])
  1562. ->setConstructorArgs([
  1563. [
  1564. 'server' => [
  1565. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1566. ],
  1567. 'cookies' => [
  1568. session_name() => 'asdf',
  1569. 'nc_sameSiteCookiestrict' => 'true',
  1570. 'nc_sameSiteCookielax' => 'true',
  1571. ],
  1572. ],
  1573. $this->secureRandom,
  1574. $this->config,
  1575. $this->csrfTokenManager,
  1576. $this->stream
  1577. ])
  1578. ->getMock();
  1579. $this->assertTrue($request->passesStrictCookieCheck());
  1580. }
  1581. public function testPassesStrictCookieCheckWithRandomCookies() {
  1582. /** @var Request $request */
  1583. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1584. ->setMethods(['getScriptName'])
  1585. ->setConstructorArgs([
  1586. [
  1587. 'server' => [
  1588. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1589. ],
  1590. 'cookies' => [
  1591. 'RandomCookie' => 'asdf',
  1592. ],
  1593. ],
  1594. $this->secureRandom,
  1595. $this->config,
  1596. $this->csrfTokenManager,
  1597. $this->stream
  1598. ])
  1599. ->getMock();
  1600. $this->assertTrue($request->passesStrictCookieCheck());
  1601. }
  1602. public function testFailsStrictCookieCheckWithSessionCookie() {
  1603. /** @var Request $request */
  1604. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1605. ->setMethods(['getScriptName'])
  1606. ->setConstructorArgs([
  1607. [
  1608. 'server' => [
  1609. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1610. ],
  1611. 'cookies' => [
  1612. session_name() => 'asdf',
  1613. ],
  1614. ],
  1615. $this->secureRandom,
  1616. $this->config,
  1617. $this->csrfTokenManager,
  1618. $this->stream
  1619. ])
  1620. ->getMock();
  1621. $this->assertFalse($request->passesStrictCookieCheck());
  1622. }
  1623. public function testFailsStrictCookieCheckWithRememberMeCookie() {
  1624. /** @var Request $request */
  1625. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1626. ->setMethods(['getScriptName'])
  1627. ->setConstructorArgs([
  1628. [
  1629. 'server' => [
  1630. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1631. ],
  1632. 'cookies' => [
  1633. 'nc_token' => 'asdf',
  1634. ],
  1635. ],
  1636. $this->secureRandom,
  1637. $this->config,
  1638. $this->csrfTokenManager,
  1639. $this->stream
  1640. ])
  1641. ->getMock();
  1642. $this->assertFalse($request->passesStrictCookieCheck());
  1643. }
  1644. public function testFailsCSRFCheckWithPostAndWithCookies() {
  1645. /** @var Request $request */
  1646. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1647. ->setMethods(['getScriptName'])
  1648. ->setConstructorArgs([
  1649. [
  1650. 'post' => [
  1651. 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1652. ],
  1653. 'cookies' => [
  1654. session_name() => 'asdf',
  1655. 'foo' => 'bar',
  1656. ],
  1657. ],
  1658. $this->secureRandom,
  1659. $this->config,
  1660. $this->csrfTokenManager,
  1661. $this->stream
  1662. ])
  1663. ->getMock();
  1664. $this->csrfTokenManager
  1665. ->expects($this->never())
  1666. ->method('isTokenValid');
  1667. $this->assertFalse($request->passesCSRFCheck());
  1668. }
  1669. public function testFailStrictCookieCheckWithOnlyLaxCookie() {
  1670. /** @var Request $request */
  1671. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1672. ->setMethods(['getScriptName'])
  1673. ->setConstructorArgs([
  1674. [
  1675. 'server' => [
  1676. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1677. ],
  1678. 'cookies' => [
  1679. session_name() => 'asdf',
  1680. 'nc_sameSiteCookielax' => 'true',
  1681. ],
  1682. ],
  1683. $this->secureRandom,
  1684. $this->config,
  1685. $this->csrfTokenManager,
  1686. $this->stream
  1687. ])
  1688. ->getMock();
  1689. $this->assertFalse($request->passesStrictCookieCheck());
  1690. }
  1691. public function testFailStrictCookieCheckWithOnlyStrictCookie() {
  1692. /** @var Request $request */
  1693. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1694. ->setMethods(['getScriptName'])
  1695. ->setConstructorArgs([
  1696. [
  1697. 'server' => [
  1698. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1699. ],
  1700. 'cookies' => [
  1701. session_name() => 'asdf',
  1702. 'nc_sameSiteCookiestrict' => 'true',
  1703. ],
  1704. ],
  1705. $this->secureRandom,
  1706. $this->config,
  1707. $this->csrfTokenManager,
  1708. $this->stream
  1709. ])
  1710. ->getMock();
  1711. $this->assertFalse($request->passesStrictCookieCheck());
  1712. }
  1713. public function testPassesLaxCookieCheck() {
  1714. /** @var Request $request */
  1715. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1716. ->setMethods(['getScriptName'])
  1717. ->setConstructorArgs([
  1718. [
  1719. 'server' => [
  1720. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1721. ],
  1722. 'cookies' => [
  1723. session_name() => 'asdf',
  1724. 'nc_sameSiteCookielax' => 'true',
  1725. ],
  1726. ],
  1727. $this->secureRandom,
  1728. $this->config,
  1729. $this->csrfTokenManager,
  1730. $this->stream
  1731. ])
  1732. ->getMock();
  1733. $this->assertTrue($request->passesLaxCookieCheck());
  1734. }
  1735. public function testFailsLaxCookieCheckWithOnlyStrictCookie() {
  1736. /** @var Request $request */
  1737. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1738. ->setMethods(['getScriptName'])
  1739. ->setConstructorArgs([
  1740. [
  1741. 'server' => [
  1742. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1743. ],
  1744. 'cookies' => [
  1745. session_name() => 'asdf',
  1746. 'nc_sameSiteCookiestrict' => 'true',
  1747. ],
  1748. ],
  1749. $this->secureRandom,
  1750. $this->config,
  1751. $this->csrfTokenManager,
  1752. $this->stream
  1753. ])
  1754. ->getMock();
  1755. $this->assertFalse($request->passesLaxCookieCheck());
  1756. }
  1757. public function testSkipCookieCheckForOCSRequests() {
  1758. /** @var Request $request */
  1759. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1760. ->setMethods(['getScriptName'])
  1761. ->setConstructorArgs([
  1762. [
  1763. 'server' => [
  1764. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1765. 'HTTP_OCS_APIREQUEST' => 'true',
  1766. ],
  1767. 'cookies' => [
  1768. session_name() => 'asdf',
  1769. 'nc_sameSiteCookiestrict' => 'false',
  1770. ],
  1771. ],
  1772. $this->secureRandom,
  1773. $this->config,
  1774. $this->csrfTokenManager,
  1775. $this->stream
  1776. ])
  1777. ->getMock();
  1778. $this->assertTrue($request->passesStrictCookieCheck());
  1779. }
  1780. /**
  1781. * @return array
  1782. */
  1783. public function invalidTokenDataProvider() {
  1784. return [
  1785. ['InvalidSentToken'],
  1786. ['InvalidSentToken:InvalidSecret'],
  1787. [''],
  1788. ];
  1789. }
  1790. /**
  1791. * @dataProvider invalidTokenDataProvider
  1792. * @param string $invalidToken
  1793. */
  1794. public function testPassesCSRFCheckWithInvalidToken($invalidToken) {
  1795. /** @var Request $request */
  1796. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1797. ->setMethods(['getScriptName'])
  1798. ->setConstructorArgs([
  1799. [
  1800. 'server' => [
  1801. 'HTTP_REQUESTTOKEN' => $invalidToken,
  1802. ],
  1803. ],
  1804. $this->secureRandom,
  1805. $this->config,
  1806. $this->csrfTokenManager,
  1807. $this->stream
  1808. ])
  1809. ->getMock();
  1810. $token = new CsrfToken($invalidToken);
  1811. $this->csrfTokenManager
  1812. ->expects($this->any())
  1813. ->method('isTokenValid')
  1814. ->with($token)
  1815. ->willReturn(false);
  1816. $this->assertFalse($request->passesCSRFCheck());
  1817. }
  1818. public function testPassesCSRFCheckWithoutTokenFail() {
  1819. /** @var Request $request */
  1820. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1821. ->setMethods(['getScriptName'])
  1822. ->setConstructorArgs([
  1823. [],
  1824. $this->secureRandom,
  1825. $this->config,
  1826. $this->csrfTokenManager,
  1827. $this->stream
  1828. ])
  1829. ->getMock();
  1830. $this->assertFalse($request->passesCSRFCheck());
  1831. }
  1832. }