1<?php 2 3/** 4 * Extension argument processing code 5 * 6 * @package OpenID 7 */ 8 9/** 10 * Import tools needed to deal with messages. 11 */ 12require_once 'Auth/OpenID.php'; 13require_once 'Auth/OpenID/KVForm.php'; 14require_once 'Auth/Yadis/XML.php'; 15require_once 'Auth/OpenID/Consumer.php'; // For Auth_OpenID_FailureResponse 16 17// This doesn't REALLY belong here, but where is better? 18define('Auth_OpenID_IDENTIFIER_SELECT', 19 "http://specs.openid.net/auth/2.0/identifier_select"); 20 21// URI for Simple Registration extension, the only commonly deployed 22// OpenID 1.x extension, and so a special case 23define('Auth_OpenID_SREG_URI', 'http://openid.net/sreg/1.0'); 24 25// The OpenID 1.X namespace URI 26define('Auth_OpenID_OPENID1_NS', 'http://openid.net/signon/1.0'); 27define('Auth_OpenID_THE_OTHER_OPENID1_NS', 'http://openid.net/signon/1.1'); 28 29function Auth_OpenID_isOpenID1($ns) 30{ 31 return ($ns == Auth_OpenID_THE_OTHER_OPENID1_NS) || 32 ($ns == Auth_OpenID_OPENID1_NS); 33} 34 35// The OpenID 2.0 namespace URI 36define('Auth_OpenID_OPENID2_NS', 'http://specs.openid.net/auth/2.0'); 37 38// The namespace consisting of pairs with keys that are prefixed with 39// "openid." but not in another namespace. 40define('Auth_OpenID_NULL_NAMESPACE', 'Null namespace'); 41 42// The null namespace, when it is an allowed OpenID namespace 43define('Auth_OpenID_OPENID_NS', 'OpenID namespace'); 44 45// The top-level namespace, excluding all pairs with keys that start 46// with "openid." 47define('Auth_OpenID_BARE_NS', 'Bare namespace'); 48 49// Sentinel for Message implementation to indicate that getArg should 50// return null instead of returning a default. 51define('Auth_OpenID_NO_DEFAULT', 'NO DEFAULT ALLOWED'); 52 53// Limit, in bytes, of identity provider and return_to URLs, including 54// response payload. See OpenID 1.1 specification, Appendix D. 55define('Auth_OpenID_OPENID1_URL_LIMIT', 2047); 56 57// All OpenID protocol fields. Used to check namespace aliases. 58global $Auth_OpenID_OPENID_PROTOCOL_FIELDS; 59$Auth_OpenID_OPENID_PROTOCOL_FIELDS = [ 60 'ns', 'mode', 'error', 'return_to', 'contact', 'reference', 61 'signed', 'assoc_type', 'session_type', 'dh_modulus', 'dh_gen', 62 'dh_consumer_public', 'claimed_id', 'identity', 'realm', 63 'invalidate_handle', 'op_endpoint', 'response_nonce', 'sig', 64 'assoc_handle', 'trust_root', 'openid' 65]; 66 67// Global namespace / alias registration map. See 68// Auth_OpenID_registerNamespaceAlias. 69global $Auth_OpenID_registered_aliases; 70$Auth_OpenID_registered_aliases = []; 71 72/** 73 * Registers a (namespace URI, alias) mapping in a global namespace 74 * alias map. Raises NamespaceAliasRegistrationError if either the 75 * namespace URI or alias has already been registered with a different 76 * value. This function is required if you want to use a namespace 77 * with an OpenID 1 message. 78 * 79 * @param string $namespace_uri 80 * @param string $alias 81 * @return bool 82 */ 83function Auth_OpenID_registerNamespaceAlias($namespace_uri, $alias) 84{ 85 global $Auth_OpenID_registered_aliases; 86 87 if (Auth_OpenID::arrayGet($Auth_OpenID_registered_aliases, 88 $alias) == $namespace_uri) { 89 return true; 90 } 91 92 if (in_array($namespace_uri, 93 array_values($Auth_OpenID_registered_aliases))) { 94 return false; 95 } 96 97 if (in_array($alias, array_keys($Auth_OpenID_registered_aliases))) { 98 return false; 99 } 100 101 $Auth_OpenID_registered_aliases[$alias] = $namespace_uri; 102 return true; 103} 104 105/** 106 * Removes a (namespace_uri, alias) registration from the global 107 * namespace alias map. Returns true if the removal succeeded; false 108 * if not (if the mapping did not exist). 109 * 110 * @param string $namespace_uri 111 * @param string $alias 112 * @return bool 113 */ 114function Auth_OpenID_removeNamespaceAlias($namespace_uri, $alias) 115{ 116 global $Auth_OpenID_registered_aliases; 117 118 if (Auth_OpenID::arrayGet($Auth_OpenID_registered_aliases, 119 $alias) === $namespace_uri) { 120 unset($Auth_OpenID_registered_aliases[$alias]); 121 return true; 122 } 123 124 return false; 125} 126 127/** 128 * An Auth_OpenID_Mapping maintains a mapping from arbitrary keys to 129 * arbitrary values. (This is unlike an ordinary PHP array, whose 130 * keys may be only simple scalars.) 131 * 132 * @package OpenID 133 */ 134class Auth_OpenID_Mapping { 135 136 private $keys = []; 137 private $values = []; 138 139 /** 140 * Initialize a mapping. If $classic_array is specified, its keys 141 * and values are used to populate the mapping. 142 * 143 * @param array|null $classic_array 144 */ 145 function __construct($classic_array = null) 146 { 147 if (is_array($classic_array)) { 148 foreach ($classic_array as $key => $value) { 149 $this->set($key, $value); 150 } 151 } 152 } 153 154 /** 155 * Returns true if $thing is an Auth_OpenID_Mapping object; false 156 * if not. 157 * 158 * @param Auth_OpenID_Mapping $thing 159 * @return bool 160 */ 161 static function isA($thing) 162 { 163 return (is_object($thing) && 164 strtolower(get_class($thing)) == 'auth_openid_mapping'); 165 } 166 167 /** 168 * Returns an array of the keys in the mapping. 169 */ 170 function keys() 171 { 172 return $this->keys; 173 } 174 175 /** 176 * Returns an array of values in the mapping. 177 */ 178 function values() 179 { 180 return $this->values; 181 } 182 183 /** 184 * Returns an array of (key, value) pairs in the mapping. 185 */ 186 function items() 187 { 188 $temp = []; 189 190 for ($i = 0; $i < count($this->keys); $i++) { 191 $temp[] = [ 192 $this->keys[$i], 193 $this->values[$i] 194 ]; 195 } 196 return $temp; 197 } 198 199 /** 200 * Returns the "length" of the mapping, or the number of keys. 201 */ 202 function len() 203 { 204 return count($this->keys); 205 } 206 207 /** 208 * Sets a key-value pair in the mapping. If the key already 209 * exists, its value is replaced with the new value. 210 * 211 * @param string|array $key 212 * @param mixed $value 213 */ 214 function set($key, $value) 215 { 216 $index = array_search($key, $this->keys); 217 218 if ($index !== false) { 219 $this->values[$index] = $value; 220 } else { 221 $this->keys[] = $key; 222 $this->values[] = $value; 223 } 224 } 225 226 /** 227 * Gets a specified value from the mapping, associated with the 228 * specified key. If the key does not exist in the mapping, 229 * $default is returned instead. 230 * 231 * @param string|array $key 232 * @param mixed $default 233 * @return mixed|null 234 */ 235 function get($key, $default = null) 236 { 237 $index = array_search($key, $this->keys); 238 239 if ($index !== false) { 240 return $this->values[$index]; 241 } else { 242 return $default; 243 } 244 } 245 246 /** 247 * @access private 248 */ 249 function _reflow() 250 { 251 // PHP is broken yet again. Sort the arrays to remove the 252 // hole in the numeric indexes that make up the array. 253 $old_keys = $this->keys; 254 $old_values = $this->values; 255 256 $this->keys = []; 257 $this->values = []; 258 259 foreach ($old_keys as $k) { 260 $this->keys[] = $k; 261 } 262 263 foreach ($old_values as $v) { 264 $this->values[] = $v; 265 } 266 } 267 268 /** 269 * Deletes a key-value pair from the mapping with the specified 270 * key. 271 * 272 * @param string|array $key 273 * @return bool 274 */ 275 function del($key) 276 { 277 $index = array_search($key, $this->keys); 278 279 if ($index !== false) { 280 unset($this->keys[$index]); 281 unset($this->values[$index]); 282 $this->_reflow(); 283 return true; 284 } 285 return false; 286 } 287 288 /** 289 * Returns true if the specified value has a key in the mapping; 290 * false if not. 291 * 292 * @param string|array $key 293 * @return bool 294 */ 295 function contains($key) 296 { 297 return array_search($key, $this->keys) !== false; 298 } 299} 300 301/** 302 * Maintains a bijective map between namespace uris and aliases. 303 * 304 * @package OpenID 305 */ 306class Auth_OpenID_NamespaceMap { 307 308 /** 309 * @var Auth_OpenID_Mapping 310 */ 311 private $alias_to_namespace; 312 313 /** 314 * @var Auth_OpenID_Mapping 315 */ 316 private $namespace_to_alias; 317 318 /** 319 * @var array 320 */ 321 private $implicit_namespaces = []; 322 323 function __construct() 324 { 325 $this->alias_to_namespace = new Auth_OpenID_Mapping(); 326 $this->namespace_to_alias = new Auth_OpenID_Mapping(); 327 $this->implicit_namespaces = []; 328 } 329 330 function getAlias($namespace_uri) 331 { 332 return $this->namespace_to_alias->get($namespace_uri); 333 } 334 335 function getNamespaceURI($alias) 336 { 337 return $this->alias_to_namespace->get($alias); 338 } 339 340 function iterNamespaceURIs() 341 { 342 // Return an iterator over the namespace URIs 343 return $this->namespace_to_alias->keys(); 344 } 345 346 function iterAliases() 347 { 348 // Return an iterator over the aliases""" 349 return $this->alias_to_namespace->keys(); 350 } 351 352 function iteritems() 353 { 354 return $this->namespace_to_alias->items(); 355 } 356 357 function isImplicit($namespace_uri) 358 { 359 return in_array($namespace_uri, $this->implicit_namespaces); 360 } 361 362 function addAlias($namespace_uri, $desired_alias, $implicit=false) 363 { 364 // Add an alias from this namespace URI to the desired alias 365 global $Auth_OpenID_OPENID_PROTOCOL_FIELDS; 366 367 // Check that desired_alias is not an openid protocol field as 368 // per the spec. 369 if (in_array($desired_alias, $Auth_OpenID_OPENID_PROTOCOL_FIELDS)) { 370 Auth_OpenID::log("\"%s\" is not an allowed namespace alias", 371 $desired_alias); 372 return null; 373 } 374 375 // Check that desired_alias does not contain a period as per 376 // the spec. 377 if (strpos($desired_alias, '.') !== false) { 378 Auth_OpenID::log('"%s" must not contain a dot', $desired_alias); 379 return null; 380 } 381 382 // Check that there is not a namespace already defined for the 383 // desired alias 384 $current_namespace_uri = 385 $this->alias_to_namespace->get($desired_alias); 386 387 if (($current_namespace_uri !== null) && 388 ($current_namespace_uri != $namespace_uri)) { 389 Auth_OpenID::log('Cannot map "%s" because previous mapping exists', 390 $namespace_uri); 391 return null; 392 } 393 394 // Check that there is not already a (different) alias for 395 // this namespace URI 396 $alias = $this->namespace_to_alias->get($namespace_uri); 397 398 if (($alias !== null) && ($alias != $desired_alias)) { 399 Auth_OpenID::log('Cannot map %s to alias %s. ' . 400 'It is already mapped to alias %s', 401 $namespace_uri, $desired_alias, $alias); 402 return null; 403 } 404 405 assert((Auth_OpenID_NULL_NAMESPACE === $desired_alias) || 406 is_string($desired_alias)); 407 408 $this->alias_to_namespace->set($desired_alias, $namespace_uri); 409 $this->namespace_to_alias->set($namespace_uri, $desired_alias); 410 if ($implicit) { 411 array_push($this->implicit_namespaces, $namespace_uri); 412 } 413 414 return $desired_alias; 415 } 416 417 function add($namespace_uri) 418 { 419 // Add this namespace URI to the mapping, without caring what 420 // alias it ends up with 421 422 // See if this namespace is already mapped to an alias 423 $alias = $this->namespace_to_alias->get($namespace_uri); 424 425 if ($alias !== null) { 426 return $alias; 427 } 428 429 // Fall back to generating a numerical alias 430 $i = 0; 431 while (1) { 432 $alias = 'ext' . strval($i); 433 if ($this->addAlias($namespace_uri, $alias) === null) { 434 $i += 1; 435 } else { 436 return $alias; 437 } 438 } 439 440 // Should NEVER be reached! 441 return null; 442 } 443 444 function contains($namespace_uri) 445 { 446 return $this->isDefined($namespace_uri); 447 } 448 449 function isDefined($namespace_uri) 450 { 451 return $this->namespace_to_alias->contains($namespace_uri); 452 } 453} 454 455/** 456 * In the implementation of this object, null represents the global 457 * namespace as well as a namespace with no key. 458 * 459 * @package OpenID 460 */ 461class Auth_OpenID_Message { 462 463 private $allowed_openid_namespaces = [ 464 Auth_OpenID_OPENID1_NS, 465 Auth_OpenID_THE_OTHER_OPENID1_NS, 466 Auth_OpenID_OPENID2_NS 467 ]; 468 469 /** 470 * @var Auth_OpenID_Mapping 471 */ 472 private $args; 473 474 /** 475 * @var Auth_OpenID_NamespaceMap 476 */ 477 public $namespaces; 478 479 /** 480 * @var null|string 481 */ 482 private $_openid_ns_uri = null; 483 484 function __construct($openid_namespace = null) 485 { 486 $this->args = new Auth_OpenID_Mapping(); 487 $this->namespaces = new Auth_OpenID_NamespaceMap(); 488 if ($openid_namespace !== null) { 489 $implicit = Auth_OpenID_isOpenID1($openid_namespace); 490 $this->setOpenIDNamespace($openid_namespace, $implicit); 491 } 492 } 493 494 function isOpenID1() 495 { 496 return Auth_OpenID_isOpenID1($this->getOpenIDNamespace()); 497 } 498 499 function isOpenID2() 500 { 501 return $this->getOpenIDNamespace() == Auth_OpenID_OPENID2_NS; 502 } 503 504 /** 505 * @param array $args 506 * @return Auth_OpenID_Message|null 507 */ 508 static function fromPostArgs($args) 509 { 510 // Construct a Message containing a set of POST arguments 511 $obj = new Auth_OpenID_Message(); 512 513 // Partition into "openid." args and bare args 514 $openid_args = []; 515 foreach ($args as $key => $value) { 516 517 if (is_array($value)) { 518 return null; 519 } 520 521 $parts = explode('.', $key, 2); 522 523 $rest = ''; 524 if (count($parts) == 2) { 525 list($prefix, $rest) = $parts; 526 } else { 527 $prefix = null; 528 } 529 530 if ($prefix != 'openid') { 531 $obj->args->set([Auth_OpenID_BARE_NS, $key], $value); 532 } else { 533 $openid_args[$rest] = $value; 534 } 535 } 536 537 if ($obj->_fromOpenIDArgs($openid_args)) { 538 return $obj; 539 } else { 540 return null; 541 } 542 } 543 544 static function fromOpenIDArgs($openid_args) 545 { 546 // Takes an array. 547 548 // Construct a Message from a parsed KVForm message 549 $obj = new Auth_OpenID_Message(); 550 if ($obj->_fromOpenIDArgs($openid_args)) { 551 return $obj; 552 } else { 553 return null; 554 } 555 } 556 557 /** 558 * @access private 559 * @param Auth_OpenID_Mapping|array $openid_args 560 * @return bool 561 */ 562 function _fromOpenIDArgs($openid_args) 563 { 564 // Takes an Auth_OpenID_Mapping instance OR an array. 565 566 if (!Auth_OpenID_Mapping::isA($openid_args)) { 567 $openid_args = new Auth_OpenID_Mapping($openid_args); 568 } 569 570 $ns_args = []; 571 572 // Resolve namespaces 573 foreach ($openid_args->items() as $pair) { 574 list($rest, $value) = $pair; 575 576 $parts = explode('.', $rest, 2); 577 578 if (count($parts) == 2) { 579 list($ns_alias, $ns_key) = $parts; 580 } else { 581 $ns_alias = Auth_OpenID_NULL_NAMESPACE; 582 $ns_key = $rest; 583 } 584 585 if ($ns_alias == 'ns') { 586 if ($this->namespaces->addAlias($value, $ns_key) === null) { 587 return false; 588 } 589 } else if (($ns_alias == Auth_OpenID_NULL_NAMESPACE) && 590 ($ns_key == 'ns')) { 591 // null namespace 592 if ($this->setOpenIDNamespace($value, false) === false) { 593 return false; 594 } 595 } else { 596 $ns_args[] = [$ns_alias, $ns_key, $value]; 597 } 598 } 599 600 if (!$this->getOpenIDNamespace()) { 601 if ($this->setOpenIDNamespace(Auth_OpenID_OPENID1_NS, true) === 602 false) { 603 return false; 604 } 605 } 606 607 // Actually put the pairs into the appropriate namespaces 608 foreach ($ns_args as $triple) { 609 list($ns_alias, $ns_key, $value) = $triple; 610 $ns_uri = $this->namespaces->getNamespaceURI($ns_alias); 611 if ($ns_uri === null) { 612 $ns_uri = $this->_getDefaultNamespace($ns_alias); 613 if ($ns_uri === null) { 614 615 $ns_uri = Auth_OpenID_OPENID_NS; 616 $ns_key = sprintf('%s.%s', $ns_alias, $ns_key); 617 } else { 618 $this->namespaces->addAlias($ns_uri, $ns_alias, true); 619 } 620 } 621 622 $this->setArg($ns_uri, $ns_key, $value); 623 } 624 625 return true; 626 } 627 628 function _getDefaultNamespace($mystery_alias) 629 { 630 global $Auth_OpenID_registered_aliases; 631 if ($this->isOpenID1()) { 632 return @$Auth_OpenID_registered_aliases[$mystery_alias]; 633 } 634 return null; 635 } 636 637 function setOpenIDNamespace($openid_ns_uri, $implicit) 638 { 639 if (!in_array($openid_ns_uri, $this->allowed_openid_namespaces)) { 640 Auth_OpenID::log('Invalid null namespace: "%s"', $openid_ns_uri); 641 return false; 642 } 643 644 $succeeded = $this->namespaces->addAlias($openid_ns_uri, 645 Auth_OpenID_NULL_NAMESPACE, 646 $implicit); 647 if ($succeeded === false) { 648 return false; 649 } 650 651 $this->_openid_ns_uri = $openid_ns_uri; 652 653 return true; 654 } 655 656 function getOpenIDNamespace() 657 { 658 return $this->_openid_ns_uri; 659 } 660 661 static function fromKVForm($kvform_string) 662 { 663 // Create a Message from a KVForm string 664 return Auth_OpenID_Message::fromOpenIDArgs( 665 Auth_OpenID_KVForm::toArray($kvform_string)); 666 } 667 668 /** 669 * @return Auth_OpenID_Message 670 */ 671 function copy() 672 { 673 return $this; 674 } 675 676 function toPostArgs() 677 { 678 // Return all arguments with openid. in front of namespaced 679 // arguments. 680 681 $args = []; 682 683 // Add namespace definitions to the output 684 foreach ($this->namespaces->iteritems() as $pair) { 685 list($ns_uri, $alias) = $pair; 686 if ($this->namespaces->isImplicit($ns_uri)) { 687 continue; 688 } 689 if ($alias == Auth_OpenID_NULL_NAMESPACE) { 690 $ns_key = 'openid.ns'; 691 } else { 692 $ns_key = 'openid.ns.' . $alias; 693 } 694 $args[$ns_key] = $ns_uri; 695 } 696 697 foreach ($this->args->items() as $pair) { 698 list($ns_parts, $value) = $pair; 699 list($ns_uri, $ns_key) = $ns_parts; 700 $key = $this->getKey($ns_uri, $ns_key); 701 $args[$key] = $value; 702 } 703 704 return $args; 705 } 706 707 function toArgs() 708 { 709 // Return all namespaced arguments, failing if any 710 // non-namespaced arguments exist. 711 $post_args = $this->toPostArgs(); 712 $kvargs = []; 713 foreach ($post_args as $k => $v) { 714 if (strpos($k, 'openid.') !== 0) { 715 // raise ValueError( 716 // 'This message can only be encoded as a POST, because it ' 717 // 'contains arguments that are not prefixed with "openid."') 718 return null; 719 } else { 720 $kvargs[substr($k, 7)] = $v; 721 } 722 } 723 724 return $kvargs; 725 } 726 727 /** 728 * @param string $action_url 729 * @param null|array $form_tag_attrs 730 * @param string $submit_text 731 * @return string 732 */ 733 function toFormMarkup($action_url, $form_tag_attrs = null, $submit_text = "Continue") 734 { 735 $form = "<form accept-charset=\"UTF-8\" ". 736 "enctype=\"application/x-www-form-urlencoded\""; 737 738 if (!$form_tag_attrs) { 739 $form_tag_attrs = []; 740 } 741 742 $form_tag_attrs['action'] = $action_url; 743 $form_tag_attrs['method'] = 'post'; 744 745 unset($form_tag_attrs['enctype']); 746 unset($form_tag_attrs['accept-charset']); 747 748 if ($form_tag_attrs) { 749 foreach ($form_tag_attrs as $name => $attr) { 750 $form .= sprintf(" %s=\"%s\"", $name, htmlspecialchars($attr)); 751 } 752 } 753 754 $form .= ">\n"; 755 756 foreach ($this->toPostArgs() as $name => $value) { 757 $form .= sprintf( 758 "<input type=\"hidden\" name=\"%s\" value=\"%s\" />\n", 759 htmlspecialchars($name), htmlspecialchars($value)); 760 } 761 762 $form .= sprintf("<input type=\"submit\" value=\"%s\" />\n", 763 htmlspecialchars($submit_text)); 764 765 $form .= "</form>\n"; 766 767 return $form; 768 } 769 770 function toURL($base_url) 771 { 772 // Generate a GET URL with the parameters in this message 773 // attached as query parameters. 774 return Auth_OpenID::appendArgs($base_url, $this->toPostArgs()); 775 } 776 777 function toKVForm() 778 { 779 // Generate a KVForm string that contains the parameters in 780 // this message. This will fail if the message contains 781 // arguments outside of the 'openid.' prefix. 782 return Auth_OpenID_KVForm::fromArray($this->toArgs()); 783 } 784 785 function toURLEncoded() 786 { 787 // Generate an x-www-urlencoded string 788 $args = []; 789 790 foreach ($this->toPostArgs() as $k => $v) { 791 $args[] = [$k, $v]; 792 } 793 794 sort($args); 795 return Auth_OpenID::httpBuildQuery($args); 796 } 797 798 /** 799 * @access private 800 * @param string $namespace 801 * @return Auth_OpenID_FailureResponse|null|string 802 */ 803 function _fixNS($namespace) 804 { 805 // Convert an input value into the internally used values of 806 // this object 807 808 if ($namespace == Auth_OpenID_OPENID_NS) { 809 if ($this->_openid_ns_uri === null) { 810 return new Auth_OpenID_FailureResponse(null, 811 'OpenID namespace not set'); 812 } else { 813 $namespace = $this->_openid_ns_uri; 814 } 815 } 816 817 if (($namespace != Auth_OpenID_BARE_NS) && 818 (!is_string($namespace))) { 819 //TypeError 820 $err_msg = sprintf("Namespace must be Auth_OpenID_BARE_NS, ". 821 "Auth_OpenID_OPENID_NS or a string. got %s", 822 print_r($namespace, true)); 823 return new Auth_OpenID_FailureResponse(null, $err_msg); 824 } 825 826 if (($namespace != Auth_OpenID_BARE_NS) && 827 (strpos($namespace, ':') === false)) { 828 // fmt = 'OpenID 2.0 namespace identifiers SHOULD be URIs. Got %r' 829 // warnings.warn(fmt % (namespace,), DeprecationWarning) 830 831 if ($namespace == 'sreg') { 832 // fmt = 'Using %r instead of "sreg" as namespace' 833 // warnings.warn(fmt % (SREG_URI,), DeprecationWarning,) 834 return Auth_OpenID_SREG_URI; 835 } 836 } 837 838 return $namespace; 839 } 840 841 function hasKey($namespace, $ns_key) 842 { 843 $namespace = $this->_fixNS($namespace); 844 if (Auth_OpenID::isFailure($namespace)) { 845 // XXX log me 846 return false; 847 } else { 848 return $this->args->contains([$namespace, $ns_key]); 849 } 850 } 851 852 function getKey($namespace, $ns_key) 853 { 854 // Get the key for a particular namespaced argument 855 $namespace = $this->_fixNS($namespace); 856 if (Auth_OpenID::isFailure($namespace)) { 857 return $namespace; 858 } 859 if ($namespace == Auth_OpenID_BARE_NS) { 860 return $ns_key; 861 } 862 863 $ns_alias = $this->namespaces->getAlias($namespace); 864 865 // No alias is defined, so no key can exist 866 if ($ns_alias === null) { 867 return null; 868 } 869 870 if ($ns_alias == Auth_OpenID_NULL_NAMESPACE) { 871 $tail = $ns_key; 872 } else { 873 $tail = sprintf('%s.%s', $ns_alias, $ns_key); 874 } 875 876 return 'openid.' . $tail; 877 } 878 879 /** 880 * @param string $namespace 881 * @param string $key 882 * @param mixed $default 883 * @return Auth_OpenID_FailureResponse|mixed|null|string 884 */ 885 function getArg($namespace, $key, $default = null) 886 { 887 // Get a value for a namespaced key. 888 $namespace = $this->_fixNS($namespace); 889 890 if (Auth_OpenID::isFailure($namespace)) { 891 return $namespace; 892 } else { 893 if ((!$this->args->contains([$namespace, $key])) && 894 ($default == Auth_OpenID_NO_DEFAULT)) { 895 $err_msg = sprintf("Namespace %s missing required field %s", 896 $namespace, $key); 897 return new Auth_OpenID_FailureResponse(null, $err_msg); 898 } else { 899 return $this->args->get([$namespace, $key], $default); 900 } 901 } 902 } 903 904 function getArgs($namespace) 905 { 906 // Get the arguments that are defined for this namespace URI 907 908 $namespace = $this->_fixNS($namespace); 909 if (Auth_OpenID::isFailure($namespace)) { 910 return $namespace; 911 } else { 912 $stuff = []; 913 foreach ($this->args->items() as $pair) { 914 list($key, $value) = $pair; 915 list($pair_ns, $ns_key) = $key; 916 if ($pair_ns == $namespace) { 917 $stuff[$ns_key] = $value; 918 } 919 } 920 921 return $stuff; 922 } 923 } 924 925 function updateArgs($namespace, $updates) 926 { 927 // Set multiple key/value pairs in one call 928 929 $namespace = $this->_fixNS($namespace); 930 931 if (Auth_OpenID::isFailure($namespace)) { 932 return $namespace; 933 } else { 934 foreach ($updates as $k => $v) { 935 $this->setArg($namespace, $k, $v); 936 } 937 return true; 938 } 939 } 940 941 function setArg($namespace, $key, $value) 942 { 943 // Set a single argument in this namespace 944 $namespace = $this->_fixNS($namespace); 945 946 if (Auth_OpenID::isFailure($namespace)) { 947 return $namespace; 948 } else { 949 $this->args->set([$namespace, $key], $value); 950 if ($namespace !== Auth_OpenID_BARE_NS) { 951 $this->namespaces->add($namespace); 952 } 953 return true; 954 } 955 } 956 957 function delArg($namespace, $key) 958 { 959 $namespace = $this->_fixNS($namespace); 960 961 if (Auth_OpenID::isFailure($namespace)) { 962 return $namespace; 963 } else { 964 return $this->args->del([$namespace, $key]); 965 } 966 } 967 968 function getAliasedArg($aliased_key, $default = null) 969 { 970 if ($aliased_key == 'ns') { 971 // Return the namespace URI for the OpenID namespace 972 return $this->getOpenIDNamespace(); 973 } 974 975 $parts = explode('.', $aliased_key, 2); 976 977 $key = null; 978 if (count($parts) != 2) { 979 $ns = null; 980 } else { 981 list($alias, $key) = $parts; 982 983 if ($alias == 'ns') { 984 // Return the namespace URI for a namespace alias 985 // parameter. 986 return $this->namespaces->getNamespaceURI($key); 987 } else { 988 $ns = $this->namespaces->getNamespaceURI($alias); 989 } 990 } 991 992 if ($ns === null) { 993 $key = $aliased_key; 994 $ns = $this->getOpenIDNamespace(); 995 } 996 997 return $this->getArg($ns, $key, $default); 998 } 999} 1000 1001 1002