Source for file Assertion.php

Documentation is available at Assertion.php

  1. <?php
  2. /**
  3.  * OpenID_Assertion
  4.  * 
  5.  * PHP Version 5.2.0+
  6.  * 
  7.  * @category  Auth
  8.  * @package   OpenID
  9.  * @author    Bill Shupp <hostmaster@shupp.org>
  10.  * @copyright 2009 Bill Shupp
  11.  * @license   http://www.opensource.org/licenses/bsd-license.php FreeBSD
  12.  * @link      http://pearopenid.googlecode.com
  13.  */
  14.  
  15. /**
  16.  * Required files
  17.  */
  18. require_once 'OpenID.php';
  19. require_once 'OpenID/Discover.php';
  20. require_once 'OpenID/Assertion/Exception.php';
  21. require_once 'OpenID/Assertion/Exception/NoClaimedID.php';
  22. require_once 'OpenID/Message.php';
  23. require_once 'OpenID/Nonce.php';
  24. require_once 'Validate.php';
  25. require_once 'Net/URL2.php';
  26.  
  27. /**
  28.  * Class for verifying assertions.  Does basic validation (nonce, return_to, etc),
  29.  * as well as signature verification and check_authentication.
  30.  * 
  31.  * @category  Auth
  32.  * @package   OpenID
  33.  * @author    Bill Shupp <hostmaster@shupp.org>
  34.  * @copyright 2009 Bill Shupp
  35.  * @license   http://www.opensource.org/licenses/bsd-license.php FreeBSD
  36.  * @link      http://pearopenid.googlecode.com
  37.  */
  38. class OpenID_Assertion extends OpenID
  39. {
  40.     /**
  41.      * Response message passed to the constructor
  42.      * 
  43.      * @var OpenID_Message 
  44.      */
  45.     protected $message = null;
  46.  
  47.     /**
  48.      * The URL of the current request (to compare with openid.return_to)
  49.      * 
  50.      * @var string 
  51.      */
  52.     protected $requestedURL = null;
  53.  
  54.     /**
  55.      * The clock skew limit for checking nonces.
  56.      * 
  57.      * @var int (in seconds)
  58.      */
  59.     protected $clockSkew = null;
  60.  
  61.     /**
  62.      * Sets the request message, url, and clock skew.  Then does some basic
  63.      * validation (return_to, nonce, discover).
  64.      * 
  65.      * @param OpenID_Message $message      Message from the request
  66.      * @param Net_URL2       $requestedURL The requested URL
  67.      * @param int            $clockSkew    Nonce clock skew in seconds
  68.      * 
  69.      * @return void 
  70.      */
  71.     public function __construct(OpenID_Message $message,
  72.                                 Net_URL2 $requestedURL,
  73.                                 $clockSkew null)
  74.     {
  75.         $this->message      = $message;
  76.         $this->requestedURL = $requestedURL;
  77.         $this->clockSkew    = $clockSkew;
  78.  
  79.         // Don't check return_to for a negative checkid_immadiate 1.1 response
  80.         if ($message->get('openid.ns'!== null
  81.             || $message->get('openid.user_setup_url'=== null{
  82.  
  83.             $this->validateReturnTo();
  84.         }
  85.  
  86.         if ($message->get('openid.ns'!== null{
  87.             $this->validateDiscover();
  88.             $this->validateNonce();
  89.         else {
  90.             $this->validateReturnToNonce();
  91.         }
  92.     }
  93.  
  94.     /**
  95.      * Verifies the signature of this message association.
  96.      * 
  97.      * @param OpenID_Association $assoc Association to use for checking the signature
  98.      * 
  99.      * @return bool result of OpenID_Association::checkMessageSignature()
  100.      * @see OpenID_Association::checkMessageSignature()
  101.      */
  102.     public function verifySignature(OpenID_Association $assoc)
  103.     {
  104.         return $assoc->checkMessageSignature($this->message);
  105.     }
  106.     
  107.     /**
  108.      * Performs a check_authentication request.
  109.      * 
  110.      * @param array $options Options to pass to HTTP_Request
  111.      * 
  112.      * @return OpenID_Message Reponse to the check_authentication request
  113.      */
  114.     public function checkAuthentication(array $options array())
  115.     {
  116.         $this->message->set('openid.mode'OpenID::MODE_CHECK_AUTHENTICATION);
  117.  
  118.         $opURL    $this->message->get('openid.op_endpoint');
  119.         $response $this->directRequest($opURL$this->message$options);
  120.  
  121.         return new OpenID_Message($response->getBody()OpenID_Message::FORMAT_KV);
  122.     }
  123.  
  124.     /**
  125.      * Validates the openid.return_to parameter in the response.
  126.      * 
  127.      * @return void 
  128.      * @throws OpenID_Assertion_Exception on failure
  129.      */
  130.     protected function validateReturnTo()
  131.     {
  132.         $returnTo $this->message->get('openid.return_to');
  133.         OpenID::setLastEvent(__METHOD__,
  134.                              'openid.return_to: ' var_export($returnTotrue));
  135.  
  136.         // Validate openid.return_to
  137.         if (!Validate::uri($returnTo)) {
  138.             throw new OpenID_Assertion_Exception(
  139.                 'openid.return_to parameter is invalid or missing'
  140.             );
  141.         }
  142.  
  143.         $obj1 new Net_URL2($returnTo);
  144.         $obj2 $this->requestedURL;
  145.  
  146.         $queryString1 $obj1->getQueryVariables();
  147.         $queryString2 $obj2->getQueryVariables();
  148.  
  149.         $obj1->setQueryVariables(array());
  150.         $obj2->setQueryVariables(array());
  151.  
  152.         if ($obj1->getURL(!= $obj2->getURL()) {
  153.             throw new OpenID_Assertion_Exception(
  154.                 'openid.return_to does not match the requested URL'
  155.             );
  156.         }
  157.  
  158.         if (!count($queryString1&& !count($queryString2)) {
  159.             return;
  160.         }
  161.  
  162.         foreach ($queryString1 as $param => $value{
  163.             if (!isset($queryString2[$param])
  164.                 || $queryString2[$param!= $value{
  165.  
  166.                 throw new OpenID_Assertion_Exception(
  167.                     'openid.return_to parameters do not match requested url'
  168.                 );
  169.             }
  170.         }
  171.     }
  172.  
  173.     /**
  174.      * Validates and performs discovery on the openid.claimed_id paramter.
  175.      * 
  176.      * @return void 
  177.      * @throws OpenID_Assertion_Exception on failure
  178.      */
  179.     protected function validateDiscover()
  180.     {
  181.         $claimedID $this->message->get('openid.claimed_id');
  182.         if ($claimedID === null{
  183.             throw new OpenID_Assertion_Exception_NoClaimedID(
  184.                 'No claimed_id in message'
  185.             );
  186.         }
  187.  
  188.         if ($claimedID === OpenID::SERVICE_2_0_SERVER{
  189.             throw new OpenID_Assertion_Exception(
  190.                 'Claimed identifier cannot be an OP identifier'
  191.             );
  192.         }
  193.  
  194.         $url new Net_URL2($claimedID);
  195.         // Remove the fragment, per the spec
  196.         $url->setFragment(false);
  197.  
  198.         $discover $this->getDiscover($url->getURL());
  199.         if (!$discover instanceof OpenID_Discover{
  200.             throw new OpenID_Assertion_Exception(
  201.                 'Unable to discover claimed_id'
  202.             );
  203.         }
  204.  
  205.         $opURL array_shift($discover->services[0]->getURIs());
  206.         if ($opURL !== $this->message->get('openid.op_endpoint')) {
  207.             throw new OpenID_Assertion_Exception(
  208.                 'This OP is not authorized to issue assertions for this claimed id'
  209.             );
  210.         }
  211.     }
  212.  
  213.     /**
  214.      * Validates the openid.response_nonce parameter.
  215.      * 
  216.      * @return void 
  217.      * @throws OpenID_Assertion_Exception on invalid or existing nonce
  218.      */
  219.     protected function validateNonce()
  220.     {
  221.         $opURL         $this->message->get('openid.op_endpoint');
  222.         $responseNonce $this->message->get('openid.response_nonce');
  223.  
  224.         $nonce new OpenID_Nonce($opURL$this->clockSkew);
  225.         if (!$nonce->verifyResponseNonce($responseNonce)) {
  226.             throw new OpenID_Assertion_Exception(
  227.                 'Invalid or already existing response_nonce'
  228.             );
  229.         }
  230.     }
  231.  
  232.     /**
  233.      * Validates the nonce embedded in the openid.return_to paramater and deletes
  234.      * it from storage.. (For use with OpenID 1.1 only)
  235.      * 
  236.      * @return void 
  237.      * @throws OpenID_Assertion_Exception on invalid or non-existing nonce
  238.      */
  239.     protected function validateReturnToNonce()
  240.     {
  241.         $returnTo $this->message->get('openid.return_to');
  242.         if ($returnTo === null{
  243.             // Must be a checkid_immediate negative assertion.
  244.             $rtURL2   new Net_URL2($this->message->get('openid.user_setup_url'));
  245.             $rtqs     $rtURL2->getQueryVariables();
  246.             $returnTo $rtqs['openid.return_to'];
  247.             $identity $rtqs['openid.identity'];
  248.         }
  249.         $netURL new Net_URL2($returnTo);
  250.         $qs     $netURL->getQueryVariables();
  251.         if (!array_key_exists(OpenID_Nonce::RETURN_TO_NONCE$qs)) {
  252.             throw new OpenID_Assertion_Exception(
  253.                 'Missing OpenID 1.1 return_to nonce'
  254.             );
  255.         }
  256.  
  257.         if (!isset($identity)) {
  258.             $identity $this->message->get('openid.identity');
  259.         }
  260.         $nonce     $qs[OpenID_Nonce::RETURN_TO_NONCE];
  261.         $discover  $this->getDiscover($identity);
  262.         $endPoint  $discover->services[0];
  263.         $opURL     array_shift($endPoint->getURIs());
  264.         $fromStore self::getStore()->getNonce(urldecode($nonce)$opURL);
  265.  
  266.         // Observing
  267.         $logMessage  "returnTo: $returnTo\n";
  268.         $logMessage .= 'OP URIs: ' print_r($endPoint->getURIs()true"\n";
  269.         $logMessage .= 'Nonce in storage?: ' var_export($fromStoretrue"\n";
  270.         OpenID::setLastEvent(__METHOD__$logMessage);
  271.  
  272.         if (!$fromStore{
  273.             throw new OpenID_Assertion_Exception(
  274.                 'Invalid OpenID 1.1 return_to nonce in response'
  275.             );
  276.         }
  277.  
  278.         self::getStore()->deleteNonce($nonce$opURL);
  279.     }
  280.  
  281.     /**
  282.      * Gets an instance of OpenID_Discover.  Abstracted for testing.
  283.      * 
  284.      * @param string $identifier OpenID Identifier
  285.      * 
  286.      * @return OpenID_Discover|false
  287.      */
  288.     protected function getDiscover($identifier)
  289.     {
  290.         return OpenID_Discover::getDiscover($identifierself::getStore());
  291.     }
  292. }
  293. ?>

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