| [ Index ] |
PHP Cross Reference of Joomla 1.5.26 DE |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * This module contains code for dealing with associations between 5 * consumers and servers. 6 * 7 * PHP versions 4 and 5 8 * 9 * LICENSE: See the COPYING file included in this distribution. 10 * 11 * @package OpenID 12 * @author JanRain, Inc. <openid@janrain.com> 13 * @copyright 2005-2008 Janrain, Inc. 14 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache 15 */ 16 17 // Do not allow direct access 18 defined( '_JEXEC' ) or die( 'Restricted access' ); 19 20 /** 21 * @access private 22 */ 23 require_once 'Auth/OpenID/CryptUtil.php'; 24 25 /** 26 * @access private 27 */ 28 require_once 'Auth/OpenID/KVForm.php'; 29 30 /** 31 * @access private 32 */ 33 require_once 'Auth/OpenID/HMAC.php'; 34 35 /** 36 * This class represents an association between a server and a 37 * consumer. In general, users of this library will never see 38 * instances of this object. The only exception is if you implement a 39 * custom {@link Auth_OpenID_OpenIDStore}. 40 * 41 * If you do implement such a store, it will need to store the values 42 * of the handle, secret, issued, lifetime, and assoc_type instance 43 * variables. 44 * 45 * @package OpenID 46 */ 47 class Auth_OpenID_Association { 48 49 /** 50 * This is a HMAC-SHA1 specific value. 51 * 52 * @access private 53 */ 54 var $SIG_LENGTH = 20; 55 56 /** 57 * The ordering and name of keys as stored by serialize. 58 * 59 * @access private 60 */ 61 var $assoc_keys = array( 62 'version', 63 'handle', 64 'secret', 65 'issued', 66 'lifetime', 67 'assoc_type' 68 ); 69 70 var $_macs = array( 71 'HMAC-SHA1' => 'Auth_OpenID_HMACSHA1', 72 'HMAC-SHA256' => 'Auth_OpenID_HMACSHA256' 73 ); 74 75 /** 76 * This is an alternate constructor (factory method) used by the 77 * OpenID consumer library to create associations. OpenID store 78 * implementations shouldn't use this constructor. 79 * 80 * @access private 81 * 82 * @param integer $expires_in This is the amount of time this 83 * association is good for, measured in seconds since the 84 * association was issued. 85 * 86 * @param string $handle This is the handle the server gave this 87 * association. 88 * 89 * @param string secret This is the shared secret the server 90 * generated for this association. 91 * 92 * @param assoc_type This is the type of association this 93 * instance represents. The only valid values of this field at 94 * this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may 95 * be defined in the future. 96 * 97 * @return association An {@link Auth_OpenID_Association} 98 * instance. 99 */ 100 function fromExpiresIn($expires_in, $handle, $secret, $assoc_type) 101 { 102 $issued = time(); 103 $lifetime = $expires_in; 104 return new Auth_OpenID_Association($handle, $secret, 105 $issued, $lifetime, $assoc_type); 106 } 107 108 /** 109 * This is the standard constructor for creating an association. 110 * The library should create all of the necessary associations, so 111 * this constructor is not part of the external API. 112 * 113 * @access private 114 * 115 * @param string $handle This is the handle the server gave this 116 * association. 117 * 118 * @param string $secret This is the shared secret the server 119 * generated for this association. 120 * 121 * @param integer $issued This is the time this association was 122 * issued, in seconds since 00:00 GMT, January 1, 1970. (ie, a 123 * unix timestamp) 124 * 125 * @param integer $lifetime This is the amount of time this 126 * association is good for, measured in seconds since the 127 * association was issued. 128 * 129 * @param string $assoc_type This is the type of association this 130 * instance represents. The only valid values of this field at 131 * this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may 132 * be defined in the future. 133 */ 134 function Auth_OpenID_Association( 135 $handle, $secret, $issued, $lifetime, $assoc_type) 136 { 137 if (!in_array($assoc_type, 138 Auth_OpenID_getSupportedAssociationTypes())) { 139 $fmt = 'Unsupported association type (%s)'; 140 trigger_error(sprintf($fmt, $assoc_type), E_USER_ERROR); 141 } 142 143 $this->handle = $handle; 144 $this->secret = $secret; 145 $this->issued = $issued; 146 $this->lifetime = $lifetime; 147 $this->assoc_type = $assoc_type; 148 } 149 150 /** 151 * This returns the number of seconds this association is still 152 * valid for, or 0 if the association is no longer valid. 153 * 154 * @return integer $seconds The number of seconds this association 155 * is still valid for, or 0 if the association is no longer valid. 156 */ 157 function getExpiresIn($now = null) 158 { 159 if ($now == null) { 160 $now = time(); 161 } 162 163 return max(0, $this->issued + $this->lifetime - $now); 164 } 165 166 /** 167 * This checks to see if two {@link Auth_OpenID_Association} 168 * instances represent the same association. 169 * 170 * @return bool $result true if the two instances represent the 171 * same association, false otherwise. 172 */ 173 function equal($other) 174 { 175 return ((gettype($this) == gettype($other)) 176 && ($this->handle == $other->handle) 177 && ($this->secret == $other->secret) 178 && ($this->issued == $other->issued) 179 && ($this->lifetime == $other->lifetime) 180 && ($this->assoc_type == $other->assoc_type)); 181 } 182 183 /** 184 * Convert an association to KV form. 185 * 186 * @return string $result String in KV form suitable for 187 * deserialization by deserialize. 188 */ 189 function serialize() 190 { 191 $data = array( 192 'version' => '2', 193 'handle' => $this->handle, 194 'secret' => base64_encode($this->secret), 195 'issued' => strval(intval($this->issued)), 196 'lifetime' => strval(intval($this->lifetime)), 197 'assoc_type' => $this->assoc_type 198 ); 199 200 assert(array_keys($data) == $this->assoc_keys); 201 202 return Auth_OpenID_KVForm::fromArray($data, $strict = true); 203 } 204 205 /** 206 * Parse an association as stored by serialize(). This is the 207 * inverse of serialize. 208 * 209 * @param string $assoc_s Association as serialized by serialize() 210 * @return Auth_OpenID_Association $result instance of this class 211 */ 212 function deserialize($class_name, $assoc_s) 213 { 214 $pairs = Auth_OpenID_KVForm::toArray($assoc_s, $strict = true); 215 $keys = array(); 216 $values = array(); 217 foreach ($pairs as $key => $value) { 218 if (is_array($value)) { 219 list($key, $value) = $value; 220 } 221 $keys[] = $key; 222 $values[] = $value; 223 } 224 225 $class_vars = get_class_vars($class_name); 226 $class_assoc_keys = $class_vars['assoc_keys']; 227 228 sort($keys); 229 sort($class_assoc_keys); 230 231 if ($keys != $class_assoc_keys) { 232 trigger_error('Unexpected key values: ' . var_export($keys, true), 233 E_USER_WARNING); 234 return null; 235 } 236 237 $version = $pairs['version']; 238 $handle = $pairs['handle']; 239 $secret = $pairs['secret']; 240 $issued = $pairs['issued']; 241 $lifetime = $pairs['lifetime']; 242 $assoc_type = $pairs['assoc_type']; 243 244 if ($version != '2') { 245 trigger_error('Unknown version: ' . $version, E_USER_WARNING); 246 return null; 247 } 248 249 $issued = intval($issued); 250 $lifetime = intval($lifetime); 251 $secret = base64_decode($secret); 252 253 return new $class_name( 254 $handle, $secret, $issued, $lifetime, $assoc_type); 255 } 256 257 /** 258 * Generate a signature for a sequence of (key, value) pairs 259 * 260 * @access private 261 * @param array $pairs The pairs to sign, in order. This is an 262 * array of two-tuples. 263 * @return string $signature The binary signature of this sequence 264 * of pairs 265 */ 266 function sign($pairs) 267 { 268 $kv = Auth_OpenID_KVForm::fromArray($pairs); 269 270 /* Invalid association types should be caught at constructor */ 271 $callback = $this->_macs[$this->assoc_type]; 272 273 return call_user_func_array($callback, array($this->secret, $kv)); 274 } 275 276 /** 277 * Generate a signature for some fields in a dictionary 278 * 279 * @access private 280 * @param array $fields The fields to sign, in order; this is an 281 * array of strings. 282 * @param array $data Dictionary of values to sign (an array of 283 * string => string pairs). 284 * @return string $signature The signature, base64 encoded 285 */ 286 function signMessage($message) 287 { 288 if ($message->hasKey(Auth_OpenID_OPENID_NS, 'sig') || 289 $message->hasKey(Auth_OpenID_OPENID_NS, 'signed')) { 290 // Already has a sig 291 return null; 292 } 293 294 $extant_handle = $message->getArg(Auth_OpenID_OPENID_NS, 295 'assoc_handle'); 296 297 if ($extant_handle && ($extant_handle != $this->handle)) { 298 // raise ValueError("Message has a different association handle") 299 return null; 300 } 301 302 $signed_message = $message; 303 $signed_message->setArg(Auth_OpenID_OPENID_NS, 'assoc_handle', 304 $this->handle); 305 306 $message_keys = array_keys($signed_message->toPostArgs()); 307 $signed_list = array(); 308 $signed_prefix = 'openid.'; 309 310 foreach ($message_keys as $k) { 311 if (strpos($k, $signed_prefix) === 0) { 312 $signed_list[] = substr($k, strlen($signed_prefix)); 313 } 314 } 315 316 $signed_list[] = 'signed'; 317 sort($signed_list); 318 319 $signed_message->setArg(Auth_OpenID_OPENID_NS, 'signed', 320 implode(',', $signed_list)); 321 $sig = $this->getMessageSignature($signed_message); 322 $signed_message->setArg(Auth_OpenID_OPENID_NS, 'sig', $sig); 323 return $signed_message; 324 } 325 326 /** 327 * Given a {@link Auth_OpenID_Message}, return the key/value pairs 328 * to be signed according to the signed list in the message. If 329 * the message lacks a signed list, return null. 330 * 331 * @access private 332 */ 333 function _makePairs(&$message) 334 { 335 $signed = $message->getArg(Auth_OpenID_OPENID_NS, 'signed'); 336 if (!$signed || Auth_OpenID::isFailure($signed)) { 337 // raise ValueError('Message has no signed list: %s' % (message,)) 338 return null; 339 } 340 341 $signed_list = explode(',', $signed); 342 $pairs = array(); 343 $data = $message->toPostArgs(); 344 foreach ($signed_list as $field) { 345 $pairs[] = array($field, Auth_OpenID::arrayGet($data, 346 'openid.' . 347 $field, '')); 348 } 349 return $pairs; 350 } 351 352 /** 353 * Given an {@link Auth_OpenID_Message}, return the signature for 354 * the signed list in the message. 355 * 356 * @access private 357 */ 358 function getMessageSignature(&$message) 359 { 360 $pairs = $this->_makePairs($message); 361 return base64_encode($this->sign($pairs)); 362 } 363 364 /** 365 * Confirm that the signature of these fields matches the 366 * signature contained in the data. 367 * 368 * @access private 369 */ 370 function checkMessageSignature(&$message) 371 { 372 $sig = $message->getArg(Auth_OpenID_OPENID_NS, 373 'sig'); 374 375 if (!$sig || Auth_OpenID::isFailure($sig)) { 376 return false; 377 } 378 379 $calculated_sig = $this->getMessageSignature($message); 380 return $calculated_sig == $sig; 381 } 382 } 383 384 function Auth_OpenID_getSecretSize($assoc_type) 385 { 386 if ($assoc_type == 'HMAC-SHA1') { 387 return 20; 388 } else if ($assoc_type == 'HMAC-SHA256') { 389 return 32; 390 } else { 391 return null; 392 } 393 } 394 395 function Auth_OpenID_getAllAssociationTypes() 396 { 397 return array('HMAC-SHA1', 'HMAC-SHA256'); 398 } 399 400 function Auth_OpenID_getSupportedAssociationTypes() 401 { 402 $a = array('HMAC-SHA1'); 403 404 if (Auth_OpenID_HMACSHA256_SUPPORTED) { 405 $a[] = 'HMAC-SHA256'; 406 } 407 408 return $a; 409 } 410 411 function Auth_OpenID_getSessionTypes($assoc_type) 412 { 413 $assoc_to_session = array( 414 'HMAC-SHA1' => array('DH-SHA1', 'no-encryption')); 415 416 if (Auth_OpenID_HMACSHA256_SUPPORTED) { 417 $assoc_to_session['HMAC-SHA256'] = 418 array('DH-SHA256', 'no-encryption'); 419 } 420 421 return Auth_OpenID::arrayGet($assoc_to_session, $assoc_type, array()); 422 } 423 424 function Auth_OpenID_checkSessionType($assoc_type, $session_type) 425 { 426 if (!in_array($session_type, 427 Auth_OpenID_getSessionTypes($assoc_type))) { 428 return false; 429 } 430 431 return true; 432 } 433 434 function Auth_OpenID_getDefaultAssociationOrder() 435 { 436 $order = array(); 437 438 if (!Auth_OpenID_noMathSupport()) { 439 $order[] = array('HMAC-SHA1', 'DH-SHA1'); 440 441 if (Auth_OpenID_HMACSHA256_SUPPORTED) { 442 $order[] = array('HMAC-SHA256', 'DH-SHA256'); 443 } 444 } 445 446 $order[] = array('HMAC-SHA1', 'no-encryption'); 447 448 if (Auth_OpenID_HMACSHA256_SUPPORTED) { 449 $order[] = array('HMAC-SHA256', 'no-encryption'); 450 } 451 452 return $order; 453 } 454 455 function Auth_OpenID_getOnlyEncryptedOrder() 456 { 457 $result = array(); 458 459 foreach (Auth_OpenID_getDefaultAssociationOrder() as $pair) { 460 list($assoc, $session) = $pair; 461 462 if ($session != 'no-encryption') { 463 if (Auth_OpenID_HMACSHA256_SUPPORTED && 464 ($assoc == 'HMAC-SHA256')) { 465 $result[] = $pair; 466 } else if ($assoc != 'HMAC-SHA256') { 467 $result[] = $pair; 468 } 469 } 470 } 471 472 return $result; 473 } 474 475 function &Auth_OpenID_getDefaultNegotiator() 476 { 477 $x = new Auth_OpenID_SessionNegotiator( 478 Auth_OpenID_getDefaultAssociationOrder()); 479 return $x; 480 } 481 482 function &Auth_OpenID_getEncryptedNegotiator() 483 { 484 $x = new Auth_OpenID_SessionNegotiator( 485 Auth_OpenID_getOnlyEncryptedOrder()); 486 return $x; 487 } 488 489 /** 490 * A session negotiator controls the allowed and preferred association 491 * types and association session types. Both the {@link 492 * Auth_OpenID_Consumer} and {@link Auth_OpenID_Server} use 493 * negotiators when creating associations. 494 * 495 * You can create and use negotiators if you: 496 497 * - Do not want to do Diffie-Hellman key exchange because you use 498 * transport-layer encryption (e.g. SSL) 499 * 500 * - Want to use only SHA-256 associations 501 * 502 * - Do not want to support plain-text associations over a non-secure 503 * channel 504 * 505 * It is up to you to set a policy for what kinds of associations to 506 * accept. By default, the library will make any kind of association 507 * that is allowed in the OpenID 2.0 specification. 508 * 509 * Use of negotiators in the library 510 * ================================= 511 * 512 * When a consumer makes an association request, it calls {@link 513 * getAllowedType} to get the preferred association type and 514 * association session type. 515 * 516 * The server gets a request for a particular association/session type 517 * and calls {@link isAllowed} to determine if it should create an 518 * association. If it is supported, negotiation is complete. If it is 519 * not, the server calls {@link getAllowedType} to get an allowed 520 * association type to return to the consumer. 521 * 522 * If the consumer gets an error response indicating that the 523 * requested association/session type is not supported by the server 524 * that contains an assocation/session type to try, it calls {@link 525 * isAllowed} to determine if it should try again with the given 526 * combination of association/session type. 527 * 528 * @package OpenID 529 */ 530 class Auth_OpenID_SessionNegotiator { 531 function Auth_OpenID_SessionNegotiator($allowed_types) 532 { 533 $this->allowed_types = array(); 534 $this->setAllowedTypes($allowed_types); 535 } 536 537 /** 538 * Set the allowed association types, checking to make sure each 539 * combination is valid. 540 * 541 * @access private 542 */ 543 function setAllowedTypes($allowed_types) 544 { 545 foreach ($allowed_types as $pair) { 546 list($assoc_type, $session_type) = $pair; 547 if (!Auth_OpenID_checkSessionType($assoc_type, $session_type)) { 548 return false; 549 } 550 } 551 552 $this->allowed_types = $allowed_types; 553 return true; 554 } 555 556 /** 557 * Add an association type and session type to the allowed types 558 * list. The assocation/session pairs are tried in the order that 559 * they are added. 560 * 561 * @access private 562 */ 563 function addAllowedType($assoc_type, $session_type = null) 564 { 565 if ($this->allowed_types === null) { 566 $this->allowed_types = array(); 567 } 568 569 if ($session_type === null) { 570 $available = Auth_OpenID_getSessionTypes($assoc_type); 571 572 if (!$available) { 573 return false; 574 } 575 576 foreach ($available as $session_type) { 577 $this->addAllowedType($assoc_type, $session_type); 578 } 579 } else { 580 if (Auth_OpenID_checkSessionType($assoc_type, $session_type)) { 581 $this->allowed_types[] = array($assoc_type, $session_type); 582 } else { 583 return false; 584 } 585 } 586 587 return true; 588 } 589 590 // Is this combination of association type and session type allowed? 591 function isAllowed($assoc_type, $session_type) 592 { 593 $assoc_good = in_array(array($assoc_type, $session_type), 594 $this->allowed_types); 595 596 $matches = in_array($session_type, 597 Auth_OpenID_getSessionTypes($assoc_type)); 598 599 return ($assoc_good && $matches); 600 } 601 602 /** 603 * Get a pair of assocation type and session type that are 604 * supported. 605 */ 606 function getAllowedType() 607 { 608 if (!$this->allowed_types) { 609 return array(null, null); 610 } 611 612 return $this->allowed_types[0]; 613 } 614 } 615 616 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Wed Mar 28 15:54:07 2012 | Cross-referenced by PHPXref 0.7.1 |