1
0

RequestTest.php 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899
  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 testGetRemoteAddressVerifyPriorityHeader() {
  416. $this->config
  417. ->expects($this->at(0))
  418. ->method('getSystemValue')
  419. ->with('trusted_proxies')
  420. ->will($this->returnValue(['10.0.0.2']));
  421. $this->config
  422. ->expects($this->at(1))
  423. ->method('getSystemValue')
  424. ->with('forwarded_for_headers')
  425. ->will($this->returnValue([
  426. 'HTTP_CLIENT_IP',
  427. 'HTTP_X_FORWARDED_FOR',
  428. 'HTTP_X_FORWARDED'
  429. ]));
  430. $request = new Request(
  431. [
  432. 'server' => [
  433. 'REMOTE_ADDR' => '10.0.0.2',
  434. 'HTTP_X_FORWARDED' => '10.4.0.5, 10.4.0.4',
  435. 'HTTP_X_FORWARDED_FOR' => '192.168.0.233'
  436. ],
  437. ],
  438. $this->secureRandom,
  439. $this->config,
  440. $this->csrfTokenManager,
  441. $this->stream
  442. );
  443. $this->assertSame('192.168.0.233', $request->getRemoteAddress());
  444. }
  445. /**
  446. * @return array
  447. */
  448. public function httpProtocolProvider() {
  449. return [
  450. // Valid HTTP 1.0
  451. ['HTTP/1.0', 'HTTP/1.0'],
  452. ['http/1.0', 'HTTP/1.0'],
  453. ['HTTp/1.0', 'HTTP/1.0'],
  454. // Valid HTTP 1.1
  455. ['HTTP/1.1', 'HTTP/1.1'],
  456. ['http/1.1', 'HTTP/1.1'],
  457. ['HTTp/1.1', 'HTTP/1.1'],
  458. // Valid HTTP 2.0
  459. ['HTTP/2', 'HTTP/2'],
  460. ['http/2', 'HTTP/2'],
  461. ['HTTp/2', 'HTTP/2'],
  462. // Invalid
  463. ['HTTp/394', 'HTTP/1.1'],
  464. ['InvalidProvider/1.1', 'HTTP/1.1'],
  465. [null, 'HTTP/1.1'],
  466. ['', 'HTTP/1.1'],
  467. ];
  468. }
  469. /**
  470. * @dataProvider httpProtocolProvider
  471. *
  472. * @param mixed $input
  473. * @param string $expected
  474. */
  475. public function testGetHttpProtocol($input, $expected) {
  476. $request = new Request(
  477. [
  478. 'server' => [
  479. 'SERVER_PROTOCOL' => $input,
  480. ],
  481. ],
  482. $this->secureRandom,
  483. $this->config,
  484. $this->csrfTokenManager,
  485. $this->stream
  486. );
  487. $this->assertSame($expected, $request->getHttpProtocol());
  488. }
  489. public function testGetServerProtocolWithOverride() {
  490. $this->config
  491. ->expects($this->at(0))
  492. ->method('getSystemValue')
  493. ->with('overwriteprotocol')
  494. ->will($this->returnValue('customProtocol'));
  495. $this->config
  496. ->expects($this->at(1))
  497. ->method('getSystemValue')
  498. ->with('overwritecondaddr')
  499. ->will($this->returnValue(''));
  500. $this->config
  501. ->expects($this->at(2))
  502. ->method('getSystemValue')
  503. ->with('overwriteprotocol')
  504. ->will($this->returnValue('customProtocol'));
  505. $request = new Request(
  506. [],
  507. $this->secureRandom,
  508. $this->config,
  509. $this->csrfTokenManager,
  510. $this->stream
  511. );
  512. $this->assertSame('customProtocol', $request->getServerProtocol());
  513. }
  514. public function testGetServerProtocolWithProtoValid() {
  515. $this->config
  516. ->expects($this->exactly(2))
  517. ->method('getSystemValue')
  518. ->with('overwriteprotocol')
  519. ->will($this->returnValue(''));
  520. $requestHttps = new Request(
  521. [
  522. 'server' => [
  523. 'HTTP_X_FORWARDED_PROTO' => 'HtTpS'
  524. ],
  525. ],
  526. $this->secureRandom,
  527. $this->config,
  528. $this->csrfTokenManager,
  529. $this->stream
  530. );
  531. $requestHttp = new Request(
  532. [
  533. 'server' => [
  534. 'HTTP_X_FORWARDED_PROTO' => 'HTTp'
  535. ],
  536. ],
  537. $this->secureRandom,
  538. $this->config,
  539. $this->csrfTokenManager,
  540. $this->stream
  541. );
  542. $this->assertSame('https', $requestHttps->getServerProtocol());
  543. $this->assertSame('http', $requestHttp->getServerProtocol());
  544. }
  545. public function testGetServerProtocolWithHttpsServerValueOn() {
  546. $this->config
  547. ->expects($this->once())
  548. ->method('getSystemValue')
  549. ->with('overwriteprotocol')
  550. ->will($this->returnValue(''));
  551. $request = new Request(
  552. [
  553. 'server' => [
  554. 'HTTPS' => 'on'
  555. ],
  556. ],
  557. $this->secureRandom,
  558. $this->config,
  559. $this->csrfTokenManager,
  560. $this->stream
  561. );
  562. $this->assertSame('https', $request->getServerProtocol());
  563. }
  564. public function testGetServerProtocolWithHttpsServerValueOff() {
  565. $this->config
  566. ->expects($this->once())
  567. ->method('getSystemValue')
  568. ->with('overwriteprotocol')
  569. ->will($this->returnValue(''));
  570. $request = new Request(
  571. [
  572. 'server' => [
  573. 'HTTPS' => 'off'
  574. ],
  575. ],
  576. $this->secureRandom,
  577. $this->config,
  578. $this->csrfTokenManager,
  579. $this->stream
  580. );
  581. $this->assertSame('http', $request->getServerProtocol());
  582. }
  583. public function testGetServerProtocolWithHttpsServerValueEmpty() {
  584. $this->config
  585. ->expects($this->once())
  586. ->method('getSystemValue')
  587. ->with('overwriteprotocol')
  588. ->will($this->returnValue(''));
  589. $request = new Request(
  590. [
  591. 'server' => [
  592. 'HTTPS' => ''
  593. ],
  594. ],
  595. $this->secureRandom,
  596. $this->config,
  597. $this->csrfTokenManager,
  598. $this->stream
  599. );
  600. $this->assertSame('http', $request->getServerProtocol());
  601. }
  602. public function testGetServerProtocolDefault() {
  603. $this->config
  604. ->expects($this->once())
  605. ->method('getSystemValue')
  606. ->with('overwriteprotocol')
  607. ->will($this->returnValue(''));
  608. $request = new Request(
  609. [],
  610. $this->secureRandom,
  611. $this->config,
  612. $this->csrfTokenManager,
  613. $this->stream
  614. );
  615. $this->assertSame('http', $request->getServerProtocol());
  616. }
  617. public function testGetServerProtocolBehindLoadBalancers() {
  618. $this->config
  619. ->expects($this->once())
  620. ->method('getSystemValue')
  621. ->with('overwriteprotocol')
  622. ->will($this->returnValue(''));
  623. $request = new Request(
  624. [
  625. 'server' => [
  626. 'HTTP_X_FORWARDED_PROTO' => 'https,http,http'
  627. ],
  628. ],
  629. $this->secureRandom,
  630. $this->config,
  631. $this->csrfTokenManager,
  632. $this->stream
  633. );
  634. $this->assertSame('https', $request->getServerProtocol());
  635. }
  636. /**
  637. * @dataProvider userAgentProvider
  638. * @param string $testAgent
  639. * @param array $userAgent
  640. * @param bool $matches
  641. */
  642. public function testUserAgent($testAgent, $userAgent, $matches) {
  643. $request = new Request(
  644. [
  645. 'server' => [
  646. 'HTTP_USER_AGENT' => $testAgent,
  647. ]
  648. ],
  649. $this->secureRandom,
  650. $this->config,
  651. $this->csrfTokenManager,
  652. $this->stream
  653. );
  654. $this->assertSame($matches, $request->isUserAgent($userAgent));
  655. }
  656. /**
  657. * @dataProvider userAgentProvider
  658. * @param string $testAgent
  659. * @param array $userAgent
  660. * @param bool $matches
  661. */
  662. public function testUndefinedUserAgent($testAgent, $userAgent, $matches) {
  663. $request = new Request(
  664. [],
  665. $this->secureRandom,
  666. $this->config,
  667. $this->csrfTokenManager,
  668. $this->stream
  669. );
  670. $this->assertFalse($request->isUserAgent($userAgent));
  671. }
  672. /**
  673. * @return array
  674. */
  675. function userAgentProvider() {
  676. return [
  677. [
  678. 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
  679. [
  680. Request::USER_AGENT_IE
  681. ],
  682. true,
  683. ],
  684. [
  685. 'Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Firefox/24.0',
  686. [
  687. Request::USER_AGENT_IE
  688. ],
  689. false,
  690. ],
  691. [
  692. 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
  693. [
  694. Request::USER_AGENT_CHROME
  695. ],
  696. true,
  697. ],
  698. [
  699. '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',
  700. [
  701. Request::USER_AGENT_CHROME
  702. ],
  703. true,
  704. ],
  705. [
  706. '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',
  707. [
  708. Request::USER_AGENT_ANDROID_MOBILE_CHROME
  709. ],
  710. true,
  711. ],
  712. [
  713. 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
  714. [
  715. Request::USER_AGENT_ANDROID_MOBILE_CHROME
  716. ],
  717. false,
  718. ],
  719. [
  720. 'Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)',
  721. [
  722. Request::USER_AGENT_IE,
  723. Request::USER_AGENT_ANDROID_MOBILE_CHROME,
  724. ],
  725. true,
  726. ],
  727. [
  728. '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',
  729. [
  730. Request::USER_AGENT_IE,
  731. Request::USER_AGENT_ANDROID_MOBILE_CHROME,
  732. ],
  733. true,
  734. ],
  735. [
  736. 'Mozilla/5.0 (X11; Linux i686; rv:24.0) Gecko/20100101 Firefox/24.0',
  737. [
  738. Request::USER_AGENT_FREEBOX
  739. ],
  740. false,
  741. ],
  742. [
  743. 'Mozilla/5.0',
  744. [
  745. Request::USER_AGENT_FREEBOX
  746. ],
  747. true,
  748. ],
  749. [
  750. 'Fake Mozilla/5.0',
  751. [
  752. Request::USER_AGENT_FREEBOX
  753. ],
  754. false,
  755. ],
  756. [
  757. 'Mozilla/5.0 (Android) ownCloud-android/2.0.0',
  758. [
  759. Request::USER_AGENT_CLIENT_ANDROID
  760. ],
  761. true,
  762. ],
  763. [
  764. 'Mozilla/5.0 (Android) Nextcloud-android/2.0.0',
  765. [
  766. Request::USER_AGENT_CLIENT_ANDROID
  767. ],
  768. true,
  769. ],
  770. ];
  771. }
  772. public function testInsecureServerHostServerNameHeader() {
  773. $request = new Request(
  774. [
  775. 'server' => [
  776. 'SERVER_NAME' => 'from.server.name:8080',
  777. ]
  778. ],
  779. $this->secureRandom,
  780. $this->config,
  781. $this->csrfTokenManager,
  782. $this->stream
  783. );
  784. $this->assertSame('from.server.name:8080', $request->getInsecureServerHost());
  785. }
  786. public function testInsecureServerHostHttpHostHeader() {
  787. $request = new Request(
  788. [
  789. 'server' => [
  790. 'SERVER_NAME' => 'from.server.name:8080',
  791. 'HTTP_HOST' => 'from.host.header:8080',
  792. ]
  793. ],
  794. $this->secureRandom,
  795. $this->config,
  796. $this->csrfTokenManager,
  797. $this->stream
  798. );
  799. $this->assertSame('from.host.header:8080', $request->getInsecureServerHost());
  800. }
  801. public function testInsecureServerHostHttpFromForwardedHeaderSingle() {
  802. $request = new Request(
  803. [
  804. 'server' => [
  805. 'SERVER_NAME' => 'from.server.name:8080',
  806. 'HTTP_HOST' => 'from.host.header:8080',
  807. 'HTTP_X_FORWARDED_HOST' => 'from.forwarded.host:8080',
  808. ]
  809. ],
  810. $this->secureRandom,
  811. $this->config,
  812. $this->csrfTokenManager,
  813. $this->stream
  814. );
  815. $this->assertSame('from.forwarded.host:8080', $request->getInsecureServerHost());
  816. }
  817. public function testInsecureServerHostHttpFromForwardedHeaderStacked() {
  818. $request = new Request(
  819. [
  820. 'server' => [
  821. 'SERVER_NAME' => 'from.server.name:8080',
  822. 'HTTP_HOST' => 'from.host.header:8080',
  823. 'HTTP_X_FORWARDED_HOST' => 'from.forwarded.host2:8080,another.one:9000',
  824. ]
  825. ],
  826. $this->secureRandom,
  827. $this->config,
  828. $this->csrfTokenManager,
  829. $this->stream
  830. );
  831. $this->assertSame('from.forwarded.host2:8080', $request->getInsecureServerHost());
  832. }
  833. public function testGetServerHostWithOverwriteHost() {
  834. $this->config
  835. ->expects($this->at(0))
  836. ->method('getSystemValue')
  837. ->with('overwritehost')
  838. ->will($this->returnValue('my.overwritten.host'));
  839. $this->config
  840. ->expects($this->at(1))
  841. ->method('getSystemValue')
  842. ->with('overwritecondaddr')
  843. ->will($this->returnValue(''));
  844. $this->config
  845. ->expects($this->at(2))
  846. ->method('getSystemValue')
  847. ->with('overwritehost')
  848. ->will($this->returnValue('my.overwritten.host'));
  849. $request = new Request(
  850. [],
  851. $this->secureRandom,
  852. $this->config,
  853. $this->csrfTokenManager,
  854. $this->stream
  855. );
  856. $this->assertSame('my.overwritten.host', $request->getServerHost());
  857. }
  858. public function testGetServerHostWithTrustedDomain() {
  859. $this->config
  860. ->expects($this->at(3))
  861. ->method('getSystemValue')
  862. ->with('trusted_domains')
  863. ->will($this->returnValue(['my.trusted.host']));
  864. $request = new Request(
  865. [
  866. 'server' => [
  867. 'HTTP_X_FORWARDED_HOST' => 'my.trusted.host',
  868. ],
  869. ],
  870. $this->secureRandom,
  871. $this->config,
  872. $this->csrfTokenManager,
  873. $this->stream
  874. );
  875. $this->assertSame('my.trusted.host', $request->getServerHost());
  876. }
  877. public function testGetServerHostWithUntrustedDomain() {
  878. $this->config
  879. ->expects($this->at(3))
  880. ->method('getSystemValue')
  881. ->with('trusted_domains')
  882. ->will($this->returnValue(['my.trusted.host']));
  883. $this->config
  884. ->expects($this->at(4))
  885. ->method('getSystemValue')
  886. ->with('trusted_domains')
  887. ->will($this->returnValue(['my.trusted.host']));
  888. $request = new Request(
  889. [
  890. 'server' => [
  891. 'HTTP_X_FORWARDED_HOST' => 'my.untrusted.host',
  892. ],
  893. ],
  894. $this->secureRandom,
  895. $this->config,
  896. $this->csrfTokenManager,
  897. $this->stream
  898. );
  899. $this->assertSame('my.trusted.host', $request->getServerHost());
  900. }
  901. public function testGetServerHostWithNoTrustedDomain() {
  902. $this->config
  903. ->expects($this->at(3))
  904. ->method('getSystemValue')
  905. ->with('trusted_domains')
  906. ->will($this->returnValue([]));
  907. $this->config
  908. ->expects($this->at(4))
  909. ->method('getSystemValue')
  910. ->with('trusted_domains')
  911. ->will($this->returnValue([]));
  912. $request = new Request(
  913. [
  914. 'server' => [
  915. 'HTTP_X_FORWARDED_HOST' => 'my.untrusted.host',
  916. ],
  917. ],
  918. $this->secureRandom,
  919. $this->config,
  920. $this->csrfTokenManager,
  921. $this->stream
  922. );
  923. $this->assertSame('', $request->getServerHost());
  924. }
  925. public function testGetOverwriteHostDefaultNull() {
  926. $this->config
  927. ->expects($this->once())
  928. ->method('getSystemValue')
  929. ->with('overwritehost')
  930. ->will($this->returnValue(''));
  931. $request = new Request(
  932. [],
  933. $this->secureRandom,
  934. $this->config,
  935. $this->csrfTokenManager,
  936. $this->stream
  937. );
  938. $this->assertNull(self::invokePrivate($request, 'getOverwriteHost'));
  939. }
  940. public function testGetOverwriteHostWithOverwrite() {
  941. $this->config
  942. ->expects($this->at(0))
  943. ->method('getSystemValue')
  944. ->with('overwritehost')
  945. ->will($this->returnValue('www.owncloud.org'));
  946. $this->config
  947. ->expects($this->at(1))
  948. ->method('getSystemValue')
  949. ->with('overwritecondaddr')
  950. ->will($this->returnValue(''));
  951. $this->config
  952. ->expects($this->at(2))
  953. ->method('getSystemValue')
  954. ->with('overwritehost')
  955. ->will($this->returnValue('www.owncloud.org'));
  956. $request = new Request(
  957. [],
  958. $this->secureRandom,
  959. $this->config,
  960. $this->csrfTokenManager,
  961. $this->stream
  962. );
  963. $this->assertSame('www.owncloud.org', self::invokePrivate($request, 'getOverwriteHost'));
  964. }
  965. /**
  966. * @expectedException \Exception
  967. * @expectedExceptionMessage The requested uri(/foo.php) cannot be processed by the script '/var/www/index.php')
  968. */
  969. public function testGetPathInfoNotProcessible() {
  970. $request = new Request(
  971. [
  972. 'server' => [
  973. 'REQUEST_URI' => '/foo.php',
  974. 'SCRIPT_NAME' => '/var/www/index.php',
  975. ]
  976. ],
  977. $this->secureRandom,
  978. $this->config,
  979. $this->csrfTokenManager,
  980. $this->stream
  981. );
  982. $request->getPathInfo();
  983. }
  984. /**
  985. * @expectedException \Exception
  986. * @expectedExceptionMessage The requested uri(/foo.php) cannot be processed by the script '/var/www/index.php')
  987. */
  988. public function testGetRawPathInfoNotProcessible() {
  989. $request = new Request(
  990. [
  991. 'server' => [
  992. 'REQUEST_URI' => '/foo.php',
  993. 'SCRIPT_NAME' => '/var/www/index.php',
  994. ]
  995. ],
  996. $this->secureRandom,
  997. $this->config,
  998. $this->csrfTokenManager,
  999. $this->stream
  1000. );
  1001. $request->getRawPathInfo();
  1002. }
  1003. /**
  1004. * @dataProvider genericPathInfoProvider
  1005. * @param string $requestUri
  1006. * @param string $scriptName
  1007. * @param string $expected
  1008. */
  1009. public function testGetPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected) {
  1010. $request = new Request(
  1011. [
  1012. 'server' => [
  1013. 'REQUEST_URI' => $requestUri,
  1014. 'SCRIPT_NAME' => $scriptName,
  1015. ]
  1016. ],
  1017. $this->secureRandom,
  1018. $this->config,
  1019. $this->csrfTokenManager,
  1020. $this->stream
  1021. );
  1022. $this->assertSame($expected, $request->getPathInfo());
  1023. }
  1024. /**
  1025. * @dataProvider genericPathInfoProvider
  1026. * @param string $requestUri
  1027. * @param string $scriptName
  1028. * @param string $expected
  1029. */
  1030. public function testGetRawPathInfoWithoutSetEnvGeneric($requestUri, $scriptName, $expected) {
  1031. $request = new Request(
  1032. [
  1033. 'server' => [
  1034. 'REQUEST_URI' => $requestUri,
  1035. 'SCRIPT_NAME' => $scriptName,
  1036. ]
  1037. ],
  1038. $this->secureRandom,
  1039. $this->config,
  1040. $this->csrfTokenManager,
  1041. $this->stream
  1042. );
  1043. $this->assertSame($expected, $request->getRawPathInfo());
  1044. }
  1045. /**
  1046. * @dataProvider rawPathInfoProvider
  1047. * @param string $requestUri
  1048. * @param string $scriptName
  1049. * @param string $expected
  1050. */
  1051. public function testGetRawPathInfoWithoutSetEnv($requestUri, $scriptName, $expected) {
  1052. $request = new Request(
  1053. [
  1054. 'server' => [
  1055. 'REQUEST_URI' => $requestUri,
  1056. 'SCRIPT_NAME' => $scriptName,
  1057. ]
  1058. ],
  1059. $this->secureRandom,
  1060. $this->config,
  1061. $this->csrfTokenManager,
  1062. $this->stream
  1063. );
  1064. $this->assertSame($expected, $request->getRawPathInfo());
  1065. }
  1066. /**
  1067. * @dataProvider pathInfoProvider
  1068. * @param string $requestUri
  1069. * @param string $scriptName
  1070. * @param string $expected
  1071. */
  1072. public function testGetPathInfoWithoutSetEnv($requestUri, $scriptName, $expected) {
  1073. $request = new Request(
  1074. [
  1075. 'server' => [
  1076. 'REQUEST_URI' => $requestUri,
  1077. 'SCRIPT_NAME' => $scriptName,
  1078. ]
  1079. ],
  1080. $this->secureRandom,
  1081. $this->config,
  1082. $this->csrfTokenManager,
  1083. $this->stream
  1084. );
  1085. $this->assertSame($expected, $request->getPathInfo());
  1086. }
  1087. /**
  1088. * @return array
  1089. */
  1090. public function genericPathInfoProvider() {
  1091. return [
  1092. ['/core/index.php?XDEBUG_SESSION_START=14600', '/core/index.php', ''],
  1093. ['/index.php/apps/files/', 'index.php', '/apps/files/'],
  1094. ['/index.php/apps/files/../&amp;/&?someQueryParameter=QueryParam', 'index.php', '/apps/files/../&amp;/&'],
  1095. ['/remote.php/漢字編碼方法 / 汉字编码方法', 'remote.php', '/漢字編碼方法 / 汉字编码方法'],
  1096. ['///removeTrailin//gSlashes///', 'remote.php', '/removeTrailin/gSlashes/'],
  1097. ['/', '/', ''],
  1098. ['', '', ''],
  1099. ];
  1100. }
  1101. /**
  1102. * @return array
  1103. */
  1104. public function rawPathInfoProvider() {
  1105. return [
  1106. ['/foo%2Fbar/subfolder', '', 'foo%2Fbar/subfolder'],
  1107. ];
  1108. }
  1109. /**
  1110. * @return array
  1111. */
  1112. public function pathInfoProvider() {
  1113. return [
  1114. ['/foo%2Fbar/subfolder', '', 'foo/bar/subfolder'],
  1115. ];
  1116. }
  1117. public function testGetRequestUriWithoutOverwrite() {
  1118. $this->config
  1119. ->expects($this->once())
  1120. ->method('getSystemValue')
  1121. ->with('overwritewebroot')
  1122. ->will($this->returnValue(''));
  1123. $request = new Request(
  1124. [
  1125. 'server' => [
  1126. 'REQUEST_URI' => '/test.php'
  1127. ]
  1128. ],
  1129. $this->secureRandom,
  1130. $this->config,
  1131. $this->csrfTokenManager,
  1132. $this->stream
  1133. );
  1134. $this->assertSame('/test.php', $request->getRequestUri());
  1135. }
  1136. public function providesGetRequestUriWithOverwriteData() {
  1137. return [
  1138. ['/scriptname.php/some/PathInfo', '/owncloud/', ''],
  1139. ['/scriptname.php/some/PathInfo', '/owncloud/', '123'],
  1140. ];
  1141. }
  1142. /**
  1143. * @dataProvider providesGetRequestUriWithOverwriteData
  1144. */
  1145. public function testGetRequestUriWithOverwrite($expectedUri, $overwriteWebRoot, $overwriteCondAddr) {
  1146. $this->config
  1147. ->expects($this->at(0))
  1148. ->method('getSystemValue')
  1149. ->with('overwritewebroot')
  1150. ->will($this->returnValue($overwriteWebRoot));
  1151. $this->config
  1152. ->expects($this->at(1))
  1153. ->method('getSystemValue')
  1154. ->with('overwritecondaddr')
  1155. ->will($this->returnValue($overwriteCondAddr));
  1156. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1157. ->setMethods(['getScriptName'])
  1158. ->setConstructorArgs([
  1159. [
  1160. 'server' => [
  1161. 'REQUEST_URI' => '/test.php/some/PathInfo',
  1162. 'SCRIPT_NAME' => '/test.php',
  1163. ]
  1164. ],
  1165. $this->secureRandom,
  1166. $this->config,
  1167. $this->csrfTokenManager,
  1168. $this->stream
  1169. ])
  1170. ->getMock();
  1171. $request
  1172. ->expects($this->once())
  1173. ->method('getScriptName')
  1174. ->will($this->returnValue('/scriptname.php'));
  1175. $this->assertSame($expectedUri, $request->getRequestUri());
  1176. }
  1177. public function testPassesCSRFCheckWithGet() {
  1178. /** @var Request $request */
  1179. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1180. ->setMethods(['getScriptName'])
  1181. ->setConstructorArgs([
  1182. [
  1183. 'get' => [
  1184. 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1185. ],
  1186. 'cookies' => [
  1187. 'nc_sameSiteCookiestrict' => 'true',
  1188. 'nc_sameSiteCookielax' => 'true',
  1189. ],
  1190. ],
  1191. $this->secureRandom,
  1192. $this->config,
  1193. $this->csrfTokenManager,
  1194. $this->stream
  1195. ])
  1196. ->getMock();
  1197. $token = new CsrfToken('AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds');
  1198. $this->csrfTokenManager
  1199. ->expects($this->once())
  1200. ->method('isTokenValid')
  1201. ->with($token)
  1202. ->willReturn(true);
  1203. $this->assertTrue($request->passesCSRFCheck());
  1204. }
  1205. public function testPassesCSRFCheckWithPost() {
  1206. /** @var Request $request */
  1207. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1208. ->setMethods(['getScriptName'])
  1209. ->setConstructorArgs([
  1210. [
  1211. 'post' => [
  1212. 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1213. ],
  1214. 'cookies' => [
  1215. 'nc_sameSiteCookiestrict' => 'true',
  1216. 'nc_sameSiteCookielax' => 'true',
  1217. ],
  1218. ],
  1219. $this->secureRandom,
  1220. $this->config,
  1221. $this->csrfTokenManager,
  1222. $this->stream
  1223. ])
  1224. ->getMock();
  1225. $token = new CsrfToken('AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds');
  1226. $this->csrfTokenManager
  1227. ->expects($this->once())
  1228. ->method('isTokenValid')
  1229. ->with($token)
  1230. ->willReturn(true);
  1231. $this->assertTrue($request->passesCSRFCheck());
  1232. }
  1233. public function testPassesCSRFCheckWithHeader() {
  1234. /** @var Request $request */
  1235. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1236. ->setMethods(['getScriptName'])
  1237. ->setConstructorArgs([
  1238. [
  1239. 'server' => [
  1240. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1241. ],
  1242. 'cookies' => [
  1243. 'nc_sameSiteCookiestrict' => 'true',
  1244. 'nc_sameSiteCookielax' => 'true',
  1245. ],
  1246. ],
  1247. $this->secureRandom,
  1248. $this->config,
  1249. $this->csrfTokenManager,
  1250. $this->stream
  1251. ])
  1252. ->getMock();
  1253. $token = new CsrfToken('AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds');
  1254. $this->csrfTokenManager
  1255. ->expects($this->once())
  1256. ->method('isTokenValid')
  1257. ->with($token)
  1258. ->willReturn(true);
  1259. $this->assertTrue($request->passesCSRFCheck());
  1260. }
  1261. public function testPassesCSRFCheckWithGetAndWithoutCookies() {
  1262. /** @var Request $request */
  1263. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1264. ->setMethods(['getScriptName'])
  1265. ->setConstructorArgs([
  1266. [
  1267. 'get' => [
  1268. 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1269. ],
  1270. ],
  1271. $this->secureRandom,
  1272. $this->config,
  1273. $this->csrfTokenManager,
  1274. $this->stream
  1275. ])
  1276. ->getMock();
  1277. $this->csrfTokenManager
  1278. ->expects($this->once())
  1279. ->method('isTokenValid')
  1280. ->willReturn(true);
  1281. $this->assertTrue($request->passesCSRFCheck());
  1282. }
  1283. public function testPassesCSRFCheckWithPostAndWithoutCookies() {
  1284. /** @var Request $request */
  1285. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1286. ->setMethods(['getScriptName'])
  1287. ->setConstructorArgs([
  1288. [
  1289. 'post' => [
  1290. 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1291. ],
  1292. ],
  1293. $this->secureRandom,
  1294. $this->config,
  1295. $this->csrfTokenManager,
  1296. $this->stream
  1297. ])
  1298. ->getMock();
  1299. $this->csrfTokenManager
  1300. ->expects($this->once())
  1301. ->method('isTokenValid')
  1302. ->willReturn(true);
  1303. $this->assertTrue($request->passesCSRFCheck());
  1304. }
  1305. public function testPassesCSRFCheckWithHeaderAndWithoutCookies() {
  1306. /** @var Request $request */
  1307. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1308. ->setMethods(['getScriptName'])
  1309. ->setConstructorArgs([
  1310. [
  1311. 'server' => [
  1312. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1313. ],
  1314. ],
  1315. $this->secureRandom,
  1316. $this->config,
  1317. $this->csrfTokenManager,
  1318. $this->stream
  1319. ])
  1320. ->getMock();
  1321. $this->csrfTokenManager
  1322. ->expects($this->once())
  1323. ->method('isTokenValid')
  1324. ->willReturn(true);
  1325. $this->assertTrue($request->passesCSRFCheck());
  1326. }
  1327. public function testFailsCSRFCheckWithHeaderAndNotAllChecksPassing() {
  1328. /** @var Request $request */
  1329. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1330. ->setMethods(['getScriptName'])
  1331. ->setConstructorArgs([
  1332. [
  1333. 'server' => [
  1334. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1335. ],
  1336. 'cookies' => [
  1337. session_name() => 'asdf',
  1338. 'nc_sameSiteCookiestrict' => 'true',
  1339. ],
  1340. ],
  1341. $this->secureRandom,
  1342. $this->config,
  1343. $this->csrfTokenManager,
  1344. $this->stream
  1345. ])
  1346. ->getMock();
  1347. $this->csrfTokenManager
  1348. ->expects($this->never())
  1349. ->method('isTokenValid');
  1350. $this->assertFalse($request->passesCSRFCheck());
  1351. }
  1352. public function testPassesStrictCookieCheckWithAllCookiesAndStrict() {
  1353. /** @var Request $request */
  1354. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1355. ->setMethods(['getScriptName', 'getCookieParams'])
  1356. ->setConstructorArgs([
  1357. [
  1358. 'server' => [
  1359. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1360. ],
  1361. 'cookies' => [
  1362. session_name() => 'asdf',
  1363. '__Host-nc_sameSiteCookiestrict' => 'true',
  1364. '__Host-nc_sameSiteCookielax' => 'true',
  1365. ],
  1366. ],
  1367. $this->secureRandom,
  1368. $this->config,
  1369. $this->csrfTokenManager,
  1370. $this->stream
  1371. ])
  1372. ->getMock();
  1373. $request
  1374. ->expects($this->any())
  1375. ->method('getCookieParams')
  1376. ->willReturn([
  1377. 'secure' => true,
  1378. 'path' => '/',
  1379. ]);
  1380. $this->assertTrue($request->passesStrictCookieCheck());
  1381. }
  1382. public function testFailsStrictCookieCheckWithAllCookiesAndMissingStrict() {
  1383. /** @var Request $request */
  1384. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1385. ->setMethods(['getScriptName', 'getCookieParams'])
  1386. ->setConstructorArgs([
  1387. [
  1388. 'server' => [
  1389. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1390. ],
  1391. 'cookies' => [
  1392. session_name() => 'asdf',
  1393. 'nc_sameSiteCookiestrict' => 'true',
  1394. 'nc_sameSiteCookielax' => 'true',
  1395. ],
  1396. ],
  1397. $this->secureRandom,
  1398. $this->config,
  1399. $this->csrfTokenManager,
  1400. $this->stream
  1401. ])
  1402. ->getMock();
  1403. $request
  1404. ->expects($this->any())
  1405. ->method('getCookieParams')
  1406. ->willReturn([
  1407. 'secure' => true,
  1408. 'path' => '/',
  1409. ]);
  1410. $this->assertFalse($request->passesStrictCookieCheck());
  1411. }
  1412. public function testGetCookieParams() {
  1413. /** @var Request $request */
  1414. $request = $this->getMockBuilder(Request::class)
  1415. ->setMethods(['getScriptName'])
  1416. ->setConstructorArgs([
  1417. [],
  1418. $this->secureRandom,
  1419. $this->config,
  1420. $this->csrfTokenManager,
  1421. $this->stream
  1422. ])
  1423. ->getMock();
  1424. $actual = $request->getCookieParams();
  1425. $this->assertSame(session_get_cookie_params(), $actual);
  1426. }
  1427. public function testPassesStrictCookieCheckWithAllCookies() {
  1428. /** @var Request $request */
  1429. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1430. ->setMethods(['getScriptName'])
  1431. ->setConstructorArgs([
  1432. [
  1433. 'server' => [
  1434. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1435. ],
  1436. 'cookies' => [
  1437. session_name() => 'asdf',
  1438. 'nc_sameSiteCookiestrict' => 'true',
  1439. 'nc_sameSiteCookielax' => 'true',
  1440. ],
  1441. ],
  1442. $this->secureRandom,
  1443. $this->config,
  1444. $this->csrfTokenManager,
  1445. $this->stream
  1446. ])
  1447. ->getMock();
  1448. $this->assertTrue($request->passesStrictCookieCheck());
  1449. }
  1450. public function testPassesStrictCookieCheckWithRandomCookies() {
  1451. /** @var Request $request */
  1452. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1453. ->setMethods(['getScriptName'])
  1454. ->setConstructorArgs([
  1455. [
  1456. 'server' => [
  1457. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1458. ],
  1459. 'cookies' => [
  1460. 'RandomCookie' => 'asdf',
  1461. ],
  1462. ],
  1463. $this->secureRandom,
  1464. $this->config,
  1465. $this->csrfTokenManager,
  1466. $this->stream
  1467. ])
  1468. ->getMock();
  1469. $this->assertTrue($request->passesStrictCookieCheck());
  1470. }
  1471. public function testFailsStrictCookieCheckWithSessionCookie() {
  1472. /** @var Request $request */
  1473. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1474. ->setMethods(['getScriptName'])
  1475. ->setConstructorArgs([
  1476. [
  1477. 'server' => [
  1478. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1479. ],
  1480. 'cookies' => [
  1481. session_name() => 'asdf',
  1482. ],
  1483. ],
  1484. $this->secureRandom,
  1485. $this->config,
  1486. $this->csrfTokenManager,
  1487. $this->stream
  1488. ])
  1489. ->getMock();
  1490. $this->assertFalse($request->passesStrictCookieCheck());
  1491. }
  1492. public function testFailsStrictCookieCheckWithRememberMeCookie() {
  1493. /** @var Request $request */
  1494. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1495. ->setMethods(['getScriptName'])
  1496. ->setConstructorArgs([
  1497. [
  1498. 'server' => [
  1499. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1500. ],
  1501. 'cookies' => [
  1502. 'nc_token' => 'asdf',
  1503. ],
  1504. ],
  1505. $this->secureRandom,
  1506. $this->config,
  1507. $this->csrfTokenManager,
  1508. $this->stream
  1509. ])
  1510. ->getMock();
  1511. $this->assertFalse($request->passesStrictCookieCheck());
  1512. }
  1513. public function testFailsCSRFCheckWithPostAndWithCookies() {
  1514. /** @var Request $request */
  1515. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1516. ->setMethods(['getScriptName'])
  1517. ->setConstructorArgs([
  1518. [
  1519. 'post' => [
  1520. 'requesttoken' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1521. ],
  1522. 'cookies' => [
  1523. session_name() => 'asdf',
  1524. 'foo' => 'bar',
  1525. ],
  1526. ],
  1527. $this->secureRandom,
  1528. $this->config,
  1529. $this->csrfTokenManager,
  1530. $this->stream
  1531. ])
  1532. ->getMock();
  1533. $this->csrfTokenManager
  1534. ->expects($this->never())
  1535. ->method('isTokenValid');
  1536. $this->assertFalse($request->passesCSRFCheck());
  1537. }
  1538. public function testFailStrictCookieCheckWithOnlyLaxCookie() {
  1539. /** @var Request $request */
  1540. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1541. ->setMethods(['getScriptName'])
  1542. ->setConstructorArgs([
  1543. [
  1544. 'server' => [
  1545. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1546. ],
  1547. 'cookies' => [
  1548. session_name() => 'asdf',
  1549. 'nc_sameSiteCookielax' => 'true',
  1550. ],
  1551. ],
  1552. $this->secureRandom,
  1553. $this->config,
  1554. $this->csrfTokenManager,
  1555. $this->stream
  1556. ])
  1557. ->getMock();
  1558. $this->assertFalse($request->passesStrictCookieCheck());
  1559. }
  1560. public function testFailStrictCookieCheckWithOnlyStrictCookie() {
  1561. /** @var Request $request */
  1562. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1563. ->setMethods(['getScriptName'])
  1564. ->setConstructorArgs([
  1565. [
  1566. 'server' => [
  1567. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1568. ],
  1569. 'cookies' => [
  1570. session_name() => 'asdf',
  1571. 'nc_sameSiteCookiestrict' => 'true',
  1572. ],
  1573. ],
  1574. $this->secureRandom,
  1575. $this->config,
  1576. $this->csrfTokenManager,
  1577. $this->stream
  1578. ])
  1579. ->getMock();
  1580. $this->assertFalse($request->passesStrictCookieCheck());
  1581. }
  1582. public function testPassesLaxCookieCheck() {
  1583. /** @var Request $request */
  1584. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1585. ->setMethods(['getScriptName'])
  1586. ->setConstructorArgs([
  1587. [
  1588. 'server' => [
  1589. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1590. ],
  1591. 'cookies' => [
  1592. session_name() => 'asdf',
  1593. 'nc_sameSiteCookielax' => 'true',
  1594. ],
  1595. ],
  1596. $this->secureRandom,
  1597. $this->config,
  1598. $this->csrfTokenManager,
  1599. $this->stream
  1600. ])
  1601. ->getMock();
  1602. $this->assertTrue($request->passesLaxCookieCheck());
  1603. }
  1604. public function testFailsLaxCookieCheckWithOnlyStrictCookie() {
  1605. /** @var Request $request */
  1606. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1607. ->setMethods(['getScriptName'])
  1608. ->setConstructorArgs([
  1609. [
  1610. 'server' => [
  1611. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1612. ],
  1613. 'cookies' => [
  1614. session_name() => 'asdf',
  1615. 'nc_sameSiteCookiestrict' => 'true',
  1616. ],
  1617. ],
  1618. $this->secureRandom,
  1619. $this->config,
  1620. $this->csrfTokenManager,
  1621. $this->stream
  1622. ])
  1623. ->getMock();
  1624. $this->assertFalse($request->passesLaxCookieCheck());
  1625. }
  1626. public function testSkipCookieCheckForOCSRequests() {
  1627. /** @var Request $request */
  1628. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1629. ->setMethods(['getScriptName'])
  1630. ->setConstructorArgs([
  1631. [
  1632. 'server' => [
  1633. 'HTTP_REQUESTTOKEN' => 'AAAHGxsTCTc3BgMQESAcNR0OAR0=:MyTotalSecretShareds',
  1634. 'HTTP_OCS_APIREQUEST' => 'true',
  1635. ],
  1636. 'cookies' => [
  1637. session_name() => 'asdf',
  1638. 'nc_sameSiteCookiestrict' => 'false',
  1639. ],
  1640. ],
  1641. $this->secureRandom,
  1642. $this->config,
  1643. $this->csrfTokenManager,
  1644. $this->stream
  1645. ])
  1646. ->getMock();
  1647. $this->assertTrue($request->passesStrictCookieCheck());
  1648. }
  1649. /**
  1650. * @return array
  1651. */
  1652. public function invalidTokenDataProvider() {
  1653. return [
  1654. ['InvalidSentToken'],
  1655. ['InvalidSentToken:InvalidSecret'],
  1656. [''],
  1657. ];
  1658. }
  1659. /**
  1660. * @dataProvider invalidTokenDataProvider
  1661. * @param string $invalidToken
  1662. */
  1663. public function testPassesCSRFCheckWithInvalidToken($invalidToken) {
  1664. /** @var Request $request */
  1665. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1666. ->setMethods(['getScriptName'])
  1667. ->setConstructorArgs([
  1668. [
  1669. 'server' => [
  1670. 'HTTP_REQUESTTOKEN' => $invalidToken,
  1671. ],
  1672. ],
  1673. $this->secureRandom,
  1674. $this->config,
  1675. $this->csrfTokenManager,
  1676. $this->stream
  1677. ])
  1678. ->getMock();
  1679. $token = new CsrfToken($invalidToken);
  1680. $this->csrfTokenManager
  1681. ->expects($this->any())
  1682. ->method('isTokenValid')
  1683. ->with($token)
  1684. ->willReturn(false);
  1685. $this->assertFalse($request->passesCSRFCheck());
  1686. }
  1687. public function testPassesCSRFCheckWithoutTokenFail() {
  1688. /** @var Request $request */
  1689. $request = $this->getMockBuilder('\OC\AppFramework\Http\Request')
  1690. ->setMethods(['getScriptName'])
  1691. ->setConstructorArgs([
  1692. [],
  1693. $this->secureRandom,
  1694. $this->config,
  1695. $this->csrfTokenManager,
  1696. $this->stream
  1697. ])
  1698. ->getMock();
  1699. $this->assertFalse($request->passesCSRFCheck());
  1700. }
  1701. }