Add OpenID auth for editing pages
[busui.git] / lib / openid-php / Auth / OpenID / AX.php
blob:a/lib/openid-php/Auth/OpenID/AX.php -> blob:b/lib/openid-php/Auth/OpenID/AX.php
  <?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