source-class-CAS_CookieJar

It appears that you are using AdBlocking software. The cost of running this website is covered by advertisements. If you like it please feel free to a small amount of money to secure the future of this website.
Overview

Classes

Interfaces

Exceptions

Functions

  1: <?php
  2: 
  3: /**
  4:  * Licensed to Jasig under one or more contributor license
  5:  * agreements. See the NOTICE file distributed with this work for
  6:  * additional information regarding copyright ownership.
  7:  *
  8:  * Jasig licenses this file to you under the Apache License,
  9:  * Version 2.0 (the "License"); you may not use this file except in
 10:  * compliance with the License. You may obtain a copy of the License at:
 11:  *
 12:  * http://www.apache.org/licenses/LICENSE-2.0
 13:  *
 14:  * Unless required by applicable law or agreed to in writing, software
 15:  * distributed under the License is distributed on an "AS IS" BASIS,
 16:  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 17:  * See the License for the specific language governing permissions and
 18:  * limitations under the License.
 19:  *
 20:  * PHP Version 5
 21:  *
 22:  * @file     CAS/CookieJar.php
 23:  * @category Authentication
 24:  * @package  PhpCAS
 25:  * @author   Adam Franco <afranco@middlebury.edu>
 26:  * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
 27:  * @link     https://wiki.jasig.org/display/CASC/phpCAS
 28:  */
 29: 
 30: /**
 31:  * This class provides access to service cookies and handles parsing of response
 32:  * headers to pull out cookie values.
 33:  *
 34:  * @class    CAS_CookieJar
 35:  * @category Authentication
 36:  * @package  PhpCAS
 37:  * @author   Adam Franco <afranco@middlebury.edu>
 38:  * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
 39:  * @link     https://wiki.jasig.org/display/CASC/phpCAS
 40:  */
 41: class CAS_CookieJar
 42: {
 43: 
 44:     private $_cookies;
 45: 
 46:     /**
 47:      * Create a new cookie jar by passing it a reference to an array in which it
 48:      * should store cookies.
 49:      *
 50:      * @param array &$storageArray Array to store cookies
 51:      *
 52:      * @return void
 53:      */
 54:     public function __construct (array &$storageArray)
 55:     {
 56:         $this->_cookies =& $storageArray;
 57:     }
 58: 
 59:     /**
 60:      * Store cookies for a web service request.
 61:      * Cookie storage is based on RFC 2965: http://www.ietf.org/rfc/rfc2965.txt
 62:      *
 63:      * @param string $request_url      The URL that generated the response headers.
 64:      * @param array  $response_headers An array of the HTTP response header strings.
 65:      *
 66:      * @return void
 67:      *
 68:      * @access private
 69:      */
 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: 
 92:     /**
 93:      * Retrieve cookies applicable for a web service request.
 94:      * Cookie applicability is based on RFC 2965: http://www.ietf.org/rfc/rfc2965.txt
 95:      *
 96:      * @param string $request_url The url that the cookies will be for.
 97:      *
 98:      * @return array An array containing cookies. E.g. array('name' => 'val');
 99:      *
100:      * @access private
101:      */
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: 
126:     /**
127:      * Parse Cookies without PECL
128:      * From the comments in http://php.net/manual/en/function.http-parse-cookie.php
129:      *
130:      * @param array  $header        array of header lines.
131:      * @param string $defaultDomain The domain to use if none is specified in
132:      * the cookie.
133:      *
134:      * @return array of cookies
135:      */
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: 
150:     /**
151:      * Parse a single cookie header line.
152:      *
153:      * Based on RFC2965 http://www.ietf.org/rfc/rfc2965.txt
154:      *
155:      * @param string $line          The header line.
156:      * @param string $defaultDomain The domain to use if none is specified in
157:      * the cookie.
158:      *
159:      * @return array
160:      */
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: 
246:     /**
247:      * Add, update, or remove a cookie.
248:      *
249:      * @param array $cookie A cookie array as created by parseCookieHeaders()
250:      *
251:      * @return void
252:      *
253:      * @access protected
254:      */
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: 
263:     /**
264:      * Discard an existing cookie
265:      *
266:      * @param array $cookie An cookie
267:      *
268:      * @return void
269:      *
270:      * @access protected
271:      */
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: 
291:     /**
292:      * Go through our stored cookies and remove any that are expired.
293:      *
294:      * @return void
295:      *
296:      * @access protected
297:      */
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: 
307:     /**
308:      * Answer true if cookie is applicable to a target.
309:      *
310:      * @param array $cookie An array of cookie attributes.
311:      * @param array $target An array of URL attributes as generated by parse_url().
312:      *
313:      * @return bool
314:      *
315:      * @access private
316:      */
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: ?>
386: 
 

© 2004-2018 – Nicola Asuni - Tecnick.com - All rights reserved.
about - disclaimer - privacy