Source for file RelyingParty.php

Documentation is available at RelyingParty.php

  1. <?php
  2. /**
  3.  * OpenID_RelyingParty
  4.  * 
  5.  * PHP Version 5.2.0+
  6.  * 
  7.  * @uses      OpenID
  8.  * @category  Auth
  9.  * @package   OpenID
  10.  * @author    Bill Shupp <hostmaster@shupp.org>
  11.  * @copyright 2009 Bill Shupp
  12.  * @license   http://www.opensource.org/licenses/bsd-license.php FreeBSD
  13.  * @link      http://pearopenid.googlecode.com
  14.  */
  15.  
  16. /**
  17.  * Required files
  18.  */
  19. require_once 'OpenID.php';
  20. require_once 'OpenID/Store.php';
  21. require_once 'OpenID/Discover.php';
  22. require_once 'OpenID/Association/Request.php';
  23. require_once 'OpenID/Assertion.php';
  24. require_once 'OpenID/Assertion/Result.php';
  25. require_once 'OpenID/Auth/Request.php';
  26. require_once 'Net/URL2.php';
  27.  
  28. /**
  29.  * OpenID_RelyingParty
  30.  *
  31.  * OpenID_RelyingParty implements all the steps required to verify a claim in two
  32.  * step interface: {@link prepare() prepare} and {@link verify() verify}.
  33.  * 
  34.  * {@link prepare() prepare} sets up the request, which includes performing
  35.  * discovery on the identifier, establishing an association with the OpenID Provider
  36.  * (optional), and then building an OpenID_Auth_Request object.  With this object,
  37.  * you can optionally add OpenID_Extension(s), and then perform the request.
  38.  * 
  39.  * {@link verify() verify} takes a Net_URL2 object as an argument, which represents
  40.  * the URL that the end user was redirected to after communicating with the the
  41.  * OpenID Provider.  It processes the URL, and if it was a positive response from
  42.  * the OP, tries to verify that assertion.
  43.  * 
  44.  * Example:
  45.  * <code>
  46.  * // First set up some things about your relying party:
  47.  * $realm    = 'http://examplerp.com';
  48.  * $returnTo = $realm . '/relyingparty.php';
  49.  *
  50.  * // Here is an example user supplied identifier
  51.  * $identifier = $_POST['identifier'];
  52.  *
  53.  * // You might want to store it in session for use in verify()
  54.  * $_SESSION['identifier'] = $identifier;
  55.  * 
  56.  * // Fire up the OpenID_RelyingParty object
  57.  * $rp = new OpenID_RelyingParty($returnTo, $realm, $identifier);
  58.  *
  59.  * // Here's an example of prepare() usage ...
  60.  * // First, grab your Auth_Request_Object
  61.  * $authRequest = $rp->prepare();
  62.  *
  63.  * // Then, optionally add an extension
  64.  *  $sreg = new OpenID_Extension_SREG11(OpenID_Extension::REQUEST);
  65.  *  $sreg->set('required', 'email');
  66.  *  $sreg->set('optional', 'nickname,gender,dob');
  67.  *
  68.  *  // You'll need to add it to OpenID_Auth_Request
  69.  *  $authRequest->addExtension($sreg);
  70.  * // Optionally get association (from cache in this example)
  71.  * 
  72.  * // Optionally make this a checkid_immediate request
  73.  * $auth->setMode(OpenID::MODE_CHECKID_IMMEDIATE);
  74.  * 
  75.  * // Send user to the OP
  76.  * header('Location: ' . $auth->getAuthorizeURL());
  77.  * exit;
  78.  *
  79.  *
  80.  *
  81.  *
  82.  * // Now, when they come back, you'll want to verify the claim ...
  83.  *
  84.  * // Assuming your $realm is the host which they came in to, build a Net_URL2
  85.  * // object from this request:
  86.  * $request = new Net_URL2($realm . $_SERVER['REQUEST_URI']);
  87.  * 
  88.  * // Now verify:
  89.  * $result = $rp->verify($request);
  90.  * if ($result->success()) {
  91.  *     echo "success! :)";
  92.  * } else {
  93.  *     echo "failure :(";
  94.  * }
  95.  * </code>
  96.  *
  97.  * @uses      OpenID
  98.  * @category  Auth
  99.  * @package   OpenID
  100.  * @author    Bill Shupp <hostmaster@shupp.org>
  101.  * @copyright 2009 Bill Shupp
  102.  * @license   http://www.opensource.org/licenses/bsd-license.php FreeBSD
  103.  * @link      http://pearopenid.googlecode.com
  104.  */
  105. class OpenID_RelyingParty extends OpenID
  106. {
  107.     /**
  108.      * The user supplied identifier, normalized
  109.      * 
  110.      * @see OpenID::normalizeIdentifier()
  111.      * @see __construct()
  112.      * @var string 
  113.      */
  114.     protected $normalizedID = null;
  115.  
  116.     /**
  117.      * The URI used for the openid.return_to parameter
  118.      * 
  119.      * @see __construct()
  120.      * @var string 
  121.      */
  122.     protected $returnTo = null;
  123.  
  124.     /**
  125.      * The URI used for the openid.realm paramater
  126.      * 
  127.      * @see __construct()
  128.      * @var string 
  129.      */
  130.     protected $realm = null;
  131.     /**
  132.      * Whether or not to use associations
  133.      * 
  134.      * @see __construct()
  135.      * @var mixed 
  136.      */
  137.     protected $useAssociations = true;
  138.  
  139.     /**
  140.      * How far off of the current time to allow for nonce checking
  141.      * 
  142.      * @see setClockSkew()
  143.      * @var int 
  144.      */
  145.     protected $clockSkew = null;
  146.  
  147.     /**
  148.      * Sets the identifier, returnTo, and realm to be used for messages.  The
  149.      * identifier is normalized before being set.
  150.      * 
  151.      * @param mixed $returnTo   The openid.return_to paramater value
  152.      * @param mixed $realm      The openid.realm paramater value
  153.      * @param mixed $identifier The user supplied identifier, defaults to null
  154.      * 
  155.      * @see OpenID::normalizeIdentifier
  156.      * @return void 
  157.      */
  158.     public function __construct($returnTo$realm$identifier null)
  159.     {
  160.         $this->returnTo = $returnTo;
  161.         $this->realm    = $realm;
  162.         if ($identifier !== null{
  163.             $this->normalizedID = OpenID::normalizeIdentifier($identifier);
  164.         }
  165.     }
  166.  
  167.     /**
  168.      * Enables the use of associations (default)
  169.      * 
  170.      * @return void 
  171.      */
  172.     public function enableAssociations()
  173.     {
  174.         $this->useAssociations = true;
  175.     }
  176.  
  177.     /**
  178.      * Disables the use if associations
  179.      * 
  180.      * @return void 
  181.      */
  182.     public function disableAssociations()
  183.     {
  184.         $this->useAssociations = false;
  185.     }
  186.  
  187.     /**
  188.      * Sets the clock skew for nonce checking
  189.      * 
  190.      * @param int $skew Skew (or timeout) in seconds
  191.      * 
  192.      * @throws OpenID_Exception if $skew is not numeric
  193.      * @return void 
  194.      */
  195.     public function setClockSkew($skew)
  196.     {
  197.         if (!is_numeric($skew)) {
  198.             throw new OpenID_Exception(
  199.                 'Invalid clock skew'
  200.             );
  201.         }
  202.         $this->clockSkew = $skew;
  203.     }
  204.  
  205.     /**
  206.      * Prepares an OpenID_Auth_Request and returns it.  This process includes
  207.      * performing discovery and optionally creating an association before preparing
  208.      * the OpenID_Auth_Request object.
  209.      * 
  210.      * @return OpenID_Auth_Request 
  211.      * @throws OpenID_Exception if no identifier was passed to the constructor
  212.      */
  213.     public function prepare()
  214.     {
  215.         if ($this->normalizedID === null{
  216.             throw new OpenID_Exception('No identifier provided');
  217.         }
  218.  
  219.         // Discover
  220.         $discover        $this->getDiscover();
  221.         $serviceEndpoint $discover->services[0];
  222.  
  223.         // Associate
  224.         $assocHandle null;
  225.         if ($this->useAssociations{
  226.             $opEndpointURL array_shift($serviceEndpoint->getURIs());
  227.             $assoc         $this->getAssociation($opEndpointURL,
  228.                                                    $serviceEndpoint->getVersion());
  229.  
  230.             if ($assoc instanceof OpenID_Association{
  231.                 $assocHandle $assoc->assocHandle;
  232.             }
  233.         }
  234.  
  235.         // Return OpenID_Auth_Request object
  236.         return new OpenID_Auth_Request($discover,
  237.                                        $this->returnTo,
  238.                                        $this->realm,
  239.                                        $assocHandle);
  240.     }
  241.  
  242.     /**
  243.      * Verifies an assertion response from the OP.  If the openid.mode is error, an
  244.      * exception is thrown.
  245.      * 
  246.      * @param Net_URL2       $requestedURL The requested URL (that the user was
  247.      *                                      directed to by the OP) as a Net_URL2
  248.      *                                      object
  249.      * @param OpenID_Message $message      The OpenID_Message instance, as extractd
  250.      *                                      from the input (GET or POST)
  251.      * 
  252.      * @throws OpenID_Exception on error or invalid openid.mode
  253.      * @return OpenID_Assertion_Response 
  254.      */
  255.     public function verify(Net_URL2 $requestedURLOpenID_Message $message)
  256.     {
  257.         // Unsolicited assertion?
  258.         if ($this->normalizedID === null{
  259.             $unsolicitedID      $message->get('openid.claimed_id');
  260.             $this->normalizedID = OpenID::normalizeIdentifier($unsolicitedID);
  261.         }
  262.  
  263.         $mode   $message->get('openid.mode');
  264.         $result new OpenID_Assertion_Result;
  265.  
  266.         OpenID::setLastEvent(__METHOD__print_r($message->getArrayFormat()true));
  267.  
  268.         switch ($mode{
  269.         case OpenID::MODE_ID_RES:
  270.             if ($message->get('openid.ns'=== null
  271.                 && $message->get('openid.user_setup_url'!== null{
  272.  
  273.                 // Negative 1.1 checkid_immediate response
  274.                 $result->setAssertionMethod($mode);
  275.                 $result->setUserSetupURL($message->get('openid.user_setup_url'));
  276.                 return $result;
  277.             }
  278.             break;
  279.         case OpenID::MODE_CANCEL:
  280.         case OpenID::MODE_SETUP_NEEDED:
  281.             $result->setAssertionMethod($mode);
  282.             return $result;
  283.         case OpenID::MODE_ERROR:
  284.             throw new OpenID_Exception($message->get('openid.error'));
  285.         default:
  286.             throw new OpenID_Exception('Unknown mode: ' $mode);
  287.         }
  288.  
  289.         $discover        $this->getDiscover();
  290.         $serviceEndpoint $discover->services[0];
  291.         $opEndpointURL   array_shift($serviceEndpoint->getURIs());
  292.         $assertion       $this->getAssertionObject($message$requestedURL);
  293.  
  294.         // Check via associations
  295.         if ($this->useAssociations{
  296.             if ($message->get('openid.invalidate_handle'=== null{
  297.                 // Don't fall back to check_authentication
  298.                 $result->setAssertionMethod(OpenID::MODE_ASSOCIATE);
  299.                 $assoc $this->getStore()
  300.                               ->getAssociation($opEndpointURL,
  301.                                                $message->get('openid.assoc_handle'));
  302.                 OpenID::setLastEvent(__METHOD__print_r($assoctrue));
  303.  
  304.                 if ($assoc instanceof OpenID_Association &&
  305.                     $assoc->checkMessageSignature($message)) {
  306.  
  307.                     $result->setAssertionResult(true);
  308.                 }
  309.  
  310.                 // If it's not an unsolicited assertion, just return
  311.                 if (!isset($unsolicitedID)) {
  312.                     return $result;
  313.                 }
  314.             }
  315.  
  316.             // Invalidate handle requested. Delete it and fall back to 
  317.             // check_authenticate
  318.             $this->getStore()->deleteAssociation($opEndpointURL);
  319.         }
  320.  
  321.         // Check via check_authenticate
  322.         $result->setAssertionMethod(OpenID::MODE_CHECK_AUTHENTICATION);
  323.         $result->setCheckAuthResponse($assertion->checkAuthentication());
  324.         if ($result->getCheckAuthResponse()->get('is_valid'== 'true'{
  325.             $result->setAssertionResult(true);
  326.         }
  327.         return $result;
  328.     }
  329.  
  330.     /**
  331.      * Gets discovered information from cache if it exists, otherwise performs
  332.      * discovery.
  333.      * 
  334.      * @throws OpenID_Exception if discovery fails
  335.      * @see OpenID_Discover::getDiscover()
  336.      * @return OpenID_Discover 
  337.      */
  338.     protected function getDiscover()
  339.     {
  340.         $discover OpenID_Discover::getDiscover($this->normalizedID,
  341.                                                  $this->getStore());
  342.         if (!$discover instanceof OpenID_Discover{
  343.             // @codeCoverageIgnoreStart
  344.             throw new OpenID_Exception('Unable to discover OP Endpoint URL');
  345.             // @codeCoverageIgnoreEnd
  346.         }
  347.  
  348.         return $discover;
  349.     }
  350.  
  351.     /**
  352.      * Gets an association from cache if it exists, otherwise, creates one.
  353.      * 
  354.      * @param string $opEndpointURL The OP Endpoint URL to communicate with
  355.      * @param string $version       The version of OpenID being used
  356.      * 
  357.      * @return OpenID_Association on success, false on failure
  358.      */
  359.     protected function getAssociation($opEndpointURL$version)
  360.     {
  361.         $assocCache $this->getStore()->getAssociation($opEndpointURL);
  362.  
  363.         if ($assocCache instanceof OpenID_Association{
  364.             return $assocCache;
  365.         }
  366.  
  367.         $assoc  $this->getAssociationRequestObject($opEndpointURL$version);
  368.         $result $assoc->associate();
  369.  
  370.         if (!$result instanceof OpenID_Association{
  371.             return false;
  372.         }
  373.  
  374.         self::getStore()->setAssociation($result);
  375.  
  376.         return $result;
  377.     }
  378.  
  379.     /**
  380.      * Gets a new OpenID_Association_Request object.  Abstracted for testing.
  381.      * 
  382.      * @param string $opEndpointURL The OP endpoint URL to communicate with
  383.      * @param string $version       The OpenID version being used
  384.      * 
  385.      * @see prepare()
  386.      * @return OpenID_Association_Request 
  387.      */
  388.     protected function getAssociationRequestObject($opEndpointURL$version)
  389.     {
  390.         return new OpenID_Association_Request($opEndpointURL$version);
  391.     }
  392.  
  393.     /**
  394.      * Gets an instance of OpenID_Assertion.  Abstracted for testing purposes.
  395.      * 
  396.      * @param OpenID_Message $message      The message passed to verify()
  397.      * @param Net_URL2       $requestedURL The URL requested (redirect from OP)
  398.      * 
  399.      * @see    verify()
  400.      * @return OpenID_Assertion 
  401.      */
  402.     protected function getAssertionObject($message$requestedURL)
  403.     {
  404.         return new OpenID_Assertion($message,
  405.                                     $requestedURL,
  406.                                     $this->clockSkew);
  407.     }
  408. }
  409. ?>

Documentation generated on Tue, 15 Dec 2009 19:00:57 -0800 by phpDocumentor 1.4.3