RequestTest.php 43 KB

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