|
<?php |
|
|
|
/** |
|
* Implements the OpenID attribute exchange specification, version 1.0 |
|
* as of svn revision 370 from openid.net svn. |
|
* |
|
* @package OpenID |
|
*/ |
|
|
|
/** |
|
* Require utility classes and functions for the consumer. |
|
*/ |
|
require_once "Auth/OpenID/Extension.php"; |
|
require_once "Auth/OpenID/Message.php"; |
|
require_once "Auth/OpenID/TrustRoot.php"; |
|
|
|
define('Auth_OpenID_AX_NS_URI', |
|
'http://openid.net/srv/ax/1.0'); |
|
|
|
// Use this as the 'count' value for an attribute in a FetchRequest to |
|
// ask for as many values as the OP can provide. |
|
define('Auth_OpenID_AX_UNLIMITED_VALUES', 'unlimited'); |
|
|
|
// Minimum supported alias length in characters. Here for |
|
// completeness. |
|
define('Auth_OpenID_AX_MINIMUM_SUPPORTED_ALIAS_LENGTH', 32); |
|
|
|
/** |
|
* AX utility class. |
|
* |
|
* @package OpenID |
|
*/ |
|
class Auth_OpenID_AX { |
|
/** |
|
* @param mixed $thing Any object which may be an |
|
* Auth_OpenID_AX_Error object. |
|
* |
|
* @return bool true if $thing is an Auth_OpenID_AX_Error; false |
|
* if not. |
|
*/ |
|
static function isError($thing) |
|
{ |
|
return is_a($thing, 'Auth_OpenID_AX_Error'); |
|
} |
|
} |
|
|
|
/** |
|
* Check an alias for invalid characters; raise AXError if any are |
|
* found. Return None if the alias is valid. |
|
*/ |
|
function Auth_OpenID_AX_checkAlias($alias) |
|
{ |
|
if (strpos($alias, ',') !== false) { |
|
return new Auth_OpenID_AX_Error(sprintf( |
|
"Alias %s must not contain comma", $alias)); |
|
} |
|
if (strpos($alias, '.') !== false) { |
|
return new Auth_OpenID_AX_Error(sprintf( |
|
"Alias %s must not contain period", $alias)); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
/** |
|
* Results from data that does not meet the attribute exchange 1.0 |
|
* specification |
|
* |
|
* @package OpenID |
|
*/ |
|
class Auth_OpenID_AX_Error { |
|
function Auth_OpenID_AX_Error($message=null) |
|
{ |
|
$this->message = $message; |
|
} |
|
} |
|
|
|
/** |
|
* Abstract class containing common code for attribute exchange |
|
* messages. |
|
* |
|
* @package OpenID |
|
*/ |
|
class Auth_OpenID_AX_Message extends Auth_OpenID_Extension { |
|
/** |
|
* ns_alias: The preferred namespace alias for attribute exchange |
|
* messages |
|
*/ |
|
var $ns_alias = 'ax'; |
|
|
|
/** |
|
* mode: The type of this attribute exchange message. This must be |
|
* overridden in subclasses. |
|
*/ |
|
var $mode = null; |
|
|
|
var $ns_uri = Auth_OpenID_AX_NS_URI; |
|
|
|
/** |
|
* Return Auth_OpenID_AX_Error if the mode in the attribute |
|
* exchange arguments does not match what is expected for this |
|
* class; true otherwise. |
|
* |
|
* @access private |
|
*/ |
|
function _checkMode($ax_args) |
|
{ |
|
$mode = Auth_OpenID::arrayGet($ax_args, 'mode'); |
|
if ($mode != $this->mode) { |
|
return new Auth_OpenID_AX_Error( |
|
sprintf( |
|
"Expected mode '%s'; got '%s'", |
|
$this->mode, $mode)); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
/** |
|
* Return a set of attribute exchange arguments containing the |
|
* basic information that must be in every attribute exchange |
|
* message. |
|
* |
|
* @access private |
|
*/ |
|
function _newArgs() |
|
{ |
|
return array('mode' => $this->mode); |
|
} |
|
} |
|
|
|
/** |
|
* Represents a single attribute in an attribute exchange |
|
* request. This should be added to an AXRequest object in order to |
|
* request the attribute. |
|
* |
|
* @package OpenID |
|
*/ |
|
class Auth_OpenID_AX_AttrInfo { |
|
/** |
|
* Construct an attribute information object. Do not call this |
|
* directly; call make(...) instead. |
|
* |
|
* @param string $type_uri The type URI for this attribute. |
|
* |
|
* @param int $count The number of values of this type to request. |
|
* |
|
* @param bool $required Whether the attribute will be marked as |
|
* required in the request. |
|
* |
|
* @param string $alias The name that should be given to this |
|
* attribute in the request. |
|
*/ |
|
function Auth_OpenID_AX_AttrInfo($type_uri, $count, $required, |
|
$alias) |
|
{ |
|
/** |
|
* required: Whether the attribute will be marked as required |
|
* when presented to the subject of the attribute exchange |
|
* request. |
|
*/ |
|
$this->required = $required; |
|
|
|
/** |
|
* count: How many values of this type to request from the |
|
* subject. Defaults to one. |
|
*/ |
|
$this->count = $count; |
|
|
|
/** |
|
* type_uri: The identifier that determines what the attribute |
|
* represents and how it is serialized. For example, one type |
|
* URI representing dates could represent a Unix timestamp in |
|
* base 10 and another could represent a human-readable |
|
* string. |
|
*/ |
|
$this->type_uri = $type_uri; |
|
|
|
/** |
|
* alias: The name that should be given to this attribute in |
|
* the request. If it is not supplied, a generic name will be |
|
* assigned. For example, if you want to call a Unix timestamp |
|
* value 'tstamp', set its alias to that value. If two |
|
* attributes in the same message request to use the same |
|
* alias, the request will fail to be generated. |
|
*/ |
|
$this->alias = $alias; |
|
} |
|
|
|
/** |
|
* Construct an attribute information object. For parameter |
|
* details, see the constructor. |
|
*/ |
|
static function make($type_uri, $count=1, $required=false, |
|
$alias=null) |
|
{ |
|
if ($alias !== null) { |
|
$result = Auth_OpenID_AX_checkAlias($alias); |
|
|
|
if (Auth_OpenID_AX::isError($result)) { |
|
return $result; |
|
} |
|
} |
|
|
|
return new Auth_OpenID_AX_AttrInfo($type_uri, $count, $required, |
|
$alias); |
|
} |
|
|
|
/** |
|
* When processing a request for this attribute, the OP should |
|
* call this method to determine whether all available attribute |
|
* values were requested. If self.count == UNLIMITED_VALUES, this |
|
* returns True. Otherwise this returns False, in which case |
|
* self.count is an integer. |
|
*/ |
|
function wantsUnlimitedValues() |
|
{ |
|
return $this->count === Auth_OpenID_AX_UNLIMITED_VALUES; |
|
} |
|
} |
|
|
|
/** |
|
* Given a namespace mapping and a string containing a comma-separated |
|
* list of namespace aliases, return a list of type URIs that |
|
* correspond to those aliases. |
|
* |
|
* @param $namespace_map The mapping from namespace URI to alias |
|
* @param $alias_list_s The string containing the comma-separated |
|
* list of aliases. May also be None for convenience. |
|
* |
|
* @return $seq The list of namespace URIs that corresponds to the |
|
* supplied list of aliases. If the string was zero-length or None, an |
|
* empty list will be returned. |
|
* |
|
* return null If an alias is present in the list of aliases but |
|
* is not present in the namespace map. |
|
*/ |
|
function Auth_OpenID_AX_toTypeURIs($namespace_map, $alias_list_s) |
|
{ |
|
$uris = array(); |
|
|
|
if ($alias_list_s) { |
|
foreach (explode(',', $alias_list_s) as $alias) { |
|
$type_uri = $namespace_map->getNamespaceURI($alias); |
|
if ($type_uri === null) { |
|
// raise KeyError( |
|
// 'No type is defined for attribute name %r' % (alias,)) |
|
return new Auth_OpenID_AX_Error( |
|
sprintf('No type is defined for attribute name %s', |
|
$alias) |
|
); |
|
} else { |
|
$uris[] = $type_uri; |
|
} |
|
} |
|
} |
|
|
|
return $uris; |
|
} |
|
|
|
/** |
|
* An attribute exchange 'fetch_request' message. This message is sent |
|
* by a relying party when it wishes to obtain attributes about the |
|
* subject of an OpenID authentication request. |
|
* |
|
* @package OpenID |
|
*/ |
|
class Auth_OpenID_AX_FetchRequest extends Auth_OpenID_AX_Message { |
|
|
|
var $mode = 'fetch_request'; |
|
|
|
function Auth_OpenID_AX_FetchRequest($update_url=null) |
|
{ |
|
/** |
|
* requested_attributes: The attributes that have been |
|
* requested thus far, indexed by the type URI. |
|
*/ |
|
$this->requested_attributes = array(); |
|
|
|
/** |
|
* update_url: A URL that will accept responses for this |
|
* attribute exchange request, even in the absence of the user |
|
* who made this request. |
|
*/ |
|
$this->update_url = $update_url; |
|
} |
|
|
|
/** |
|
* Add an attribute to this attribute exchange request. |
|
* |
|
* @param attribute: The attribute that is being requested |
|
* @return true on success, false when the requested attribute is |
|
* already present in this fetch request. |
|
*/ |
|
function add($attribute) |
|
{ |
|
if ($this->contains($attribute->type_uri)) { |
|
return new Auth_OpenID_AX_Error( |
|
sprintf("The attribute %s has already been requested", |
|
$attribute->type_uri)); |
|
} |
|
|
|
$this->requested_attributes[$attribute->type_uri] = $attribute; |
|
|
|
return true; |
|
} |
|
|
|
/** |
|
* Get the serialized form of this attribute fetch request. |
|
* |
|
* @returns Auth_OpenID_AX_FetchRequest The fetch request message parameters |
|
*/ |
|
function getExtensionArgs() |
|
{ |
|
$aliases = new Auth_OpenID_NamespaceMap(); |
|
|
|
$required = array(); |
|
$if_available = array(); |
|
|
|
$ax_args = $this->_newArgs(); |
|
|
|
foreach ($this->requested_attributes as $type_uri => $attribute) { |
|
if ($attribute->alias === null) { |
|
$alias = $aliases->add($type_uri); |
|
} else { |
|
$alias = $aliases->addAlias($type_uri, $attribute->alias); |
|
|
|
if ($alias === null) { |
|
return new Auth_OpenID_AX_Error( |
|
sprintf("Could not add alias %s for URI %s", |
|
$attribute->alias, $type_uri |
|
)); |
|
} |
|
} |
|
|
|
if ($attribute->required) { |
|
$required[] = $alias; |
|
} else { |
|
$if_available[] = $alias; |
|
} |
|
|
|
if ($attribute->count != 1) { |
|
$ax_args['count.' . $alias] = strval($attribute->count); |
|
} |
|
|
|
$ax_args['type.' . $alias] = $type_uri; |
|
} |
|
|
|
if ($required) { |
|
$ax_args['required'] = implode(',', $required); |
|
} |
|
|
|
if ($if_available) { |
|
$ax_args['if_available'] = implode(',', $if_available); |
|
} |
|
|
|
return $ax_args; |
|
} |
|
|
|
/** |
|
* Get the type URIs for all attributes that have been marked as |
|
* required. |
|
* |
|
* @return A list of the type URIs for attributes that have been |
|
* marked as required. |
|
*/ |
|
function getRequiredAttrs() |
|
{ |
|
$required = array(); |
|
foreach ($this->requested_attributes as $type_uri => $attribute) { |
|
if ($attribute->required) { |
|
$required[] = $type_uri; |
|
} |
|
} |
|
|
|
return $required; |
|
} |
|
|
|
/** |
|
* Extract a FetchRequest from an OpenID message |
|
* |
|
* @param request: The OpenID request containing the attribute |
|
* fetch request |
|
* |
|
* @returns mixed An Auth_OpenID_AX_Error or the |
|
* Auth_OpenID_AX_FetchRequest extracted from the request message if |