Source for file Association.php

Documentation is available at Association.php

  1. <?php
  2. /**
  3.  * OpenID_Association
  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/Association/Exception.php';
  19. require_once 'OpenID.php';
  20. require_once 'OpenID/Message.php';
  21. require_once 'Validate.php';
  22.  
  23. /**
  24.  * OpenID_Association
  25.  * 
  26.  * A class that represents an association.  This class can be serialized for
  27.  * storage.  It also allows you to add and check signatures of an OpenID_Message.
  28.  * 
  29.  * @category  Auth
  30.  * @package   OpenID
  31.  * @author    Bill Shupp <hostmaster@shupp.org>
  32.  * @copyright 2009 Bill Shupp
  33.  * @license   http://www.opensource.org/licenses/bsd-license.php FreeBSD
  34.  * @link      http://pearopenid.googlecode.com
  35.  * @see       OpenID_Association_Request::buildRequest()
  36.  */
  37. {
  38.     /**
  39.      * URI of the OP Endpoint
  40.      * 
  41.      * @var string 
  42.      */
  43.     protected $uri = null;
  44.  
  45.     /**
  46.      * expires_in paramater of the association.  Time is in seconds.
  47.      * 
  48.      * @var mixed 
  49.      */
  50.     protected $expiresIn = null;
  51.  
  52.     /**
  53.      * Unix timestamp of when this association was created.
  54.      * 
  55.      * @var int 
  56.      */
  57.     protected $created = null;
  58.  
  59.     /**
  60.      * assoc_type parameter of the association.  Should be one of HMAC-SHA1 or
  61.      * HMAC-SHA256
  62.      * 
  63.      * @var string 
  64.      */
  65.     protected $assocType = null;
  66.  
  67.     /**
  68.      * assoc_handle parameter of the association.
  69.      * 
  70.      * @var string 
  71.      */
  72.     protected $assocHandle = null;
  73.  
  74.     /**
  75.      * In the association response, this is also referred to as the "mac_key", or is
  76.      * derived from the "enc_mac_key" if the session used encryption.
  77.      * 
  78.      * @var mixed 
  79.      */
  80.     protected $sharedSecret = null;
  81.  
  82.     /**
  83.      * Required parameters for storing an association.
  84.      * 
  85.      * @see __construct()
  86.      * @var array 
  87.      */
  88.     protected $requiredParams = array(
  89.         'uri',
  90.         'expiresIn',
  91.         'created',
  92.         'assocType',
  93.         'assocHandle',
  94.         'sharedSecret'
  95.     );
  96.  
  97.     /**
  98.      * Local list of supported association types.
  99.      * 
  100.      * @see $assocType
  101.      * @see __construct()
  102.      * @var array 
  103.      */
  104.     protected $supportedTypes = array(
  105.         OpenID::ASSOC_TYPE_HMAC_SHA1,
  106.         OpenID::ASSOC_TYPE_HMAC_SHA256
  107.     );
  108.  
  109.     /**
  110.      * Validates some association values before setting them as member variables.
  111.      * 
  112.      * @param array $params Array of relevant parameters from the association
  113.      *                       response
  114.      * 
  115.      * @throws OpenID_Association_Exception if the response is not valid
  116.      * @return void 
  117.      */
  118.     public function __construct(array $params)
  119.     {
  120.         // Make sure required params are present
  121.         foreach ($this->requiredParams as $key{
  122.             if (!isset($params[$key])) {
  123.                 throw new OpenID_Association_Exception(
  124.                     "Missing parameter: $key"
  125.                 );
  126.             }
  127.         }
  128.  
  129.         // Validate URI
  130.         if (!Validate::uri($params['uri'])) {
  131.             throw new OpenID_Association_Exception(
  132.                 "Invalid uri: " $params['uri']
  133.             );
  134.         }
  135.  
  136.         // Validate assocType
  137.         if (!in_array(strtoupper($params['assocType'])$this->supportedTypes)) {
  138.             throw new OpenID_Association_Exception(
  139.                 "Invalid association type: " $params['assocType']
  140.             );
  141.         }
  142.  
  143.         // Set values
  144.         reset($this->requiredParams);
  145.         foreach ($this->requiredParams as $key{
  146.             $this->$key $params[$key];
  147.         }
  148.     }
  149.  
  150.     /**
  151.      * Allows access to association data via $assoc->name
  152.      * 
  153.      * @param string $name Name of the item to get
  154.      * 
  155.      * @return mixed Value
  156.      */
  157.     public function __get($name)
  158.     {
  159.         return $this->$name;
  160.     }
  161.  
  162.     /**
  163.      * Gets the algo part of the assoc_type (strips 'HMAC-')
  164.      * 
  165.      * @return string Algorithm part of the assoc_type handle
  166.      */
  167.     public function getAlgorithm()
  168.     {
  169.         return str_replace('HMAC-'''$this->assocType);
  170.     }
  171.  
  172.     /**
  173.      * Checks the signature of an OpenID_Message using this association
  174.      * 
  175.      * @param OpenID_Message $message Instance of OpenID_Message
  176.      * 
  177.      * @throws OpenID_Association_Exception if the handles don't match
  178.      * @return bool true if the signatures match, false otherwise
  179.      */
  180.     public function checkMessageSignature(OpenID_Message $message)
  181.     {
  182.         // Make sure the handles match for this OP and response
  183.         if ($this->assocHandle != $message->get('openid.assoc_handle')) {
  184.  
  185.             throw new OpenID_Association_Exception(
  186.                 'Association handles do not match'
  187.             );
  188.         }
  189.  
  190.         // Make sure the OP Endpoints match for this association and response
  191.         if ($this->uri != $message->get('openid.op_endpoint')) {
  192.  
  193.             throw new OpenID_Association_Exception(
  194.                 'Endpoint URLs do not match'
  195.             );
  196.         }
  197.  
  198.         if (!strlen($message->get('openid.signed'))) {
  199.             OpenID::setLastEvent(__METHOD__'openid.signed is empty');
  200.             return false;
  201.         }
  202.         $list explode(','$message->get('openid.signed'));
  203.  
  204.         // Create a message with only keys in the signature
  205.         $signedOnly $this->getMessageForSigning($message);
  206.  
  207.         $signedOnlyDigest base64_encode($this->hashHMAC($signedOnly));
  208.  
  209.         $event array(
  210.             'assocHandle'       => $this->assocHandle,
  211.             'algo'              => $this->getAlgorithm(),
  212.             'secret'            => $this->sharedSecret,
  213.             'openid.sig'        => $message->get('openid.sig'),
  214.             'signature'         => $signedOnlyDigest,
  215.             'SignedKVFormat'    => $signedOnly,
  216.             'MessageHTTPFormat' => $message->getHTTPFormat(),
  217.             'phpInput'          => file_get_contents('php://input')
  218.         );
  219.         OpenID::setLastEvent(__METHOD__print_r($eventtrue));
  220.  
  221.         return $signedOnlyDigest == $message->get('openid.sig');
  222.     }
  223.  
  224.     /**
  225.      * Returns a KV formatted message for signing based on the contents of the
  226.      * openid.signed key.  This allows for duplicate entries, which
  227.      * OpenID_Message::getKVFormat() doesn't.  (Yahoo! uses duplicates)
  228.      * 
  229.      * @param OpenID_Message $message An instance of the OpenID_Message you want to
  230.      *                                 sign
  231.      * 
  232.      * @return string The openid.signed items in KV form
  233.      */
  234.     public function getMessageForSigning(OpenID_Message $message)
  235.     {
  236.         $list explode(','$message->get('openid.signed'));
  237.  
  238.         $signedOnly '';
  239.         foreach ($list as $key{
  240.             $signedOnly .= "$key:$message->get('openid.' $key"\n";
  241.         }
  242.         return $signedOnly;
  243.     }
  244.  
  245.     /**
  246.      * Signs an OpenID_Message instance
  247.      * 
  248.      * @param OpenID_Message $message Message to be signed
  249.      * 
  250.      * @throws OpenID_Association_Exception if the message is already signed,
  251.                or the association handles do not match
  252.      * @return void 
  253.      */
  254.     public function signMessage(OpenID_Message $message)
  255.     {
  256.         if ($message->get('openid.sig'!== null ||
  257.             $message->get('openid.signed'!== null{
  258.             throw new OpenID_Association_Exception(
  259.                 'This message appears to be already signed'
  260.             );
  261.         }
  262.  
  263.         // Make sure the handles match for this OP and response
  264.         if ($this->assocHandle != $message->get('openid.assoc_handle')) {
  265.  
  266.             throw new OpenID_Association_Exception(
  267.                 'Association handles do not match'
  268.             );
  269.         }
  270.  
  271.         $keys array('signed');
  272.         foreach ($message->getArrayFormat(as $key => $val{
  273.             if (strncmp('openid.'$key7== 0{
  274.                 $keys[substr($key7);
  275.             }
  276.         }
  277.         sort($keys);
  278.         $message->set('openid.signed'implode(','$keys));
  279.  
  280.         $signedMessage new OpenID_Message;
  281.  
  282.         foreach ($keys as $key{
  283.             $signedMessage->set($key$message->get('openid.' $key));
  284.         }
  285.  
  286.         $rawSignature $this->hashHMAC($signedMessage->getKVFormat());
  287.  
  288.         $message->set('openid.sig'base64_encode($rawSignature));
  289.     }
  290.  
  291.     /**
  292.      * Gets a an HMAC hash of an OpenID_Message using this association.
  293.      * 
  294.      * @param OpenID_Message $message The message format of the items to hash
  295.      * 
  296.      * @return string The HMAC hash
  297.      */
  298.     protected function hashHMAC($message)
  299.     {
  300.         return hash_hmac($this->getAlgorithm(),
  301.                          $message,
  302.                          base64_decode($this->sharedSecret),
  303.                          true);
  304.     }
  305. }
  306. ?>

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