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/Association.php

Documentation is available at Association.php

  1. <?php
  2.  
  3. /**
  4.  * This module contains code for dealing with associations between
  5.  * consumers and servers.
  6.  *
  7.  * PHP versions 4 and 5
  8.  *
  9.  * LICENSE: See the COPYING file included in this distribution.
  10.  *
  11.  * @package OpenID
  12.  * @author JanRain, Inc. <openid@janrain.com>
  13.  * @copyright 2005-2008 Janrain, Inc.
  14.  * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
  15.  */
  16.  
  17. // Do not allow direct access
  18. defined'_JEXEC' or die'Restricted access' );
  19.  
  20. /**
  21.  * @access private
  22.  */
  23. require_once 'Auth/OpenID/CryptUtil.php';
  24.  
  25. /**
  26.  * @access private
  27.  */
  28. require_once 'Auth/OpenID/KVForm.php';
  29.  
  30. /**
  31.  * @access private
  32.  */
  33. require_once 'Auth/OpenID/HMAC.php';
  34.  
  35. /**
  36.  * This class represents an association between a server and a
  37.  * consumer.  In general, users of this library will never see
  38.  * instances of this object.  The only exception is if you implement a
  39.  * custom {@link Auth_OpenID_OpenIDStore}.
  40.  *
  41.  * If you do implement such a store, it will need to store the values
  42.  * of the handle, secret, issued, lifetime, and assoc_type instance
  43.  * variables.
  44.  *
  45.  * @package OpenID
  46.  */
  47.  
  48.     /**
  49.      * This is a HMAC-SHA1 specific value.
  50.      *
  51.      * @access private
  52.      */
  53.     var $SIG_LENGTH 20;
  54.  
  55.     /**
  56.      * The ordering and name of keys as stored by serialize.
  57.      *
  58.      * @access private
  59.      */
  60.     var $assoc_keys array(
  61.                             'version',
  62.                             'handle',
  63.                             'secret',
  64.                             'issued',
  65.                             'lifetime',
  66.                             'assoc_type'
  67.                             );
  68.  
  69.     var $_macs = array(
  70.                        'HMAC-SHA1' => 'Auth_OpenID_HMACSHA1',
  71.                        'HMAC-SHA256' => 'Auth_OpenID_HMACSHA256'
  72.                        );
  73.  
  74.     /**
  75.      * This is an alternate constructor (factory method) used by the
  76.      * OpenID consumer library to create associations.  OpenID store
  77.      * implementations shouldn't use this constructor.
  78.      *
  79.      * @access private
  80.      *
  81.      * @param integer $expires_in This is the amount of time this
  82.      *  association is good for, measured in seconds since the
  83.      *  association was issued.
  84.      *
  85.      * @param string $handle This is the handle the server gave this
  86.      *  association.
  87.      *
  88.      * @param string secret This is the shared secret the server
  89.      *  generated for this association.
  90.      *
  91.      * @param assoc_type This is the type of association this
  92.      *  instance represents.  The only valid values of this field at
  93.      *  this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may
  94.      *  be defined in the future.
  95.      *
  96.      * @return association An {@link Auth_OpenID_Association}
  97.      *  instance.
  98.      */
  99.     function fromExpiresIn($expires_in$handle$secret$assoc_type)
  100.     {
  101.         $issued time();
  102.         $lifetime $expires_in;
  103.         return new Auth_OpenID_Association($handle$secret,
  104.                                            $issued$lifetime$assoc_type);
  105.     }
  106.  
  107.     /**
  108.      * This is the standard constructor for creating an association.
  109.      * The library should create all of the necessary associations, so
  110.      * this constructor is not part of the external API.
  111.      *
  112.      * @access private
  113.      *
  114.      * @param string $handle This is the handle the server gave this
  115.      *  association.
  116.      *
  117.      * @param string $secret This is the shared secret the server
  118.      *  generated for this association.
  119.      *
  120.      * @param integer $issued This is the time this association was
  121.      *  issued, in seconds since 00:00 GMT, January 1, 1970.  (ie, a
  122.      *  unix timestamp)
  123.      *
  124.      * @param integer $lifetime This is the amount of time this
  125.      *  association is good for, measured in seconds since the
  126.      *  association was issued.
  127.      *
  128.      * @param string $assoc_type This is the type of association this
  129.      *  instance represents.  The only valid values of this field at
  130.      *  this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may
  131.      *  be defined in the future.
  132.      */
  133.     function Auth_OpenID_Association(
  134.         $handle$secret$issued$lifetime$assoc_type)
  135.     {
  136.         if (!in_array($assoc_type,
  137.                       Auth_OpenID_getSupportedAssociationTypes())) {
  138.             $fmt 'Unsupported association type (%s)';
  139.             trigger_error(sprintf($fmt$assoc_type)E_USER_ERROR);
  140.         }
  141.  
  142.         $this->handle $handle;
  143.         $this->secret $secret;
  144.         $this->issued $issued;
  145.         $this->lifetime $lifetime;
  146.         $this->assoc_type $assoc_type;
  147.     }
  148.  
  149.     /**
  150.      * This returns the number of seconds this association is still
  151.      * valid for, or 0 if the association is no longer valid.
  152.      *
  153.      * @return integer $seconds The number of seconds this association
  154.      *  is still valid for, or 0 if the association is no longer valid.
  155.      */
  156.     function getExpiresIn($now null)
  157.     {
  158.         if ($now == null{
  159.             $now time();
  160.         }
  161.  
  162.         return max(0$this->issued $this->lifetime $now);
  163.     }
  164.  
  165.     /**
  166.      * This checks to see if two {@link Auth_OpenID_Association}
  167.      * instances represent the same association.
  168.      *
  169.      * @return bool $result true if the two instances represent the
  170.      *  same association, false otherwise.
  171.      */
  172.     function equal($other)
  173.     {
  174.         return ((gettype($this== gettype($other))
  175.                 && ($this->handle == $other->handle)
  176.                 && ($this->secret == $other->secret)
  177.                 && ($this->issued == $other->issued)
  178.                 && ($this->lifetime == $other->lifetime)
  179.                 && ($this->assoc_type == $other->assoc_type));
  180.     }
  181.  
  182.     /**
  183.      * Convert an association to KV form.
  184.      *
  185.      * @return string $result String in KV form suitable for
  186.      *  deserialization by deserialize.
  187.      */
  188.     function serialize()
  189.     {
  190.         $data array(
  191.                      'version' => '2',
  192.                      'handle' => $this->handle,
  193.                      'secret' => base64_encode($this->secret),
  194.                      'issued' => strval(intval($this->issued)),
  195.                      'lifetime' => strval(intval($this->lifetime)),
  196.                      'assoc_type' => $this->assoc_type
  197.                      );
  198.  
  199.         assert(array_keys($data== $this->assoc_keys);
  200.  
  201.         return Auth_OpenID_KVForm::fromArray($data$strict true);
  202.     }
  203.  
  204.     /**
  205.      * Parse an association as stored by serialize().  This is the
  206.      * inverse of serialize.
  207.      *
  208.      * @param string $assoc_s Association as serialized by serialize()
  209.      * @return Auth_OpenID_Association $result instance of this class
  210.      */
  211.     function deserialize($class_name$assoc_s)
  212.     {
  213.         $pairs Auth_OpenID_KVForm::toArray($assoc_s$strict true);
  214.         $keys array();
  215.         $values array();
  216.         foreach ($pairs as $key => $value{
  217.             if (is_array($value)) {
  218.                 list($key$value$value;
  219.             }
  220.             $keys[$key;
  221.             $values[$value;
  222.         }
  223.  
  224.         $class_vars get_class_vars($class_name);
  225.         $class_assoc_keys $class_vars['assoc_keys'];
  226.  
  227.         sort($keys);
  228.         sort($class_assoc_keys);
  229.  
  230.         if ($keys != $class_assoc_keys{
  231.             trigger_error('Unexpected key values: ' var_export($keystrue),
  232.                           E_USER_WARNING);
  233.             return null;
  234.         }
  235.  
  236.         $version $pairs['version'];
  237.         $handle $pairs['handle'];
  238.         $secret $pairs['secret'];
  239.         $issued $pairs['issued'];
  240.         $lifetime $pairs['lifetime'];
  241.         $assoc_type $pairs['assoc_type'];
  242.  
  243.         if ($version != '2'{
  244.             trigger_error('Unknown version: ' $versionE_USER_WARNING);
  245.             return null;
  246.         }
  247.  
  248.         $issued intval($issued);
  249.         $lifetime intval($lifetime);
  250.         $secret base64_decode($secret);
  251.  
  252.         return new $class_name(
  253.             $handle$secret$issued$lifetime$assoc_type);
  254.     }
  255.  
  256.     /**
  257.      * Generate a signature for a sequence of (key, value) pairs
  258.      *
  259.      * @access private
  260.      * @param array $pairs The pairs to sign, in order.  This is an
  261.      *  array of two-tuples.
  262.      * @return string $signature The binary signature of this sequence
  263.      *  of pairs
  264.      */
  265.     function sign($pairs)
  266.     {
  267.         $kv Auth_OpenID_KVForm::fromArray($pairs);
  268.  
  269.         /* Invalid association types should be caught at constructor */
  270.         $callback $this->_macs[$this->assoc_type];
  271.  
  272.         return call_user_func_array($callbackarray($this->secret$kv));
  273.     }
  274.  
  275.     /**
  276.      * Generate a signature for some fields in a dictionary
  277.      *
  278.      * @access private
  279.      * @param array $fields The fields to sign, in order; this is an
  280.      *  array of strings.
  281.      * @param array $data Dictionary of values to sign (an array of
  282.      *  string => string pairs).
  283.      * @return string $signature The signature, base64 encoded
  284.      */
  285.     function signMessage($message)
  286.     {
  287.         if ($message->hasKey(Auth_OpenID_OPENID_NS'sig'||
  288.             $message->hasKey(Auth_OpenID_OPENID_NS'signed')) {
  289.             // Already has a sig
  290.             return null;
  291.         }
  292.  
  293.         $extant_handle $message->getArg(Auth_OpenID_OPENID_NS,
  294.                                           'assoc_handle');
  295.  
  296.         if ($extant_handle && ($extant_handle != $this->handle)) {
  297.             // raise ValueError("Message has a different association handle")
  298.             return null;
  299.         }
  300.  
  301.         $signed_message $message;
  302.         $signed_message->setArg(Auth_OpenID_OPENID_NS'assoc_handle',
  303.                                 $this->handle);
  304.  
  305.         $message_keys array_keys($signed_message->toPostArgs());
  306.         $signed_list array();
  307.         $signed_prefix 'openid.';
  308.  
  309.         foreach ($message_keys as $k{
  310.             if (strpos($k$signed_prefix=== 0{
  311.                 $signed_list[substr($kstrlen($signed_prefix));
  312.             }
  313.         }
  314.  
  315.         $signed_list['signed';
  316.         sort($signed_list);
  317.  
  318.         $signed_message->setArg(Auth_OpenID_OPENID_NS'signed',
  319.                                 implode(','$signed_list));
  320.         $sig $this->getMessageSignature($signed_message);
  321.         $signed_message->setArg(Auth_OpenID_OPENID_NS'sig'$sig);
  322.         return $signed_message;
  323.     }
  324.  
  325.     /**
  326.      * Given a {@link Auth_OpenID_Message}, return the key/value pairs
  327.      * to be signed according to the signed list in the message.  If
  328.      * the message lacks a signed list, return null.
  329.      *
  330.      * @access private
  331.      */
  332.     function _makePairs(&$message)
  333.     {
  334.         $signed $message->getArg(Auth_OpenID_OPENID_NS'signed');
  335.         if (!$signed || Auth_OpenID::isFailure($signed)) {
  336.             // raise ValueError('Message has no signed list: %s' % (message,))
  337.             return null;
  338.         }
  339.  
  340.         $signed_list explode(','$signed);
  341.         $pairs array();
  342.         $data $message->toPostArgs();
  343.         foreach ($signed_list as $field{
  344.             $pairs[array($fieldAuth_OpenID::arrayGet($data,
  345.                                                            'openid.' .
  346.                                                            $field''));
  347.         }
  348.         return $pairs;
  349.     }
  350.  
  351.     /**
  352.      * Given an {@link Auth_OpenID_Message}, return the signature for
  353.      * the signed list in the message.
  354.      *
  355.      * @access private
  356.      */
  357.     function getMessageSignature(&$message)
  358.     {
  359.         $pairs $this->_makePairs($message);
  360.         return base64_encode($this->sign($pairs));
  361.     }
  362.  
  363.     /**
  364.      * Confirm that the signature of these fields matches the
  365.      * signature contained in the data.
  366.      *
  367.      * @access private
  368.      */
  369.     function checkMessageSignature(&$message)
  370.     {
  371.         $sig $message->getArg(Auth_OpenID_OPENID_NS,
  372.                                 'sig');
  373.  
  374.         if (!$sig || Auth_OpenID::isFailure($sig)) {
  375.             return false;
  376.         }
  377.  
  378.         $calculated_sig $this->getMessageSignature($message);
  379.         return $calculated_sig == $sig;
  380.     }
  381. }
  382.  
  383. function Auth_OpenID_getSecretSize($assoc_type)
  384. {
  385.     if ($assoc_type == 'HMAC-SHA1'{
  386.         return 20;
  387.     else if ($assoc_type == 'HMAC-SHA256'{
  388.         return 32;
  389.     else {
  390.         return null;
  391.     }
  392. }
  393.  
  394. {
  395.     return array('HMAC-SHA1''HMAC-SHA256');
  396. }
  397.  
  398. {
  399.     $a array('HMAC-SHA1');
  400.  
  401.     if (Auth_OpenID_HMACSHA256_SUPPORTED{
  402.         $a['HMAC-SHA256';
  403.     }
  404.  
  405.     return $a;
  406. }
  407.  
  408. function Auth_OpenID_getSessionTypes($assoc_type)
  409. {
  410.     $assoc_to_session array(
  411.        'HMAC-SHA1' => array('DH-SHA1''no-encryption'));
  412.  
  413.     if (Auth_OpenID_HMACSHA256_SUPPORTED{
  414.         $assoc_to_session['HMAC-SHA256'=
  415.             array('DH-SHA256''no-encryption');
  416.     }
  417.  
  418.     return Auth_OpenID::arrayGet($assoc_to_session$assoc_typearray());
  419. }
  420.  
  421. function Auth_OpenID_checkSessionType($assoc_type$session_type)
  422. {
  423.     if (!in_array($session_type,
  424.                   Auth_OpenID_getSessionTypes($assoc_type))) {
  425.         return false;
  426.     }
  427.  
  428.     return true;
  429. }
  430.  
  431. {
  432.     $order array();
  433.  
  434.     if (!Auth_OpenID_noMathSupport()) {
  435.         $order[array('HMAC-SHA1''DH-SHA1');
  436.  
  437.         if (Auth_OpenID_HMACSHA256_SUPPORTED{
  438.             $order[array('HMAC-SHA256''DH-SHA256');
  439.         }
  440.     }
  441.  
  442.     $order[array('HMAC-SHA1''no-encryption');
  443.  
  444.     if (Auth_OpenID_HMACSHA256_SUPPORTED{
  445.         $order[array('HMAC-SHA256''no-encryption');
  446.     }
  447.  
  448.     return $order;
  449. }
  450.  
  451. {
  452.     $result array();
  453.  
  454.     foreach (Auth_OpenID_getDefaultAssociationOrder(as $pair{
  455.         list($assoc$session$pair;
  456.  
  457.         if ($session != 'no-encryption'{
  458.             if (Auth_OpenID_HMACSHA256_SUPPORTED &&
  459.                 ($assoc == 'HMAC-SHA256')) {
  460.                 $result[$pair;
  461.             else if ($assoc != 'HMAC-SHA256'{
  462.                 $result[$pair;
  463.             }
  464.         }
  465.     }
  466.  
  467.     return $result;
  468. }
  469.  
  470. {
  471.     $x new Auth_OpenID_SessionNegotiator(
  472.                  Auth_OpenID_getDefaultAssociationOrder());
  473.     return $x;
  474. }
  475.  
  476. {
  477.     $x new Auth_OpenID_SessionNegotiator(
  478.                  Auth_OpenID_getOnlyEncryptedOrder());
  479.     return $x;
  480. }
  481.  
  482. /**
  483.  * A session negotiator controls the allowed and preferred association
  484.  * types and association session types. Both the {@link }
  485.  * Auth_OpenID_Consumer} and {@link Auth_OpenID_Server} use
  486.  * negotiators when creating associations.
  487.  *
  488.  * You can create and use negotiators if you:
  489.  
  490.  * - Do not want to do Diffie-Hellman key exchange because you use
  491.  * transport-layer encryption (e.g. SSL)
  492.  *
  493.  * - Want to use only SHA-256 associations
  494.  *
  495.  * - Do not want to support plain-text associations over a non-secure
  496.  * channel
  497.  *
  498.  * It is up to you to set a policy for what kinds of associations to
  499.  * accept. By default, the library will make any kind of association
  500.  * that is allowed in the OpenID 2.0 specification.
  501.  *
  502.  * Use of negotiators in the library
  503.  * =================================
  504.  *
  505.  * When a consumer makes an association request, it calls {@link }
  506.  * getAllowedType} to get the preferred association type and
  507.  * association session type.
  508.  *
  509.  * The server gets a request for a particular association/session type
  510.  * and calls {@link isAllowed} to determine if it should create an
  511.  * association. If it is supported, negotiation is complete. If it is
  512.  * not, the server calls {@link getAllowedType} to get an allowed
  513.  * association type to return to the consumer.
  514.  *
  515.  * If the consumer gets an error response indicating that the
  516.  * requested association/session type is not supported by the server
  517.  * that contains an assocation/session type to try, it calls {@link }
  518.  * isAllowed} to determine if it should try again with the given
  519.  * combination of association/session type.
  520.  *
  521.  * @package OpenID
  522.  */
  523.     function Auth_OpenID_SessionNegotiator($allowed_types)
  524.     {
  525.         $this->allowed_types array();
  526.         $this->setAllowedTypes($allowed_types);
  527.     }
  528.  
  529.     /**
  530.      * Set the allowed association types, checking to make sure each
  531.      * combination is valid.
  532.      *
  533.      * @access private
  534.      */
  535.     function setAllowedTypes($allowed_types)
  536.     {
  537.         foreach ($allowed_types as $pair{
  538.             list($assoc_type$session_type$pair;
  539.             if (!Auth_OpenID_checkSessionType($assoc_type$session_type)) {
  540.                 return false;
  541.             }
  542.         }
  543.  
  544.         $this->allowed_types $allowed_types;
  545.         return true;
  546.     }
  547.  
  548.     /**
  549.      * Add an association type and session type to the allowed types
  550.      * list. The assocation/session pairs are tried in the order that
  551.      * they are added.
  552.      *
  553.      * @access private
  554.      */
  555.     function addAllowedType($assoc_type$session_type null)
  556.     {
  557.         if ($this->allowed_types === null{
  558.             $this->allowed_types array();
  559.         }
  560.  
  561.         if ($session_type === null{
  562.             $available Auth_OpenID_getSessionTypes($assoc_type);
  563.  
  564.             if (!$available{
  565.                 return false;
  566.             }
  567.  
  568.             foreach ($available as $session_type{
  569.                 $this->addAllowedType($assoc_type$session_type);
  570.             }
  571.         else {
  572.             if (Auth_OpenID_checkSessionType($assoc_type$session_type)) {
  573.                 $this->allowed_types[array($assoc_type$session_type);
  574.             else {
  575.                 return false;
  576.             }
  577.         }
  578.  
  579.         return true;
  580.     }
  581.  
  582.     // Is this combination of association type and session type allowed?
  583.         function isAllowed($assoc_type$session_type)
  584.     {
  585.         $assoc_good in_array(array($assoc_type$session_type),
  586.                                $this->allowed_types);
  587.  
  588.         $matches in_array($session_type,
  589.                             Auth_OpenID_getSessionTypes($assoc_type));
  590.  
  591.         return ($assoc_good && $matches);
  592.     }
  593.  
  594.     /**
  595.      * Get a pair of assocation type and session type that are
  596.      * supported.
  597.      */
  598.     function getAllowedType()
  599.     {
  600.         if (!$this->allowed_types{
  601.             return array(nullnull);
  602.         }
  603.  
  604.         return $this->allowed_types[0];
  605.     }
  606. }
  607.  
  608. ?>

Documentation generated on Sat, 14 Nov 2009 11:10:41 +0000 by phpDocumentor 1.3.1