Source code for file /openid/Auth/OpenID/Association.php
Documentation is available at Association.php
* This module contains code for dealing with associations between
* LICENSE: See the COPYING file included in this distribution.
* @author JanRain, Inc. <openid@janrain.com>
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
// Do not allow direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
require_once 'Auth/OpenID/CryptUtil.php';
require_once 'Auth/OpenID/KVForm.php';
require_once 'Auth/OpenID/HMAC.php';
* This class represents an association between a server and a
* consumer. In general, users of this library will never see
* instances of this object. The only exception is if you implement a
* custom {@link Auth_OpenID_OpenIDStore}.
* If you do implement such a store, it will need to store the values
* of the handle, secret, issued, lifetime, and assoc_type instance
* This is a HMAC-SHA1 specific value.
* The ordering and name of keys as stored by serialize.
'HMAC-SHA1' =>
'Auth_OpenID_HMACSHA1',
'HMAC-SHA256' =>
'Auth_OpenID_HMACSHA256'
* This is an alternate constructor (factory method) used by the
* OpenID consumer library to create associations. OpenID store
* implementations shouldn't use this constructor.
* @param integer $expires_in This is the amount of time this
* association is good for, measured in seconds since the
* association was issued.
* @param string $handle This is the handle the server gave this
* @param string secret This is the shared secret the server
* generated for this association.
* @param assoc_type This is the type of association this
* instance represents. The only valid values of this field at
* this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may
* be defined in the future.
* @return association An {@link Auth_OpenID_Association}
function fromExpiresIn($expires_in, $handle, $secret, $assoc_type)
$issued, $lifetime, $assoc_type);
* This is the standard constructor for creating an association.
* The library should create all of the necessary associations, so
* this constructor is not part of the external API.
* @param string $handle This is the handle the server gave this
* @param string $secret This is the shared secret the server
* generated for this association.
* @param integer $issued This is the time this association was
* issued, in seconds since 00:00 GMT, January 1, 1970. (ie, a
* @param integer $lifetime This is the amount of time this
* association is good for, measured in seconds since the
* association was issued.
* @param string $assoc_type This is the type of association this
* instance represents. The only valid values of this field at
* this time is 'HMAC-SHA1' and 'HMAC-SHA256', but new types may
* be defined in the future.
function Auth_OpenID_Association(
$handle, $secret, $issued, $lifetime, $assoc_type)
$fmt =
'Unsupported association type (%s)';
$this->lifetime =
$lifetime;
$this->assoc_type =
$assoc_type;
* This returns the number of seconds this association is still
* valid for, or 0 if the association is no longer valid.
* @return integer $seconds The number of seconds this association
* is still valid for, or 0 if the association is no longer valid.
return max(0, $this->issued +
$this->lifetime -
$now);
* This checks to see if two {@link Auth_OpenID_Association}
* instances represent the same association.
* @return bool $result true if the two instances represent the
* same association, false otherwise.
&&
($this->handle ==
$other->handle)
&&
($this->secret ==
$other->secret)
&&
($this->issued ==
$other->issued)
&&
($this->lifetime ==
$other->lifetime)
&&
($this->assoc_type ==
$other->assoc_type));
* Convert an association to KV form.
* @return string $result String in KV form suitable for
* deserialization by deserialize.
'handle' =>
$this->handle,
'assoc_type' =>
$this->assoc_type
* Parse an association as stored by serialize(). This is the
* @param string $assoc_s Association as serialized by serialize()
* @return Auth_OpenID_Association $result instance of this class
foreach ($pairs as $key =>
$value) {
list
($key, $value) =
$value;
$class_assoc_keys =
$class_vars['assoc_keys'];
if ($keys !=
$class_assoc_keys) {
$version =
$pairs['version'];
$handle =
$pairs['handle'];
$secret =
$pairs['secret'];
$issued =
$pairs['issued'];
$lifetime =
$pairs['lifetime'];
$assoc_type =
$pairs['assoc_type'];
$lifetime =
intval($lifetime);
$handle, $secret, $issued, $lifetime, $assoc_type);
* Generate a signature for a sequence of (key, value) pairs
* @param array $pairs The pairs to sign, in order. This is an
* @return string $signature The binary signature of this sequence
/* Invalid association types should be caught at constructor */
$callback =
$this->_macs[$this->assoc_type];
* Generate a signature for some fields in a dictionary
* @param array $fields The fields to sign, in order; this is an
* @param array $data Dictionary of values to sign (an array of
* string => string pairs).
* @return string $signature The signature, base64 encoded
function signMessage($message)
if ($extant_handle &&
($extant_handle !=
$this->handle)) {
// raise ValueError("Message has a different association handle")
$signed_message =
$message;
$message_keys =
array_keys($signed_message->toPostArgs());
$signed_prefix =
'openid.';
foreach ($message_keys as $k) {
if (strpos($k, $signed_prefix) ===
0) {
$signed_list[] =
'signed';
$sig =
$this->getMessageSignature($signed_message);
* Given a {@link Auth_OpenID_Message}, return the key/value pairs
* to be signed according to the signed list in the message. If
* the message lacks a signed list, return null.
function _makePairs(&$message)
if (!$signed ||
Auth_OpenID::isFailure($signed)) {
// raise ValueError('Message has no signed list: %s' % (message,))
$signed_list =
explode(',', $signed);
$data =
$message->toPostArgs();
foreach ($signed_list as $field) {
$pairs[] =
array($field, Auth_OpenID::arrayGet($data,
* Given an {@link Auth_OpenID_Message}, return the signature for
* the signed list in the message.
function getMessageSignature(&$message)
$pairs =
$this->_makePairs($message);
* Confirm that the signature of these fields matches the
* signature contained in the data.
function checkMessageSignature(&$message)
if (!$sig ||
Auth_OpenID::isFailure($sig)) {
$calculated_sig =
$this->getMessageSignature($message);
return $calculated_sig ==
$sig;
if ($assoc_type ==
'HMAC-SHA1') {
} else if ($assoc_type ==
'HMAC-SHA256') {
return array('HMAC-SHA1', 'HMAC-SHA256');
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
$assoc_to_session =
array(
'HMAC-SHA1' =>
array('DH-SHA1', 'no-encryption'));
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
$assoc_to_session['HMAC-SHA256'] =
array('DH-SHA256', 'no-encryption');
return Auth_OpenID::arrayGet($assoc_to_session, $assoc_type, array());
if (!Auth_OpenID_noMathSupport()) {
$order[] =
array('HMAC-SHA1', 'DH-SHA1');
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
$order[] =
array('HMAC-SHA256', 'DH-SHA256');
$order[] =
array('HMAC-SHA1', 'no-encryption');
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
$order[] =
array('HMAC-SHA256', 'no-encryption');
list
($assoc, $session) =
$pair;
if ($session !=
'no-encryption') {
if (Auth_OpenID_HMACSHA256_SUPPORTED &&
($assoc ==
'HMAC-SHA256')) {
} else if ($assoc !=
'HMAC-SHA256') {
* A session negotiator controls the allowed and preferred association
* types and association session types. Both the {@link }
* Auth_OpenID_Consumer} and {@link Auth_OpenID_Server} use
* negotiators when creating associations.
* You can create and use negotiators if you:
* - Do not want to do Diffie-Hellman key exchange because you use
* transport-layer encryption (e.g. SSL)
* - Want to use only SHA-256 associations
* - Do not want to support plain-text associations over a non-secure
* It is up to you to set a policy for what kinds of associations to
* accept. By default, the library will make any kind of association
* that is allowed in the OpenID 2.0 specification.
* Use of negotiators in the library
* =================================
* When a consumer makes an association request, it calls {@link }
* getAllowedType} to get the preferred association type and
* association session type.
* The server gets a request for a particular association/session type
* and calls {@link isAllowed} to determine if it should create an
* association. If it is supported, negotiation is complete. If it is
* not, the server calls {@link getAllowedType} to get an allowed
* association type to return to the consumer.
* If the consumer gets an error response indicating that the
* requested association/session type is not supported by the server
* that contains an assocation/session type to try, it calls {@link }
* isAllowed} to determine if it should try again with the given
* combination of association/session type.
$this->allowed_types =
array();
$this->setAllowedTypes($allowed_types);
* Set the allowed association types, checking to make sure each
function setAllowedTypes($allowed_types)
foreach ($allowed_types as $pair) {
list
($assoc_type, $session_type) =
$pair;
$this->allowed_types =
$allowed_types;
* Add an association type and session type to the allowed types
* list. The assocation/session pairs are tried in the order that
function addAllowedType($assoc_type, $session_type =
null)
if ($this->allowed_types ===
null) {
$this->allowed_types =
array();
if ($session_type ===
null) {
foreach ($available as $session_type) {
$this->addAllowedType($assoc_type, $session_type);
$this->allowed_types[] =
array($assoc_type, $session_type);
// Is this combination of association type and session type allowed?
function isAllowed($assoc_type, $session_type)
$assoc_good =
in_array(array($assoc_type, $session_type),
return ($assoc_good &&
$matches);
* Get a pair of assocation type and session type that are
if (!$this->allowed_types) {
return array(null, null);
return $this->allowed_types[0];