Add OpenID auth for editing pages
[busui.git] / lib / openid-php / Auth / OpenID / Server.php
blob:a/lib/openid-php/Auth/OpenID/Server.php -> blob:b/lib/openid-php/Auth/OpenID/Server.php
  <?php
   
  /**
  * OpenID server protocol and logic.
  *
  * Overview
  *
  * An OpenID server must perform three tasks:
  *
  * 1. Examine the incoming request to determine its nature and validity.
  * 2. Make a decision about how to respond to this request.
  * 3. Format the response according to the protocol.
  *
  * The first and last of these tasks may performed by the {@link
  * Auth_OpenID_Server::decodeRequest()} and {@link
  * Auth_OpenID_Server::encodeResponse} methods. Who gets to do the
  * intermediate task -- deciding how to respond to the request -- will
  * depend on what type of request it is.
  *
  * If it's a request to authenticate a user (a 'checkid_setup' or
  * 'checkid_immediate' request), you need to decide if you will assert
  * that this user may claim the identity in question. Exactly how you
  * do that is a matter of application policy, but it generally
  * involves making sure the user has an account with your system and
  * is logged in, checking to see if that identity is hers to claim,
  * and verifying with the user that she does consent to releasing that
  * information to the party making the request.
  *
  * Examine the properties of the {@link Auth_OpenID_CheckIDRequest}
  * object, and if and when you've come to a decision, form a response
  * by calling {@link Auth_OpenID_CheckIDRequest::answer()}.
  *
  * Other types of requests relate to establishing associations between
  * client and server and verifing the authenticity of previous
  * communications. {@link Auth_OpenID_Server} contains all the logic
  * and data necessary to respond to such requests; just pass it to
  * {@link Auth_OpenID_Server::handleRequest()}.
  *
  * OpenID Extensions
  *
  * Do you want to provide other information for your users in addition
  * to authentication? Version 1.2 of the OpenID protocol allows
  * consumers to add extensions to their requests. For example, with
  * sites using the Simple Registration
  * Extension
  * (http://openid.net/specs/openid-simple-registration-extension-1_0.html),
  * a user can agree to have their nickname and e-mail address sent to
  * a site when they sign up.
  *
  * Since extensions do not change the way OpenID authentication works,
  * code to handle extension requests may be completely separate from
  * the {@link Auth_OpenID_Request} class here. But you'll likely want
  * data sent back by your extension to be signed. {@link
  * Auth_OpenID_ServerResponse} provides methods with which you can add
  * data to it which can be signed with the other data in the OpenID
  * signature.
  *
  * For example:
  *
  * <pre> // when request is a checkid_* request
  * $response = $request->answer(true);
  * // this will a signed 'openid.sreg.timezone' parameter to the response
  * response.addField('sreg', 'timezone', 'America/Los_Angeles')</pre>
  *
  * Stores
  *
  * The OpenID server needs to maintain state between requests in order
  * to function. Its mechanism for doing this is called a store. The
  * store interface is defined in Interface.php. Additionally, several
  * concrete store implementations are provided, so that most sites
  * won't need to implement a custom store. For a store backed by flat
  * files on disk, see {@link Auth_OpenID_FileStore}. For stores based
  * on MySQL, SQLite, or PostgreSQL, see the {@link
  * Auth_OpenID_SQLStore} subclasses.
  *
  * Upgrading
  *
  * The keys by which a server looks up associations in its store have
  * changed in version 1.2 of this library. If your store has entries
  * created from version 1.0 code, you should empty it.
  *
  * PHP versions 4 and 5
  *
  * LICENSE: See the COPYING file included in this distribution.
  *
  * @package OpenID
  * @author JanRain, Inc. <openid@janrain.com>
  * @copyright 2005-2008 Janrain, Inc.
  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
  */
   
  /**
  * Required imports
  */
  require_once "Auth/OpenID.php";
  require_once "Auth/OpenID/Association.php";
  require_once "Auth/OpenID/CryptUtil.php";
  require_once "Auth/OpenID/BigMath.php";
  require_once "Auth/OpenID/DiffieHellman.php";
  require_once "Auth/OpenID/KVForm.php";
  require_once "Auth/OpenID/TrustRoot.php";
  require_once "Auth/OpenID/ServerRequest.php";
  require_once "Auth/OpenID/Message.php";
  require_once "Auth/OpenID/Nonce.php";
   
  define('AUTH_OPENID_HTTP_OK', 200);
  define('AUTH_OPENID_HTTP_REDIRECT', 302);
  define('AUTH_OPENID_HTTP_ERROR', 400);
   
  /**
  * @access private
  */
  global $_Auth_OpenID_Request_Modes;
  $_Auth_OpenID_Request_Modes = array('checkid_setup',
  'checkid_immediate');
   
  /**
  * @access private
  */
  define('Auth_OpenID_ENCODE_KVFORM', 'kfvorm');
   
  /**
  * @access private
  */
  define('Auth_OpenID_ENCODE_URL', 'URL/redirect');
   
  /**
  * @access private
  */
  define('Auth_OpenID_ENCODE_HTML_FORM', 'HTML form');
   
  /**
  * @access private
  */
  function Auth_OpenID_isError($obj, $cls = 'Auth_OpenID_ServerError')
  {
  return is_a($obj, $cls);
  }
   
  /**
  * An error class which gets instantiated and returned whenever an
  * OpenID protocol error occurs. Be prepared to use this in place of
  * an ordinary server response.
  *
  * @package OpenID
  */
  class Auth_OpenID_ServerError {
  /**
  * @access private
  */
  function Auth_OpenID_ServerError($message = null, $text = null,
  $reference = null, $contact = null)
  {
  $this->message = $message;
  $this->text = $text;
  $this->contact = $contact;
  $this->reference = $reference;
  }
   
  function getReturnTo()
  {
  if ($this->message &&
  $this->message->hasKey(Auth_OpenID_OPENID_NS, 'return_to')) {
  return $this->message->getArg(Auth_OpenID_OPENID_NS,
  'return_to');
  } else {
  return null;
  }
  }
   
  /**
  * Returns the return_to URL for the request which caused this
  * error.
  */
  function hasReturnTo()
  {
  return $this->getReturnTo() !== null;
  }
   
  /**
  * Encodes this error's response as a URL suitable for
  * redirection. If the response has no return_to, another
  * Auth_OpenID_ServerError is returned.
  */
  function encodeToURL()
  {
  if (!$this->message) {
  return null;
  }
   
  $msg = $this->toMessage();
  return $msg->toURL($this->getReturnTo());
  }
   
  /**
  * Encodes the response to key-value form. This is a
  * machine-readable format used to respond to messages which came
  * directly from the consumer and not through the user-agent. See
  * the OpenID specification.
  */
  function encodeToKVForm()
  {
  return Auth_OpenID_KVForm::fromArray(
  array('mode' => 'error',
  'error' => $this->toString()));
  }
   
  function toFormMarkup($form_tag_attrs=null)
  {
  $msg = $this->toMessage();
  return $msg->toFormMarkup($this->getReturnTo(), $form_tag_attrs);
  }
   
  function toHTML($form_tag_attrs=null)
  {
  return Auth_OpenID::autoSubmitHTML(
  $this->toFormMarkup($form_tag_attrs));
  }
   
  function toMessage()
  {
  // Generate a Message object for sending to the relying party,
  // after encoding.
  $namespace = $this->message->getOpenIDNamespace();
  $reply = new Auth_OpenID_Message($namespace);
  $reply->setArg(Auth_OpenID_OPENID_NS, 'mode', 'error');
  $reply->setArg(Auth_OpenID_OPENID_NS, 'error', $this->toString());
   
  if ($this->contact !== null) {
  $reply->setArg(Auth_OpenID_OPENID_NS, 'contact', $this->contact);
  }
   
  if ($this->reference !== null) {
  $reply->setArg(Auth_OpenID_OPENID_NS, 'reference',
  $this->reference);
  }
   
  return $reply;
  }
   
  /**
  * Returns one of Auth_OpenID_ENCODE_URL,
  * Auth_OpenID_ENCODE_KVFORM, or null, depending on the type of
  * encoding expected for this error's payload.
  */
  function whichEncoding()
  {
  global $_Auth_OpenID_Request_Modes;
   
  if ($this->hasReturnTo()) {
  if ($this->message->isOpenID2() &&
  (strlen($this->encodeToURL()) >
  Auth_OpenID_OPENID1_URL_LIMIT)) {
  return Auth_OpenID_ENCODE_HTML_FORM;
  } else {
  return Auth_OpenID_ENCODE_URL;
  }
  }
   
  if (!$this->message) {
  return null;
  }
   
  $mode = $this->message->getArg(Auth_OpenID_OPENID_NS,
  'mode');
   
  if ($mode) {
  if (!in_array($mode, $_Auth_OpenID_Request_Modes)) {
  return Auth_OpenID_ENCODE_KVFORM;
  }
  }
  return null;
  }
   
  /**
  * Returns this error message.
  */
  function toString()
  {
  if ($this->text) {
  return $this->text;
  } else {
  return get_class($this) . " error";
  }
  }
  }
   
  /**
  * Error returned by the server code when a return_to is absent from a
  * request.
  *
  * @package OpenID
  */
  class Auth_OpenID_NoReturnToError extends Auth_OpenID_ServerError {
  function Auth_OpenID_NoReturnToError($message = null,
  $text = "No return_to URL available")
  {
  parent::Auth_OpenID_ServerError($message, $text);
  }
   
  function toString()
  {
  return "No return_to available";
  }
  }
   
  /**
  * An error indicating that the return_to URL is malformed.
  *
  * @package OpenID
  */
  class Auth_OpenID_MalformedReturnURL extends Auth_OpenID_ServerError {
  function Auth_OpenID_MalformedReturnURL($message, $return_to)
  {
  $this->return_to = $return_to;
  parent::Auth_OpenID_ServerError($message, "malformed return_to URL");
  }
  }
   
  /**
  * This error is returned when the trust_root value is malformed.
  *
  * @package OpenID
  */
  class Auth_OpenID_MalformedTrustRoot extends Auth_OpenID_ServerError {
  function Auth_OpenID_MalformedTrustRoot($message = null,
  $text = "Malformed trust root")
  {
  parent::Auth_OpenID_ServerError($message, $text);
  }
   
  function toString()
  {
  return "Malformed trust root";
  }
  }
   
  /**
  * The base class for all server request classes.
  *
  * @package OpenID
  */
  class Auth_OpenID_Request {
  var $mode = null;
  }
   
  /**
  * A request to verify the validity of a previous response.
  *
  * @package OpenID
  */
  class Auth_OpenID_CheckAuthRequest extends Auth_OpenID_Request {
  var $mode = "check_authentication";
  var $invalidate_handle = null;
   
  function Auth_OpenID_CheckAuthRequest($assoc_handle, $signed,
  $invalidate_handle = null)
  {
  $this->assoc_handle = $assoc_handle;
  $this->signed = $signed;
  if ($invalidate_handle !== null) {
  $this->invalidate_handle = $invalidate_handle;
  }
  $this->namespace = Auth_OpenID_OPENID2_NS;
  $this->message = null;
  }
   
  static function fromMessage($message, $server=null)
  {
  $required_keys = array('assoc_handle', 'sig', 'signed');
   
  foreach ($required_keys as $k) {
  if (!$message->getArg(Auth_OpenID_OPENID_NS, $k)) {
  return new Auth_OpenID_ServerError($message,
  sprintf("%s request missing required parameter %s from \
  query", "check_authentication", $k));
  }
  }
   
  $assoc_handle = $message->getArg(Auth_OpenID_OPENID_NS, 'assoc_handle');