Support Joomla!

Packages

Package: OpenID

License

Content on this site is copyright © 2005 - 2008 Open Source Matters Inc and can be used in accordance with the Joomla! Electronic Documentation License. Some parts of this website may be subject to other licenses.
Source code for file /openid/Auth/OpenID/Server.php

Documentation is available at Server.php

  1. <?php
  2.  
  3. /**
  4.  * OpenID server protocol and logic.
  5.  * 
  6.  * Overview
  7.  *
  8.  * An OpenID server must perform three tasks:
  9.  *
  10.  *  1. Examine the incoming request to determine its nature and validity.
  11.  *  2. Make a decision about how to respond to this request.
  12.  *  3. Format the response according to the protocol.
  13.  * 
  14.  * The first and last of these tasks may performed by the {@link }
  15.  * Auth_OpenID_Server::decodeRequest()} and {@link }
  16.  * Auth_OpenID_Server::encodeResponse} methods.  Who gets to do the
  17.  * intermediate task -- deciding how to respond to the request -- will
  18.  * depend on what type of request it is.
  19.  *
  20.  * If it's a request to authenticate a user (a 'checkid_setup' or
  21.  * 'checkid_immediate' request), you need to decide if you will assert
  22.  * that this user may claim the identity in question.  Exactly how you
  23.  * do that is a matter of application policy, but it generally
  24.  * involves making sure the user has an account with your system and
  25.  * is logged in, checking to see if that identity is hers to claim,
  26.  * and verifying with the user that she does consent to releasing that
  27.  * information to the party making the request.
  28.  *
  29.  * Examine the properties of the {@link Auth_OpenID_CheckIDRequest}
  30.  * object, and if and when you've come to a decision, form a response
  31.  * by calling {@link Auth_OpenID_CheckIDRequest::answer()}.
  32.  *
  33.  * Other types of requests relate to establishing associations between
  34.  * client and server and verifing the authenticity of previous
  35.  * communications.  {@link Auth_OpenID_Server} contains all the logic
  36.  * and data necessary to respond to such requests; just pass it to
  37.  * {@link Auth_OpenID_Server::handleRequest()}.
  38.  *
  39.  * OpenID Extensions
  40.  * 
  41.  * Do you want to provide other information for your users in addition
  42.  * to authentication?  Version 1.2 of the OpenID protocol allows
  43.  * consumers to add extensions to their requests.  For example, with
  44.  * sites using the Simple Registration
  45.  * Extension
  46.  * (http://www.openidenabled.com/openid/simple-registration-extension/),
  47.  * a user can agree to have their nickname and e-mail address sent to
  48.  * a site when they sign up.
  49.  *
  50.  * Since extensions do not change the way OpenID authentication works,
  51.  * code to handle extension requests may be completely separate from
  52.  * the {@link Auth_OpenID_Request} class here.  But you'll likely want
  53.  * data sent back by your extension to be signed.  {@link }
  54.  * Auth_OpenID_ServerResponse} provides methods with which you can add
  55.  * data to it which can be signed with the other data in the OpenID
  56.  * signature.
  57.  *
  58.  * For example:
  59.  *
  60.  * <pre>  // when request is a checkid_* request
  61.  *  $response = $request->answer(true);
  62.  *  // this will a signed 'openid.sreg.timezone' parameter to the response
  63.  *  response.addField('sreg', 'timezone', 'America/Los_Angeles')</pre>
  64.  *
  65.  * Stores
  66.  *
  67.  * The OpenID server needs to maintain state between requests in order
  68.  * to function.  Its mechanism for doing this is called a store.  The
  69.  * store interface is defined in Interface.php.  Additionally, several
  70.  * concrete store implementations are provided, so that most sites
  71.  * won't need to implement a custom store.  For a store backed by flat
  72.  * files on disk, see {@link Auth_OpenID_FileStore}.  For stores based
  73.  * on MySQL, SQLite, or PostgreSQL, see the {@link }
  74.  * Auth_OpenID_SQLStore} subclasses.
  75.  *
  76.  * Upgrading
  77.  *
  78.  * The keys by which a server looks up associations in its store have
  79.  * changed in version 1.2 of this library.  If your store has entries
  80.  * created from version 1.0 code, you should empty it.
  81.  *
  82.  * PHP versions 4 and 5
  83.  *
  84.  * LICENSE: See the COPYING file included in this distribution.
  85.  *
  86.  * @package OpenID
  87.  * @author JanRain, Inc. <openid@janrain.com>
  88.  * @copyright 2005-2008 Janrain, Inc.
  89.  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
  90.  */
  91.  
  92. // Do not allow direct access
  93. defined'_JEXEC' or die'Restricted access' );
  94.  
  95. /**
  96.  * Required imports
  97.  */
  98. require_once "Auth/OpenID.php";
  99. require_once "Auth/OpenID/Association.php";
  100. require_once "Auth/OpenID/CryptUtil.php";
  101. require_once "Auth/OpenID/BigMath.php";
  102. require_once "Auth/OpenID/DiffieHellman.php";
  103. require_once "Auth/OpenID/KVForm.php";
  104. require_once "Auth/OpenID/TrustRoot.php";
  105. require_once "Auth/OpenID/ServerRequest.php";
  106. require_once "Auth/OpenID/Message.php";
  107. require_once "Auth/OpenID/Nonce.php";
  108.  
  109. define('AUTH_OPENID_HTTP_OK'200);
  110. define('AUTH_OPENID_HTTP_REDIRECT'302);
  111. define('AUTH_OPENID_HTTP_ERROR'400);
  112.  
  113. /**
  114.  * @access private
  115.  */
  116. global $_Auth_OpenID_Request_Modes;
  117. $_Auth_OpenID_Request_Modes array('checkid_setup',
  118.                                     'checkid_immediate');
  119.  
  120. /**
  121.  * @access private
  122.  */
  123. define('Auth_OpenID_ENCODE_KVFORM''kfvorm');
  124.  
  125. /**
  126.  * @access private
  127.  */
  128. define('Auth_OpenID_ENCODE_URL''URL/redirect');
  129.  
  130. /**
  131.  * @access private
  132.  */
  133. define('Auth_OpenID_ENCODE_HTML_FORM''HTML form');
  134.  
  135. /**
  136.  * @access private
  137.  */
  138. function Auth_OpenID_isError($obj$cls 'Auth_OpenID_ServerError')
  139. {
  140.     return is_a($obj$cls);
  141. }
  142.  
  143. /**
  144.  * An error class which gets instantiated and returned whenever an
  145.  * OpenID protocol error occurs.  Be prepared to use this in place of
  146.  * an ordinary server response.
  147.  *
  148.  * @package OpenID
  149.  */
  150.     /**
  151.      * @access private
  152.      */
  153.     function Auth_OpenID_ServerError($message null$text null,
  154.                                      $reference null$contact null)
  155.     {
  156.         $this->message $message;
  157.         $this->text $text;
  158.         $this->contact $contact;
  159.         $this->reference $reference;
  160.     }
  161.  
  162.     function getReturnTo()
  163.     {
  164.         if ($this->message &&
  165.             $this->message->hasKey(Auth_OpenID_OPENID_NS'return_to')) {
  166.             return $this->message->getArg(Auth_OpenID_OPENID_NS,
  167.                                           'return_to');
  168.         else {
  169.             return null;
  170.         }
  171.     }
  172.  
  173.     /**
  174.      * Returns the return_to URL for the request which caused this
  175.      * error.
  176.      */
  177.     function hasReturnTo()
  178.     {
  179.         return $this->getReturnTo(!== null;
  180.     }
  181.  
  182.     /**
  183.      * Encodes this error's response as a URL suitable for
  184.      * redirection.  If the response has no return_to, another
  185.      * Auth_OpenID_ServerError is returned.
  186.      */
  187.     function encodeToURL()
  188.     {
  189.         if (!$this->message{
  190.             return null;
  191.         }
  192.  
  193.         $msg $this->toMessage();
  194.         return $msg->toURL($this->getReturnTo());
  195.     }
  196.  
  197.     /**
  198.      * Encodes the response to key-value form.  This is a
  199.      * machine-readable format used to respond to messages which came
  200.      * directly from the consumer and not through the user-agent.  See
  201.      * the OpenID specification.
  202.      */
  203.     function encodeToKVForm()
  204.     {
  205.         return Auth_OpenID_KVForm::fromArray(
  206.                                       array('mode' => 'error',
  207.                                             'error' => $this->toString()));
  208.     }
  209.  
  210.     function toFormMarkup($form_tag_attrs=null)
  211.     {
  212.         $msg $this->toMessage();
  213.         return $msg->toFormMarkup($this->getReturnTo()$form_tag_attrs);
  214.     }
  215.  
  216.     function toHTML($form_tag_attrs=null)
  217.     {
  218.         return Auth_OpenID::autoSubmitHTML(
  219.                       $this->toFormMarkup($form_tag_attrs));
  220.     }
  221.  
  222.     function toMessage()
  223.     {
  224.         // Generate a Message object for sending to the relying party,
  225.         // after encoding.
  226.         $namespace $this->message->getOpenIDNamespace();
  227.         $reply new Auth_OpenID_Message($namespace);
  228.         $reply->setArg(Auth_OpenID_OPENID_NS'mode''error');
  229.         $reply->setArg(Auth_OpenID_OPENID_NS'error'$this->toString());
  230.  
  231.         if ($this->contact !== null{
  232.             $reply->setArg(Auth_OpenID_OPENID_NS'contact'$this->contact);
  233.         }
  234.  
  235.         if ($this->reference !== null{
  236.             $reply->setArg(Auth_OpenID_OPENID_NS'reference',
  237.                            $this->reference);
  238.         }
  239.  
  240.         return $reply;
  241.     }
  242.  
  243.     /**
  244.      * Returns one of Auth_OpenID_ENCODE_URL,
  245.      * Auth_OpenID_ENCODE_KVFORM, or null, depending on the type of
  246.      * encoding expected for this error's payload.
  247.      */
  248.     function whichEncoding()
  249.     {
  250.         global $_Auth_OpenID_Request_Modes;
  251.  
  252.         if ($this->hasReturnTo()) {
  253.             if ($this->message->isOpenID2(&&
  254.                 (strlen($this->encodeToURL()) >
  255.                    Auth_OpenID_OPENID1_URL_LIMIT)) {
  256.                 return Auth_OpenID_ENCODE_HTML_FORM;
  257.             else {
  258.                 return Auth_OpenID_ENCODE_URL;
  259.             }
  260.         }
  261.  
  262.         if (!$this->message{
  263.             return null;
  264.         }
  265.  
  266.         $mode $this->message->getArg(Auth_OpenID_OPENID_NS,
  267.                                        'mode');
  268.  
  269.         if ($mode{
  270.             if (!in_array($mode$_Auth_OpenID_Request_Modes)) {
  271.                 return Auth_OpenID_ENCODE_KVFORM;
  272.             }
  273.         }
  274.         return null;
  275.     }
  276.  
  277.     /**
  278.      * Returns this error message.
  279.      */
  280.     function toString()
  281.     {
  282.         if ($this->text{
  283.             return $this->text;
  284.         else {
  285.             return get_class($this" error";
  286.         }
  287.     }
  288. }
  289.  
  290. /**
  291.  * Error returned by the server code when a return_to is absent from a
  292.  * request.
  293.  *
  294.  * @package OpenID
  295.  */
  296.     function Auth_OpenID_NoReturnToError($message null,
  297.                                          $text "No return_to URL available")
  298.     {
  299.         parent::Auth_OpenID_ServerError($message$text);
  300.     }
  301.  
  302.     function toString()
  303.     {
  304.         return "No return_to available";
  305.     }
  306. }
  307.  
  308. /**
  309.  * An error indicating that the return_to URL is malformed.
  310.  *
  311.  * @package OpenID
  312.  */
  313.     function Auth_OpenID_MalformedReturnURL($message$return_to)
  314.     {
  315.         $this->return_to $return_to;
  316.         parent::Auth_OpenID_ServerError($message"malformed return_to URL");
  317.     }
  318. }
  319.  
  320. /**
  321.  * This error is returned when the trust_root value is malformed.
  322.  *
  323.  * @package OpenID
  324.  */
  325.     function Auth_OpenID_MalformedTrustRoot($message null,
  326.                                             $text "Malformed trust root")
  327.     {
  328.         parent::Auth_OpenID_ServerError($message$text);
  329.     }
  330.  
  331.     function toString()
  332.     {
  333.         return "Malformed trust root";
  334.     }
  335. }
  336.  
  337. /**
  338.  * The base class for all server request classes.
  339.  *
  340.  * @package OpenID
  341.  */
  342.     var $mode = null;
  343. }
  344.  
  345. /**
  346.  * A request to verify the validity of a previous response.
  347.  *
  348.  * @package OpenID
  349.  */
  350.     var $mode = "check_authentication";
  351.     var $invalidate_handle = null;
  352.  
  353.     function Auth_OpenID_CheckAuthRequest($assoc_handle$signed,
  354.                                           $invalidate_handle null)
  355.     {
  356.         $this->assoc_handle $assoc_handle;
  357.         $this->signed $signed;
  358.         if ($invalidate_handle !== null{
  359.             $this->invalidate_handle = $invalidate_handle;
  360.         }
  361.         $this->namespace Auth_OpenID_OPENID2_NS;
  362.         $this->message null;
  363.     }
  364.  
  365.     function fromMessage($message$server=null)
  366.     {
  367.         $required_keys array('assoc_handle''sig''signed');
  368.  
  369.         foreach ($required_keys as $k{
  370.             if (!$message->getArg(Auth_OpenID_OPENID_NS$k)) {
  371.                 return new Auth_OpenID_ServerError($message,
  372.                     sprintf("%s request missing required parameter %s from \
  373.                             query""check_authentication"$k));
  374.             }
  375.         }
  376.  
  377.         $assoc_handle $message->getArg(Auth_OpenID_OPENID_NS'assoc_handle');
  378.         $sig $message->getArg(Auth_OpenID_OPENID_NS'sig');
  379.  
  380.         $signed_list $message->getArg(Auth_OpenID_OPENID_NS'signed');
  381.         $signed_list explode(","$signed_list);
  382.  
  383.         $signed $message;
  384.         if ($signed->hasKey(Auth_OpenID_OPENID_NS'mode')) {
  385.             $signed->setArg(Auth_OpenID_OPENID_NS'mode''id_res');
  386.         }
  387.  
  388.         $result new Auth_OpenID_CheckAuthRequest($assoc_handle$signed);
  389.         $result->message $message;
  390.         $result->sig $sig;
  391.         $result->invalidate_handle $message->getArg(Auth_OpenID_OPENID_NS,
  392.                                                       'invalidate_handle');
  393.         return $result;
  394.     }
  395.  
  396.     function answer(&$signatory)
  397.     {
  398.         $is_valid $signatory->verify($this->assoc_handle$this->signed);
  399.  
  400.         // Now invalidate that assoc_handle so it this checkAuth
  401.         // message cannot be replayed.
  402.         $signatory->invalidate($this->assoc_handletrue);
  403.         $response new Auth_OpenID_ServerResponse($this);
  404.  
  405.         $response->fields->setArg(Auth_OpenID_OPENID_NS,
  406.                                   'is_valid',
  407.                                   ($is_valid "true" "false"));
  408.  
  409.         if ($this->invalidate_handle{
  410.             $assoc $signatory->getAssociation($this->invalidate_handle,
  411.                                                 false);
  412.             if (!$assoc{
  413.                 $response->fields->setArg(Auth_OpenID_OPENID_NS,
  414.                                           'invalidate_handle',
  415.                                           $this->invalidate_handle);
  416.             }
  417.         }
  418.         return $response;
  419.     }
  420. }
  421.  
  422. /**
  423.  * A class implementing plaintext server sessions.
  424.  *
  425.  * @package OpenID
  426.  */
  427.     /**
  428.      * An object that knows how to handle association requests with no
  429.      * session type.
  430.      */
  431.     var $session_type = 'no-encryption';
  432.     var $needs_math = false;
  433.     var $allowed_assoc_types = array('HMAC-SHA1''HMAC-SHA256');
  434.  
  435.     function fromMessage($unused_request)
  436.     {
  437.         return new Auth_OpenID_PlainTextServerSession();
  438.     }
  439.  
  440.     function answer($secret)
  441.     {
  442.         return array('mac_key' => base64_encode($secret));
  443.     }
  444. }
  445.  
  446. /**
  447.  * A class implementing DH-SHA1 server sessions.
  448.  *
  449.  * @package OpenID
  450.  */
  451.     /**
  452.      * An object that knows how to handle association requests with
  453.      * the Diffie-Hellman session type.
  454.      */
  455.  
  456.     var $session_type = 'DH-SHA1';
  457.     var $needs_math = true;
  458.     var $allowed_assoc_types = array('HMAC-SHA1');
  459.     var $hash_func = 'Auth_OpenID_SHA1';
  460.  
  461.     function Auth_OpenID_DiffieHellmanSHA1ServerSession($dh$consumer_pubkey)
  462.     {
  463.         $this->dh $dh;
  464.         $this->consumer_pubkey $consumer_pubkey;
  465.     }
  466.  
  467.     function getDH($message)
  468.     {
  469.         $dh_modulus $message->getArg(Auth_OpenID_OPENID_NS'dh_modulus');
  470.         $dh_gen $message->getArg(Auth_OpenID_OPENID_NS'dh_gen');
  471.  
  472.         if ((($dh_modulus === null&& ($dh_gen !== null)) ||
  473.             (($dh_gen === null&& ($dh_modulus !== null))) {
  474.  
  475.             if ($dh_modulus === null{
  476.                 $missing 'modulus';
  477.             else {
  478.                 $missing 'generator';
  479.             }
  480.  
  481.             return new Auth_OpenID_ServerError($message,
  482.                                 'If non-default modulus or generator is '.
  483.                                 'supplied, both must be supplied.  Missing '.
  484.                                 $missing);
  485.         }
  486.  
  487.         $lib =Auth_OpenID_getMathLib();
  488.  
  489.         if ($dh_modulus || $dh_gen{
  490.             $dh_modulus $lib->base64ToLong($dh_modulus);
  491.             $dh_gen $lib->base64ToLong($dh_gen);
  492.             if ($lib->cmp($dh_modulus0== ||
  493.                 $lib->cmp($dh_gen0== 0{
  494.                 return new Auth_OpenID_ServerError(
  495.                   $message"Failed to parse dh_mod or dh_gen");
  496.             }
  497.             $dh new Auth_OpenID_DiffieHellman($dh_modulus$dh_gen);
  498.         else {
  499.             $dh new Auth_OpenID_DiffieHellman();
  500.         }
  501.  
  502.         $consumer_pubkey $message->getArg(Auth_OpenID_OPENID_NS,
  503.                                             'dh_consumer_public');
  504.         if ($consumer_pubkey === null{
  505.             return new Auth_OpenID_ServerError($message,
  506.                                   'Public key for DH-SHA1 session '.
  507.                                   'not found in query');
  508.         }
  509.  
  510.         $consumer_pubkey =
  511.             $lib->base64ToLong($consumer_pubkey);
  512.  
  513.         if ($consumer_pubkey === false{
  514.             return new Auth_OpenID_ServerError($message,
  515.                                        "dh_consumer_public is not base64");
  516.         }
  517.  
  518.         return array($dh$consumer_pubkey);
  519.     }
  520.  
  521.     function fromMessage($message)
  522.     {
  523.         $result Auth_OpenID_DiffieHellmanSHA1ServerSession::getDH($message);
  524.  
  525.         if (is_a($result'Auth_OpenID_ServerError')) {
  526.             return $result;
  527.         else {
  528.             list($dh$consumer_pubkey$result;
  529.             return new Auth_OpenID_DiffieHellmanSHA1ServerSession($dh,
  530.                                                     $consumer_pubkey);
  531.         }
  532.     }
  533.  
  534.     function answer($secret)
  535.     {
  536.         $lib =Auth_OpenID_getMathLib();
  537.         $mac_key $this->dh->xorSecret($this->consumer_pubkey$secret,
  538.                                         $this->hash_func);
  539.         return array(
  540.            'dh_server_public' =>
  541.                 $lib->longToBase64($this->dh->public),
  542.            'enc_mac_key' => base64_encode($mac_key));
  543.     }
  544. }
  545.  
  546. /**
  547.  * A class implementing DH-SHA256 server sessions.
  548.  *
  549.  * @package OpenID
  550.  */
  551.  
  552.     var $session_type = 'DH-SHA256';
  553.     var $hash_func = 'Auth_OpenID_SHA256';
  554.     var $allowed_assoc_types = array('HMAC-SHA256');
  555.  
  556.     function fromMessage($message)
  557.     {
  558.         $result Auth_OpenID_DiffieHellmanSHA1ServerSession::getDH($message);
  559.  
  560.         if (is_a($result'Auth_OpenID_ServerError')) {
  561.             return $result;
  562.         else {
  563.             list($dh$consumer_pubkey$result;
  564.             return new Auth_OpenID_DiffieHellmanSHA256ServerSession($dh,
  565.                                                       $consumer_pubkey);
  566.         }
  567.     }
  568. }
  569.  
  570. /**
  571.  * A request to associate with the server.
  572.  *
  573.  * @package OpenID
  574.  */
  575.     var $mode = "associate";
  576.  
  577.     function getSessionClasses()
  578.     {
  579.         return array(
  580.           'no-encryption' => 'Auth_OpenID_PlainTextServerSession',
  581.           'DH-SHA1' => 'Auth_OpenID_DiffieHellmanSHA1ServerSession',
  582.           'DH-SHA256' => 'Auth_OpenID_DiffieHellmanSHA256ServerSession');
  583.     }
  584.  
  585.     function Auth_OpenID_AssociateRequest(&$session$assoc_type)
  586.     {
  587.         $this->session =$session;
  588.         $this->namespace Auth_OpenID_OPENID2_NS;
  589.         $this->assoc_type $assoc_type;
  590.     }
  591.  
  592.     function fromMessage($message$server=null)
  593.     {
  594.         if ($message->isOpenID1()) {
  595.             $session_type $message->getArg(Auth_OpenID_OPENID_NS,
  596.                                              'session_type');
  597.  
  598.             if ($session_type == 'no-encryption'{
  599.                 // oidutil.log('Received OpenID 1 request with a no-encryption '
  600.                 //             'assocaition session type. Continuing anyway.')
  601.             else if (!$session_type{
  602.                 $session_type 'no-encryption';
  603.             }
  604.         else {
  605.             $session_type $message->getArg(Auth_OpenID_OPENID_NS,
  606.                                              'session_type');
  607.             if ($session_type === null{
  608.                 return new Auth_OpenID_ServerError($message,
  609.                   "session_type missing from request");
  610.             }
  611.         }
  612.  
  613.         $session_class Auth_OpenID::arrayGet(
  614.            $session_type);
  615.  
  616.         if ($session_class === null{
  617.             return new Auth_OpenID_ServerError($message,
  618.                                                "Unknown session type " .
  619.                                                $session_type);
  620.         }
  621.  
  622.         $session call_user_func(array($session_class'fromMessage'),
  623.                                   $message);
  624.         if (is_a($session'Auth_OpenID_ServerError')) {
  625.             return $session;
  626.         }
  627.  
  628.         $assoc_type $message->getArg(Auth_OpenID_OPENID_NS,
  629.                                        'assoc_type''HMAC-SHA1');
  630.  
  631.         if (!in_array($assoc_type$session->allowed_assoc_types)) {
  632.             $fmt "Session type %s does not support association type %s";
  633.             return new Auth_OpenID_ServerError($message,
  634.               sprintf($fmt$session_type$assoc_type));
  635.         }
  636.  
  637.         $obj new Auth_OpenID_AssociateRequest($session$assoc_type);
  638.         $obj->message $message;
  639.         $obj->namespace $message->getOpenIDNamespace();
  640.         return $obj;
  641.     }
  642.  
  643.     function answer($assoc)
  644.     {
  645.         $response new Auth_OpenID_ServerResponse($this);
  646.         $response->fields->updateArgs(Auth_OpenID_OPENID_NS,
  647.            array(
  648.                  'expires_in' => sprintf('%d'$assoc->getExpiresIn()),
  649.                  'assoc_type' => $this->assoc_type,
  650.                  'assoc_handle' => $assoc->handle));
  651.  
  652.         $response->fields->updateArgs(Auth_OpenID_OPENID_NS,
  653.            $this->session->answer($assoc->secret));
  654.  
  655.         if (($this->session->session_type == 'no-encryption' 
  656.                && $this->message->isOpenID1())) {
  657.             $response->fields->setArg(Auth_OpenID_OPENID_NS,
  658.                                       'session_type',
  659.                                       $this->session->session_type);
  660.         }
  661.  
  662.         return $response;
  663.     }
  664.  
  665.     function answerUnsupported($text_message,
  666.                                $preferred_association_type=null,
  667.                                $preferred_session_type=null)
  668.     {
  669.         if ($this->message->isOpenID1()) {
  670.             return new Auth_OpenID_ServerError($this->message);
  671.         }
  672.  
  673.         $response new Auth_OpenID_ServerResponse($this);
  674.         $response->fields->setArg(Auth_OpenID_OPENID_NS,
  675.                                   'error_code''unsupported-type');
  676.         $response->fields->setArg(Auth_OpenID_OPENID_NS,
  677.                                   'error'$text_message);
  678.  
  679.         if ($preferred_association_type{
  680.             $response->fields->setArg(Auth_OpenID_OPENID_NS,
  681.                                       'assoc_type',
  682.                                       $preferred_association_type);
  683.         }
  684.  
  685.         if ($preferred_session_type{
  686.             $response->fields->setArg(Auth_OpenID_OPENID_NS,
  687.                                       'session_type',
  688.                                       $preferred_session_type);
  689.         }
  690.  
  691.         return $response;
  692.     }
  693. }
  694.  
  695. /**
  696.  * A request to confirm the identity of a user.
  697.  *
  698.  * @package OpenID
  699.  */
  700.     /**
  701.      * Return-to verification callback.  Default is
  702.      * Auth_OpenID_verifyReturnTo from TrustRoot.php.
  703.      */
  704.     var $verifyReturnTo = 'Auth_OpenID_verifyReturnTo';
  705.  
  706.     /**
  707.      * The mode of this request.
  708.      */
  709.     var $mode = "checkid_setup"// or "checkid_immediate"
  710.  
  711.     
  712.     /**
  713.      * Whether this request is for immediate mode.
  714.      */
  715.     var $immediate = false;
  716.  
  717.     /**
  718.      * The trust_root value for this request.
  719.      */
  720.     var $trust_root = null;
  721.  
  722.     /**
  723.      * The OpenID namespace for this request.
  724.      * deprecated since version 2.0.2
  725.      */
  726.     var $namespace;
  727.     
  728.     function make(&$message$identity$return_to$trust_root null,
  729.                   $immediate false$assoc_handle null$server null)
  730.     {
  731.         if ($server === null{
  732.             return new Auth_OpenID_ServerError($message,
  733.                                                "server must not be null");
  734.         }
  735.  
  736.         if ($return_to &&
  737.             !Auth_OpenID_TrustRoot::_parse($return_to)) {
  738.             return new Auth_OpenID_MalformedReturnURL($message$return_to);
  739.         }
  740.  
  741.         $r new Auth_OpenID_CheckIDRequest($identity$return_to,
  742.                                             $trust_root$immediate,
  743.                                             $assoc_handle$server);
  744.  
  745.         $r->namespace $message->getOpenIDNamespace();
  746.         $r->message =$message;
  747.  
  748.         if (!$r->trustRootValid()) {
  749.             return new Auth_OpenID_UntrustedReturnURL($message,
  750.                                                       $return_to,
  751.                                                       $trust_root);
  752.         else {
  753.             return $r;
  754.         }
  755.     }
  756.  
  757.     function Auth_OpenID_CheckIDRequest($identity$return_to,
  758.                                         $trust_root null$immediate false,
  759.                                         $assoc_handle null$server null,
  760.                                         $claimed_id null)
  761.     {
  762.         $this->namespace = Auth_OpenID_OPENID2_NS;
  763.         $this->assoc_handle $assoc_handle;
  764.         $this->identity $identity;
  765.         if ($claimed_id === null{
  766.             $this->claimed_id $identity;
  767.         else {
  768.             $this->claimed_id $claimed_id;
  769.         }
  770.         $this->return_to $return_to;
  771.         $this->trust_root = $trust_root;
  772.         $this->server =$server;
  773.  
  774.         if ($immediate{
  775.             $this->immediate = true;
  776.             $this->mode = "checkid_immediate";
  777.         else {
  778.             $this->immediate = false;
  779.             $this->mode = "checkid_setup";
  780.         }
  781.     }
  782.  
  783.     function equals($other)
  784.     {
  785.         return (
  786.                 (is_a($other'Auth_OpenID_CheckIDRequest')) &&
  787.                 ($this->namespace == $other->namespace&&
  788.                 ($this->assoc_handle == $other->assoc_handle&&
  789.                 ($this->identity == $other->identity&&
  790.                 ($this->claimed_id == $other->claimed_id&&
  791.                 ($this->return_to == $other->return_to&&
  792.                 ($this->trust_root == $other->trust_root));
  793.     }
  794.  
  795.     /*
  796.      * Does the relying party publish the return_to URL for this
  797.      * response under the realm? It is up to the provider to set a
  798.      * policy for what kinds of realms should be allowed. This
  799.      * return_to URL verification reduces vulnerability to data-theft
  800.      * attacks based on open proxies, corss-site-scripting, or open
  801.      * redirectors.
  802.      *
  803.      * This check should only be performed after making sure that the
  804.      * return_to URL matches the realm.
  805.      *
  806.      * @return true if the realm publishes a document with the
  807.      * return_to URL listed, false if not or if discovery fails
  808.      */
  809.     function returnToVerified()
  810.     {
  811.         return call_user_func_array($this->verifyReturnTo,
  812.                                     array($this->trust_root$this->return_to));
  813.     }
  814.  
  815.     function fromMessage(&$message$server)
  816.     {
  817.         $mode $message->getArg(Auth_OpenID_OPENID_NS'mode');
  818.         $immediate null;
  819.  
  820.         if ($mode == "checkid_immediate"{
  821.             $immediate true;
  822.             $mode "checkid_immediate";
  823.         else {
  824.             $immediate false;
  825.             $mode "checkid_setup";
  826.         }
  827.  
  828.         $return_to $message->getArg(Auth_OpenID_OPENID_NS,
  829.                                       'return_to');
  830.  
  831.         if (($message->isOpenID1()) &&
  832.             (!$return_to)) {
  833.             $fmt "Missing required field 'return_to' from checkid request";
  834.             return new Auth_OpenID_ServerError($message$fmt);
  835.         }
  836.  
  837.         $identity $message->getArg(Auth_OpenID_OPENID_NS,
  838.                                      'identity');
  839.         $claimed_id $message->getArg(Auth_OpenID_OPENID_NS'claimed_id');
  840.         if ($message->isOpenID1()) {
  841.             if ($identity === null{
  842.                 $s "OpenID 1 message did not contain openid.identity";
  843.                 return new Auth_OpenID_ServerError($message$s);
  844.             }
  845.         else {
  846.             if ($identity && !$claimed_id{
  847.                 $s "OpenID 2.0 message contained openid.identity but not " .
  848.                   "claimed_id";
  849.                 return new Auth_OpenID_ServerError($message$s);
  850.             else if ($claimed_id && !$identity{
  851.                 $s "OpenID 2.0 message contained openid.claimed_id " .
  852.                   "but not identity";
  853.                 return new Auth_OpenID_ServerError($message$s);
  854.             }
  855.         }
  856.  
  857.         // There's a case for making self.trust_root be a TrustRoot
  858.         // here.  But if TrustRoot isn't currently part of the
  859.         // "public" API, I'm not sure it's worth doing.
  860.         if ($message->isOpenID1()) {
  861.             $trust_root_param 'trust_root';
  862.         else {
  863.             $trust_root_param 'realm';
  864.         }
  865.         $trust_root $message->getArg(Auth_OpenID_OPENID_NS
  866.                                        $trust_root_param);
  867.         if ($trust_root{
  868.             $trust_root $return_to;
  869.         }
  870.  
  871.         if ($message->isOpenID1(&& 
  872.             ($return_to === null&&
  873.             ($trust_root === null)) {
  874.             return new Auth_OpenID_ServerError($message,
  875.               "openid.realm required when openid.return_to absent");
  876.         }
  877.  
  878.         $assoc_handle $message->getArg(Auth_OpenID_OPENID_NS,
  879.                                          'assoc_handle');
  880.  
  881.         $obj Auth_OpenID_CheckIDRequest::make($message,
  882.                                                 $identity,
  883.                                                 $return_to,
  884.                                                 $trust_root,
  885.                                                 $immediate,
  886.                                                 $assoc_handle,
  887.                                                 $server);
  888.  
  889.         if (is_a($obj'Auth_OpenID_ServerError')) {
  890.             return $obj;
  891.         }
  892.  
  893.         $obj->claimed_id $claimed_id;
  894.  
  895.         return $obj;
  896.     }
  897.  
  898.     function idSelect()
  899.     {
  900.         // Is the identifier to be selected by the IDP?
  901.         // So IDPs don't have to import the constant
  902.         return $this->identity == Auth_OpenID_IDENTIFIER_SELECT;
  903.     }
  904.  
  905.     function trustRootValid()
  906.     {
  907.         if (!$this->trust_root{
  908.             return true;
  909.         }
  910.  
  911.         $tr Auth_OpenID_TrustRoot::_parse($this->trust_root);
  912.         if ($tr === false{
  913.             return new Auth_OpenID_MalformedTrustRoot($this->message,
  914.                                                       $this->trust_root);
  915.         }
  916.  
  917.         if ($this->return_to !== null{
  918.             return Auth_OpenID_TrustRoot::match($this->trust_root,
  919.                                                 $this->return_to);
  920.         else {
  921.             return true;
  922.         }
  923.     }
  924.  
  925.     /**
  926.      * Respond to this request.  Return either an
  927.      * {@link Auth_OpenID_ServerResponse} or
  928.      * {@link Auth_OpenID_ServerError}.
  929.      *
  930.      * @param bool $allow Allow this user to claim this identity, and
  931.      *  allow the consumer to have this information?
  932.      *
  933.      * @param string $server_url DEPRECATED.  Passing $op_endpoint to
  934.      *  the {@link Auth_OpenID_Server} constructor makes this optional.
  935.      *
  936.      *  When an OpenID 1.x immediate mode request does not succeed, it
  937.      *  gets back a URL where the request may be carried out in a
  938.      *  not-so-immediate fashion.  Pass my URL in here (the fully
  939.      *  qualified address of this server's endpoint, i.e.
  940.      *  http://example.com/server), and I will use it as a base for the
  941.      *  URL for a new request.
  942.      *
  943.      *  Optional for requests where {@link $immediate} is false or
  944.      *  $allow is true.
  945.      *
  946.      * @param string $identity The OP-local identifier to answer with.
  947.      *  Only for use when the relying party requested identifier
  948.      *  selection.
  949.      *
  950.      * @param string $claimed_id The claimed identifier to answer
  951.      *  with, for use with identifier selection in the case where the
  952.      *  claimed identifier and the OP-local identifier differ,
  953.      *  i.e. when the claimed_id uses delegation.
  954.      *
  955.      *  If $identity is provided but this is not, $claimed_id will
  956.      *  default to the value of $identity.  When answering requests
  957.      *  that did not ask for identifier selection, the response
  958.      *  $claimed_id will default to that of the request.
  959.      *
  960.      *  This parameter is new in OpenID 2.0.
  961.      *
  962.      * @return mixed 
  963.      */
  964.     function answer($allow$server_url null$identity null,
  965.                     $claimed_id null)
  966.     {
  967.         if (!$this->return_to{
  968.             return new Auth_OpenID_NoReturnToError();
  969.         }
  970.  
  971.         if (!$server_url{
  972.             if ((!$this->message->isOpenID1()) &&
  973.                 (!$this->server->op_endpoint)) {
  974.                 return new Auth_OpenID_ServerError(null,
  975.                   "server should be constructed with op_endpoint to " .
  976.                   "respond to OpenID 2.0 messages.");
  977.             }
  978.  
  979.             $server_url $this->server->op_endpoint;
  980.         }
  981.  
  982.         if ($allow{
  983.             $mode 'id_res';
  984.         else if ($this->message->isOpenID1()) {
  985.             if ($this->immediate{
  986.                 $mode 'id_res';
  987.             else {
  988.                 $mode 'cancel';
  989.             }
  990.         else {
  991.             if ($this->immediate{
  992.                 $mode 'setup_needed';
  993.             else {
  994.                 $mode 'cancel';
  995.             }
  996.         }
  997.  
  998.         if (!$this->trustRootValid()) {
  999.             return new Auth_OpenID_UntrustedReturnURL(null,
  1000.                                                       $this->return_to,
  1001.                                                       $this->trust_root);
  1002.         }
  1003.  
  1004.         $response new Auth_OpenID_ServerResponse($this);
  1005.  
  1006.         if ($claimed_id &&
  1007.             ($this->message->isOpenID1())) {
  1008.             return new Auth_OpenID_ServerError(null,
  1009.               "claimed_id is new in OpenID 2.0 and not " .
  1010.               "available for ".$this->namespace);
  1011.         }
  1012.  
  1013.         if ($identity && !$claimed_id{
  1014.             $claimed_id $identity;
  1015.         }
  1016.  
  1017.         if ($allow{
  1018.  
  1019.             if ($this->identity == Auth_OpenID_IDENTIFIER_SELECT{
  1020.                 if (!$identity{
  1021.                     return new Auth_OpenID_ServerError(null,
  1022.                       "This request uses IdP-driven identifier selection.  " .
  1023.                       "You must supply an identifier in the response.");
  1024.                 }
  1025.  
  1026.                 $response_identity $identity;
  1027.                 $response_claimed_id $claimed_id;
  1028.  
  1029.             else if ($this->identity{
  1030.                 if ($identity &&
  1031.                     ($this->identity != $identity)) {
  1032.                     $fmt "Request was for %s, cannot reply with identity %s";
  1033.                     return new Auth_OpenID_ServerError(null,
  1034.                       sprintf($fmt$this->identity$identity));
  1035.                 }
  1036.  
  1037.                 $response_identity $this->identity;
  1038.                 $response_claimed_id $this->claimed_id;
  1039.             else {
  1040.                 if ($identity{
  1041.                     return new Auth_OpenID_ServerError(null,
  1042.                       "This request specified no identity and " .
  1043.                       "you supplied ".$identity);
  1044.                 }
  1045.  
  1046.                 $response_identity null;
  1047.             }
  1048.  
  1049.             if (($this->message->isOpenID1()) &&
  1050.                 ($response_identity === null)) {
  1051.                 return new Auth_OpenID_ServerError(null,
  1052.                   "Request was an OpenID 1 request, so response must " .
  1053.                   "include an identifier.");
  1054.             }
  1055.  
  1056.             $response->fields->updateArgs(Auth_OpenID_OPENID_NS,
  1057.                    array('mode' => $mode,
  1058.                          'return_to' => $this->return_to,
  1059.                          'response_nonce' => Auth_OpenID_mkNonce()));
  1060.  
  1061.             if (!$this->message->isOpenID1()) {
  1062.                 $response->fields->setArg(Auth_OpenID_OPENID_NS,
  1063.                                           'op_endpoint'$server_url);
  1064.             }
  1065.  
  1066.             if ($response_identity !== null{
  1067.                 $response->fields->setArg(
  1068.                                           Auth_OpenID_OPENID_NS,
  1069.                                           'identity',
  1070.                                           $response_identity);
  1071.                 if ($this->message->isOpenID2()) {
  1072.                     $response->fields->setArg(
  1073.                                               Auth_OpenID_OPENID_NS,
  1074.                                               'claimed_id',
  1075.                                               $response_claimed_id);
  1076.                 }
  1077.             }
  1078.  
  1079.         else {
  1080.             $response->fields->setArg(Auth_OpenID_OPENID_NS,
  1081.                                       'mode'$mode);
  1082.  
  1083.             if ($this->immediate{
  1084.                 if (($this->message->isOpenID1()) &&
  1085.                     (!$server_url)) {
  1086.                     return new Auth_OpenID_ServerError(null,
  1087.                                  'setup_url is required for $allow=false \
  1088.                                   in OpenID 1.x immediate mode.');
  1089.                 }
  1090.  
  1091.                 $setup_request =new Auth_OpenID_CheckIDRequest(
  1092.                                                 $this->identity,
  1093.                                                 $this->return_to,
  1094.                                                 $this->trust_root,
  1095.                                                 false,
  1096.                                                 $this->assoc_handle,
  1097.                                                 $this->server,
  1098.                                                 $this->claimed_id);
  1099.                 $setup_request->message $this->message;
  1100.  
  1101.                 $setup_url $setup_request->encodeToURL($server_url);
  1102.  
  1103.                 if ($setup_url === null{
  1104.                     return new Auth_OpenID_NoReturnToError();
  1105.                 }
  1106.  
  1107.                 $response->fields->setArg(Auth_OpenID_OPENID_NS,
  1108.                                           'user_setup_url',
  1109.                                           $setup_url);
  1110.             }
  1111.         }
  1112.  
  1113.         return $response;
  1114.     }
  1115.  
  1116.     function encodeToURL($server_url)
  1117.     {
  1118.         if (!$this->return_to{
  1119.             return new Auth_OpenID_NoReturnToError();
  1120.         }
  1121.  
  1122.         // Imported from the alternate reality where these classes are
  1123.         // used in both the client and server code, so Requests are
  1124.         // Encodable too.  That's right, code imported from alternate
  1125.         // realities all for the love of you, id_res/user_setup_url.
  1126.  
  1127.         $q array('mode' => $this->mode,
  1128.                    'identity' => $this->identity,
  1129.                    'claimed_id' => $this->claimed_id,
  1130.                    'return_to' => $this->return_to);
  1131.  
  1132.         if ($this->trust_root{
  1133.             if ($this->message->isOpenID1()) {
  1134.                 $q['trust_root'$this->trust_root;
  1135.             else {
  1136.                 $q['realm'$this->trust_root;
  1137.             }
  1138.         }
  1139.  
  1140.         if ($this->assoc_handle{
  1141.             $q['assoc_handle'$this->assoc_handle;
  1142.         }
  1143.  
  1144.         $response new Auth_OpenID_Message(
  1145.             $this->message->getOpenIDNamespace());
  1146.         $response->updateArgs(Auth_OpenID_OPENID_NS$q);
  1147.         return $response->toURL($server_url);
  1148.     }
  1149.  
  1150.     function getCancelURL()
  1151.     {
  1152.         if (!$this->return_to{
  1153.             return new Auth_OpenID_NoReturnToError();
  1154.         }
  1155.  
  1156.         if ($this->immediate{
  1157.             return new Auth_OpenID_ServerError(null,
  1158.                                                "Cancel is not an appropriate \
  1159.                                                response to immediate mode \
  1160.                                                requests.");
  1161.         }
  1162.  
  1163.         $response new Auth_OpenID_Message(
  1164.             $this->message->getOpenIDNamespace());
  1165.         $response->setArg(Auth_OpenID_OPENID_NS'mode''cancel');
  1166.         return $response->toURL($this->return_to);
  1167.     }
  1168. }
  1169.  
  1170. /**
  1171.  * This class encapsulates the response to an OpenID server request.
  1172.  *
  1173.  * @package OpenID
  1174.  */
  1175.  
  1176.     function Auth_OpenID_ServerResponse(&$request)
  1177.     {
  1178.         $this->request =$request;
  1179.         $this->fields new Auth_OpenID_Message($this->request->namespace);
  1180.     }
  1181.  
  1182.     function whichEncoding()
  1183.     {
  1184.       global $_Auth_OpenID_Request_Modes;
  1185.  
  1186.         if (in_array($this->request->mode$_Auth_OpenID_Request_Modes)) {
  1187.             if ($this->fields->isOpenID2(&&
  1188.                 (strlen($this->encodeToURL()) >
  1189.                    Auth_OpenID_OPENID1_URL_LIMIT)) {
  1190.                 return Auth_OpenID_ENCODE_HTML_FORM;
  1191.             else {
  1192.                 return Auth_OpenID_ENCODE_URL;
  1193.             }
  1194.         else {
  1195.             return Auth_OpenID_ENCODE_KVFORM;
  1196.         }
  1197.     }
  1198.  
  1199.     /*
  1200.      * Returns the form markup for this response.
  1201.      *
  1202.      * @return str
  1203.      */
  1204.     function toFormMarkup($form_tag_attrs=null)
  1205.     {
  1206.         return $this->fields->toFormMarkup($this->request->return_to,
  1207.                                            $form_tag_attrs);
  1208.     }
  1209.  
  1210.     /*
  1211.      * Returns an HTML document containing the form markup for this
  1212.      * response that autosubmits with javascript.
  1213.      */
  1214.     function toHTML()
  1215.     {
  1216.         return Auth_OpenID::autoSubmitHTML($this->toFormMarkup());
  1217.     }
  1218.  
  1219.     /*
  1220.      * Returns True if this response's encoding is ENCODE_HTML_FORM.
  1221.      * Convenience method for server authors.
  1222.      *
  1223.      * @return bool
  1224.      */
  1225.     function renderAsForm()
  1226.     {
  1227.         return $this->whichEncoding(== Auth_OpenID_ENCODE_HTML_FORM;
  1228.     }
  1229.  
  1230.  
  1231.     function encodeToURL()
  1232.     {
  1233.         return $this->fields->toURL($this->request->return_to);
  1234.     }
  1235.  
  1236.     function addExtension($extension_response)
  1237.     {
  1238.         $extension_response->toMessage($this->fields);
  1239.     }
  1240.  
  1241.     function needsSigning()
  1242.     {
  1243.         return $this->fields->getArg(Auth_OpenID_OPENID_NS,
  1244.                                      'mode'== 'id_res';
  1245.     }
  1246.  
  1247.     function encodeToKVForm()
  1248.     {
  1249.         return $this->fields->toKVForm();
  1250.     }
  1251. }
  1252.  
  1253. /**
  1254.  * A web-capable response object which you can use to generate a
  1255.  * user-agent response.
  1256.  *
  1257.  * @package OpenID
  1258.  */
  1259.     var $code = AUTH_OPENID_HTTP_OK;
  1260.     var $body = "";
  1261.  
  1262.     function Auth_OpenID_WebResponse($code null$headers null,
  1263.                                      $body null)
  1264.     {
  1265.         if ($code{
  1266.             $this->code = $code;
  1267.         }
  1268.  
  1269.         if ($headers !== null{
  1270.             $this->headers $headers;
  1271.         else {
  1272.             $this->headers array();
  1273.         }
  1274.  
  1275.         if ($body !== null{
  1276.             $this->body = $body;
  1277.         }
  1278.     }
  1279. }
  1280.  
  1281. /**
  1282.  * Responsible for the signature of query data and the verification of
  1283.  * OpenID signature values.
  1284.  *
  1285.  * @package OpenID
  1286.  */
  1287.  
  1288.     // = 14 * 24 * 60 * 60; # 14 days, in seconds
  1289.         var $SECRET_LIFETIME = 1209600;
  1290.  
  1291.     // keys have a bogus server URL in them because the filestore
  1292.     // really does expect that key to be a URL.  This seems a little
  1293.     // silly for the server store, since I expect there to be only one
  1294.     // server URL.
  1295.         var $normal_key = 'http://localhost/|normal';
  1296.     var $dumb_key = 'http://localhost/|dumb';
  1297.  
  1298.     /**
  1299.      * Create a new signatory using a given store.
  1300.      */
  1301.     function Auth_OpenID_Signatory(&$store)
  1302.     {
  1303.         // assert store is not None
  1304.         $this->store =$store;
  1305.     }
  1306.  
  1307.     /**
  1308.      * Verify, using a given association handle, a signature with
  1309.      * signed key-value pairs from an HTTP request.
  1310.      */
  1311.     function verify($assoc_handle$message)
  1312.     {
  1313.         $assoc $this->getAssociation($assoc_handletrue);
  1314.         if (!$assoc{
  1315.             // oidutil.log("failed to get assoc with handle %r to verify sig %r"
  1316.             //             % (assoc_handle, sig))
  1317.             return false;
  1318.         }
  1319.  
  1320.         return $assoc->checkMessageSignature($message);
  1321.     }
  1322.  
  1323.     /**
  1324.      * Given a response, sign the fields in the response's 'signed'
  1325.      * list, and insert the signature into the response.
  1326.      */
  1327.     function sign($response)
  1328.     {
  1329.         $signed_response $response;
  1330.         $assoc_handle $response->request->assoc_handle;
  1331.  
  1332.         if ($assoc_handle{
  1333.             // normal mode
  1334.             $assoc $this->getAssociation($assoc_handlefalsefalse);
  1335.             if (!$assoc || ($assoc->getExpiresIn(<= 0)) {
  1336.                 // fall back to dumb mode
  1337.                 $signed_response->fields->setArg(Auth_OpenID_OPENID_NS,
  1338.                              'invalidate_handle'$assoc_handle);
  1339.                 $assoc_type ($assoc $assoc->assoc_type 'HMAC-SHA1');
  1340.  
  1341.                 if ($assoc && ($assoc->getExpiresIn(<= 0)) {
  1342.                     $this->invalidate($assoc_handlefalse);
  1343.                 }
  1344.  
  1345.                 $assoc $this->createAssociation(true$assoc_type);
  1346.             }
  1347.         else {
  1348.             // dumb mode.
  1349.             $assoc $this->createAssociation(true);
  1350.         }
  1351.  
  1352.         $signed_response->fields $assoc->signMessage(
  1353.                                       $signed_response->fields);
  1354.         return $signed_response;
  1355.     }
  1356.  
  1357.     /**
  1358.      * Make a new association.
  1359.      */
  1360.     function createAssociation($dumb true$assoc_type 'HMAC-SHA1')
  1361.     {
  1362.         $secret Auth_OpenID_CryptUtil::getBytes(
  1363.                     Auth_OpenID_getSecretSize($assoc_type));
  1364.  
  1365.         $uniq base64_encode(Auth_OpenID_CryptUtil::getBytes(4));
  1366.         $handle sprintf('{%s}{%x}{%s}'$assoc_typeintval(time())$uniq);
  1367.  
  1368.         $assoc Auth_OpenID_Association::fromExpiresIn(
  1369.                       $this->SECRET_LIFETIME$handle$secret$assoc_type);
  1370.  
  1371.         if ($dumb{
  1372.             $key $this->dumb_key;
  1373.         else {
  1374.             $key $this->normal_key;
  1375.         }
  1376.  
  1377.         $this->store->storeAssociation($key$assoc);
  1378.         return $assoc;
  1379.     }
  1380.  
  1381.     /**
  1382.      * Given an association handle, get the association from the
  1383.      * store, or return a ServerError or null if something goes wrong.
  1384.      */
  1385.     function getAssociation($assoc_handle$dumb$check_expiration=true)
  1386.     {
  1387.         if ($assoc_handle === null{
  1388.             return new Auth_OpenID_ServerError(null,
  1389.                                      "assoc_handle must not be null");
  1390.         }
  1391.  
  1392.         if ($dumb{
  1393.             $key $this->dumb_key;
  1394.         else {
  1395.             $key $this->normal_key;
  1396.         }
  1397.  
  1398.         $assoc $this->store->getAssociation($key$assoc_handle);
  1399.  
  1400.         if (($assoc !== null&& ($assoc->getExpiresIn(<= 0)) {
  1401.             if ($check_expiration{
  1402.                 $this->store->removeAssociation($key$assoc_handle);
  1403.                 $assoc null;
  1404.             }
  1405.         }
  1406.  
  1407.         return $assoc;
  1408.     }
  1409.  
  1410.     /**
  1411.      * Invalidate a given association handle.
  1412.      */
  1413.     function invalidate($assoc_handle$dumb)
  1414.     {
  1415.         if ($dumb{
  1416.             $key $this->dumb_key;
  1417.         else {
  1418.             $key $this->normal_key;
  1419.         }
  1420.         $this->store->removeAssociation($key$assoc_handle);
  1421.     }
  1422. }
  1423.  
  1424. /**
  1425.  * Encode an {@link Auth_OpenID_ServerResponse} to an
  1426.  * {@link Auth_OpenID_WebResponse}.
  1427.  *
  1428.  * @package OpenID
  1429.  */
  1430.  
  1431.     var $responseFactory = 'Auth_OpenID_WebResponse';
  1432.  
  1433.     /**
  1434.      * Encode an {@link Auth_OpenID_ServerResponse} and return an
  1435.      * {@link Auth_OpenID_WebResponse}.
  1436.      */
  1437.     function encode(&$response)
  1438.     {
  1439.         $cls $this->responseFactory;
  1440.  
  1441.         $encode_as $response->whichEncoding();
  1442.         if ($encode_as == Auth_OpenID_ENCODE_KVFORM{
  1443.             $wr new $cls(nullnull$response->encodeToKVForm());
  1444.             if (is_a($response'Auth_OpenID_ServerError')) {
  1445.                 $wr->code AUTH_OPENID_HTTP_ERROR;
  1446.             }
  1447.         else if ($encode_as == Auth_OpenID_ENCODE_URL{
  1448.             $location $response->encodeToURL();
  1449.             $wr new $cls(AUTH_OPENID_HTTP_REDIRECT,
  1450.                            array('location' => $location));
  1451.         else if ($encode_as == Auth_OpenID_ENCODE_HTML_FORM{
  1452.           $wr new $cls(AUTH_OPENID_HTTP_OKarray(),
  1453.                          $response->toFormMarkup());
  1454.         else {
  1455.             return new Auth_OpenID_EncodingError($response);
  1456.         }
  1457.         return $wr;
  1458.     }
  1459. }
  1460.  
  1461. /**
  1462.  * An encoder which also takes care of signing fields when required.
  1463.  *
  1464.  * @package OpenID
  1465.  */
  1466.  
  1467.     function Auth_OpenID_SigningEncoder(&$signatory)
  1468.     {
  1469.         $this->signatory =$signatory;
  1470.     }
  1471.  
  1472.     /**
  1473.      * Sign an {@link Auth_OpenID_ServerResponse} and return an
  1474.      * {@link Auth_OpenID_WebResponse}.
  1475.      */
  1476.     function encode(&$response)
  1477.     {
  1478.         // the isinstance is a bit of a kludge... it means there isn't
  1479.         // really an adapter to make the interfaces quite match.
  1480.         if (!is_a($response'Auth_OpenID_ServerError'&&
  1481.             $response->needsSigning()) {
  1482.  
  1483.             if (!$this->signatory{
  1484.                 return new Auth_OpenID_ServerError(null,
  1485.                                        "Must have a store to sign request");
  1486.             }
  1487.  
  1488.             if ($response->fields->hasKey(Auth_OpenID_OPENID_NS'sig')) {
  1489.                 return new Auth_OpenID_AlreadySigned($response);
  1490.             }
  1491.             $response $this->signatory->sign($response);
  1492.         }
  1493.  
  1494.         return parent::encode($response);
  1495.     }
  1496. }
  1497.  
  1498. /**
  1499.  * Decode an incoming query into an Auth_OpenID_Request.
  1500.  *
  1501.  * @package OpenID
  1502.  */
  1503.  
  1504.     function Auth_OpenID_Decoder(&$server)
  1505.     {
  1506.         $this->server =$server;
  1507.  
  1508.         $this->handlers array(
  1509.             'checkid_setup' => 'Auth_OpenID_CheckIDRequest',
  1510.             'checkid_immediate' => 'Auth_OpenID_CheckIDRequest',
  1511.             'check_authentication' => 'Auth_OpenID_CheckAuthRequest',
  1512.             'associate' => 'Auth_OpenID_AssociateRequest'
  1513.             );
  1514.     }
  1515.  
  1516.     /**
  1517.      * Given an HTTP query in an array (key-value pairs), decode it
  1518.      * into an Auth_OpenID_Request object.
  1519.      */
  1520.     function decode($query)
  1521.     {
  1522.         if (!$query{
  1523.             return null;
  1524.         }
  1525.  
  1526.         $message Auth_OpenID_Message::fromPostArgs($query);
  1527.  
  1528.         if ($message === null{
  1529.             /*
  1530.              * It's useful to have a Message attached to a
  1531.              * ProtocolError, so we override the bad ns value to build
  1532.              * a Message out of it.  Kinda kludgy, since it's made of
  1533.              * lies, but the parts that aren't lies are more useful
  1534.              * than a 'None'.
  1535.              */
  1536.             $old_ns $query['openid.ns'];
  1537.  
  1538.             $query['openid.ns'Auth_OpenID_OPENID2_NS;
  1539.             $message Auth_OpenID_Message::fromPostArgs($query);
  1540.             return new Auth_OpenID_ServerError(
  1541.                   $message,
  1542.                   sprintf("Invalid OpenID namespace URI: %s"$old_ns));
  1543.         }
  1544.  
  1545.         $mode $message->getArg(Auth_OpenID_OPENID_NS'mode');
  1546.         if (!$mode{
  1547.             return new Auth_OpenID_ServerError($message,
  1548.                                                "No mode value in message");
  1549.         }
  1550.  
  1551.         if (Auth_OpenID::isFailure($mode)) {
  1552.             return new Auth_OpenID_ServerError($message,
  1553.                                                $mode->message);
  1554.         }
  1555.  
  1556.         $handlerCls Auth_OpenID::arrayGet($this->handlers$mode,
  1557.                                             $this->defaultDecoder($message));
  1558.  
  1559.         if (!is_a($handlerCls'Auth_OpenID_ServerError')) {
  1560.             return call_user_func_array(array($handlerCls'fromMessage'),
  1561.                                         array($message$this->server));
  1562.         else {
  1563.             return $handlerCls;
  1564.         }
  1565.     }
  1566.  
  1567.     function defaultDecoder($message)
  1568.     {
  1569.         $mode $message->getArg(Auth_OpenID_OPENID_NS'mode');
  1570.  
  1571.         if (Auth_OpenID::isFailure($mode)) {
  1572.             return new Auth_OpenID_ServerError($message,
  1573.                                                $mode->message);
  1574.         }
  1575.  
  1576.         return new Auth_OpenID_ServerError($message,
  1577.                        sprintf("Unrecognized OpenID mode %s"$mode));
  1578.     }
  1579. }
  1580.  
  1581. /**
  1582.  * An error that indicates an encoding problem occurred.
  1583.  *
  1584.  * @package OpenID
  1585.  */
  1586.     function Auth_OpenID_EncodingError(&$response)
  1587.     {
  1588.         $this->response =$response;
  1589.     }
  1590. }
  1591.  
  1592. /**
  1593.  * An error that indicates that a response was already signed.
  1594.  *
  1595.  * @package OpenID
  1596.  */
  1597.     // This response is already signed.
  1598. }
  1599.  
  1600. /**
  1601.  * An error that indicates that the given return_to is not under the
  1602.  * given trust_root.
  1603.  *
  1604.  * @package OpenID
  1605.  */
  1606.     function Auth_OpenID_UntrustedReturnURL($message$return_to,
  1607.                                             $trust_root)
  1608.     {
  1609.         parent::Auth_OpenID_ServerError($message"Untrusted return_to URL");
  1610.         $this->return_to $return_to;
  1611.         $this->trust_root $trust_root;
  1612.     }
  1613.  
  1614.     function toString()
  1615.     {
  1616.         return sprintf("return_to %s not under trust_root %s",
  1617.                        $this->return_to$this->trust_root);
  1618.     }
  1619. }
  1620.  
  1621. /**
  1622.  * I handle requests for an OpenID server.
  1623.  *
  1624.  * Some types of requests (those which are not checkid requests) may
  1625.  * be handed to my {@link handleRequest} method, and I will take care
  1626.  * of it and return a response.
  1627.  *
  1628.  * For your convenience, I also provide an interface to {@link }
  1629.  * Auth_OpenID_Decoder::decode()} and {@link }
  1630.  * Auth_OpenID_SigningEncoder::encode()} through my methods {@link }
  1631.  * decodeRequest} and {@link encodeResponse}.
  1632.  *
  1633.  * All my state is encapsulated in an {@link Auth_OpenID_OpenIDStore}.
  1634.  *
  1635.  * Example:
  1636.  *
  1637.  * <pre> $oserver = new Auth_OpenID_Server(Auth_OpenID_FileStore($data_path),
  1638.  *                                   "http://example.com/op");
  1639.  * $request = $oserver->decodeRequest();
  1640.  * if (in_array($request->mode, array('checkid_immediate',
  1641.  *                                    'checkid_setup'))) {
  1642.  *     if ($app->isAuthorized($request->identity, $request->trust_root)) {
  1643.  *         $response = $request->answer(true);
  1644.  *     } else if ($request->immediate) {
  1645.  *         $response = $request->answer(false);
  1646.  *     } else {
  1647.  *         $app->showDecidePage($request);
  1648.  *         return;
  1649.  *     }
  1650.  * } else {
  1651.  *     $response = $oserver->handleRequest($request);
  1652.  * }
  1653.  *
  1654.  * $webresponse = $oserver->encode($response);</pre>
  1655.  *
  1656.  * @package OpenID
  1657.  */
  1658.     function Auth_OpenID_Server(&$store$op_endpoint=null)
  1659.     {
  1660.         $this->store =$store;
  1661.         $this->signatory =new Auth_OpenID_Signatory($this->store);
  1662.         $this->encoder =new Auth_OpenID_SigningEncoder($this->signatory);
  1663.         $this->decoder =new Auth_OpenID_Decoder($this);
  1664.         $this->op_endpoint $op_endpoint;
  1665.         $this->negotiator =Auth_OpenID_getDefaultNegotiator();
  1666.     }
  1667.  
  1668.     /**
  1669.      * Handle a request.  Given an {@link Auth_OpenID_Request} object,
  1670.      * call the appropriate {@link Auth_OpenID_Server} method to
  1671.      * process the request and generate a response.
  1672.      *
  1673.      * @param Auth_OpenID_Request $request An {@link Auth_OpenID_Request}
  1674.      *  returned by {@link Auth_OpenID_Server::decodeRequest()}.
  1675.      *
  1676.      * @return Auth_OpenID_ServerResponse $response A response object
  1677.      *  capable of generating a user-agent reply.
  1678.      */
  1679.     function handleRequest($request)
  1680.     {
  1681.         if (method_exists($this"openid_" $request->mode)) {
  1682.             $handler array($this"openid_" $request->mode);
  1683.             return call_user_func($handler$request);
  1684.         }
  1685.         return null;
  1686.     }
  1687.  
  1688.     /**
  1689.      * The callback for 'check_authentication' messages.
  1690.      */
  1691.     function openid_check_authentication(&$request)
  1692.     {
  1693.         return $request->answer($this->signatory);
  1694.     }
  1695.  
  1696.     /**
  1697.      * The callback for 'associate' messages.
  1698.      */
  1699.     function openid_associate(&$request)
  1700.     {
  1701.         $assoc_type $request->assoc_type;
  1702.         $session_type $request->session->session_type;
  1703.         if ($this->negotiator->isAllowed($assoc_type$session_type)) {
  1704.             $assoc $this->signatory->createAssociation(false,
  1705.                                                          $assoc_type);
  1706.             return $request->answer($assoc);
  1707.         else {
  1708.             $message sprintf('Association type %s is not supported with '.
  1709.                                'session type %s'$assoc_type$session_type);
  1710.             list($preferred_assoc_type$preferred_session_type=
  1711.                 $this->negotiator->getAllowedType();
  1712.             return $request->answerUnsupported($message,
  1713.                                                $preferred_assoc_type,
  1714.                                                $preferred_session_type);
  1715.         }
  1716.     }
  1717.  
  1718.     /**
  1719.      * Encodes as response in the appropriate format suitable for
  1720.      * sending to the user agent.
  1721.      */
  1722.     function encodeResponse(&$response)
  1723.     {
  1724.         return $this->encoder->encode($response);
  1725.     }
  1726.  
  1727.     /**
  1728.      * Decodes a query args array into the appropriate
  1729.      * {@link Auth_OpenID_Request} object.
  1730.      */
  1731.     function decodeRequest($query=null)
  1732.     {
  1733.         if ($query === null{
  1734.             $query Auth_OpenID::getQuery();
  1735.         }
  1736.  
  1737.         return $this->decoder->decode($query);
  1738.     }
  1739. }
  1740.  
  1741. ?>

Documentation generated on Sat, 14 Nov 2009 11:18:49 +0000 by phpDocumentor 1.3.1