|
TYPO3 API
SVNRelease
|
00001 <?php 00002 00003 /** 00004 * Yadis service manager to be used during yadis-driven authentication 00005 * attempts. 00006 * 00007 * @package OpenID 00008 */ 00009 00010 /** 00011 * The base session class used by the Auth_Yadis_Manager. This 00012 * class wraps the default PHP session machinery and should be 00013 * subclassed if your application doesn't use PHP sessioning. 00014 * 00015 * @package OpenID 00016 */ 00017 class Auth_Yadis_PHPSession { 00018 /** 00019 * Set a session key/value pair. 00020 * 00021 * @param string $name The name of the session key to add. 00022 * @param string $value The value to add to the session. 00023 */ 00024 function set($name, $value) 00025 { 00026 $_SESSION[$name] = $value; 00027 } 00028 00029 /** 00030 * Get a key's value from the session. 00031 * 00032 * @param string $name The name of the key to retrieve. 00033 * @param string $default The optional value to return if the key 00034 * is not found in the session. 00035 * @return string $result The key's value in the session or 00036 * $default if it isn't found. 00037 */ 00038 function get($name, $default=null) 00039 { 00040 if (array_key_exists($name, $_SESSION)) { 00041 return $_SESSION[$name]; 00042 } else { 00043 return $default; 00044 } 00045 } 00046 00047 /** 00048 * Remove a key/value pair from the session. 00049 * 00050 * @param string $name The name of the key to remove. 00051 */ 00052 function del($name) 00053 { 00054 unset($_SESSION[$name]); 00055 } 00056 00057 /** 00058 * Return the contents of the session in array form. 00059 */ 00060 function contents() 00061 { 00062 return $_SESSION; 00063 } 00064 } 00065 00066 /** 00067 * A session helper class designed to translate between arrays and 00068 * objects. Note that the class used must have a constructor that 00069 * takes no parameters. This is not a general solution, but it works 00070 * for dumb objects that just need to have attributes set. The idea 00071 * is that you'll subclass this and override $this->check($data) -> 00072 * bool to implement your own session data validation. 00073 * 00074 * @package OpenID 00075 */ 00076 class Auth_Yadis_SessionLoader { 00077 /** 00078 * Override this. 00079 * 00080 * @access private 00081 */ 00082 function check($data) 00083 { 00084 return true; 00085 } 00086 00087 /** 00088 * Given a session data value (an array), this creates an object 00089 * (returned by $this->newObject()) whose attributes and values 00090 * are those in $data. Returns null if $data lacks keys found in 00091 * $this->requiredKeys(). Returns null if $this->check($data) 00092 * evaluates to false. Returns null if $this->newObject() 00093 * evaluates to false. 00094 * 00095 * @access private 00096 */ 00097 function fromSession($data) 00098 { 00099 if (!$data) { 00100 return null; 00101 } 00102 00103 $required = $this->requiredKeys(); 00104 00105 foreach ($required as $k) { 00106 if (!array_key_exists($k, $data)) { 00107 return null; 00108 } 00109 } 00110 00111 if (!$this->check($data)) { 00112 return null; 00113 } 00114 00115 $data = array_merge($data, $this->prepareForLoad($data)); 00116 $obj = $this->newObject($data); 00117 00118 if (!$obj) { 00119 return null; 00120 } 00121 00122 foreach ($required as $k) { 00123 $obj->$k = $data[$k]; 00124 } 00125 00126 return $obj; 00127 } 00128 00129 /** 00130 * Prepares the data array by making any necessary changes. 00131 * Returns an array whose keys and values will be used to update 00132 * the original data array before calling $this->newObject($data). 00133 * 00134 * @access private 00135 */ 00136 function prepareForLoad($data) 00137 { 00138 return array(); 00139 } 00140 00141 /** 00142 * Returns a new instance of this loader's class, using the 00143 * session data to construct it if necessary. The object need 00144 * only be created; $this->fromSession() will take care of setting 00145 * the object's attributes. 00146 * 00147 * @access private 00148 */ 00149 function newObject($data) 00150 { 00151 return null; 00152 } 00153 00154 /** 00155 * Returns an array of keys and values built from the attributes 00156 * of $obj. If $this->prepareForSave($obj) returns an array, its keys 00157 * and values are used to update the $data array of attributes 00158 * from $obj. 00159 * 00160 * @access private 00161 */ 00162 function toSession($obj) 00163 { 00164 $data = array(); 00165 foreach ($obj as $k => $v) { 00166 $data[$k] = $v; 00167 } 00168 00169 $extra = $this->prepareForSave($obj); 00170 00171 if ($extra && is_array($extra)) { 00172 foreach ($extra as $k => $v) { 00173 $data[$k] = $v; 00174 } 00175 } 00176 00177 return $data; 00178 } 00179 00180 /** 00181 * Override this. 00182 * 00183 * @access private 00184 */ 00185 function prepareForSave($obj) 00186 { 00187 return array(); 00188 } 00189 } 00190 00191 /** 00192 * A concrete loader implementation for Auth_OpenID_ServiceEndpoints. 00193 * 00194 * @package OpenID 00195 */ 00196 class Auth_OpenID_ServiceEndpointLoader extends Auth_Yadis_SessionLoader { 00197 function newObject($data) 00198 { 00199 return new Auth_OpenID_ServiceEndpoint(); 00200 } 00201 00202 function requiredKeys() 00203 { 00204 $obj = new Auth_OpenID_ServiceEndpoint(); 00205 $data = array(); 00206 foreach ($obj as $k => $v) { 00207 $data[] = $k; 00208 } 00209 return $data; 00210 } 00211 00212 function check($data) 00213 { 00214 return is_array($data['type_uris']); 00215 } 00216 } 00217 00218 /** 00219 * A concrete loader implementation for Auth_Yadis_Managers. 00220 * 00221 * @package OpenID 00222 */ 00223 class Auth_Yadis_ManagerLoader extends Auth_Yadis_SessionLoader { 00224 function requiredKeys() 00225 { 00226 return array('starting_url', 00227 'yadis_url', 00228 'services', 00229 'session_key', 00230 '_current', 00231 'stale'); 00232 } 00233 00234 function newObject($data) 00235 { 00236 return new Auth_Yadis_Manager($data['starting_url'], 00237 $data['yadis_url'], 00238 $data['services'], 00239 $data['session_key']); 00240 } 00241 00242 function check($data) 00243 { 00244 return is_array($data['services']); 00245 } 00246 00247 function prepareForLoad($data) 00248 { 00249 $loader = new Auth_OpenID_ServiceEndpointLoader(); 00250 $services = array(); 00251 foreach ($data['services'] as $s) { 00252 $services[] = $loader->fromSession($s); 00253 } 00254 return array('services' => $services); 00255 } 00256 00257 function prepareForSave($obj) 00258 { 00259 $loader = new Auth_OpenID_ServiceEndpointLoader(); 00260 $services = array(); 00261 foreach ($obj->services as $s) { 00262 $services[] = $loader->toSession($s); 00263 } 00264 return array('services' => $services); 00265 } 00266 } 00267 00268 /** 00269 * The Yadis service manager which stores state in a session and 00270 * iterates over <Service> elements in a Yadis XRDS document and lets 00271 * a caller attempt to use each one. This is used by the Yadis 00272 * library internally. 00273 * 00274 * @package OpenID 00275 */ 00276 class Auth_Yadis_Manager { 00277 00278 /** 00279 * Intialize a new yadis service manager. 00280 * 00281 * @access private 00282 */ 00283 function Auth_Yadis_Manager($starting_url, $yadis_url, 00284 $services, $session_key) 00285 { 00286 // The URL that was used to initiate the Yadis protocol 00287 $this->starting_url = $starting_url; 00288 00289 // The URL after following redirects (the identifier) 00290 $this->yadis_url = $yadis_url; 00291 00292 // List of service elements 00293 $this->services = $services; 00294 00295 $this->session_key = $session_key; 00296 00297 // Reference to the current service object 00298 $this->_current = null; 00299 00300 // Stale flag for cleanup if PHP lib has trouble. 00301 $this->stale = false; 00302 } 00303 00304 /** 00305 * @access private 00306 */ 00307 function length() 00308 { 00309 // How many untried services remain? 00310 return count($this->services); 00311 } 00312 00313 /** 00314 * Return the next service 00315 * 00316 * $this->current() will continue to return that service until the 00317 * next call to this method. 00318 */ 00319 function nextService() 00320 { 00321 00322 if ($this->services) { 00323 $this->_current = array_shift($this->services); 00324 } else { 00325 $this->_current = null; 00326 } 00327 00328 return $this->_current; 00329 } 00330 00331 /** 00332 * @access private 00333 */ 00334 function current() 00335 { 00336 // Return the current service. 00337 // Returns None if there are no services left. 00338 return $this->_current; 00339 } 00340 00341 /** 00342 * @access private 00343 */ 00344 function forURL($url) 00345 { 00346 return in_array($url, array($this->starting_url, $this->yadis_url)); 00347 } 00348 00349 /** 00350 * @access private 00351 */ 00352 function started() 00353 { 00354 // Has the first service been returned? 00355 return $this->_current !== null; 00356 } 00357 } 00358 00359 /** 00360 * State management for discovery. 00361 * 00362 * High-level usage pattern is to call .getNextService(discover) in 00363 * order to find the next available service for this user for this 00364 * session. Once a request completes, call .cleanup() to clean up the 00365 * session state. 00366 * 00367 * @package OpenID 00368 */ 00369 class Auth_Yadis_Discovery { 00370 00371 /** 00372 * @access private 00373 */ 00374 var $DEFAULT_SUFFIX = 'auth'; 00375 00376 /** 00377 * @access private 00378 */ 00379 var $PREFIX = '_yadis_services_'; 00380 00381 /** 00382 * Initialize a discovery object. 00383 * 00384 * @param Auth_Yadis_PHPSession $session An object which 00385 * implements the Auth_Yadis_PHPSession API. 00386 * @param string $url The URL on which to attempt discovery. 00387 * @param string $session_key_suffix The optional session key 00388 * suffix override. 00389 */ 00390 function Auth_Yadis_Discovery(&$session, $url, 00391 $session_key_suffix = null) 00392 { 00393 /// Initialize a discovery object 00394 $this->session =& $session; 00395 $this->url = $url; 00396 if ($session_key_suffix === null) { 00397 $session_key_suffix = $this->DEFAULT_SUFFIX; 00398 } 00399 00400 $this->session_key_suffix = $session_key_suffix; 00401 $this->session_key = $this->PREFIX . $this->session_key_suffix; 00402 } 00403 00404 /** 00405 * Return the next authentication service for the pair of 00406 * user_input and session. This function handles fallback. 00407 */ 00408 function getNextService($discover_cb, &$fetcher) 00409 { 00410 $manager = $this->getManager(); 00411 if (!$manager || (!$manager->services)) { 00412 $this->destroyManager(); 00413 00414 list($yadis_url, $services) = call_user_func($discover_cb, 00415 $this->url, 00416 $fetcher); 00417 00418 $manager = $this->createManager($services, $yadis_url); 00419 } 00420 00421 if ($manager) { 00422 $loader = new Auth_Yadis_ManagerLoader(); 00423 $service = $manager->nextService(); 00424 $this->session->set($this->session_key, 00425 serialize($loader->toSession($manager))); 00426 } else { 00427 $service = null; 00428 } 00429 00430 return $service; 00431 } 00432 00433 /** 00434 * Clean up Yadis-related services in the session and return the 00435 * most-recently-attempted service from the manager, if one 00436 * exists. 00437 * 00438 * @param $force True if the manager should be deleted regardless 00439 * of whether it's a manager for $this->url. 00440 */ 00441 function cleanup($force=false) 00442 { 00443 $manager = $this->getManager($force); 00444 if ($manager) { 00445 $service = $manager->current(); 00446 $this->destroyManager($force); 00447 } else { 00448 $service = null; 00449 } 00450 00451 return $service; 00452 } 00453 00454 /** 00455 * @access private 00456 */ 00457 function getSessionKey() 00458 { 00459 // Get the session key for this starting URL and suffix 00460 return $this->PREFIX . $this->session_key_suffix; 00461 } 00462 00463 /** 00464 * @access private 00465 * 00466 * @param $force True if the manager should be returned regardless 00467 * of whether it's a manager for $this->url. 00468 */ 00469 function &getManager($force=false) 00470 { 00471 // Extract the YadisServiceManager for this object's URL and 00472 // suffix from the session. 00473 00474 $manager_str = $this->session->get($this->getSessionKey()); 00475 $manager = null; 00476 00477 if ($manager_str !== null) { 00478 $loader = new Auth_Yadis_ManagerLoader(); 00479 $manager = $loader->fromSession(unserialize($manager_str)); 00480 } 00481 00482 if ($manager && ($manager->forURL($this->url) || $force)) { 00483 return $manager; 00484 } else { 00485 $unused = null; 00486 return $unused; 00487 } 00488 } 00489 00490 /** 00491 * @access private 00492 */ 00493 function &createManager($services, $yadis_url = null) 00494 { 00495 $key = $this->getSessionKey(); 00496 if ($this->getManager()) { 00497 return $this->getManager(); 00498 } 00499 00500 if ($services) { 00501 $loader = new Auth_Yadis_ManagerLoader(); 00502 $manager = new Auth_Yadis_Manager($this->url, $yadis_url, 00503 $services, $key); 00504 $this->session->set($this->session_key, 00505 serialize($loader->toSession($manager))); 00506 return $manager; 00507 } else { 00508 // Oh, PHP. 00509 $unused = null; 00510 return $unused; 00511 } 00512 } 00513 00514 /** 00515 * @access private 00516 * 00517 * @param $force True if the manager should be deleted regardless 00518 * of whether it's a manager for $this->url. 00519 */ 00520 function destroyManager($force=false) 00521 { 00522 if ($this->getManager($force) !== null) { 00523 $key = $this->getSessionKey(); 00524 $this->session->del($key); 00525 } 00526 } 00527 } 00528 00529 ?>
1.8.0