PageRenderTime 58ms CodeModel.GetById 33ms RepoModel.GetById 1ms app.codeStats 0ms

/test/CAS/Tests/ProxyTicketValidationTest.php

http://github.com/Jasig/phpCAS
PHP | 472 lines | 334 code | 22 blank | 116 comment | 0 complexity | 55790b736c91e4104f5b5eba18d3ffc0 MD5 | raw file
Possible License(s): Apache-2.0
  1. <?php
  2. /**
  3. * Licensed to Jasig under one or more contributor license
  4. * agreements. See the NOTICE file distributed with this work for
  5. * additional information regarding copyright ownership.
  6. *
  7. * Jasig licenses this file to you under the Apache License,
  8. * Version 2.0 (the "License"); you may not use this file except in
  9. * compliance with the License. You may obtain a copy of the License at:
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. *
  19. * PHP Version 7
  20. *
  21. * @file CAS/Tests/ProxyTicketValidationTest.php
  22. * @category Authentication
  23. * @package PhpCAS
  24. * @author Adam Franco <afranco@middlebury.edu>
  25. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
  26. * @link https://wiki.jasig.org/display/CASC/phpCAS
  27. */
  28. namespace PhpCas\Tests;
  29. use PhpCas\TestHarness\BasicResponse;
  30. use PhpCas\TestHarness\DummyRequest;
  31. use PHPUnit\Framework\TestCase;
  32. /**
  33. * Test class for verifying the operation of service tickets.
  34. *
  35. * @class ProxyTicketValidationTest
  36. * @category Authentication
  37. * @package PhpCAS
  38. * @author Adam Franco <afranco@middlebury.edu>
  39. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
  40. * @link https://wiki.jasig.org/display/CASC/phpCAS
  41. */
  42. class ProxyTicketValidationTest extends TestCase
  43. {
  44. /**
  45. * @var CAS_Client
  46. */
  47. protected $object;
  48. /**
  49. * Sets up the fixture, for example, opens a network connection.
  50. * This method is called before a test is executed.
  51. */
  52. protected function setUp(): void
  53. {
  54. $_SERVER['SERVER_NAME'] = 'www.service.com';
  55. $_SERVER['SERVER_PORT'] = '80';
  56. $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
  57. $_SERVER['SERVER_ADMIN'] = 'root@localhost';
  58. $_SERVER['REQUEST_URI'] = '/';
  59. $_SERVER['SCRIPT_NAME'] = '/index.php';
  60. $_SERVER['PHP_SELF'] = '/index.php';
  61. $_SESSION = array();
  62. // $_GET['ticket'] = 'ST-123456-asdfasdfasgww2323radf3';
  63. $this->object = new \CAS_Client(
  64. CAS_VERSION_2_0, // Server Version
  65. false, // Proxy
  66. 'cas.example.edu', // Server Hostname
  67. 443, // Server port
  68. '/cas/', // Server URI
  69. false // Start Session
  70. );
  71. $this->object->setRequestImplementation('PhpCas\TestHarness\DummyRequest');
  72. $this->object->setCasServerCACert(__FILE__, true);
  73. /*********************************************************
  74. * Enumerate our responses
  75. *********************************************************/
  76. // Valid ticket response
  77. $response = new BasicResponse(
  78. 'https', 'cas.example.edu', '/cas/proxyValidate'
  79. );
  80. $response->matchQueryParameters(
  81. array('service' => 'http://www.service.com/',
  82. 'ticket' => 'ST-123456-asdfasdfasgww2323radf3',
  83. )
  84. );
  85. $response->setResponseHeaders(
  86. array('HTTP/1.1 200 OK', 'Date: Wed, 29 Sep 2010 19:20:57 GMT',
  87. 'Server: Apache-Coyote/1.1', 'Pragma: no-cache',
  88. 'Expires: Thu, 01 Jan 1970 00:00:00 GMT',
  89. 'Cache-Control: no-cache, no-store',
  90. 'Content-Type: text/html;charset=UTF-8',
  91. 'Content-Language: en-US', 'Via: 1.1 cas.example.edu',
  92. 'Connection: close', 'Transfer-Encoding: chunked',
  93. )
  94. );
  95. $response->setResponseBody(
  96. "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
  97. <cas:authenticationSuccess>
  98. <cas:user>jsmith</cas:user>
  99. <cas:proxies>
  100. <cas:proxy>http://firstproxy.com/mysite/test</cas:proxy>
  101. <cas:proxy>https://anotherdomain.org/mysite/test2</cas:proxy>
  102. </cas:proxies>
  103. </cas:authenticationSuccess>
  104. </cas:serviceResponse>
  105. "
  106. );
  107. $response->ensureCaCertPathEquals(__FILE__);
  108. DummyRequest::addResponse($response);
  109. // Invalid ticket response
  110. $response = new BasicResponse(
  111. 'https', 'cas.example.edu', '/cas/proxyValidate'
  112. );
  113. $response->matchQueryParameters(
  114. array('service' => 'http://www.service.com/',)
  115. );
  116. $response->setResponseHeaders(
  117. array('HTTP/1.1 200 OK', 'Date: Wed, 29 Sep 2010 19:20:57 GMT',
  118. 'Server: Apache-Coyote/1.1', 'Pragma: no-cache',
  119. 'Expires: Thu, 01 Jan 1970 00:00:00 GMT',
  120. 'Cache-Control: no-cache, no-store',
  121. 'Content-Type: text/html;charset=UTF-8',
  122. 'Content-Language: en-US', 'Via: 1.1 cas.example.edu',
  123. 'Connection: close', 'Transfer-Encoding: chunked',
  124. )
  125. );
  126. $response->setResponseBody(
  127. "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
  128. <cas:authenticationFailure code='INVALID_TICKET'>
  129. Ticket ST-1856339-aA5Yuvrxzpv8Tau1cYQ7 not recognized
  130. </cas:authenticationFailure>
  131. </cas:serviceResponse>
  132. "
  133. );
  134. $response->ensureCaCertPathEquals(__FILE__);
  135. DummyRequest::addResponse($response);
  136. }
  137. /**
  138. * Tears down the fixture, for example, closes a network connection.
  139. * This method is called after a test is executed.
  140. */
  141. protected function tearDown(): void
  142. {
  143. DummyRequest::clearResponses();
  144. }
  145. /**
  146. * Test that a service ticket can be successfully validated.
  147. *
  148. * @return void
  149. */
  150. public function testValidationSuccess()
  151. {
  152. $this->object->setTicket('ST-123456-asdfasdfasgww2323radf3');
  153. $this->object->getAllowedProxyChains()
  154. ->allowProxyChain(new \CAS_ProxyChain_Any());
  155. $result = $this->object
  156. ->validateCAS20($url, $text_response, $tree_response);
  157. $this->assertTrue($result);
  158. $this->assertEquals(
  159. "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
  160. <cas:authenticationSuccess>
  161. <cas:user>jsmith</cas:user>
  162. <cas:proxies>
  163. <cas:proxy>http://firstproxy.com/mysite/test</cas:proxy>
  164. <cas:proxy>https://anotherdomain.org/mysite/test2</cas:proxy>
  165. </cas:proxies>
  166. </cas:authenticationSuccess>
  167. </cas:serviceResponse>
  168. ", $text_response
  169. );
  170. $this->assertInstanceOf('DOMElement', $tree_response);
  171. }
  172. /**
  173. * Test that our list of proxies is available
  174. *
  175. * @return void
  176. */
  177. public function testValidationSuccessProxyList()
  178. {
  179. $this->object->setTicket('ST-123456-asdfasdfasgww2323radf3');
  180. $this->object->getAllowedProxyChains()
  181. ->allowProxyChain(new \CAS_ProxyChain_Any());
  182. $result = $this->object
  183. ->validateCAS20($url, $text_response, $tree_response);
  184. $this->assertTrue($result);
  185. $this->assertEquals(
  186. array('http://firstproxy.com/mysite/test',
  187. 'https://anotherdomain.org/mysite/test2'
  188. ),
  189. $this->object->getProxies(),
  190. "The list of proxies in front of the client."
  191. );
  192. }
  193. /**
  194. * Test that a service ticket can be successfully fails.
  195. *
  196. * @return void
  197. *
  198. */
  199. public function testInvalidTicketFailure()
  200. {
  201. $this->object->setTicket('ST-1856339-aA5Yuvrxzpv8Tau1cYQ7');
  202. ob_start();
  203. $this->expectException(\CAS_AuthenticationException::class);
  204. try {
  205. $this->object->validateCAS20($url, $text_response, $tree_response);
  206. } catch (\Exception $e) {
  207. ob_end_clean();
  208. throw $e;
  209. }
  210. ob_end_clean();
  211. }
  212. /**
  213. * Test that our list of proxies is not availible on ticket failure.
  214. *
  215. * @return void
  216. */
  217. public function testInvalidTicketProxyList()
  218. {
  219. $this->object->setTicket('ST-1856339-aA5Yuvrxzpv8Tau1cYQ7');
  220. ob_start();
  221. try {
  222. $result = $this->object
  223. ->validateCAS20($url, $text_response, $tree_response);
  224. } catch (\CAS_AuthenticationException $e) {
  225. }
  226. ob_end_clean();
  227. $this->assertEquals(
  228. array(), $this->object->getProxies(),
  229. "The list of proxies in front of the client."
  230. );
  231. }
  232. /**
  233. * Test allowed proxies
  234. *
  235. * @return void
  236. */
  237. public function testAllowedProxiesStringSuccess()
  238. {
  239. $this->object->setTicket('ST-123456-asdfasdfasgww2323radf3');
  240. $this->object->getAllowedProxyChains()->allowProxyChain(
  241. new \CAS_ProxyChain(
  242. array('http://firstproxy.com',
  243. 'https://anotherdomain.org/mysite/test2'
  244. )
  245. )
  246. );
  247. $this->object->getAllowedProxyChains()->allowProxyChain(
  248. new \CAS_ProxyChain(
  249. array('https://anotherdomain.php')
  250. )
  251. );
  252. $result = $this->object
  253. ->validateCAS20($url, $text_response, $tree_response);
  254. $this->assertTrue($result);
  255. $this->assertEquals(
  256. "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
  257. <cas:authenticationSuccess>
  258. <cas:user>jsmith</cas:user>
  259. <cas:proxies>
  260. <cas:proxy>http://firstproxy.com/mysite/test</cas:proxy>
  261. <cas:proxy>https://anotherdomain.org/mysite/test2</cas:proxy>
  262. </cas:proxies>
  263. </cas:authenticationSuccess>
  264. </cas:serviceResponse>
  265. ",
  266. $text_response
  267. );
  268. $this->assertInstanceOf('DOMElement', $tree_response);
  269. }
  270. /**
  271. * Test that the trusted proxy allows any proxies beyond the one we trust.
  272. *
  273. * @return void
  274. */
  275. public function testAllowedProxiesTrustedSuccess()
  276. {
  277. $this->object->setTicket('ST-123456-asdfasdfasgww2323radf3');
  278. $this->object->getAllowedProxyChains()->allowProxyChain(
  279. new \CAS_ProxyChain_Trusted(
  280. array('http://firstproxy.com')
  281. )
  282. );
  283. $this->object->getAllowedProxyChains()->allowProxyChain(
  284. new \CAS_ProxyChain(
  285. array('https://anotherdomain.php')
  286. )
  287. );
  288. $result = $this->object
  289. ->validateCAS20($url, $text_response, $tree_response);
  290. $this->assertTrue($result);
  291. $this->assertEquals(
  292. "<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
  293. <cas:authenticationSuccess>
  294. <cas:user>jsmith</cas:user>
  295. <cas:proxies>
  296. <cas:proxy>http://firstproxy.com/mysite/test</cas:proxy>
  297. <cas:proxy>https://anotherdomain.org/mysite/test2</cas:proxy>
  298. </cas:proxies>
  299. </cas:authenticationSuccess>
  300. </cas:serviceResponse>
  301. ",
  302. $text_response
  303. );
  304. $this->assertInstanceOf('DOMElement', $tree_response);
  305. }
  306. /**
  307. * Test that proxies fail if one is missing from the chain
  308. *
  309. * @return void
  310. *
  311. */
  312. public function testAllowedProxiesStringFailureMissingProxy()
  313. {
  314. $this->object->setTicket('ST-123456-asdfasdfasgww2323radf3');
  315. $this->object->getAllowedProxyChains()->allowProxyChain(
  316. new \CAS_ProxyChain(
  317. array('https://anotherdomain.php')
  318. )
  319. );
  320. ob_start();
  321. $this->expectException(\CAS_AuthenticationException::class);
  322. try {
  323. $this->object->validateCAS20($url, $text_response, $tree_response);
  324. } catch (\Exception $e) {
  325. ob_end_clean();
  326. throw $e;
  327. }
  328. ob_end_clean();
  329. }
  330. /**
  331. * Test that proxies fail if in wrong order and definded as string
  332. *
  333. * @return void
  334. */
  335. public function testAllowedProxiesStringFailureWrongOrder()
  336. {
  337. $this->object->setTicket('ST-123456-asdfasdfasgww2323radf3');
  338. $this->object->getAllowedProxyChains()->allowProxyChain(
  339. new \CAS_ProxyChain(
  340. array('https://anotherdomain.org/mysite/test2',
  341. 'http://firstproxy.com'
  342. )
  343. )
  344. );
  345. $this->object->getAllowedProxyChains()->allowProxyChain(
  346. new \CAS_ProxyChain(
  347. array('https://anotherdomain.php')
  348. )
  349. );
  350. ob_start();
  351. $this->expectException(\CAS_AuthenticationException::class);
  352. try {
  353. $this->object->validateCAS20($url, $text_response, $tree_response);
  354. } catch (\Exception $e) {
  355. ob_end_clean();
  356. throw $e;
  357. }
  358. ob_end_clean();
  359. }
  360. /**
  361. * Test that if proxies exist a response with proxies will fail unless allowed
  362. *
  363. * @return void
  364. */
  365. public function testAllowedProxiesFailure()
  366. {
  367. $this->object->setTicket('ST-123456-asdfasdfasgww2323radf3');
  368. ob_start();
  369. $this->expectException(\CAS_AuthenticationException::class);
  370. try {
  371. // By default no proxies are allowed.
  372. $this->object->validateCAS20($url, $text_response, $tree_response);
  373. } catch (\Exception $e) {
  374. ob_end_clean();
  375. throw $e;
  376. }
  377. ob_end_clean();
  378. }
  379. /**
  380. * Test that regexp filtering of allowed proxies works
  381. *
  382. * @return void
  383. */
  384. public function testAllowedProxiesRegexpSuccess()
  385. {
  386. $this->object->setTicket('ST-123456-asdfasdfasgww2323radf3');
  387. $this->object->getAllowedProxyChains()->allowProxyChain(
  388. new \CAS_ProxyChain(array('/badregexp/'))
  389. );
  390. $this->object->getAllowedProxyChains()->allowProxyChain(
  391. new \CAS_ProxyChain(
  392. array('/http\:\/\/firstproxy\.com.*$/',
  393. '/^https\:\/\/anotherdomain.org\/mysite\/test2$/'
  394. )
  395. )
  396. );
  397. $result = $this->object
  398. ->validateCAS20($url, $text_response, $tree_response);
  399. $this->assertTrue($result);
  400. }
  401. /**
  402. * Wrong regexp to mach proxies
  403. *
  404. * @return void
  405. */
  406. public function testAllowedProxiesRegexpFailureWrong()
  407. {
  408. $this->object->setTicket('ST-123456-asdfasdfasgww2323radf3');
  409. $this->object->getAllowedProxyChains()->allowProxyChain(
  410. new \CAS_ProxyChain(
  411. array('/^http:\/\/secondproxy\.com/', '/^https.*$/')
  412. )
  413. );
  414. ob_start();
  415. $this->expectException(\CAS_AuthenticationException::class);
  416. try {
  417. $this->object->validateCAS20($url, $text_response, $tree_response);
  418. } catch (\Exception $e) {
  419. ob_end_clean();
  420. throw $e;
  421. }
  422. ob_end_clean();
  423. }
  424. /**
  425. * Wrong order of valid regexp
  426. *
  427. * @return void
  428. */
  429. public function testAllowedProxiesRegexpFailureWrongOrder()
  430. {
  431. $this->object->setTicket('ST-123456-asdfasdfasgww2323radf3');
  432. $this->object->getAllowedProxyChains()->allowProxyChain(
  433. new \CAS_ProxyChain(
  434. array('/^https\:\/\/anotherdomain.org\/mysite\/test2$/',
  435. '/http\:\/\/firstproxy\.com.*$/'
  436. )
  437. )
  438. );
  439. ob_start();
  440. $this->expectException(\CAS_AuthenticationException::class);
  441. try {
  442. $this->object->validateCAS20($url, $text_response, $tree_response);
  443. } catch (\Exception $e) {
  444. ob_end_clean();
  445. throw $e;
  446. }
  447. ob_end_clean();
  448. }
  449. }
  450. ?>