Add OpenID auth for editing pages
[busui.git] / lib / openid-php / Auth / OpenID / Discover.php
blob:a/lib/openid-php/Auth/OpenID/Discover.php -> blob:b/lib/openid-php/Auth/OpenID/Discover.php
  <?php
   
  /**
  * The OpenID and Yadis discovery implementation for OpenID 1.2.
  */
   
  require_once "Auth/OpenID.php";
  require_once "Auth/OpenID/Parse.php";
  require_once "Auth/OpenID/Message.php";
  require_once "Auth/Yadis/XRIRes.php";
  require_once "Auth/Yadis/Yadis.php";
   
  // XML namespace value
  define('Auth_OpenID_XMLNS_1_0', 'http://openid.net/xmlns/1.0');
   
  // Yadis service types
  define('Auth_OpenID_TYPE_1_2', 'http://openid.net/signon/1.2');
  define('Auth_OpenID_TYPE_1_1', 'http://openid.net/signon/1.1');
  define('Auth_OpenID_TYPE_1_0', 'http://openid.net/signon/1.0');
  define('Auth_OpenID_TYPE_2_0_IDP', 'http://specs.openid.net/auth/2.0/server');
  define('Auth_OpenID_TYPE_2_0', 'http://specs.openid.net/auth/2.0/signon');
  define('Auth_OpenID_RP_RETURN_TO_URL_TYPE',
  'http://specs.openid.net/auth/2.0/return_to');
   
  function Auth_OpenID_getOpenIDTypeURIs()
  {
  return array(Auth_OpenID_TYPE_2_0_IDP,
  Auth_OpenID_TYPE_2_0,
  Auth_OpenID_TYPE_1_2,
  Auth_OpenID_TYPE_1_1,
  Auth_OpenID_TYPE_1_0);
  }
   
  function Auth_OpenID_getOpenIDConsumerTypeURIs()
  {
  return array(Auth_OpenID_RP_RETURN_TO_URL_TYPE);
  }
   
   
  /*
  * Provides a user-readable interpretation of a type uri.
  * Useful for error messages.
  */
  function Auth_OpenID_getOpenIDTypeName($type_uri) {
  switch ($type_uri) {
  case Auth_OpenID_TYPE_2_0_IDP:
  return 'OpenID 2.0 IDP';
  case Auth_OpenID_TYPE_2_0:
  return 'OpenID 2.0';
  case Auth_OpenID_TYPE_1_2:
  return 'OpenID 1.2';
  case Auth_OpenID_TYPE_1_1:
  return 'OpenID 1.1';
  case Auth_OpenID_TYPE_1_0:
  return 'OpenID 1.0';
  case Auth_OpenID_RP_RETURN_TO_URL_TYPE:
  return 'OpenID relying party';
  }
  }
   
  /**
  * Object representing an OpenID service endpoint.
  */
  class Auth_OpenID_ServiceEndpoint {
  function Auth_OpenID_ServiceEndpoint()
  {
  $this->claimed_id = null;
  $this->server_url = null;
  $this->type_uris = array();
  $this->local_id = null;
  $this->canonicalID = null;
  $this->used_yadis = false; // whether this came from an XRDS
  $this->display_identifier = null;
  }
   
  function getDisplayIdentifier()
  {
  if ($this->display_identifier) {
  return $this->display_identifier;
  }
  if (! $this->claimed_id) {
  return $this->claimed_id;
  }
  $parsed = parse_url($this->claimed_id);
  $scheme = $parsed['scheme'];
  $host = $parsed['host'];
  $path = $parsed['path'];
  if (array_key_exists('query', $parsed)) {
  $query = $parsed['query'];
  $no_frag = "$scheme://$host$path?$query";
  } else {
  $no_frag = "$scheme://$host$path";
  }
  return $no_frag;
  }
   
  function usesExtension($extension_uri)
  {
  return in_array($extension_uri, $this->type_uris);
  }
   
  function preferredNamespace()
  {
  if (in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris) ||
  in_array(Auth_OpenID_TYPE_2_0, $this->type_uris)) {
  return Auth_OpenID_OPENID2_NS;
  } else {
  return Auth_OpenID_OPENID1_NS;
  }
  }
   
  /*
  * Query this endpoint to see if it has any of the given type
  * URIs. This is useful for implementing other endpoint classes
  * that e.g. need to check for the presence of multiple versions
  * of a single protocol.
  *
  * @param $type_uris The URIs that you wish to check
  *
  * @return all types that are in both in type_uris and
  * $this->type_uris
  */
  function matchTypes($type_uris)
  {
  $result = array();
  foreach ($type_uris as $test_uri) {
  if ($this->supportsType($test_uri)) {
  $result[] = $test_uri;
  }
  }
   
  return $result;
  }
   
  function supportsType($type_uri)
  {
  // Does this endpoint support this type?
  return ((in_array($type_uri, $this->type_uris)) ||
  (($type_uri == Auth_OpenID_TYPE_2_0) &&
  $this->isOPIdentifier()));
  }
   
  function compatibilityMode()
  {
  return $this->preferredNamespace() != Auth_OpenID_OPENID2_NS;
  }
   
  function isOPIdentifier()
  {
  return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris);
  }
   
  static function fromOPEndpointURL($op_endpoint_url)
  {
  // Construct an OP-Identifier OpenIDServiceEndpoint object for
  // a given OP Endpoint URL
  $obj = new Auth_OpenID_ServiceEndpoint();
  $obj->server_url = $op_endpoint_url;
  $obj->type_uris = array(Auth_OpenID_TYPE_2_0_IDP);
  return $obj;
  }
   
  function parseService($yadis_url, $uri, $type_uris, $service_element)
  {
  // Set the state of this object based on the contents of the
  // service element. Return true if successful, false if not
  // (if findOPLocalIdentifier returns false).
  $this->type_uris = $type_uris;
  $this->server_url = $uri;
  $this->used_yadis = true;
   
  if (!$this->isOPIdentifier()) {
  $this->claimed_id = $yadis_url;
  $this->local_id = Auth_OpenID_findOPLocalIdentifier(
  $service_element,
  $this->type_uris);
  if ($this->local_id === false) {
  return false;
  }
  }
   
  return true;
  }
   
  function getLocalID()
  {
  // Return the identifier that should be sent as the
  // openid.identity_url parameter to the server.
  if ($this->local_id === null && $this->canonicalID === null) {
  return $this->claimed_id;
  } else {
  if ($this->local_id) {
  return $this->local_id;
  } else {
  return $this->canonicalID;
  }
  }
  }
   
  /*
  * Parse the given document as XRDS looking for OpenID consumer services.
  *
  * @return array of Auth_OpenID_ServiceEndpoint or null if the
  * document cannot be parsed.
  */
  function consumerFromXRDS($uri, $xrds_text)
  {
  $xrds =& Auth_Yadis_XRDS::parseXRDS($xrds_text);
   
  if ($xrds) {
  $yadis_services =
  $xrds->services(array('filter_MatchesAnyOpenIDConsumerType'));
  return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
  }
   
  return null;
  }
   
  /*
  * Parse the given document as XRDS looking for OpenID services.
  *
  * @return array of Auth_OpenID_ServiceEndpoint or null if the
  * document cannot be parsed.
  */
  static function fromXRDS($uri, $xrds_text)
  {
  $xrds = Auth_Yadis_XRDS::parseXRDS($xrds_text);
   
  if ($xrds) {
  $yadis_services =
  $xrds->services(array('filter_MatchesAnyOpenIDType'));
  return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
  }
   
  return null;
  }
   
  /*
  * Create endpoints from a DiscoveryResult.
  *
  * @param discoveryResult Auth_Yadis_DiscoveryResult
  * @return array of Auth_OpenID_ServiceEndpoint or null if
  * endpoints cannot be created.
  */
  static function fromDiscoveryResult($discoveryResult)
  {
  if ($discoveryResult->isXRDS()) {
  return Auth_OpenID_ServiceEndpoint::fromXRDS(
  $discoveryResult->normalized_uri,
  $discoveryResult->response_text);
  } else {
  return Auth_OpenID_ServiceEndpoint::fromHTML(
  $discoveryResult->normalized_uri,
  $discoveryResult->response_text);
  }
  }
   
  static function fromHTML($uri, $html)
  {
  $discovery_types = array(
  array(Auth_OpenID_TYPE_2_0,
  'openid2.provider', 'openid2.local_id'),
  array(Auth_OpenID_TYPE_1_1,
  'openid.server', 'openid.delegate')
  );
   
  $services = array();
   
  foreach ($discovery_types as $triple) {
  list($type_uri, $server_rel, $delegate_rel) = $triple;
   
  $urls = Auth_OpenID_legacy_discover($html, $server_rel,
  $delegate_rel);
   
  if ($urls === false) {
  continue;
  }
   
  list($delegate_url, $server_url) = $urls;
   
  $service = new Auth_OpenID_ServiceEndpoint();
  $service->claimed_id = $uri;
  $service->local_id = $delegate_url;
  $service->server_url = $server_url;
  $service->type_uris = array($type_uri);
   
  $services[] = $service;
  }
   
  return $services;
  }
   
  function copy()
  {
  $x = new Auth_OpenID_ServiceEndpoint();
   
  $x->claimed_id = $this->claimed_id;
  $x->server_url = $this->server_url;
  $x->type_uris = $this->type_uris;
  $x->local_id = $this->local_id;
  $x->canonicalID = $this->canonicalID;
  $x->used_yadis = $this->used_yadis;
   
  return $x;
  }
  }
   
  function Auth_OpenID_findOPLocalIdentifier($service, $type_uris)
  {
  // Extract a openid:Delegate value from a Yadis Service element.
  // If no delegate is found, returns null. Returns false on
  // discovery failure (when multiple delegate/localID tags have
  // different values).
   
  $service->parser->registerNamespace('openid',
  Auth_OpenID_XMLNS_1_0);
   
  $service->parser->registerNamespace('xrd',
  Auth_Yadis_XMLNS_XRD_2_0);
   
  $parser = $service->parser;
   
  $permitted_tags = array();
   
  if (in_array(Auth_OpenID_TYPE_1_1, $type_uris) ||
  in_array(Auth_OpenID_TYPE_1_0, $type_uris)) {
  $permitted_tags[] = 'openid:Delegate';
  }
   
  if (in_array(Auth_OpenID_TYPE_2_0, $type_uris)) {
  $permitted_tags[] = 'xrd:LocalID';
  }
   
  $local_id = null;
   
  foreach ($permitted_tags as $tag_name) {
  $tags = $service->getElements($tag_name);
   
  foreach ($tags as $tag) {
  $content = $parser->content($tag);
   
  if ($local_id === null) {
  $local_id = $content;
  } else if ($local_id != $content) {
  return false;
  }
  }
  }
   
  return $local_id;
  }
   
  function filter_MatchesAnyOpenIDType($service)
  {
  $uris = $service->getTypes();
   
  foreach ($uris as $uri) {
  if (in_array($uri, Auth_OpenID_getOpenIDTypeURIs())) {
  return true;
  }
  }
   
  return false;
  }
   
  function filter_MatchesAnyOpenIDConsumerType(&$service)
  {
  $uris = $service->getTypes();
   
  foreach ($uris as $uri) {
  if (in_array($uri, Auth_OpenID_getOpenIDConsumerTypeURIs())) {
  return true;
  }
  }
   
  return false;
  }
   
  function Auth_OpenID_bestMatchingService($service, $preferred_types)
  {
  // Return the index of the first matching type, or something
  // higher if no type matches.
  //