diff options
author | Evan Prodromou <evan@controlyourself.ca> | 2009-01-08 20:56:09 +0000 |
---|---|---|
committer | Evan Prodromou <evan@controlyourself.ca> | 2009-01-08 20:56:09 +0000 |
commit | 07e9e2dc3241eef1b803e655a5273f79cb758806 (patch) | |
tree | 0846f3e3cbefd39041e580bffbc7556eb7f45c93 /_darcs/pristine/extlib/Auth/OpenID/Server.php | |
parent | e67affdbbcdcaa9f43750389922b802d0b425ddb (diff) |
Remove _darcs from git repository
Not sure how or why this got in there.
Diffstat (limited to '_darcs/pristine/extlib/Auth/OpenID/Server.php')
-rw-r--r-- | _darcs/pristine/extlib/Auth/OpenID/Server.php | 1754 |
1 files changed, 0 insertions, 1754 deletions
diff --git a/_darcs/pristine/extlib/Auth/OpenID/Server.php b/_darcs/pristine/extlib/Auth/OpenID/Server.php deleted file mode 100644 index e746bcc57..000000000 --- a/_darcs/pristine/extlib/Auth/OpenID/Server.php +++ /dev/null @@ -1,1754 +0,0 @@ -<?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://www.openidenabled.com/openid/simple-registration-extension/), - * 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; - } - - 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'); - $sig = $message->getArg(Auth_OpenID_OPENID_NS, 'sig'); - - $signed_list = $message->getArg(Auth_OpenID_OPENID_NS, 'signed'); - $signed_list = explode(",", $signed_list); - - $signed = $message; - if ($signed->hasKey(Auth_OpenID_OPENID_NS, 'mode')) { - $signed->setArg(Auth_OpenID_OPENID_NS, 'mode', 'id_res'); - } - - $result = new Auth_OpenID_CheckAuthRequest($assoc_handle, $signed); - $result->message = $message; - $result->sig = $sig; - $result->invalidate_handle = $message->getArg(Auth_OpenID_OPENID_NS, - 'invalidate_handle'); - return $result; - } - - function answer(&$signatory) - { - $is_valid = $signatory->verify($this->assoc_handle, $this->signed); - - // Now invalidate that assoc_handle so it this checkAuth - // message cannot be replayed. - $signatory->invalidate($this->assoc_handle, true); - $response = new Auth_OpenID_ServerResponse($this); - - $response->fields->setArg(Auth_OpenID_OPENID_NS, - 'is_valid', - ($is_valid ? "true" : "false")); - - if ($this->invalidate_handle) { - $assoc = $signatory->getAssociation($this->invalidate_handle, - false); - if (!$assoc) { - $response->fields->setArg(Auth_OpenID_OPENID_NS, - 'invalidate_handle', - $this->invalidate_handle); - } - } - return $response; - } -} - -/** - * A class implementing plaintext server sessions. - * - * @package OpenID - */ -class Auth_OpenID_PlainTextServerSession { - /** - * An object that knows how to handle association requests with no - * session type. - */ - var $session_type = 'no-encryption'; - var $needs_math = false; - var $allowed_assoc_types = array('HMAC-SHA1', 'HMAC-SHA256'); - - function fromMessage($unused_request) - { - return new Auth_OpenID_PlainTextServerSession(); - } - - function answer($secret) - { - return array('mac_key' => base64_encode($secret)); - } -} - -/** - * A class implementing DH-SHA1 server sessions. - * - * @package OpenID - */ -class Auth_OpenID_DiffieHellmanSHA1ServerSession { - /** - * An object that knows how to handle association requests with - * the Diffie-Hellman session type. - */ - - var $session_type = 'DH-SHA1'; - var $needs_math = true; - var $allowed_assoc_types = array('HMAC-SHA1'); - var $hash_func = 'Auth_OpenID_SHA1'; - - function Auth_OpenID_DiffieHellmanSHA1ServerSession($dh, $consumer_pubkey) - { - $this->dh = $dh; - $this->consumer_pubkey = $consumer_pubkey; - } - - function getDH($message) - { - $dh_modulus = $message->getArg(Auth_OpenID_OPENID_NS, 'dh_modulus'); - $dh_gen = $message->getArg(Auth_OpenID_OPENID_NS, 'dh_gen'); - - if ((($dh_modulus === null) && ($dh_gen !== null)) || - (($dh_gen === null) && ($dh_modulus !== null))) { - - if ($dh_modulus === null) { - $missing = 'modulus'; - } else { - $missing = 'generator'; - } - - return new Auth_OpenID_ServerError($message, - 'If non-default modulus or generator is '. - 'supplied, both must be supplied. Missing '. - $missing); - } - - $lib =& Auth_OpenID_getMathLib(); - - if ($dh_modulus || $dh_gen) { - $dh_modulus = $lib->base64ToLong($dh_modulus); - $dh_gen = $lib->base64ToLong($dh_gen); - if ($lib->cmp($dh_modulus, 0) == 0 || - $lib->cmp($dh_gen, 0) == 0) { - return new Auth_OpenID_ServerError( - $message, "Failed to parse dh_mod or dh_gen"); - } - $dh = new Auth_OpenID_DiffieHellman($dh_modulus, $dh_gen); - } else { - $dh = new Auth_OpenID_DiffieHellman(); - } - - $consumer_pubkey = $message->getArg(Auth_OpenID_OPENID_NS, - 'dh_consumer_public'); - if ($consumer_pubkey === null) { - return new Auth_OpenID_ServerError($message, - 'Public key for DH-SHA1 session '. - 'not found in query'); - } - - $consumer_pubkey = - $lib->base64ToLong($consumer_pubkey); - - if ($consumer_pubkey === false) { - return new Auth_OpenID_ServerError($message, - "dh_consumer_public is not base64"); - } - - return array($dh, $consumer_pubkey); - } - - function fromMessage($message) - { - $result = Auth_OpenID_DiffieHellmanSHA1ServerSession::getDH($message); - - if (is_a($result, 'Auth_OpenID_ServerError')) { - return $result; - } else { - list($dh, $consumer_pubkey) = $result; - return new Auth_OpenID_DiffieHellmanSHA1ServerSession($dh, - $consumer_pubkey); - } - } - - function answer($secret) - { - $lib =& Auth_OpenID_getMathLib(); - $mac_key = $this->dh->xorSecret($this->consumer_pubkey, $secret, - $this->hash_func); - return array( - 'dh_server_public' => - $lib->longToBase64($this->dh->public), - 'enc_mac_key' => base64_encode($mac_key)); - } -} - -/** - * A class implementing DH-SHA256 server sessions. - * - * @package OpenID - */ -class Auth_OpenID_DiffieHellmanSHA256ServerSession - extends Auth_OpenID_DiffieHellmanSHA1ServerSession { - - var $session_type = 'DH-SHA256'; - var $hash_func = 'Auth_OpenID_SHA256'; - var $allowed_assoc_types = array('HMAC-SHA256'); - - function fromMessage($message) - { - $result = Auth_OpenID_DiffieHellmanSHA1ServerSession::getDH($message); - - if (is_a($result, 'Auth_OpenID_ServerError')) { - return $result; - } else { - list($dh, $consumer_pubkey) = $result; - return new Auth_OpenID_DiffieHellmanSHA256ServerSession($dh, - $consumer_pubkey); - } - } -} - -/** - * A request to associate with the server. - * - * @package OpenID - */ -class Auth_OpenID_AssociateRequest extends Auth_OpenID_Request { - var $mode = "associate"; - - function getSessionClasses() - { - return array( - 'no-encryption' => 'Auth_OpenID_PlainTextServerSession', - 'DH-SHA1' => 'Auth_OpenID_DiffieHellmanSHA1ServerSession', - 'DH-SHA256' => 'Auth_OpenID_DiffieHellmanSHA256ServerSession'); - } - - function Auth_OpenID_AssociateRequest(&$session, $assoc_type) - { - $this->session =& $session; - $this->namespace = Auth_OpenID_OPENID2_NS; - $this->assoc_type = $assoc_type; - } - - function fromMessage($message, $server=null) - { - if ($message->isOpenID1()) { - $session_type = $message->getArg(Auth_OpenID_OPENID_NS, - 'session_type'); - - if ($session_type == 'no-encryption') { - // oidutil.log('Received OpenID 1 request with a no-encryption ' - // 'assocaition session type. Continuing anyway.') - } else if (!$session_type) { - $session_type = 'no-encryption'; - } - } else { - $session_type = $message->getArg(Auth_OpenID_OPENID_NS, - 'session_type'); - if ($session_type === null) { - return new Auth_OpenID_ServerError($message, - "session_type missing from request"); - } - } - - $session_class = Auth_OpenID::arrayGet( - Auth_OpenID_AssociateRequest::getSessionClasses(), - $session_type); - - if ($session_class === null) { - return new Auth_OpenID_ServerError($message, - "Unknown session type " . - $session_type); - } - - $session = call_user_func(array($session_class, 'fromMessage'), - $message); - if (is_a($session, 'Auth_OpenID_ServerError')) { - return $session; - } - - $assoc_type = $message->getArg(Auth_OpenID_OPENID_NS, - 'assoc_type', 'HMAC-SHA1'); - - if (!in_array($assoc_type, $session->allowed_assoc_types)) { - $fmt = "Session type %s does not support association type %s"; - return new Auth_OpenID_ServerError($message, - sprintf($fmt, $session_type, $assoc_type)); - } - - $obj = new Auth_OpenID_AssociateRequest($session, $assoc_type); - $obj->message = $message; - $obj->namespace = $message->getOpenIDNamespace(); - return $obj; - } - - function answer($assoc) - { - $response = new Auth_OpenID_ServerResponse($this); - $response->fields->updateArgs(Auth_OpenID_OPENID_NS, - array( - 'expires_in' => sprintf('%d', $assoc->getExpiresIn()), - 'assoc_type' => $this->assoc_type, - 'assoc_handle' => $assoc->handle)); - - $response->fields->updateArgs(Auth_OpenID_OPENID_NS, - $this->session->answer($assoc->secret)); - - if (! ($this->session->session_type == 'no-encryption' - && $this->message->isOpenID1())) { - $response->fields->setArg(Auth_OpenID_OPENID_NS, - 'session_type', - $this->session->session_type); - } - - return $response; - } - - function answerUnsupported($text_message, - $preferred_association_type=null, - $preferred_session_type=null) - { - if ($this->message->isOpenID1()) { - return new Auth_OpenID_ServerError($this->message); - } - - $response = new Auth_OpenID_ServerResponse($this); - $response->fields->setArg(Auth_OpenID_OPENID_NS, - 'error_code', 'unsupported-type'); - $response->fields->setArg(Auth_OpenID_OPENID_NS, - 'error', $text_message); - - if ($preferred_association_type) { - $response->fields->setArg(Auth_OpenID_OPENID_NS, - 'assoc_type', - $preferred_association_type); - } - - if ($preferred_session_type) { - $response->fields->setArg(Auth_OpenID_OPENID_NS, - 'session_type', - $preferred_session_type); - } - - return $response; - } -} - -/** - * A request to confirm the identity of a user. - * - * @package OpenID - */ -class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request { - /** - * Return-to verification callback. Default is - * Auth_OpenID_verifyReturnTo from TrustRoot.php. - */ - var $verifyReturnTo = 'Auth_OpenID_verifyReturnTo'; - - /** - * The mode of this request. - */ - var $mode = "checkid_setup"; // or "checkid_immediate" - - /** - * Whether this request is for immediate mode. - */ - var $immediate = false; - - /** - * The trust_root value for this request. - */ - var $trust_root = null; - - /** - * The OpenID namespace for this request. - * deprecated since version 2.0.2 - */ - var $namespace; - - function make(&$message, $identity, $return_to, $trust_root = null, - $immediate = false, $assoc_handle = null, $server = null) - { - if ($server === null) { - return new Auth_OpenID_ServerError($message, - "server must not be null"); - } - - if ($return_to && - !Auth_OpenID_TrustRoot::_parse($return_to)) { - return new Auth_OpenID_MalformedReturnURL($message, $return_to); - } - - $r = new Auth_OpenID_CheckIDRequest($identity, $return_to, - $trust_root, $immediate, - $assoc_handle, $server); - - $r->namespace = $message->getOpenIDNamespace(); - $r->message =& $message; - - if (!$r->trustRootValid()) { - return new Auth_OpenID_UntrustedReturnURL($message, - $return_to, - $trust_root); - } else { - return $r; - } - } - - function Auth_OpenID_CheckIDRequest($identity, $return_to, - $trust_root = null, $immediate = false, - $assoc_handle = null, $server = null) - { - $this->namespace = Auth_OpenID_OPENID2_NS; - $this->assoc_handle = $assoc_handle; - $this->identity = $identity; - $this->claimed_id = $identity; - $this->return_to = $return_to; - $this->trust_root = $trust_root; - $this->server =& $server; - - if ($immediate) { - $this->immediate = true; - $this->mode = "checkid_immediate"; - } else { - $this->immediate = false; - $this->mode = "checkid_setup"; - } - } - - function equals($other) - { - return ( - (is_a($other, 'Auth_OpenID_CheckIDRequest')) && - ($this->namespace == $other->namespace) && - ($this->assoc_handle == $other->assoc_handle) && - ($this->identity == $other->identity) && - ($this->claimed_id == $other->claimed_id) && - ($this->return_to == $other->return_to) && - ($this->trust_root == $other->trust_root)); - } - - /* - * Does the relying party publish the return_to URL for this - * response under the realm? It is up to the provider to set a - * policy for what kinds of realms should be allowed. This - * return_to URL verification reduces vulnerability to data-theft - * attacks based on open proxies, corss-site-scripting, or open - * redirectors. - * - * This check should only be performed after making sure that the - * return_to URL matches the realm. - * - * @return true if the realm publishes a document with the - * return_to URL listed, false if not or if discovery fails - */ - function returnToVerified() - { - return call_user_func_array($this->verifyReturnTo, - array($this->trust_root, $this->return_to)); - } - - function fromMessage(&$message, $server) - { - $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode'); - $immediate = null; - - if ($mode == "checkid_immediate") { - $immediate = true; - $mode = "checkid_immediate"; - } else { - $immediate = false; - $mode = "checkid_setup"; - } - - $return_to = $message->getArg(Auth_OpenID_OPENID_NS, - 'return_to'); - - if (($message->isOpenID1()) && - (!$return_to)) { - $fmt = "Missing required field 'return_to' from checkid request"; - return new Auth_OpenID_ServerError($message, $fmt); - } - - $identity = $message->getArg(Auth_OpenID_OPENID_NS, - 'identity'); - $claimed_id = $message->getArg(Auth_OpenID_OPENID_NS, 'claimed_id'); - if ($message->isOpenID1()) { - if ($identity === null) { - $s = "OpenID 1 message did not contain openid.identity"; - return new Auth_OpenID_ServerError($message, $s); - } - } else { - if ($identity && !$claimed_id) { - $s = "OpenID 2.0 message contained openid.identity but not " . - "claimed_id"; - return new Auth_OpenID_ServerError($message, $s); - } else if ($claimed_id && !$identity) { - $s = "OpenID 2.0 message contained openid.claimed_id " . - "but not identity"; - return new Auth_OpenID_ServerError($message, $s); - } - } - - // There's a case for making self.trust_root be a TrustRoot - // here. But if TrustRoot isn't currently part of the - // "public" API, I'm not sure it's worth doing. - if ($message->isOpenID1()) { - $trust_root_param = 'trust_root'; - } else { - $trust_root_param = 'realm'; - } - $trust_root = $message->getArg(Auth_OpenID_OPENID_NS, - $trust_root_param); - if (! $trust_root) { - $trust_root = $return_to; - } - - if (! $message->isOpenID1() && - ($return_to === null) && - ($trust_root === null)) { - return new Auth_OpenID_ServerError($message, - "openid.realm required when openid.return_to absent"); - } - - $assoc_handle = $message->getArg(Auth_OpenID_OPENID_NS, - 'assoc_handle'); - - $obj = Auth_OpenID_CheckIDRequest::make($message, - $identity, - $return_to, - $trust_root, - $immediate, - $assoc_handle, - $server); - - if (is_a($obj, 'Auth_OpenID_ServerError')) { - return $obj; - } - - $obj->claimed_id = $claimed_id; - - return $obj; - } - - function idSelect() - { - // Is the identifier to be selected by the IDP? - // So IDPs don't have to import the constant - return $this->identity == Auth_OpenID_IDENTIFIER_SELECT; - } - - function trustRootValid() - { - if (!$this->trust_root) { - return true; - } - - $tr = Auth_OpenID_TrustRoot::_parse($this->trust_root); - if ($tr === false) { - return new Auth_OpenID_MalformedTrustRoot($this->message, - $this->trust_root); - } - - if ($this->return_to !== null) { - return Auth_OpenID_TrustRoot::match($this->trust_root, - $this->return_to); - } else { - return true; - } - } - - /** - * Respond to this request. Return either an - * {@link Auth_OpenID_ServerResponse} or - * {@link Auth_OpenID_ServerError}. - * - * @param bool $allow Allow this user to claim this identity, and - * allow the consumer to have this information? - * - * @param string $server_url DEPRECATED. Passing $op_endpoint to - * the {@link Auth_OpenID_Server} constructor makes this optional. - * - * When an OpenID 1.x immediate mode request does not succeed, it - * gets back a URL where the request may be carried out in a - * not-so-immediate fashion. Pass my URL in here (the fully - * qualified address of this server's endpoint, i.e. - * http://example.com/server), and I will use it as a base for the - * URL for a new request. - * - * Optional for requests where {@link $immediate} is false or - * $allow is true. - * - * @param string $identity The OP-local identifier to answer with. - * Only for use when the relying party requested identifier - * selection. - * - * @param string $claimed_id The claimed identifier to answer - * with, for use with identifier selection in the case where the - * claimed identifier and the OP-local identifier differ, - * i.e. when the claimed_id uses delegation. - * - * If $identity is provided but this is not, $claimed_id will - * default to the value of $identity. When answering requests - * that did not ask for identifier selection, the response - * $claimed_id will default to that of the request. - * - * This parameter is new in OpenID 2.0. - * - * @return mixed - */ - function answer($allow, $server_url = null, $identity = null, - $claimed_id = null) - { - if (!$this->return_to) { - return new Auth_OpenID_NoReturnToError(); - } - - if (!$server_url) { - if ((!$this->message->isOpenID1()) && - (!$this->server->op_endpoint)) { - return new Auth_OpenID_ServerError(null, - "server should be constructed with op_endpoint to " . - "respond to OpenID 2.0 messages."); - } - - $server_url = $this->server->op_endpoint; - } - - if ($allow) { - $mode = 'id_res'; - } else if ($this->message->isOpenID1()) { - if ($this->immediate) { - $mode = 'id_res'; - } else { - $mode = 'cancel'; - } - } else { - if ($this->immediate) { - $mode = 'setup_needed'; - } else { - $mode = 'cancel'; - } - } - - if (!$this->trustRootValid()) { - return new Auth_OpenID_UntrustedReturnURL(null, - $this->return_to, - $this->trust_root); - } - - $response = new Auth_OpenID_ServerResponse($this); - - if ($claimed_id && - ($this->message->isOpenID1())) { - return new Auth_OpenID_ServerError(null, - "claimed_id is new in OpenID 2.0 and not " . - "available for ".$this->namespace); - } - - if ($identity && !$claimed_id) { - $claimed_id = $identity; - } - - if ($allow) { - - if ($this->identity == Auth_OpenID_IDENTIFIER_SELECT) { - if (!$identity) { - return new Auth_OpenID_ServerError(null, - "This request uses IdP-driven identifier selection. " . - "You must supply an identifier in the response."); - } - - $response_identity = $identity; - $response_claimed_id = $claimed_id; - - } else if ($this->identity) { - if ($identity && - ($this->identity != $identity)) { - $fmt = "Request was for %s, cannot reply with identity %s"; - return new Auth_OpenID_ServerError(null, - sprintf($fmt, $this->identity, $identity)); - } - - $response_identity = $this->identity; - $response_claimed_id = $this->claimed_id; - } else { - if ($identity) { - return new Auth_OpenID_ServerError(null, - "This request specified no identity and " . - "you supplied ".$identity); - } - - $response_identity = null; - } - - if (($this->message->isOpenID1()) && - ($response_identity === null)) { - return new Auth_OpenID_ServerError(null, - "Request was an OpenID 1 request, so response must " . - "include an identifier."); - } - - $response->fields->updateArgs(Auth_OpenID_OPENID_NS, - array('mode' => $mode, - 'return_to' => $this->return_to, - 'response_nonce' => Auth_OpenID_mkNonce())); - - if (!$this->message->isOpenID1()) { - $response->fields->setArg(Auth_OpenID_OPENID_NS, - 'op_endpoint', $server_url); - } - - if ($response_identity !== null) { - $response->fields->setArg( - Auth_OpenID_OPENID_NS, - 'identity', - $response_identity); - if ($this->message->isOpenID2()) { - $response->fields->setArg( - Auth_OpenID_OPENID_NS, - 'claimed_id', - $response_claimed_id); - } - } - - } else { - $response->fields->setArg(Auth_OpenID_OPENID_NS, - 'mode', $mode); - - if ($this->immediate) { - if (($this->message->isOpenID1()) && - (!$server_url)) { - return new Auth_OpenID_ServerError(null, - 'setup_url is required for $allow=false \ - in OpenID 1.x immediate mode.'); - } - - $setup_request =& new Auth_OpenID_CheckIDRequest( - $this->identity, - $this->return_to, - $this->trust_root, - false, - $this->assoc_handle, - $this->server); - $setup_request->message = $this->message; - - $setup_url = $setup_request->encodeToURL($server_url); - - if ($setup_url === null) { - return new Auth_OpenID_NoReturnToError(); - } - - $response->fields->setArg(Auth_OpenID_OPENID_NS, - 'user_setup_url', - $setup_url); - } - } - - return $response; - } - - function encodeToURL($server_url) - { - if (!$this->return_to) { - return new Auth_OpenID_NoReturnToError(); - } - - // Imported from the alternate reality where these classes are - // used in both the client and server code, so Requests are - // Encodable too. That's right, code imported from alternate - // realities all for the love of you, id_res/user_setup_url. - - $q = array('mode' => $this->mode, - 'identity' => $this->identity, - 'claimed_id' => $this->claimed_id, - 'return_to' => $this->return_to); - - if ($this->trust_root) { - if ($this->message->isOpenID1()) { - $q['trust_root'] = $this->trust_root; - } else { - $q['realm'] = $this->trust_root; - } - } - - if ($this->assoc_handle) { - $q['assoc_handle'] = $this->assoc_handle; - } - - $response = new Auth_OpenID_Message( - $this->message->getOpenIDNamespace()); - $response->updateArgs(Auth_OpenID_OPENID_NS, $q); - return $response->toURL($server_url); - } - - function getCancelURL() - { - if (!$this->return_to) { - return new Auth_OpenID_NoReturnToError(); - } - - if ($this->immediate) { - return new Auth_OpenID_ServerError(null, - "Cancel is not an appropriate \ - response to immediate mode \ - requests."); - } - - $response = new Auth_OpenID_Message( - $this->message->getOpenIDNamespace()); - $response->setArg(Auth_OpenID_OPENID_NS, 'mode', 'cancel'); - return $response->toURL($this->return_to); - } -} - -/** - * This class encapsulates the response to an OpenID server request. - * - * @package OpenID - */ -class Auth_OpenID_ServerResponse { - - function Auth_OpenID_ServerResponse(&$request) - { - $this->request =& $request; - $this->fields = new Auth_OpenID_Message($this->request->namespace); - } - - function whichEncoding() - { - global $_Auth_OpenID_Request_Modes; - - if (in_array($this->request->mode, $_Auth_OpenID_Request_Modes)) { - if ($this->fields->isOpenID2() && - (strlen($this->encodeToURL()) > - Auth_OpenID_OPENID1_URL_LIMIT)) { - return Auth_OpenID_ENCODE_HTML_FORM; - } else { - return Auth_OpenID_ENCODE_URL; - } - } else { - return Auth_OpenID_ENCODE_KVFORM; - } - } - - /* - * Returns the form markup for this response. - * - * @return str - */ - function toFormMarkup($form_tag_attrs=null) - { - return $this->fields->toFormMarkup($this->request->return_to, - $form_tag_attrs); - } - - /* - * Returns an HTML document containing the form markup for this - * response that autosubmits with javascript. - */ - function toHTML() - { - return Auth_OpenID::autoSubmitHTML($this->toFormMarkup()); - } - - /* - * Returns True if this response's encoding is ENCODE_HTML_FORM. - * Convenience method for server authors. - * - * @return bool - */ - function renderAsForm() - { - return $this->whichEncoding() == Auth_OpenID_ENCODE_HTML_FORM; - } - - - function encodeToURL() - { - return $this->fields->toURL($this->request->return_to); - } - - function addExtension($extension_response) - { - $extension_response->toMessage($this->fields); - } - - function needsSigning() - { - return $this->fields->getArg(Auth_OpenID_OPENID_NS, - 'mode') == 'id_res'; - } - - function encodeToKVForm() - { - return $this->fields->toKVForm(); - } -} - -/** - * A web-capable response object which you can use to generate a - * user-agent response. - * - * @package OpenID - */ -class Auth_OpenID_WebResponse { - var $code = AUTH_OPENID_HTTP_OK; - var $body = ""; - - function Auth_OpenID_WebResponse($code = null, $headers = null, - $body = null) - { - if ($code) { - $this->code = $code; - } - - if ($headers !== null) { - $this->headers = $headers; - } else { - $this->headers = array(); - } - - if ($body !== null) { - $this->body = $body; - } - } -} - -/** - * Responsible for the signature of query data and the verification of - * OpenID signature values. - * - * @package OpenID - */ -class Auth_OpenID_Signatory { - - // = 14 * 24 * 60 * 60; # 14 days, in seconds - var $SECRET_LIFETIME = 1209600; - - // keys have a bogus server URL in them because the filestore - // really does expect that key to be a URL. This seems a little - // silly for the server store, since I expect there to be only one - // server URL. - var $normal_key = 'http://localhost/|normal'; - var $dumb_key = 'http://localhost/|dumb'; - - /** - * Create a new signatory using a given store. - */ - function Auth_OpenID_Signatory(&$store) - { - // assert store is not None - $this->store =& $store; - } - - /** - * Verify, using a given association handle, a signature with - * signed key-value pairs from an HTTP request. - */ - function verify($assoc_handle, $message) - { - $assoc = $this->getAssociation($assoc_handle, true); - if (!$assoc) { - // oidutil.log("failed to get assoc with handle %r to verify sig %r" - // % (assoc_handle, sig)) - return false; - } - - return $assoc->checkMessageSignature($message); - } - - /** - * Given a response, sign the fields in the response's 'signed' - * list, and insert the signature into the response. - */ - function sign($response) - { - $signed_response = $response; - $assoc_handle = $response->request->assoc_handle; - - if ($assoc_handle) { - // normal mode - $assoc = $this->getAssociation($assoc_handle, false, false); - if (!$assoc || ($assoc->getExpiresIn() <= 0)) { - // fall back to dumb mode - $signed_response->fields->setArg(Auth_OpenID_OPENID_NS, - 'invalidate_handle', $assoc_handle); - $assoc_type = ($assoc ? $assoc->assoc_type : 'HMAC-SHA1'); - - if ($assoc && ($assoc->getExpiresIn() <= 0)) { - $this->invalidate($assoc_handle, false); - } - - $assoc = $this->createAssociation(true, $assoc_type); - } - } else { - // dumb mode. - $assoc = $this->createAssociation(true); - } - - $signed_response->fields = $assoc->signMessage( - $signed_response->fields); - return $signed_response; - } - - /** - * Make a new association. - */ - function createAssociation($dumb = true, $assoc_type = 'HMAC-SHA1') - { - $secret = Auth_OpenID_CryptUtil::getBytes( - Auth_OpenID_getSecretSize($assoc_type)); - - $uniq = base64_encode(Auth_OpenID_CryptUtil::getBytes(4)); - $handle = sprintf('{%s}{%x}{%s}', $assoc_type, intval(time()), $uniq); - - $assoc = Auth_OpenID_Association::fromExpiresIn( - $this->SECRET_LIFETIME, $handle, $secret, $assoc_type); - - if ($dumb) { - $key = $this->dumb_key; - } else { - $key = $this->normal_key; - } - - $this->store->storeAssociation($key, $assoc); - return $assoc; - } - - /** - * Given an association handle, get the association from the - * store, or return a ServerError or null if something goes wrong. - */ - function getAssociation($assoc_handle, $dumb, $check_expiration=true) - { - if ($assoc_handle === null) { - return new Auth_OpenID_ServerError(null, - "assoc_handle must not be null"); - } - - if ($dumb) { - $key = $this->dumb_key; - } else { - $key = $this->normal_key; - } - - $assoc = $this->store->getAssociation($key, $assoc_handle); - - if (($assoc !== null) && ($assoc->getExpiresIn() <= 0)) { - if ($check_expiration) { - $this->store->removeAssociation($key, $assoc_handle); - $assoc = null; - } - } - - return $assoc; - } - - /** - * Invalidate a given association handle. - */ - function invalidate($assoc_handle, $dumb) - { - if ($dumb) { - $key = $this->dumb_key; - } else { - $key = $this->normal_key; - } - $this->store->removeAssociation($key, $assoc_handle); - } -} - -/** - * Encode an {@link Auth_OpenID_ServerResponse} to an - * {@link Auth_OpenID_WebResponse}. - * - * @package OpenID - */ -class Auth_OpenID_Encoder { - - var $responseFactory = 'Auth_OpenID_WebResponse'; - - /** - * Encode an {@link Auth_OpenID_ServerResponse} and return an - * {@link Auth_OpenID_WebResponse}. - */ - function encode(&$response) - { - $cls = $this->responseFactory; - - $encode_as = $response->whichEncoding(); - if ($encode_as == Auth_OpenID_ENCODE_KVFORM) { - $wr = new $cls(null, null, $response->encodeToKVForm()); - if (is_a($response, 'Auth_OpenID_ServerError')) { - $wr->code = AUTH_OPENID_HTTP_ERROR; - } - } else if ($encode_as == Auth_OpenID_ENCODE_URL) { - $location = $response->encodeToURL(); - $wr = new $cls(AUTH_OPENID_HTTP_REDIRECT, - array('location' => $location)); - } else if ($encode_as == Auth_OpenID_ENCODE_HTML_FORM) { - $wr = new $cls(AUTH_OPENID_HTTP_OK, array(), - $response->toFormMarkup()); - } else { - return new Auth_OpenID_EncodingError($response); - } - return $wr; - } -} - -/** - * An encoder which also takes care of signing fields when required. - * - * @package OpenID - */ -class Auth_OpenID_SigningEncoder extends Auth_OpenID_Encoder { - - function Auth_OpenID_SigningEncoder(&$signatory) - { - $this->signatory =& $signatory; - } - - /** - * Sign an {@link Auth_OpenID_ServerResponse} and return an - * {@link Auth_OpenID_WebResponse}. - */ - function encode(&$response) - { - // the isinstance is a bit of a kludge... it means there isn't - // really an adapter to make the interfaces quite match. - if (!is_a($response, 'Auth_OpenID_ServerError') && - $response->needsSigning()) { - - if (!$this->signatory) { - return new Auth_OpenID_ServerError(null, - "Must have a store to sign request"); - } - - if ($response->fields->hasKey(Auth_OpenID_OPENID_NS, 'sig')) { - return new Auth_OpenID_AlreadySigned($response); - } - $response = $this->signatory->sign($response); - } - - return parent::encode($response); - } -} - -/** - * Decode an incoming query into an Auth_OpenID_Request. - * - * @package OpenID - */ -class Auth_OpenID_Decoder { - - function Auth_OpenID_Decoder(&$server) - { - $this->server =& $server; - - $this->handlers = array( - 'checkid_setup' => 'Auth_OpenID_CheckIDRequest', - 'checkid_immediate' => 'Auth_OpenID_CheckIDRequest', - 'check_authentication' => 'Auth_OpenID_CheckAuthRequest', - 'associate' => 'Auth_OpenID_AssociateRequest' - ); - } - - /** - * Given an HTTP query in an array (key-value pairs), decode it - * into an Auth_OpenID_Request object. - */ - function decode($query) - { - if (!$query) { - return null; - } - - $message = Auth_OpenID_Message::fromPostArgs($query); - - if ($message === null) { - /* - * It's useful to have a Message attached to a - * ProtocolError, so we override the bad ns value to build - * a Message out of it. Kinda kludgy, since it's made of - * lies, but the parts that aren't lies are more useful - * than a 'None'. - */ - $old_ns = $query['openid.ns']; - - $query['openid.ns'] = Auth_OpenID_OPENID2_NS; - $message = Auth_OpenID_Message::fromPostArgs($query); - return new Auth_OpenID_ServerError( - $message, - sprintf("Invalid OpenID namespace URI: %s", $old_ns)); - } - - $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode'); - if (!$mode) { - return new Auth_OpenID_ServerError($message, - "No mode value in message"); - } - - if (Auth_OpenID::isFailure($mode)) { - return new Auth_OpenID_ServerError($message, - $mode->message); - } - - $handlerCls = Auth_OpenID::arrayGet($this->handlers, $mode, - $this->defaultDecoder($message)); - - if (!is_a($handlerCls, 'Auth_OpenID_ServerError')) { - return call_user_func_array(array($handlerCls, 'fromMessage'), - array($message, $this->server)); - } else { - return $handlerCls; - } - } - - function defaultDecoder($message) - { - $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode'); - - if (Auth_OpenID::isFailure($mode)) { - return new Auth_OpenID_ServerError($message, - $mode->message); - } - - return new Auth_OpenID_ServerError($message, - sprintf("Unrecognized OpenID mode %s", $mode)); - } -} - -/** - * An error that indicates an encoding problem occurred. - * - * @package OpenID - */ -class Auth_OpenID_EncodingError { - function Auth_OpenID_EncodingError(&$response) - { - $this->response =& $response; - } -} - -/** - * An error that indicates that a response was already signed. - * - * @package OpenID - */ -class Auth_OpenID_AlreadySigned extends Auth_OpenID_EncodingError { - // This response is already signed. -} - -/** - * An error that indicates that the given return_to is not under the - * given trust_root. - * - * @package OpenID - */ -class Auth_OpenID_UntrustedReturnURL extends Auth_OpenID_ServerError { - function Auth_OpenID_UntrustedReturnURL($message, $return_to, - $trust_root) - { - parent::Auth_OpenID_ServerError($message, "Untrusted return_to URL"); - $this->return_to = $return_to; - $this->trust_root = $trust_root; - } - - function toString() - { - return sprintf("return_to %s not under trust_root %s", - $this->return_to, $this->trust_root); - } -} - -/** - * I handle requests for an OpenID server. - * - * Some types of requests (those which are not checkid requests) may - * be handed to my {@link handleRequest} method, and I will take care - * of it and return a response. - * - * For your convenience, I also provide an interface to {@link - * Auth_OpenID_Decoder::decode()} and {@link - * Auth_OpenID_SigningEncoder::encode()} through my methods {@link - * decodeRequest} and {@link encodeResponse}. - * - * All my state is encapsulated in an {@link Auth_OpenID_OpenIDStore}. - * - * Example: - * - * <pre> $oserver = new Auth_OpenID_Server(Auth_OpenID_FileStore($data_path), - * "http://example.com/op"); - * $request = $oserver->decodeRequest(); - * if (in_array($request->mode, array('checkid_immediate', - * 'checkid_setup'))) { - * if ($app->isAuthorized($request->identity, $request->trust_root)) { - * $response = $request->answer(true); - * } else if ($request->immediate) { - * $response = $request->answer(false); - * } else { - * $app->showDecidePage($request); - * return; - * } - * } else { - * $response = $oserver->handleRequest($request); - * } - * - * $webresponse = $oserver->encode($response);</pre> - * - * @package OpenID - */ -class Auth_OpenID_Server { - function Auth_OpenID_Server(&$store, $op_endpoint=null) - { - $this->store =& $store; - $this->signatory =& new Auth_OpenID_Signatory($this->store); - $this->encoder =& new Auth_OpenID_SigningEncoder($this->signatory); - $this->decoder =& new Auth_OpenID_Decoder($this); - $this->op_endpoint = $op_endpoint; - $this->negotiator =& Auth_OpenID_getDefaultNegotiator(); - } - - /** - * Handle a request. Given an {@link Auth_OpenID_Request} object, - * call the appropriate {@link Auth_OpenID_Server} method to - * process the request and generate a response. - * - * @param Auth_OpenID_Request $request An {@link Auth_OpenID_Request} - * returned by {@link Auth_OpenID_Server::decodeRequest()}. - * - * @return Auth_OpenID_ServerResponse $response A response object - * capable of generating a user-agent reply. - */ - function handleRequest($request) - { - if (method_exists($this, "openid_" . $request->mode)) { - $handler = array($this, "openid_" . $request->mode); - return call_user_func($handler, $request); - } - return null; - } - - /** - * The callback for 'check_authentication' messages. - */ - function openid_check_authentication(&$request) - { - return $request->answer($this->signatory); - } - - /** - * The callback for 'associate' messages. - */ - function openid_associate(&$request) - { - $assoc_type = $request->assoc_type; - $session_type = $request->session->session_type; - if ($this->negotiator->isAllowed($assoc_type, $session_type)) { - $assoc = $this->signatory->createAssociation(false, - $assoc_type); - return $request->answer($assoc); - } else { - $message = sprintf('Association type %s is not supported with '. - 'session type %s', $assoc_type, $session_type); - list($preferred_assoc_type, $preferred_session_type) = - $this->negotiator->getAllowedType(); - return $request->answerUnsupported($message, - $preferred_assoc_type, - $preferred_session_type); - } - } - - /** - * Encodes as response in the appropriate format suitable for - * sending to the user agent. - */ - function encodeResponse(&$response) - { - return $this->encoder->encode($response); - } - - /** - * Decodes a query args array into the appropriate - * {@link Auth_OpenID_Request} object. - */ - function decodeRequest($query=null) - { - if ($query === null) { - $query = Auth_OpenID::getQuery(); - } - - return $this->decoder->decode($query); - } -} - -?> |