PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/application/classes/CAS/CAS/ProxiedService/Http/Abstract.php

https://bitbucket.org/FREEZX/finkical
PHP | 332 lines | 119 code | 38 blank | 175 comment | 14 complexity | d73a2c7617744daaa7562e0f0cf4353f MD5 | raw file
Possible License(s): Apache-2.0, GPL-3.0, BSD-3-Clause
  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 5
  20. *
  21. * @file CAS/ProxiedService/Http/Abstract.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. /**
  29. * This class implements common methods for ProxiedService implementations included
  30. * with phpCAS.
  31. *
  32. * @class CAS_ProxiedService_Http_Abstract
  33. * @category Authentication
  34. * @package PhpCAS
  35. * @author Adam Franco <afranco@middlebury.edu>
  36. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
  37. * @link https://wiki.jasig.org/display/CASC/phpCAS
  38. */
  39. abstract class CAS_ProxiedService_Http_Abstract
  40. extends CAS_ProxiedService_Abstract
  41. implements CAS_ProxiedService_Http
  42. {
  43. /**
  44. * The HTTP request mechanism talking to the target service.
  45. *
  46. * @var CAS_Request_RequestInterface $requestHandler
  47. */
  48. protected $requestHandler;
  49. /**
  50. * The storage mechanism for cookies set by the target service.
  51. *
  52. * @var CAS_CookieJar $_cookieJar
  53. */
  54. private $_cookieJar;
  55. /**
  56. * Constructor.
  57. *
  58. * @param CAS_Request_RequestInterface $requestHandler request handler object
  59. * @param CAS_CookieJar $cookieJar cookieJar object
  60. *
  61. * @return void
  62. */
  63. public function __construct (CAS_Request_RequestInterface $requestHandler, CAS_CookieJar $cookieJar)
  64. {
  65. $this->requestHandler = $requestHandler;
  66. $this->_cookieJar = $cookieJar;
  67. }
  68. /**
  69. * The target service url.
  70. * @var string $_url;
  71. */
  72. private $_url;
  73. /**
  74. * Answer a service identifier (URL) for whom we should fetch a proxy ticket.
  75. *
  76. * @return string
  77. * @throws Exception If no service url is available.
  78. */
  79. public function getServiceUrl ()
  80. {
  81. if (empty($this->_url)) {
  82. throw new CAS_ProxiedService_Exception('No URL set via '.get_class($this).'->setUrl($url).');
  83. }
  84. return $this->_url;
  85. }
  86. /*********************************************************
  87. * Configure the Request
  88. *********************************************************/
  89. /**
  90. * Set the URL of the Request
  91. *
  92. * @param string $url url to set
  93. *
  94. * @return void
  95. * @throws CAS_OutOfSequenceException If called after the Request has been sent.
  96. */
  97. public function setUrl ($url)
  98. {
  99. if ($this->hasBeenSent()) {
  100. throw new CAS_OutOfSequenceException('Cannot set the URL, request already sent.');
  101. }
  102. if (!is_string($url)) {
  103. throw new CAS_InvalidArgumentException('$url must be a string.');
  104. }
  105. $this->_url = $url;
  106. }
  107. /*********************************************************
  108. * 2. Send the Request
  109. *********************************************************/
  110. /**
  111. * Perform the request.
  112. *
  113. * @return void
  114. * @throws CAS_OutOfSequenceException If called multiple times.
  115. * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
  116. * The code of the Exception will be one of:
  117. * PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
  118. * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
  119. * PHPCAS_SERVICE_PT_FAILURE
  120. * @throws CAS_ProxiedService_Exception If there is a failure sending the
  121. * request to the target service.
  122. */
  123. public function send ()
  124. {
  125. if ($this->hasBeenSent()) {
  126. throw new CAS_OutOfSequenceException('Cannot send, request already sent.');
  127. }
  128. phpCAS::traceBegin();
  129. // Get our proxy ticket and append it to our URL.
  130. $this->initializeProxyTicket();
  131. $url = $this->getServiceUrl();
  132. if (strstr($url, '?') === false) {
  133. $url = $url.'?ticket='.$this->getProxyTicket();
  134. } else {
  135. $url = $url.'&ticket='.$this->getProxyTicket();
  136. }
  137. try {
  138. $this->makeRequest($url);
  139. } catch (Exception $e) {
  140. phpCAS::traceEnd();
  141. throw $e;
  142. }
  143. }
  144. /**
  145. * Indicator of the number of requests (including redirects performed.
  146. *
  147. * @var int $_numRequests;
  148. */
  149. private $_numRequests = 0;
  150. /**
  151. * The response headers.
  152. *
  153. * @var array $_responseHeaders;
  154. */
  155. private $_responseHeaders = array();
  156. /**
  157. * The response status code.
  158. *
  159. * @var string $_responseStatusCode;
  160. */
  161. private $_responseStatusCode = '';
  162. /**
  163. * The response headers.
  164. *
  165. * @var string $_responseBody;
  166. */
  167. private $_responseBody = '';
  168. /**
  169. * Build and perform a request, following redirects
  170. *
  171. * @param string $url url for the request
  172. *
  173. * @return void
  174. * @throws CAS_ProxyTicketException If there is a proxy-ticket failure.
  175. * The code of the Exception will be one of:
  176. * PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
  177. * PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
  178. * PHPCAS_SERVICE_PT_FAILURE
  179. * @throws CAS_ProxiedService_Exception If there is a failure sending the
  180. * request to the target service.
  181. */
  182. protected function makeRequest ($url)
  183. {
  184. // Verify that we are not in a redirect loop
  185. $this->_numRequests++;
  186. if ($this->_numRequests > 4) {
  187. $message = 'Exceeded the maximum number of redirects (3) in proxied service request.';
  188. phpCAS::trace($message);
  189. throw new CAS_ProxiedService_Exception($message);
  190. }
  191. // Create a new request.
  192. $request = clone $this->requestHandler;
  193. $request->setUrl($url);
  194. // Add any cookies to the request.
  195. $request->addCookies($this->_cookieJar->getCookies($url));
  196. // Add any other parts of the request needed by concrete classes
  197. $this->populateRequest($request);
  198. // Perform the request.
  199. phpCAS::trace('Performing proxied service request to \''.$url.'\'');
  200. if (!$request->send()) {
  201. $message = 'Could not perform proxied service request to URL`'.$url.'\'. '.$request->getErrorMessage();
  202. phpCAS::trace($message);
  203. throw new CAS_ProxiedService_Exception($message);
  204. }
  205. // Store any cookies from the response;
  206. $this->_cookieJar->storeCookies($url, $request->getResponseHeaders());
  207. // Follow any redirects
  208. if ($redirectUrl = $this->getRedirectUrl($request->getResponseHeaders())) {
  209. phpCAS :: trace('Found redirect:'.$redirectUrl);
  210. $this->makeRequest($redirectUrl);
  211. } else {
  212. $this->_responseHeaders = $request->getResponseHeaders();
  213. $this->_responseBody = $request->getResponseBody();
  214. $this->_responseStatusCode = $request->getResponseStatusCode();
  215. }
  216. }
  217. /**
  218. * Add any other parts of the request needed by concrete classes
  219. *
  220. * @param CAS_Request_RequestInterface $request request interface object
  221. *
  222. * @return void
  223. */
  224. abstract protected function populateRequest (CAS_Request_RequestInterface $request);
  225. /**
  226. * Answer a redirect URL if a redirect header is found, otherwise null.
  227. *
  228. * @param array $responseHeaders response header to extract a redirect from
  229. *
  230. * @return string or null
  231. */
  232. protected function getRedirectUrl (array $responseHeaders)
  233. {
  234. // Check for the redirect after authentication
  235. foreach ($responseHeaders as $header) {
  236. if (preg_match('/^(Location:|URI:)\s*([^\s]+.*)$/', $header, $matches)) {
  237. return trim(array_pop($matches));
  238. }
  239. }
  240. return null;
  241. }
  242. /*********************************************************
  243. * 3. Access the response
  244. *********************************************************/
  245. /**
  246. * Answer true if our request has been sent yet.
  247. *
  248. * @return bool
  249. */
  250. protected function hasBeenSent ()
  251. {
  252. return ($this->_numRequests > 0);
  253. }
  254. /**
  255. * Answer the headers of the response.
  256. *
  257. * @return array An array of header strings.
  258. * @throws CAS_OutOfSequenceException If called before the Request has been sent.
  259. */
  260. public function getResponseHeaders ()
  261. {
  262. if (!$this->hasBeenSent()) {
  263. throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
  264. }
  265. return $this->_responseHeaders;
  266. }
  267. /**
  268. * Answer HTTP status code of the response
  269. *
  270. * @return int
  271. * @throws CAS_OutOfSequenceException If called before the Request has been sent.
  272. */
  273. public function getResponseStatusCode ()
  274. {
  275. if (!$this->hasBeenSent()) {
  276. throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
  277. }
  278. return $this->_responseStatusCode;
  279. }
  280. /**
  281. * Answer the body of response.
  282. *
  283. * @return string
  284. * @throws CAS_OutOfSequenceException If called before the Request has been sent.
  285. */
  286. public function getResponseBody ()
  287. {
  288. if (!$this->hasBeenSent()) {
  289. throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
  290. }
  291. return $this->_responseBody;
  292. }
  293. }
  294. ?>