Source code for file /openid/Auth/OpenID/Message.php
Documentation is available at Message.php
* Extension argument processing code
// Do not allow direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
* Import tools needed to deal with messages.
require_once 'Auth/OpenID.php';
require_once 'Auth/OpenID/KVForm.php';
require_once 'Auth/Yadis/XML.php';
require_once 'Auth/OpenID/Consumer.php'; // For Auth_OpenID_FailureResponse
// This doesn't REALLY belong here, but where is better?
define('Auth_OpenID_IDENTIFIER_SELECT',
"http://specs.openid.net/auth/2.0/identifier_select");
// URI for Simple Registration extension, the only commonly deployed
// OpenID 1.x extension, and so a special case
define('Auth_OpenID_SREG_URI', 'http://openid.net/sreg/1.0');
// The OpenID 1.X namespace URI
define('Auth_OpenID_OPENID1_NS', 'http://openid.net/signon/1.0');
define('Auth_OpenID_THE_OTHER_OPENID1_NS', 'http://openid.net/signon/1.1');
// The OpenID 2.0 namespace URI
define('Auth_OpenID_OPENID2_NS', 'http://specs.openid.net/auth/2.0');
// The namespace consisting of pairs with keys that are prefixed with
// "openid." but not in another namespace.
define('Auth_OpenID_NULL_NAMESPACE', 'Null namespace');
// The null namespace, when it is an allowed OpenID namespace
define('Auth_OpenID_OPENID_NS', 'OpenID namespace');
// The top-level namespace, excluding all pairs with keys that start
define('Auth_OpenID_BARE_NS', 'Bare namespace');
// Sentinel for Message implementation to indicate that getArg should
// return null instead of returning a default.
define('Auth_OpenID_NO_DEFAULT', 'NO DEFAULT ALLOWED');
// Limit, in bytes, of identity provider and return_to URLs, including
// response payload. See OpenID 1.1 specification, Appendix D.
define('Auth_OpenID_OPENID1_URL_LIMIT', 2047);
// All OpenID protocol fields. Used to check namespace aliases.
global $Auth_OpenID_OPENID_PROTOCOL_FIELDS;
$Auth_OpenID_OPENID_PROTOCOL_FIELDS =
array(
'ns', 'mode', 'error', 'return_to', 'contact', 'reference',
'signed', 'assoc_type', 'session_type', 'dh_modulus', 'dh_gen',
'dh_consumer_public', 'claimed_id', 'identity', 'realm',
'invalidate_handle', 'op_endpoint', 'response_nonce', 'sig',
'assoc_handle', 'trust_root', 'openid');
// Global namespace / alias registration map. See
// Auth_OpenID_registerNamespaceAlias.
global $Auth_OpenID_registered_aliases;
$Auth_OpenID_registered_aliases =
array();
* Registers a (namespace URI, alias) mapping in a global namespace
* alias map. Raises NamespaceAliasRegistrationError if either the
* namespace URI or alias has already been registered with a different
* value. This function is required if you want to use a namespace
* with an OpenID 1 message.
global $Auth_OpenID_registered_aliases;
if (Auth_OpenID::arrayGet($Auth_OpenID_registered_aliases,
$alias) ==
$namespace_uri) {
$Auth_OpenID_registered_aliases[$alias] =
$namespace_uri;
* Removes a (namespace_uri, alias) registration from the global
* namespace alias map. Returns true if the removal succeeded; false
* if not (if the mapping did not exist).
global $Auth_OpenID_registered_aliases;
if (Auth_OpenID::arrayGet($Auth_OpenID_registered_aliases,
$alias) ===
$namespace_uri) {
unset
($Auth_OpenID_registered_aliases[$alias]);
* An Auth_OpenID_Mapping maintains a mapping from arbitrary keys to
* arbitrary values. (This is unlike an ordinary PHP array, whose
* keys may be only simple scalars.)
* Initialize a mapping. If $classic_array is specified, its keys
* and values are used to populate the mapping.
foreach ($classic_array as $key =>
$value) {
$this->set($key, $value);
* Returns true if $thing is an Auth_OpenID_Mapping object; false
* Returns an array of the keys in the mapping.
* Returns an array of values in the mapping.
* Returns an array of (key, value) pairs in the mapping.
for ($i =
0; $i <
count($this->keys); $i++
) {
$temp[] =
array($this->keys[$i],
* Returns the "length" of the mapping, or the number of keys.
return count($this->keys);
* Sets a key-value pair in the mapping. If the key already
* exists, its value is replaced with the new value.
function set($key, $value)
$this->values[$index] =
$value;
$this->values[] =
$value;
* Gets a specified value from the mapping, associated with the
* specified key. If the key does not exist in the mapping,
* $default is returned instead.
function get($key, $default =
null)
return $this->values[$index];
// PHP is broken yet again. Sort the arrays to remove the
// hole in the numeric indexes that make up the array.
$old_values =
$this->values;
foreach ($old_keys as $k) {
foreach ($old_values as $v) {
* Deletes a key-value pair from the mapping with the specified
unset
($this->keys[$index]);
unset
($this->values[$index]);
* Returns true if the specified value has a key in the mapping;
* Maintains a bijective map between namespace uris and aliases.
$this->implicit_namespaces =
array();
return $this->namespace_to_alias->get($namespace_uri);
return $this->alias_to_namespace->get($alias);
// Return an iterator over the namespace URIs
return $this->namespace_to_alias->keys();
// Return an iterator over the aliases"""
return $this->alias_to_namespace->keys();
return $this->namespace_to_alias->items();
return in_array($namespace_uri, $this->implicit_namespaces);
function addAlias($namespace_uri, $desired_alias, $implicit=
false)
// Add an alias from this namespace URI to the desired alias
global $Auth_OpenID_OPENID_PROTOCOL_FIELDS;
// Check that desired_alias is not an openid protocol field as
if (in_array($desired_alias, $Auth_OpenID_OPENID_PROTOCOL_FIELDS)) {
Auth_OpenID::log("\"%s\" is not an allowed namespace alias",
// Check that desired_alias does not contain a period as per
if (strpos($desired_alias, '.') !==
false) {
Auth_OpenID::log('"%s" must not contain a dot', $desired_alias);
// Check that there is not a namespace already defined for the
$this->alias_to_namespace->get($desired_alias);
if (($current_namespace_uri !==
null) &&
($current_namespace_uri !=
$namespace_uri)) {
Auth_OpenID::log('Cannot map "%s" because previous mapping exists',
// Check that there is not already a (different) alias for
$alias =
$this->namespace_to_alias->get($namespace_uri);
if (($alias !==
null) &&
($alias !=
$desired_alias)) {
Auth_OpenID::log('Cannot map %s to alias %s. ' .
'It is already mapped to alias %s',
$namespace_uri, $desired_alias, $alias);
$this->alias_to_namespace->set($desired_alias, $namespace_uri);
$this->namespace_to_alias->set($namespace_uri, $desired_alias);
array_push($this->implicit_namespaces, $namespace_uri);
function add($namespace_uri)
// Add this namespace URI to the mapping, without caring what
// See if this namespace is already mapped to an alias
$alias =
$this->namespace_to_alias->get($namespace_uri);
// Fall back to generating a numerical alias
if ($this->addAlias($namespace_uri, $alias) ===
null) {
// Should NEVER be reached!
return $this->namespace_to_alias->contains($namespace_uri);
* In the implementation of this object, null represents the global
* namespace as well as a namespace with no key.
// Create an empty Message
$this->allowed_openid_namespaces =
array(
if ($openid_namespace ===
null) {
$this->_openid_ns_uri =
null;
// Construct a Message containing a set of POST arguments
// Partition into "openid." args and bare args
foreach ($args as $key =>
$value) {
if (count($parts) ==
2) {
list
($prefix, $rest) =
$parts;
if ($prefix !=
'openid') {
$openid_args[$rest] =
$value;
if ($obj->_fromOpenIDArgs($openid_args)) {
// Construct a Message from a parsed KVForm message
if ($obj->_fromOpenIDArgs($openid_args)) {
function _fromOpenIDArgs($openid_args)
global $Auth_OpenID_registered_aliases;
// Takes an Auth_OpenID_Mapping instance OR an array.
foreach ($openid_args->items() as $pair) {
list
($rest, $value) =
$pair;
if (count($parts) ==
2) {
list
($ns_alias, $ns_key) =
$parts;
if ($this->namespaces->addAlias($value, $ns_key) ===
null) {
$ns_args[] =
array($ns_alias, $ns_key, $value);
// Actually put the pairs into the appropriate namespaces
foreach ($ns_args as $triple) {
list
($ns_alias, $ns_key, $value) =
$triple;
$ns_uri =
$this->namespaces->getNamespaceURI($ns_alias);
$ns_key =
sprintf('%s.%s', $ns_alias, $ns_key);
$this->namespaces->addAlias($ns_uri, $ns_alias, true);
$this->setArg($ns_uri, $ns_key, $value);
global $Auth_OpenID_registered_aliases;
return @$Auth_OpenID_registered_aliases[$mystery_alias];
if (!in_array($openid_ns_uri, $this->allowed_openid_namespaces)) {
Auth_OpenID::log('Invalid null namespace: "%s"', $openid_ns_uri);
$succeeded =
$this->namespaces->addAlias($openid_ns_uri,
if ($succeeded ===
false) {
$this->_openid_ns_uri =
$openid_ns_uri;
return $this->_openid_ns_uri;
// Create a Message from a KVForm string
// Return all arguments with openid. in front of namespaced
// Add namespace definitions to the output
foreach ($this->namespaces->iteritems() as $pair) {
list
($ns_uri, $alias) =
$pair;
if ($this->namespaces->isImplicit($ns_uri)) {
$ns_key =
'openid.ns.' .
$alias;
$args[$ns_key] =
$ns_uri;
foreach ($this->args->items() as $pair) {
list
($ns_parts, $value) =
$pair;
list
($ns_uri, $ns_key) =
$ns_parts;
$key =
$this->getKey($ns_uri, $ns_key);
// Return all namespaced arguments, failing if any
// non-namespaced arguments exist.
foreach ($post_args as $k =>
$v) {
if (strpos($k, 'openid.') !==
0) {
// 'This message can only be encoded as a POST, because it '
// 'contains arguments that are not prefixed with "openid."')
$submit_text =
"Continue")
$form =
"<form accept-charset=\"UTF-8\" ".
"enctype=\"application/x-www-form-urlencoded\"";
$form_tag_attrs =
array();
$form_tag_attrs['action'] =
$action_url;
$form_tag_attrs['method'] =
'post';
unset
($form_tag_attrs['enctype']);
unset
($form_tag_attrs['accept-charset']);
foreach ($form_tag_attrs as $name =>
$attr) {
$form .=
sprintf(" %s=\"%s\"", $name, $attr);
foreach ($this->toPostArgs() as $name =>
$value) {
"<input type=\"hidden\" name=\"%s\" value=\"%s\" />\n",
$form .=
sprintf("<input type=\"submit\" value=\"%s\" />\n",
function toURL($base_url)
// Generate a GET URL with the parameters in this message
// attached as query parameters.
return Auth_OpenID::appendArgs($base_url, $this->toPostArgs());
// Generate a KVForm string that contains the parameters in
// this message. This will fail if the message contains
// arguments outside of the 'openid.' prefix.
// Generate an x-www-urlencoded string
return Auth_OpenID::httpBuildQuery($args);
function _fixNS($namespace)
// Convert an input value into the internally used values of
if ($this->_openid_ns_uri ===
null) {
'OpenID namespace not set');
$namespace =
$this->_openid_ns_uri;
$err_msg =
sprintf("Namespace must be Auth_OpenID_BARE_NS, ".
"Auth_OpenID_OPENID_NS or a string. got %s",
(strpos($namespace, ':') ===
false)) {
// fmt = 'OpenID 2.0 namespace identifiers SHOULD be URIs. Got %r'
// warnings.warn(fmt % (namespace,), DeprecationWarning)
if ($namespace ==
'sreg') {
// fmt = 'Using %r instead of "sreg" as namespace'
// warnings.warn(fmt % (SREG_URI,), DeprecationWarning,)
function hasKey($namespace, $ns_key)
$namespace =
$this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $this->args->contains(array($namespace, $ns_key));
function getKey($namespace, $ns_key)
// Get the key for a particular namespaced argument
$namespace =
$this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
$ns_alias =
$this->namespaces->getAlias($namespace);
// No alias is defined, so no key can exist
if ($ns_alias ===
null) {
$tail =
sprintf('%s.%s', $ns_alias, $ns_key);
return 'openid.' .
$tail;
function getArg($namespace, $key, $default =
null)
// Get a value for a namespaced key.
$namespace =
$this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
if ((!$this->args->contains(array($namespace, $key))) &&
$err_msg =
sprintf("Namespace %s missing required field %s",
return $this->args->get(array($namespace, $key), $default);
// Get the arguments that are defined for this namespace URI
$namespace =
$this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
foreach ($this->args->items() as $pair) {
list
($key, $value) =
$pair;
list
($pair_ns, $ns_key) =
$key;
if ($pair_ns ==
$namespace) {
$stuff[$ns_key] =
$value;
// Set multiple key/value pairs in one call
$namespace =
$this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
foreach ($updates as $k =>
$v) {
$this->setArg($namespace, $k, $v);
function setArg($namespace, $key, $value)
// Set a single argument in this namespace
$namespace =
$this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
$this->args->set(array($namespace, $key), $value);
$this->namespaces->add($namespace);
function delArg($namespace, $key)
$namespace =
$this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $this->args->del(array($namespace, $key));
$parts =
explode('.', $aliased_key, 2);
if (count($parts) !=
2) {
list
($alias, $key) =
$parts;
// Return the namespace URI for a namespace alias
return $this->namespaces->getNamespaceURI($key);
$ns =
$this->namespaces->getNamespaceURI($alias);
return $this->getArg($ns, $key, $default);