phpCAS version 1.3.6

CookieJar.php
Go to the documentation of this file.
1 <?php
2
41 class CAS_CookieJar
42 {
43
44 private $_cookies;
45
54 public function __construct (array &$storageArray)
55 {
56 $this->_cookies =& $storageArray;
57 }
58
70 public function storeCookies ($request_url, $response_headers)
71 {
72 $urlParts = parse_url($request_url);
73 $defaultDomain = $urlParts['host'];
74
75 $cookies = $this->parseCookieHeaders($response_headers, $defaultDomain);
76
77 // var_dump($cookies);
78 foreach ($cookies as $cookie) {
79 // Enforce the same-origin policy by verifying that the cookie
80 // would match the url that is setting it
81 if (!$this->cookieMatchesTarget($cookie, $urlParts)) {
82 continue;
83 }
84
85 // store the cookie
86 $this->storeCookie($cookie);
87
88 phpCAS::trace($cookie['name'].' -> '.$cookie['value']);
89 }
90 }
91
102 public function getCookies ($request_url)
103 {
104 if (!count($this->_cookies)) {
105 return array();
106 }
107
108 // If our request URL can't be parsed, no cookies apply.
109 $target = parse_url($request_url);
110 if ($target === false) {
111 return array();
112 }
113
114 $this->expireCookies();
115
116 $matching_cookies = array();
117 foreach ($this->_cookies as $key => $cookie) {
118 if ($this->cookieMatchesTarget($cookie, $target)) {
119 $matching_cookies[$cookie['name']] = $cookie['value'];
120 }
121 }
122 return $matching_cookies;
123 }
124
125
136 protected function parseCookieHeaders( $header, $defaultDomain )
137 {
138 phpCAS::traceBegin();
139 $cookies = array();
140 foreach ( $header as $line ) {
141 if ( preg_match('/^Set-Cookie2?: /i', $line)) {
142 $cookies[] = $this->parseCookieHeader($line, $defaultDomain);
143 }
144 }
145
146 phpCAS::traceEnd($cookies);
147 return $cookies;
148 }
149
161 protected function parseCookieHeader ($line, $defaultDomain)
162 {
163 if (!$defaultDomain) {
164 throw new CAS_InvalidArgumentException(
165 '$defaultDomain was not provided.'
166 );
167 }
168
169 // Set our default values
170 $cookie = array(
171 'domain' => $defaultDomain,
172 'path' => '/',
173 'secure' => false,
174 );
175
176 $line = preg_replace('/^Set-Cookie2?: /i', '', trim($line));
177
178 // trim any trailing semicolons.
179 $line = trim($line, ';');
180
181 phpCAS::trace("Cookie Line: $line");
182
183 // This implementation makes the assumption that semicolons will not
184 // be present in quoted attribute values. While attribute values that
185 // contain semicolons are allowed by RFC2965, they are hopefully rare
186 // enough to ignore for our purposes. Most browsers make the same
187 // assumption.
188 $attributeStrings = explode(';', $line);
189
190 foreach ( $attributeStrings as $attributeString ) {
191 // split on the first equals sign and use the rest as value
192 $attributeParts = explode('=', $attributeString, 2);
193
194 $attributeName = trim($attributeParts[0]);
195 $attributeNameLC = strtolower($attributeName);
196
197 if (isset($attributeParts[1])) {
198 $attributeValue = trim($attributeParts[1]);
199 // Values may be quoted strings.
200 if (strpos($attributeValue, '"') === 0) {
201 $attributeValue = trim($attributeValue, '"');
202 // unescape any escaped quotes:
203 $attributeValue = str_replace('\"', '"', $attributeValue);
204 }
205 } else {
206 $attributeValue = null;
207 }
208
209 switch ($attributeNameLC) {
210 case 'expires':
211 $cookie['expires'] = strtotime($attributeValue);
212 break;
213 case 'max-age':
214 $cookie['max-age'] = (int)$attributeValue;
215 // Set an expiry time based on the max-age
216 if ($cookie['max-age']) {
217 $cookie['expires'] = time() + $cookie['max-age'];
218 } else {
219 // If max-age is zero, then the cookie should be removed
220 // imediately so set an expiry before now.
221 $cookie['expires'] = time() - 1;
222 }
223 break;
224 case 'secure':
225 $cookie['secure'] = true;
226 break;
227 case 'domain':
228 case 'path':
229 case 'port':
230 case 'version':
231 case 'comment':
232 case 'commenturl':
233 case 'discard':
234 case 'httponly':
235 $cookie[$attributeNameLC] = $attributeValue;
236 break;
237 default:
238 $cookie['name'] = $attributeName;
239 $cookie['value'] = $attributeValue;
240 }
241 }
242
243 return $cookie;
244 }
245
255 protected function storeCookie ($cookie)
256 {
257 // Discard any old versions of this cookie.
258 $this->discardCookie($cookie);
259 $this->_cookies[] = $cookie;
260
261 }
262
272 protected function discardCookie ($cookie)
273 {
274 if (!isset($cookie['domain'])
275 || !isset($cookie['path'])
276 || !isset($cookie['path'])
277 ) {
278 throw new CAS_InvalidArgumentException('Invalid Cookie array passed.');
279 }
280
281 foreach ($this->_cookies as $key => $old_cookie) {
282 if ( $cookie['domain'] == $old_cookie['domain']
283 && $cookie['path'] == $old_cookie['path']
284 && $cookie['name'] == $old_cookie['name']
285 ) {
286 unset($this->_cookies[$key]);
287 }
288 }
289 }
290
298 protected function expireCookies ()
299 {
300 foreach ($this->_cookies as $key => $cookie) {
301 if (isset($cookie['expires']) && $cookie['expires'] < time()) {
302 unset($this->_cookies[$key]);
303 }
304 }
305 }
306
317 protected function cookieMatchesTarget ($cookie, $target)
318 {
319 if (!is_array($target)) {
320 throw new CAS_InvalidArgumentException(
321 '$target must be an array of URL attributes as generated by parse_url().'
322 );
323 }
324 if (!isset($target['host'])) {
325 throw new CAS_InvalidArgumentException(
326 '$target must be an array of URL attributes as generated by parse_url().'
327 );
328 }
329
330 // Verify that the scheme matches
331 if ($cookie['secure'] && $target['scheme'] != 'https') {
332 return false;
333 }
334
335 // Verify that the host matches
336 // Match domain and mulit-host cookies
337 if (strpos($cookie['domain'], '.') === 0) {
338 // .host.domain.edu cookies are valid for host.domain.edu
339 if (substr($cookie['domain'], 1) == $target['host']) {
340 // continue with other checks
341 } else {
342 // non-exact host-name matches.
343 // check that the target host a.b.c.edu is within .b.c.edu
344 $pos = strripos($target['host'], $cookie['domain']);
345 if (!$pos) {
346 return false;
347 }
348 // verify that the cookie domain is the last part of the host.
349 if ($pos + strlen($cookie['domain']) != strlen($target['host'])) {
350 return false;
351 }
352 // verify that the host name does not contain interior dots as per
353 // RFC 2965 section 3.3.2 Rejecting Cookies
354 // http://www.ietf.org/rfc/rfc2965.txt
355 $hostname = substr($target['host'], 0, $pos);
356 if (strpos($hostname, '.') !== false) {
357 return false;
358 }
359 }
360 } else {
361 // If the cookie host doesn't begin with '.',
362 // the host must case-insensitive match exactly
363 if (strcasecmp($target['host'], $cookie['domain']) !== 0) {
364 return false;
365 }
366 }
367
368 // Verify that the port matches
369 if (isset($cookie['ports'])
370 && !in_array($target['port'], $cookie['ports'])
371 ) {
372 return false;
373 }
374
375 // Verify that the path matches
376 if (strpos($target['path'], $cookie['path']) !== 0) {
377 return false;
378 }
379
380 return true;
381 }
382
383 }
384
385 ?>
CAS_CookieJar\parseCookieHeader
parseCookieHeader($line, $defaultDomain)
Definition: CookieJar.php:161
CAS_CookieJar\cookieMatchesTarget
cookieMatchesTarget($cookie, $target)
Definition: CookieJar.php:317
phpCAS\traceEnd
static traceEnd($res='')
Definition: CAS.php:638
CAS_CookieJar\__construct
__construct(array &$storageArray)
Definition: CookieJar.php:54
phpCAS\trace
static trace($str)
Definition: CAS.php:579
CAS_InvalidArgumentException
Definition: InvalidArgumentException.php:40
CAS_CookieJar\storeCookie
storeCookie($cookie)
Definition: CookieJar.php:255
CAS_CookieJar\$_cookies
$_cookies
Definition: CookieJar.php:44
CAS_CookieJar\expireCookies
expireCookies()
Definition: CookieJar.php:298
CAS_CookieJar\getCookies
getCookies($request_url)
Definition: CookieJar.php:102
CAS_CookieJar\parseCookieHeaders
parseCookieHeaders( $header, $defaultDomain)
Definition: CookieJar.php:136
CAS_CookieJar\storeCookies
storeCookies($request_url, $response_headers)
Definition: CookieJar.php:70
phpCAS\traceBegin
static traceBegin()
Definition: CAS.php:591
CAS_CookieJar\discardCookie
discardCookie($cookie)
Definition: CookieJar.php:272
CAS_CookieJar
Definition: CookieJar.php:41