pax_global_header 0000666 0000000 0000000 00000000064 11366367341 0014524 g ustar 00root root 0000000 0000000 52 comment=a287b2d85e753c84b3b883ed8ee3ffe8692c8477
openid-php-openid-782224d/ 0000775 0000000 0000000 00000000000 11366367341 0015321 5 ustar 00root root 0000000 0000000 openid-php-openid-782224d/Auth/ 0000775 0000000 0000000 00000000000 11366367341 0016222 5 ustar 00root root 0000000 0000000 openid-php-openid-782224d/Auth/OpenID.php 0000664 0000000 0000000 00000036435 11366367341 0020064 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* The library version string
*/
define('Auth_OpenID_VERSION', '2.2.2');
/**
* Require the fetcher code.
*/
require_once "Auth/Yadis/PlainHTTPFetcher.php";
require_once "Auth/Yadis/ParanoidHTTPFetcher.php";
require_once "Auth/OpenID/BigMath.php";
require_once "Auth/OpenID/URINorm.php";
/**
* Status code returned by the server when the only option is to show
* an error page, since we do not have enough information to redirect
* back to the consumer. The associated value is an error message that
* should be displayed on an HTML error page.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_LOCAL_ERROR', 'local_error');
/**
* Status code returned when there is an error to return in key-value
* form to the consumer. The caller should return a 400 Bad Request
* response with content-type text/plain and the value as the body.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_REMOTE_ERROR', 'remote_error');
/**
* Status code returned when there is a key-value form OK response to
* the consumer. The value associated with this code is the
* response. The caller should return a 200 OK response with
* content-type text/plain and the value as the body.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_REMOTE_OK', 'remote_ok');
/**
* Status code returned when there is a redirect back to the
* consumer. The value is the URL to redirect back to. The caller
* should return a 302 Found redirect with a Location: header
* containing the URL.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_REDIRECT', 'redirect');
/**
* Status code returned when the caller needs to authenticate the
* user. The associated value is a {@link Auth_OpenID_ServerRequest}
* object that can be used to complete the authentication. If the user
* has taken some authentication action, use the retry() method of the
* {@link Auth_OpenID_ServerRequest} object to complete the request.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_DO_AUTH', 'do_auth');
/**
* Status code returned when there were no OpenID arguments
* passed. This code indicates that the caller should return a 200 OK
* response and display an HTML page that says that this is an OpenID
* server endpoint.
*
* @see Auth_OpenID_Server
*/
define('Auth_OpenID_DO_ABOUT', 'do_about');
/**
* Defines for regexes and format checking.
*/
define('Auth_OpenID_letters',
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
define('Auth_OpenID_digits',
"0123456789");
define('Auth_OpenID_punct',
"!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
Auth_OpenID_include_init();
/**
* The OpenID utility function class.
*
* @package OpenID
* @access private
*/
class Auth_OpenID {
/**
* Return true if $thing is an Auth_OpenID_FailureResponse object;
* false if not.
*
* @access private
*/
static function isFailure($thing)
{
return is_a($thing, 'Auth_OpenID_FailureResponse');
}
/**
* Gets the query data from the server environment based on the
* request method used. If GET was used, this looks at
* $_SERVER['QUERY_STRING'] directly. If POST was used, this
* fetches data from the special php://input file stream.
*
* Returns an associative array of the query arguments.
*
* Skips invalid key/value pairs (i.e. keys with no '=value'
* portion).
*
* Returns an empty array if neither GET nor POST was used, or if
* POST was used but php://input cannot be opened.
*
* See background:
* http://lists.openidenabled.com/pipermail/dev/2007-March/000395.html
*
* @access private
*/
static function getQuery($query_str=null)
{
$data = array();
if ($query_str !== null) {
$data = Auth_OpenID::params_from_string($query_str);
} else if (!array_key_exists('REQUEST_METHOD', $_SERVER)) {
// Do nothing.
} else {
// XXX HACK FIXME HORRIBLE.
//
// POSTing to a URL with query parameters is acceptable, but
// we don't have a clean way to distinguish those parameters
// when we need to do things like return_to verification
// which only want to look at one kind of parameter. We're
// going to emulate the behavior of some other environments
// by defaulting to GET and overwriting with POST if POST
// data is available.
$data = Auth_OpenID::params_from_string($_SERVER['QUERY_STRING']);
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$str = file_get_contents('php://input');
if ($str === false) {
$post = array();
} else {
$post = Auth_OpenID::params_from_string($str);
}
$data = array_merge($data, $post);
}
}
return $data;
}
static function params_from_string($str)
{
$chunks = explode("&", $str);
$data = array();
foreach ($chunks as $chunk) {
$parts = explode("=", $chunk, 2);
if (count($parts) != 2) {
continue;
}
list($k, $v) = $parts;
$data[urldecode($k)] = urldecode($v);
}
return $data;
}
/**
* Create dir_name as a directory if it does not exist. If it
* exists, make sure that it is, in fact, a directory. Returns
* true if the operation succeeded; false if not.
*
* @access private
*/
static function ensureDir($dir_name)
{
if (is_dir($dir_name) || @mkdir($dir_name)) {
return true;
} else {
$parent_dir = dirname($dir_name);
// Terminal case; there is no parent directory to create.
if ($parent_dir == $dir_name) {
return true;
}
return (Auth_OpenID::ensureDir($parent_dir) && @mkdir($dir_name));
}
}
/**
* Adds a string prefix to all values of an array. Returns a new
* array containing the prefixed values.
*
* @access private
*/
static function addPrefix($values, $prefix)
{
$new_values = array();
foreach ($values as $s) {
$new_values[] = $prefix . $s;
}
return $new_values;
}
/**
* Convenience function for getting array values. Given an array
* $arr and a key $key, get the corresponding value from the array
* or return $default if the key is absent.
*
* @access private
*/
static function arrayGet($arr, $key, $fallback = null)
{
if (is_array($arr)) {
if (array_key_exists($key, $arr)) {
return $arr[$key];
} else {
return $fallback;
}
} else {
trigger_error("Auth_OpenID::arrayGet (key = ".$key.") expected " .
"array as first parameter, got " .
gettype($arr), E_USER_WARNING);
return false;
}
}
/**
* Replacement for PHP's broken parse_str.
*/
static function parse_str($query)
{
if ($query === null) {
return null;
}
$parts = explode('&', $query);
$new_parts = array();
for ($i = 0; $i < count($parts); $i++) {
$pair = explode('=', $parts[$i]);
if (count($pair) != 2) {
continue;
}
list($key, $value) = $pair;
$new_parts[urldecode($key)] = urldecode($value);
}
return $new_parts;
}
/**
* Implements the PHP 5 'http_build_query' functionality.
*
* @access private
* @param array $data Either an array key/value pairs or an array
* of arrays, each of which holding two values: a key and a value,
* sequentially.
* @return string $result The result of url-encoding the key/value
* pairs from $data into a URL query string
* (e.g. "username=bob&id=56").
*/
static function httpBuildQuery($data)
{
$pairs = array();
foreach ($data as $key => $value) {
if (is_array($value)) {
$pairs[] = urlencode($value[0])."=".urlencode($value[1]);
} else {
$pairs[] = urlencode($key)."=".urlencode($value);
}
}
return implode("&", $pairs);
}
/**
* "Appends" query arguments onto a URL. The URL may or may not
* already have arguments (following a question mark).
*
* @access private
* @param string $url A URL, which may or may not already have
* arguments.
* @param array $args Either an array key/value pairs or an array of
* arrays, each of which holding two values: a key and a value,
* sequentially. If $args is an ordinary key/value array, the
* parameters will be added to the URL in sorted alphabetical order;
* if $args is an array of arrays, their order will be preserved.
* @return string $url The original URL with the new parameters added.
*
*/
static function appendArgs($url, $args)
{
if (count($args) == 0) {
return $url;
}
// Non-empty array; if it is an array of arrays, use
// multisort; otherwise use sort.
if (array_key_exists(0, $args) &&
is_array($args[0])) {
// Do nothing here.
} else {
$keys = array_keys($args);
sort($keys);
$new_args = array();
foreach ($keys as $key) {
$new_args[] = array($key, $args[$key]);
}
$args = $new_args;
}
$sep = '?';
if (strpos($url, '?') !== false) {
$sep = '&';
}
return $url . $sep . Auth_OpenID::httpBuildQuery($args);
}
/**
* Implements python's urlunparse, which is not available in PHP.
* Given the specified components of a URL, this function rebuilds
* and returns the URL.
*
* @access private
* @param string $scheme The scheme (e.g. 'http'). Defaults to 'http'.
* @param string $host The host. Required.
* @param string $port The port.
* @param string $path The path.
* @param string $query The query.
* @param string $fragment The fragment.
* @return string $url The URL resulting from assembling the
* specified components.
*/
static function urlunparse($scheme, $host, $port = null, $path = '/',
$query = '', $fragment = '')
{
if (!$scheme) {
$scheme = 'http';
}
if (!$host) {
return false;
}
if (!$path) {
$path = '';
}
$result = $scheme . "://" . $host;
if ($port) {
$result .= ":" . $port;
}
$result .= $path;
if ($query) {
$result .= "?" . $query;
}
if ($fragment) {
$result .= "#" . $fragment;
}
return $result;
}
/**
* Given a URL, this "normalizes" it by adding a trailing slash
* and / or a leading http:// scheme where necessary. Returns
* null if the original URL is malformed and cannot be normalized.
*
* @access private
* @param string $url The URL to be normalized.
* @return mixed $new_url The URL after normalization, or null if
* $url was malformed.
*/
static function normalizeUrl($url)
{
@$parsed = parse_url($url);
if (!$parsed) {
return null;
}
if (isset($parsed['scheme']) &&
isset($parsed['host'])) {
$scheme = strtolower($parsed['scheme']);
if (!in_array($scheme, array('http', 'https'))) {
return null;
}
} else {
$url = 'http://' . $url;
}
$normalized = Auth_OpenID_urinorm($url);
if ($normalized === null) {
return null;
}
list($defragged, $frag) = Auth_OpenID::urldefrag($normalized);
return $defragged;
}
/**
* Replacement (wrapper) for PHP's intval() because it's broken.
*
* @access private
*/
static function intval($value)
{
$re = "/^\\d+$/";
if (!preg_match($re, $value)) {
return false;
}
return intval($value);
}
/**
* Count the number of bytes in a string independently of
* multibyte support conditions.
*
* @param string $str The string of bytes to count.
* @return int The number of bytes in $str.
*/
static function bytes($str)
{
return strlen(bin2hex($str)) / 2;
}
/**
* Get the bytes in a string independently of multibyte support
* conditions.
*/
static function toBytes($str)
{
$hex = bin2hex($str);
if (!$hex) {
return array();
}
$b = array();
for ($i = 0; $i < strlen($hex); $i += 2) {
$b[] = chr(base_convert(substr($hex, $i, 2), 16, 10));
}
return $b;
}
static function urldefrag($url)
{
$parts = explode("#", $url, 2);
if (count($parts) == 1) {
return array($parts[0], "");
} else {
return $parts;
}
}
static function filter($callback, &$sequence)
{
$result = array();
foreach ($sequence as $item) {
if (call_user_func_array($callback, array($item))) {
$result[] = $item;
}
}
return $result;
}
static function update(&$dest, &$src)
{
foreach ($src as $k => $v) {
$dest[$k] = $v;
}
}
/**
* Wrap PHP's standard error_log functionality. Use this to
* perform all logging. It will interpolate any additional
* arguments into the format string before logging.
*
* @param string $format_string The sprintf format for the message
*/
static function log($format_string)
{
$args = func_get_args();
$message = call_user_func_array('sprintf', $args);
error_log($message);
}
static function autoSubmitHTML($form, $title="OpenId transaction in progress")
{
return("".
"
".
$title .
"".
"".
$form .
"".
"".
"");
}
}
/*
* Function to run when this file is included.
* Abstracted to a function to make life easier
* for some PHP optimizers.
*/
function Auth_OpenID_include_init() {
if (Auth_OpenID_getMathLib() === null) {
Auth_OpenID_setNoMathSupport();
}
}
openid-php-openid-782224d/Auth/OpenID/ 0000775 0000000 0000000 00000000000 11366367341 0017340 5 ustar 00root root 0000000 0000000 openid-php-openid-782224d/Auth/OpenID/AX.php 0000664 0000000 0000000 00000075165 11366367341 0020377 0 ustar 00root root 0000000 0000000 message = $message;
}
}
/**
* Abstract class containing common code for attribute exchange
* messages.
*
* @package OpenID
*/
class Auth_OpenID_AX_Message extends Auth_OpenID_Extension {
/**
* ns_alias: The preferred namespace alias for attribute exchange
* messages
*/
var $ns_alias = 'ax';
/**
* mode: The type of this attribute exchange message. This must be
* overridden in subclasses.
*/
var $mode = null;
var $ns_uri = Auth_OpenID_AX_NS_URI;
/**
* Return Auth_OpenID_AX_Error if the mode in the attribute
* exchange arguments does not match what is expected for this
* class; true otherwise.
*
* @access private
*/
function _checkMode($ax_args)
{
$mode = Auth_OpenID::arrayGet($ax_args, 'mode');
if ($mode != $this->mode) {
return new Auth_OpenID_AX_Error(
sprintf(
"Expected mode '%s'; got '%s'",
$this->mode, $mode));
}
return true;
}
/**
* Return a set of attribute exchange arguments containing the
* basic information that must be in every attribute exchange
* message.
*
* @access private
*/
function _newArgs()
{
return array('mode' => $this->mode);
}
}
/**
* Represents a single attribute in an attribute exchange
* request. This should be added to an AXRequest object in order to
* request the attribute.
*
* @package OpenID
*/
class Auth_OpenID_AX_AttrInfo {
/**
* Construct an attribute information object. Do not call this
* directly; call make(...) instead.
*
* @param string $type_uri The type URI for this attribute.
*
* @param int $count The number of values of this type to request.
*
* @param bool $required Whether the attribute will be marked as
* required in the request.
*
* @param string $alias The name that should be given to this
* attribute in the request.
*/
function Auth_OpenID_AX_AttrInfo($type_uri, $count, $required,
$alias)
{
/**
* required: Whether the attribute will be marked as required
* when presented to the subject of the attribute exchange
* request.
*/
$this->required = $required;
/**
* count: How many values of this type to request from the
* subject. Defaults to one.
*/
$this->count = $count;
/**
* type_uri: The identifier that determines what the attribute
* represents and how it is serialized. For example, one type
* URI representing dates could represent a Unix timestamp in
* base 10 and another could represent a human-readable
* string.
*/
$this->type_uri = $type_uri;
/**
* alias: The name that should be given to this attribute in
* the request. If it is not supplied, a generic name will be
* assigned. For example, if you want to call a Unix timestamp
* value 'tstamp', set its alias to that value. If two
* attributes in the same message request to use the same
* alias, the request will fail to be generated.
*/
$this->alias = $alias;
}
/**
* Construct an attribute information object. For parameter
* details, see the constructor.
*/
static function make($type_uri, $count=1, $required=false,
$alias=null)
{
if ($alias !== null) {
$result = Auth_OpenID_AX_checkAlias($alias);
if (Auth_OpenID_AX::isError($result)) {
return $result;
}
}
return new Auth_OpenID_AX_AttrInfo($type_uri, $count, $required,
$alias);
}
/**
* When processing a request for this attribute, the OP should
* call this method to determine whether all available attribute
* values were requested. If self.count == UNLIMITED_VALUES, this
* returns True. Otherwise this returns False, in which case
* self.count is an integer.
*/
function wantsUnlimitedValues()
{
return $this->count === Auth_OpenID_AX_UNLIMITED_VALUES;
}
}
/**
* Given a namespace mapping and a string containing a comma-separated
* list of namespace aliases, return a list of type URIs that
* correspond to those aliases.
*
* @param $namespace_map The mapping from namespace URI to alias
* @param $alias_list_s The string containing the comma-separated
* list of aliases. May also be None for convenience.
*
* @return $seq The list of namespace URIs that corresponds to the
* supplied list of aliases. If the string was zero-length or None, an
* empty list will be returned.
*
* return null If an alias is present in the list of aliases but
* is not present in the namespace map.
*/
function Auth_OpenID_AX_toTypeURIs($namespace_map, $alias_list_s)
{
$uris = array();
if ($alias_list_s) {
foreach (explode(',', $alias_list_s) as $alias) {
$type_uri = $namespace_map->getNamespaceURI($alias);
if ($type_uri === null) {
// raise KeyError(
// 'No type is defined for attribute name %r' % (alias,))
return new Auth_OpenID_AX_Error(
sprintf('No type is defined for attribute name %s',
$alias)
);
} else {
$uris[] = $type_uri;
}
}
}
return $uris;
}
/**
* An attribute exchange 'fetch_request' message. This message is sent
* by a relying party when it wishes to obtain attributes about the
* subject of an OpenID authentication request.
*
* @package OpenID
*/
class Auth_OpenID_AX_FetchRequest extends Auth_OpenID_AX_Message {
var $mode = 'fetch_request';
function Auth_OpenID_AX_FetchRequest($update_url=null)
{
/**
* requested_attributes: The attributes that have been
* requested thus far, indexed by the type URI.
*/
$this->requested_attributes = array();
/**
* update_url: A URL that will accept responses for this
* attribute exchange request, even in the absence of the user
* who made this request.
*/
$this->update_url = $update_url;
}
/**
* Add an attribute to this attribute exchange request.
*
* @param attribute: The attribute that is being requested
* @return true on success, false when the requested attribute is
* already present in this fetch request.
*/
function add($attribute)
{
if ($this->contains($attribute->type_uri)) {
return new Auth_OpenID_AX_Error(
sprintf("The attribute %s has already been requested",
$attribute->type_uri));
}
$this->requested_attributes[$attribute->type_uri] = $attribute;
return true;
}
/**
* Get the serialized form of this attribute fetch request.
*
* @returns Auth_OpenID_AX_FetchRequest The fetch request message parameters
*/
function getExtensionArgs()
{
$aliases = new Auth_OpenID_NamespaceMap();
$required = array();
$if_available = array();
$ax_args = $this->_newArgs();
foreach ($this->requested_attributes as $type_uri => $attribute) {
if ($attribute->alias === null) {
$alias = $aliases->add($type_uri);
} else {
$alias = $aliases->addAlias($type_uri, $attribute->alias);
if ($alias === null) {
return new Auth_OpenID_AX_Error(
sprintf("Could not add alias %s for URI %s",
$attribute->alias, $type_uri
));
}
}
if ($attribute->required) {
$required[] = $alias;
} else {
$if_available[] = $alias;
}
if ($attribute->count != 1) {
$ax_args['count.' . $alias] = strval($attribute->count);
}
$ax_args['type.' . $alias] = $type_uri;
}
if ($required) {
$ax_args['required'] = implode(',', $required);
}
if ($if_available) {
$ax_args['if_available'] = implode(',', $if_available);
}
return $ax_args;
}
/**
* Get the type URIs for all attributes that have been marked as
* required.
*
* @return A list of the type URIs for attributes that have been
* marked as required.
*/
function getRequiredAttrs()
{
$required = array();
foreach ($this->requested_attributes as $type_uri => $attribute) {
if ($attribute->required) {
$required[] = $type_uri;
}
}
return $required;
}
/**
* Extract a FetchRequest from an OpenID message
*
* @param request: The OpenID request containing the attribute
* fetch request
*
* @returns mixed An Auth_OpenID_AX_Error or the
* Auth_OpenID_AX_FetchRequest extracted from the request message if
* successful
*/
static function fromOpenIDRequest($request)
{
$m = $request->message;
$obj = new Auth_OpenID_AX_FetchRequest();
$ax_args = $m->getArgs($obj->ns_uri);
$result = $obj->parseExtensionArgs($ax_args);
if (Auth_OpenID_AX::isError($result)) {
return $result;
}
if ($obj->update_url) {
// Update URL must match the openid.realm of the
// underlying OpenID 2 message.
$realm = $m->getArg(Auth_OpenID_OPENID_NS, 'realm',
$m->getArg(
Auth_OpenID_OPENID_NS,
'return_to'));
if (!$realm) {
$obj = new Auth_OpenID_AX_Error(
sprintf("Cannot validate update_url %s " .
"against absent realm", $obj->update_url));
} else if (!Auth_OpenID_TrustRoot::match($realm,
$obj->update_url)) {
$obj = new Auth_OpenID_AX_Error(
sprintf("Update URL %s failed validation against realm %s",
$obj->update_url, $realm));
}
}
return $obj;
}
/**
* Given attribute exchange arguments, populate this FetchRequest.
*
* @return $result Auth_OpenID_AX_Error if the data to be parsed
* does not follow the attribute exchange specification. At least
* when 'if_available' or 'required' is not specified for a
* particular attribute type. Returns true otherwise.
*/
function parseExtensionArgs($ax_args)
{
$result = $this->_checkMode($ax_args);
if (Auth_OpenID_AX::isError($result)) {
return $result;
}
$aliases = new Auth_OpenID_NamespaceMap();
foreach ($ax_args as $key => $value) {
if (strpos($key, 'type.') === 0) {
$alias = substr($key, 5);
$type_uri = $value;
$alias = $aliases->addAlias($type_uri, $alias);
if ($alias === null) {
return new Auth_OpenID_AX_Error(
sprintf("Could not add alias %s for URI %s",
$alias, $type_uri)
);
}
$count_s = Auth_OpenID::arrayGet($ax_args, 'count.' . $alias);
if ($count_s) {
$count = Auth_OpenID::intval($count_s);
if (($count === false) &&
($count_s === Auth_OpenID_AX_UNLIMITED_VALUES)) {
$count = $count_s;
}
} else {
$count = 1;
}
if ($count === false) {
return new Auth_OpenID_AX_Error(
sprintf("Integer value expected for %s, got %s",
'count.' . $alias, $count_s));
}
$attrinfo = Auth_OpenID_AX_AttrInfo::make($type_uri, $count,
false, $alias);
if (Auth_OpenID_AX::isError($attrinfo)) {
return $attrinfo;
}
$this->add($attrinfo);
}
}
$required = Auth_OpenID_AX_toTypeURIs($aliases,
Auth_OpenID::arrayGet($ax_args, 'required'));
foreach ($required as $type_uri) {
$attrib = $this->requested_attributes[$type_uri];
$attrib->required = true;
}
$if_available = Auth_OpenID_AX_toTypeURIs($aliases,
Auth_OpenID::arrayGet($ax_args, 'if_available'));
$all_type_uris = array_merge($required, $if_available);
foreach ($aliases->iterNamespaceURIs() as $type_uri) {
if (!in_array($type_uri, $all_type_uris)) {
return new Auth_OpenID_AX_Error(
sprintf('Type URI %s was in the request but not ' .
'present in "required" or "if_available"',
$type_uri));
}
}
$this->update_url = Auth_OpenID::arrayGet($ax_args, 'update_url');
return true;
}
/**
* Iterate over the AttrInfo objects that are contained in this
* fetch_request.
*/
function iterAttrs()
{
return array_values($this->requested_attributes);
}
function iterTypes()
{
return array_keys($this->requested_attributes);
}
/**
* Is the given type URI present in this fetch_request?
*/
function contains($type_uri)
{
return in_array($type_uri, $this->iterTypes());
}
}
/**
* An abstract class that implements a message that has attribute keys
* and values. It contains the common code between fetch_response and
* store_request.
*
* @package OpenID
*/
class Auth_OpenID_AX_KeyValueMessage extends Auth_OpenID_AX_Message {
function Auth_OpenID_AX_KeyValueMessage()
{
$this->data = array();
}
/**
* Add a single value for the given attribute type to the
* message. If there are already values specified for this type,
* this value will be sent in addition to the values already
* specified.
*
* @param type_uri: The URI for the attribute
* @param value: The value to add to the response to the relying
* party for this attribute
* @return null
*/
function addValue($type_uri, $value)
{
if (!array_key_exists($type_uri, $this->data)) {
$this->data[$type_uri] = array();
}
$values =& $this->data[$type_uri];
$values[] = $value;
}
/**
* Set the values for the given attribute type. This replaces any
* values that have already been set for this attribute.
*
* @param type_uri: The URI for the attribute
* @param values: A list of values to send for this attribute.
*/
function setValues($type_uri, &$values)
{
$this->data[$type_uri] =& $values;
}
/**
* Get the extension arguments for the key/value pairs contained
* in this message.
*
* @param aliases: An alias mapping. Set to None if you don't care
* about the aliases for this request.
*
* @access private
*/
function _getExtensionKVArgs($aliases)
{
if ($aliases === null) {
$aliases = new Auth_OpenID_NamespaceMap();
}
$ax_args = array();
foreach ($this->data as $type_uri => $values) {
$alias = $aliases->add($type_uri);
$ax_args['type.' . $alias] = $type_uri;
$ax_args['count.' . $alias] = strval(count($values));
foreach ($values as $i => $value) {
$key = sprintf('value.%s.%d', $alias, $i + 1);
$ax_args[$key] = $value;
}
}
return $ax_args;
}
/**
* Parse attribute exchange key/value arguments into this object.
*
* @param ax_args: The attribute exchange fetch_response
* arguments, with namespacing removed.
*
* @return Auth_OpenID_AX_Error or true
*/
function parseExtensionArgs($ax_args)
{
$result = $this->_checkMode($ax_args);
if (Auth_OpenID_AX::isError($result)) {
return $result;
}
$aliases = new Auth_OpenID_NamespaceMap();
foreach ($ax_args as $key => $value) {
if (strpos($key, 'type.') === 0) {
$type_uri = $value;
$alias = substr($key, 5);
$result = Auth_OpenID_AX_checkAlias($alias);
if (Auth_OpenID_AX::isError($result)) {
return $result;
}
$alias = $aliases->addAlias($type_uri, $alias);
if ($alias === null) {
return new Auth_OpenID_AX_Error(
sprintf("Could not add alias %s for URI %s",
$alias, $type_uri)
);
}
}
}
foreach ($aliases->iteritems() as $pair) {
list($type_uri, $alias) = $pair;
if (array_key_exists('count.' . $alias, $ax_args) && ($ax_args['count.' . $alias] !== Auth_OpenID_AX_UNLIMITED_VALUES)) {
$count_key = 'count.' . $alias;
$count_s = $ax_args[$count_key];
$count = Auth_OpenID::intval($count_s);
if ($count === false) {
return new Auth_OpenID_AX_Error(
sprintf("Integer value expected for %s, got %s",
'count. %s' . $alias, $count_s,
Auth_OpenID_AX_UNLIMITED_VALUES)
);
}
$values = array();
for ($i = 1; $i < $count + 1; $i++) {
$value_key = sprintf('value.%s.%d', $alias, $i);
if (!array_key_exists($value_key, $ax_args)) {
return new Auth_OpenID_AX_Error(
sprintf(
"No value found for key %s",
$value_key));
}
$value = $ax_args[$value_key];
$values[] = $value;
}
} else {
$key = 'value.' . $alias;
if (!array_key_exists($key, $ax_args)) {
return new Auth_OpenID_AX_Error(
sprintf(
"No value found for key %s",
$key));
}
$value = $ax_args['value.' . $alias];
if ($value == '') {
$values = array();
} else {
$values = array($value);
}
}
$this->data[$type_uri] = $values;
}
return true;
}
/**
* Get a single value for an attribute. If no value was sent for
* this attribute, use the supplied default. If there is more than
* one value for this attribute, this method will fail.
*
* @param type_uri: The URI for the attribute
* @param default: The value to return if the attribute was not
* sent in the fetch_response.
*
* @return $value Auth_OpenID_AX_Error on failure or the value of
* the attribute in the fetch_response message, or the default
* supplied
*/
function getSingle($type_uri, $default=null)
{
$values = Auth_OpenID::arrayGet($this->data, $type_uri);
if (!$values) {
return $default;
} else if (count($values) == 1) {
return $values[0];
} else {
return new Auth_OpenID_AX_Error(
sprintf('More than one value present for %s',
$type_uri)
);
}
}
/**
* Get the list of values for this attribute in the
* fetch_response.
*
* XXX: what to do if the values are not present? default
* parameter? this is funny because it's always supposed to return
* a list, so the default may break that, though it's provided by
* the user's code, so it might be okay. If no default is
* supplied, should the return be None or []?
*
* @param type_uri: The URI of the attribute
*
* @return $values The list of values for this attribute in the
* response. May be an empty list. If the attribute was not sent
* in the response, returns Auth_OpenID_AX_Error.
*/
function get($type_uri)
{
if (array_key_exists($type_uri, $this->data)) {
return $this->data[$type_uri];
} else {
return new Auth_OpenID_AX_Error(
sprintf("Type URI %s not found in response",
$type_uri)
);
}
}
/**
* Get the number of responses for a particular attribute in this
* fetch_response message.
*
* @param type_uri: The URI of the attribute
*
* @returns int The number of values sent for this attribute. If
* the attribute was not sent in the response, returns
* Auth_OpenID_AX_Error.
*/
function count($type_uri)
{
if (array_key_exists($type_uri, $this->data)) {
return count($this->get($type_uri));
} else {
return new Auth_OpenID_AX_Error(
sprintf("Type URI %s not found in response",
$type_uri)
);
}
}
}
/**
* A fetch_response attribute exchange message.
*
* @package OpenID
*/
class Auth_OpenID_AX_FetchResponse extends Auth_OpenID_AX_KeyValueMessage {
var $mode = 'fetch_response';
function Auth_OpenID_AX_FetchResponse($update_url=null)
{
$this->Auth_OpenID_AX_KeyValueMessage();
$this->update_url = $update_url;
}
/**
* Serialize this object into arguments in the attribute exchange
* namespace
*
* @return $args The dictionary of unqualified attribute exchange
* arguments that represent this fetch_response, or
* Auth_OpenID_AX_Error on error.
*/
function getExtensionArgs($request=null)
{
$aliases = new Auth_OpenID_NamespaceMap();
$zero_value_types = array();
if ($request !== null) {
// Validate the data in the context of the request (the
// same attributes should be present in each, and the
// counts in the response must be no more than the counts
// in the request)
foreach ($this->data as $type_uri => $unused) {
if (!$request->contains($type_uri)) {
return new Auth_OpenID_AX_Error(
sprintf("Response attribute not present in request: %s",
$type_uri)
);
}
}
foreach ($request->iterAttrs() as $attr_info) {
// Copy the aliases from the request so that reading
// the response in light of the request is easier
if ($attr_info->alias === null) {
$aliases->add($attr_info->type_uri);
} else {
$alias = $aliases->addAlias($attr_info->type_uri,
$attr_info->alias);
if ($alias === null) {
return new Auth_OpenID_AX_Error(
sprintf("Could not add alias %s for URI %s",
$attr_info->alias, $attr_info->type_uri)
);
}
}
if (array_key_exists($attr_info->type_uri, $this->data)) {
$values = $this->data[$attr_info->type_uri];
} else {
$values = array();
$zero_value_types[] = $attr_info;
}
if (($attr_info->count != Auth_OpenID_AX_UNLIMITED_VALUES) &&
($attr_info->count < count($values))) {
return new Auth_OpenID_AX_Error(
sprintf("More than the number of requested values " .
"were specified for %s",
$attr_info->type_uri)
);
}
}
}
$kv_args = $this->_getExtensionKVArgs($aliases);
// Add the KV args into the response with the args that are
// unique to the fetch_response
$ax_args = $this->_newArgs();
// For each requested attribute, put its type/alias and count
// into the response even if no data were returned.
foreach ($zero_value_types as $attr_info) {
$alias = $aliases->getAlias($attr_info->type_uri);
$kv_args['type.' . $alias] = $attr_info->type_uri;
$kv_args['count.' . $alias] = '0';
}
$update_url = null;
if ($request) {
$update_url = $request->update_url;
} else {
$update_url = $this->update_url;
}
if ($update_url) {
$ax_args['update_url'] = $update_url;
}
Auth_OpenID::update($ax_args, $kv_args);
return $ax_args;
}
/**
* @return $result Auth_OpenID_AX_Error on failure or true on
* success.
*/
function parseExtensionArgs($ax_args)
{
$result = parent::parseExtensionArgs($ax_args);
if (Auth_OpenID_AX::isError($result)) {
return $result;
}
$this->update_url = Auth_OpenID::arrayGet($ax_args, 'update_url');
return true;
}
/**
* Construct a FetchResponse object from an OpenID library
* SuccessResponse object.
*
* @param success_response: A successful id_res response object
*
* @param signed: Whether non-signed args should be processsed. If
* True (the default), only signed arguments will be processsed.
*
* @return $response A FetchResponse containing the data from the
* OpenID message
*/
static function fromSuccessResponse($success_response, $signed=true)
{
$obj = new Auth_OpenID_AX_FetchResponse();
if ($signed) {
$ax_args = $success_response->getSignedNS($obj->ns_uri);
} else {
$ax_args = $success_response->message->getArgs($obj->ns_uri);
}
if ($ax_args === null || Auth_OpenID::isFailure($ax_args) ||
sizeof($ax_args) == 0) {
return null;
}
$result = $obj->parseExtensionArgs($ax_args);
if (Auth_OpenID_AX::isError($result)) {
#XXX log me
return null;
}
return $obj;
}
}
/**
* A store request attribute exchange message representation.
*
* @package OpenID
*/
class Auth_OpenID_AX_StoreRequest extends Auth_OpenID_AX_KeyValueMessage {
var $mode = 'store_request';
/**
* @param array $aliases The namespace aliases to use when making
* this store response. Leave as None to use defaults.
*/
function getExtensionArgs($aliases=null)
{
$ax_args = $this->_newArgs();
$kv_args = $this->_getExtensionKVArgs($aliases);
Auth_OpenID::update($ax_args, $kv_args);
return $ax_args;
}
}
/**
* An indication that the store request was processed along with this
* OpenID transaction. Use make(), NOT the constructor, to create
* response objects.
*
* @package OpenID
*/
class Auth_OpenID_AX_StoreResponse extends Auth_OpenID_AX_Message {
var $SUCCESS_MODE = 'store_response_success';
var $FAILURE_MODE = 'store_response_failure';
/**
* Returns Auth_OpenID_AX_Error on error or an
* Auth_OpenID_AX_StoreResponse object on success.
*/
function make($succeeded=true, $error_message=null)
{
if (($succeeded) && ($error_message !== null)) {
return new Auth_OpenID_AX_Error('An error message may only be '.
'included in a failing fetch response');
}
return new Auth_OpenID_AX_StoreResponse($succeeded, $error_message);
}
function Auth_OpenID_AX_StoreResponse($succeeded=true, $error_message=null)
{
if ($succeeded) {
$this->mode = $this->SUCCESS_MODE;
} else {
$this->mode = $this->FAILURE_MODE;
}
$this->error_message = $error_message;
}
/**
* Was this response a success response?
*/
function succeeded()
{
return $this->mode == $this->SUCCESS_MODE;
}
function getExtensionArgs()
{
$ax_args = $this->_newArgs();
if ((!$this->succeeded()) && $this->error_message) {
$ax_args['error'] = $this->error_message;
}
return $ax_args;
}
}
openid-php-openid-782224d/Auth/OpenID/Association.php 0000664 0000000 0000000 00000043570 11366367341 0022336 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* @access private
*/
require_once 'Auth/OpenID/CryptUtil.php';
/**
* @access private
*/
require_once 'Auth/OpenID/KVForm.php';
/**
* @access private
*/
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
* variables.
*
* @package OpenID
*/
class Auth_OpenID_Association {
/**
* This is a HMAC-SHA1 specific value.
*
* @access private
*/
var $SIG_LENGTH = 20;
/**
* The ordering and name of keys as stored by serialize.
*
* @access private
*/
var $assoc_keys = array(
'version',
'handle',
'secret',
'issued',
'lifetime',
'assoc_type'
);
var $_macs = array(
'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.
*
* @access private
*
* @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
* association.
*
* @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}
* instance.
*/
static function fromExpiresIn($expires_in, $handle, $secret, $assoc_type)
{
$issued = time();
$lifetime = $expires_in;
return new Auth_OpenID_Association($handle, $secret,
$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.
*
* @access private
*
* @param string $handle This is the handle the server gave this
* association.
*
* @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
* unix timestamp)
*
* @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)
{
if (!in_array($assoc_type,
Auth_OpenID_getSupportedAssociationTypes(), true)) {
$fmt = 'Unsupported association type (%s)';
trigger_error(sprintf($fmt, $assoc_type), E_USER_ERROR);
}
$this->handle = $handle;
$this->secret = $secret;
$this->issued = $issued;
$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.
*/
function getExpiresIn($now = null)
{
if ($now == null) {
$now = time();
}
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.
*/
function equal($other)
{
return ((gettype($this) == gettype($other))
&& ($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.
*/
function serialize()
{
$data = array(
'version' => '2',
'handle' => $this->handle,
'secret' => base64_encode($this->secret),
'issued' => strval(intval($this->issued)),
'lifetime' => strval(intval($this->lifetime)),
'assoc_type' => $this->assoc_type
);
assert(array_keys($data) == $this->assoc_keys);
return Auth_OpenID_KVForm::fromArray($data, $strict = true);
}
/**
* Parse an association as stored by serialize(). This is the
* inverse of serialize.
*
* @param string $assoc_s Association as serialized by serialize()
* @return Auth_OpenID_Association $result instance of this class
*/
static function deserialize($class_name, $assoc_s)
{
$pairs = Auth_OpenID_KVForm::toArray($assoc_s, $strict = true);
$keys = array();
$values = array();
foreach ($pairs as $key => $value) {
if (is_array($value)) {
list($key, $value) = $value;
}
$keys[] = $key;
$values[] = $value;
}
$class_vars = get_class_vars($class_name);
$class_assoc_keys = $class_vars['assoc_keys'];
sort($keys);
sort($class_assoc_keys);
if ($keys != $class_assoc_keys) {
trigger_error('Unexpected key values: ' . var_export($keys, true),
E_USER_WARNING);
return null;
}
$version = $pairs['version'];
$handle = $pairs['handle'];
$secret = $pairs['secret'];
$issued = $pairs['issued'];
$lifetime = $pairs['lifetime'];
$assoc_type = $pairs['assoc_type'];
if ($version != '2') {
trigger_error('Unknown version: ' . $version, E_USER_WARNING);
return null;
}
$issued = intval($issued);
$lifetime = intval($lifetime);
$secret = base64_decode($secret);
return new $class_name(
$handle, $secret, $issued, $lifetime, $assoc_type);
}
/**
* Generate a signature for a sequence of (key, value) pairs
*
* @access private
* @param array $pairs The pairs to sign, in order. This is an
* array of two-tuples.
* @return string $signature The binary signature of this sequence
* of pairs
*/
function sign($pairs)
{
$kv = Auth_OpenID_KVForm::fromArray($pairs);
/* Invalid association types should be caught at constructor */
$callback = $this->_macs[$this->assoc_type];
return call_user_func_array($callback, array($this->secret, $kv));
}
/**
* Generate a signature for some fields in a dictionary
*
* @access private
* @param array $fields The fields to sign, in order; this is an
* array of strings.
* @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 ($message->hasKey(Auth_OpenID_OPENID_NS, 'sig') ||
$message->hasKey(Auth_OpenID_OPENID_NS, 'signed')) {
// Already has a sig
return null;
}
$extant_handle = $message->getArg(Auth_OpenID_OPENID_NS,
'assoc_handle');
if ($extant_handle && ($extant_handle != $this->handle)) {
// raise ValueError("Message has a different association handle")
return null;
}
$signed_message = $message;
$signed_message->setArg(Auth_OpenID_OPENID_NS, 'assoc_handle',
$this->handle);
$message_keys = array_keys($signed_message->toPostArgs());
$signed_list = array();
$signed_prefix = 'openid.';
foreach ($message_keys as $k) {
if (strpos($k, $signed_prefix) === 0) {
$signed_list[] = substr($k, strlen($signed_prefix));
}
}
$signed_list[] = 'signed';
sort($signed_list);
$signed_message->setArg(Auth_OpenID_OPENID_NS, 'signed',
implode(',', $signed_list));
$sig = $this->getMessageSignature($signed_message);
$signed_message->setArg(Auth_OpenID_OPENID_NS, 'sig', $sig);
return $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.
*
* @access private
*/
function _makePairs($message)
{
$signed = $message->getArg(Auth_OpenID_OPENID_NS, 'signed');
if (!$signed || Auth_OpenID::isFailure($signed)) {
// raise ValueError('Message has no signed list: %s' % (message,))
return null;
}
$signed_list = explode(',', $signed);
$pairs = array();
$data = $message->toPostArgs();
foreach ($signed_list as $field) {
$pairs[] = array($field, Auth_OpenID::arrayGet($data,
'openid.' .
$field, ''));
}
return $pairs;
}
/**
* Given an {@link Auth_OpenID_Message}, return the signature for
* the signed list in the message.
*
* @access private
*/
function getMessageSignature($message)
{
$pairs = $this->_makePairs($message);
return base64_encode($this->sign($pairs));
}
/**
* Confirm that the signature of these fields matches the
* signature contained in the data.
*
* @access private
*/
function checkMessageSignature($message)
{
$sig = $message->getArg(Auth_OpenID_OPENID_NS,
'sig');
if (!$sig || Auth_OpenID::isFailure($sig)) {
return false;
}
$calculated_sig = $this->getMessageSignature($message);
return $calculated_sig == $sig;
}
}
function Auth_OpenID_getSecretSize($assoc_type)
{
if ($assoc_type == 'HMAC-SHA1') {
return 20;
} else if ($assoc_type == 'HMAC-SHA256') {
return 32;
} else {
return null;
}
}
function Auth_OpenID_getAllAssociationTypes()
{
return array('HMAC-SHA1', 'HMAC-SHA256');
}
function Auth_OpenID_getSupportedAssociationTypes()
{
$a = array('HMAC-SHA1');
if (Auth_OpenID_HMACSHA256_SUPPORTED) {
$a[] = 'HMAC-SHA256';
}
return $a;
}
function Auth_OpenID_getSessionTypes($assoc_type)
{
$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());
}
function Auth_OpenID_checkSessionType($assoc_type, $session_type)
{
if (!in_array($session_type,
Auth_OpenID_getSessionTypes($assoc_type))) {
return false;
}
return true;
}
function Auth_OpenID_getDefaultAssociationOrder()
{
$order = 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');
}
return $order;
}
function Auth_OpenID_getOnlyEncryptedOrder()
{
$result = array();
foreach (Auth_OpenID_getDefaultAssociationOrder() as $pair) {
list($assoc, $session) = $pair;
if ($session != 'no-encryption') {
if (Auth_OpenID_HMACSHA256_SUPPORTED &&
($assoc == 'HMAC-SHA256')) {
$result[] = $pair;
} else if ($assoc != 'HMAC-SHA256') {
$result[] = $pair;
}
}
}
return $result;
}
function Auth_OpenID_getDefaultNegotiator()
{
return new Auth_OpenID_SessionNegotiator(
Auth_OpenID_getDefaultAssociationOrder());
}
function Auth_OpenID_getEncryptedNegotiator()
{
return new Auth_OpenID_SessionNegotiator(
Auth_OpenID_getOnlyEncryptedOrder());
}
/**
* 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
* channel
*
* 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.
*
* @package OpenID
*/
class Auth_OpenID_SessionNegotiator {
function Auth_OpenID_SessionNegotiator($allowed_types)
{
$this->allowed_types = array();
$this->setAllowedTypes($allowed_types);
}
/**
* Set the allowed association types, checking to make sure each
* combination is valid.
*
* @access private
*/
function setAllowedTypes($allowed_types)
{
foreach ($allowed_types as $pair) {
list($assoc_type, $session_type) = $pair;
if (!Auth_OpenID_checkSessionType($assoc_type, $session_type)) {
return false;
}
}
$this->allowed_types = $allowed_types;
return true;
}
/**
* Add an association type and session type to the allowed types
* list. The assocation/session pairs are tried in the order that
* they are added.
*
* @access private
*/
function addAllowedType($assoc_type, $session_type = null)
{
if ($this->allowed_types === null) {
$this->allowed_types = array();
}
if ($session_type === null) {
$available = Auth_OpenID_getSessionTypes($assoc_type);
if (!$available) {
return false;
}
foreach ($available as $session_type) {
$this->addAllowedType($assoc_type, $session_type);
}
} else {
if (Auth_OpenID_checkSessionType($assoc_type, $session_type)) {
$this->allowed_types[] = array($assoc_type, $session_type);
} else {
return false;
}
}
return true;
}
// 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),
$this->allowed_types);
$matches = in_array($session_type,
Auth_OpenID_getSessionTypes($assoc_type));
return ($assoc_good && $matches);
}
/**
* Get a pair of assocation type and session type that are
* supported.
*/
function getAllowedType()
{
if (!$this->allowed_types) {
return array(null, null);
}
return $this->allowed_types[0];
}
}
openid-php-openid-782224d/Auth/OpenID/BigMath.php 0000664 0000000 0000000 00000026233 11366367341 0021372 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Needed for random number generation
*/
require_once 'Auth/OpenID/CryptUtil.php';
/**
* Need Auth_OpenID::bytes().
*/
require_once 'Auth/OpenID.php';
/**
* The superclass of all big-integer math implementations
* @access private
* @package OpenID
*/
class Auth_OpenID_MathLibrary {
/**
* Given a long integer, returns the number converted to a binary
* string. This function accepts long integer values of arbitrary
* magnitude and uses the local large-number math library when
* available.
*
* @param integer $long The long number (can be a normal PHP
* integer or a number created by one of the available long number
* libraries)
* @return string $binary The binary version of $long
*/
function longToBinary($long)
{
$cmp = $this->cmp($long, 0);
if ($cmp < 0) {
$msg = __FUNCTION__ . " takes only positive integers.";
trigger_error($msg, E_USER_ERROR);
return null;
}
if ($cmp == 0) {
return "\x00";
}
$bytes = array();
while ($this->cmp($long, 0) > 0) {
array_unshift($bytes, $this->mod($long, 256));
$long = $this->div($long, pow(2, 8));
}
if ($bytes && ($bytes[0] > 127)) {
array_unshift($bytes, 0);
}
$string = '';
foreach ($bytes as $byte) {
$string .= pack('C', $byte);
}
return $string;
}
/**
* Given a binary string, returns the binary string converted to a
* long number.
*
* @param string $binary The binary version of a long number,
* probably as a result of calling longToBinary
* @return integer $long The long number equivalent of the binary
* string $str
*/
function binaryToLong($str)
{
if ($str === null) {
return null;
}
// Use array_merge to return a zero-indexed array instead of a
// one-indexed array.
$bytes = array_merge(unpack('C*', $str));
$n = $this->init(0);
if ($bytes && ($bytes[0] > 127)) {
trigger_error("bytesToNum works only for positive integers.",
E_USER_WARNING);
return null;
}
foreach ($bytes as $byte) {
$n = $this->mul($n, pow(2, 8));
$n = $this->add($n, $byte);
}
return $n;
}
function base64ToLong($str)
{
$b64 = base64_decode($str);
if ($b64 === false) {
return false;
}
return $this->binaryToLong($b64);
}
function longToBase64($str)
{
return base64_encode($this->longToBinary($str));
}
/**
* Returns a random number in the specified range. This function
* accepts $start, $stop, and $step values of arbitrary magnitude
* and will utilize the local large-number math library when
* available.
*
* @param integer $start The start of the range, or the minimum
* random number to return
* @param integer $stop The end of the range, or the maximum
* random number to return
* @param integer $step The step size, such that $result - ($step
* * N) = $start for some N
* @return integer $result The resulting randomly-generated number
*/
function rand($stop)
{
static $duplicate_cache = array();
// Used as the key for the duplicate cache
$rbytes = $this->longToBinary($stop);
if (array_key_exists($rbytes, $duplicate_cache)) {
list($duplicate, $nbytes) = $duplicate_cache[$rbytes];
} else {
if ($rbytes[0] == "\x00") {
$nbytes = Auth_OpenID::bytes($rbytes) - 1;
} else {
$nbytes = Auth_OpenID::bytes($rbytes);
}
$mxrand = $this->pow(256, $nbytes);
// If we get a number less than this, then it is in the
// duplicated range.
$duplicate = $this->mod($mxrand, $stop);
if (count($duplicate_cache) > 10) {
$duplicate_cache = array();
}
$duplicate_cache[$rbytes] = array($duplicate, $nbytes);
}
do {
$bytes = "\x00" . Auth_OpenID_CryptUtil::getBytes($nbytes);
$n = $this->binaryToLong($bytes);
// Keep looping if this value is in the low duplicated range
} while ($this->cmp($n, $duplicate) < 0);
return $this->mod($n, $stop);
}
}
/**
* Exposes BCmath math library functionality.
*
* {@link Auth_OpenID_BcMathWrapper} wraps the functionality provided
* by the BCMath extension.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_BcMathWrapper extends Auth_OpenID_MathLibrary{
var $type = 'bcmath';
function add($x, $y)
{
return bcadd($x, $y);
}
function sub($x, $y)
{
return bcsub($x, $y);
}
function pow($base, $exponent)
{
return bcpow($base, $exponent);
}
function cmp($x, $y)
{
return bccomp($x, $y);
}
function init($number, $base = 10)
{
return $number;
}
function mod($base, $modulus)
{
return bcmod($base, $modulus);
}
function mul($x, $y)
{
return bcmul($x, $y);
}
function div($x, $y)
{
return bcdiv($x, $y);
}
/**
* Same as bcpowmod when bcpowmod is missing
*
* @access private
*/
function _powmod($base, $exponent, $modulus)
{
$square = $this->mod($base, $modulus);
$result = 1;
while($this->cmp($exponent, 0) > 0) {
if ($this->mod($exponent, 2)) {
$result = $this->mod($this->mul($result, $square), $modulus);
}
$square = $this->mod($this->mul($square, $square), $modulus);
$exponent = $this->div($exponent, 2);
}
return $result;
}
function powmod($base, $exponent, $modulus)
{
if (function_exists('bcpowmod')) {
return bcpowmod($base, $exponent, $modulus);
} else {
return $this->_powmod($base, $exponent, $modulus);
}
}
function toString($num)
{
return $num;
}
}
/**
* Exposes GMP math library functionality.
*
* {@link Auth_OpenID_GmpMathWrapper} wraps the functionality provided
* by the GMP extension.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_GmpMathWrapper extends Auth_OpenID_MathLibrary{
var $type = 'gmp';
function add($x, $y)
{
return gmp_add($x, $y);
}
function sub($x, $y)
{
return gmp_sub($x, $y);
}
function pow($base, $exponent)
{
return gmp_pow($base, $exponent);
}
function cmp($x, $y)
{
return gmp_cmp($x, $y);
}
function init($number, $base = 10)
{
return gmp_init($number, $base);
}
function mod($base, $modulus)
{
return gmp_mod($base, $modulus);
}
function mul($x, $y)
{
return gmp_mul($x, $y);
}
function div($x, $y)
{
return gmp_div_q($x, $y);
}
function powmod($base, $exponent, $modulus)
{
return gmp_powm($base, $exponent, $modulus);
}
function toString($num)
{
return gmp_strval($num);
}
}
/**
* Define the supported extensions. An extension array has keys
* 'modules', 'extension', and 'class'. 'modules' is an array of PHP
* module names which the loading code will attempt to load. These
* values will be suffixed with a library file extension (e.g. ".so").
* 'extension' is the name of a PHP extension which will be tested
* before 'modules' are loaded. 'class' is the string name of a
* {@link Auth_OpenID_MathWrapper} subclass which should be
* instantiated if a given extension is present.
*
* You can define new math library implementations and add them to
* this array.
*/
function Auth_OpenID_math_extensions()
{
$result = array();
if (!defined('Auth_OpenID_BUGGY_GMP')) {
$result[] =
array('modules' => array('gmp', 'php_gmp'),
'extension' => 'gmp',
'class' => 'Auth_OpenID_GmpMathWrapper');
}
$result[] = array('modules' => array('bcmath', 'php_bcmath'),
'extension' => 'bcmath',
'class' => 'Auth_OpenID_BcMathWrapper');
return $result;
}
/**
* Detect which (if any) math library is available
*/
function Auth_OpenID_detectMathLibrary($exts)
{
$loaded = false;
$hasDl = function_exists('dl');
foreach ($exts as $extension) {
if (extension_loaded($extension['extension'])) {
return $extension;
}
}
return false;
}
/**
* {@link Auth_OpenID_getMathLib} checks for the presence of long
* number extension modules and returns an instance of
* {@link Auth_OpenID_MathWrapper} which exposes the module's
* functionality.
*
* Checks for the existence of an extension module described by the
* result of {@link Auth_OpenID_math_extensions()} and returns an
* instance of a wrapper for that extension module. If no extension
* module is found, an instance of {@link Auth_OpenID_MathWrapper} is
* returned, which wraps the native PHP integer implementation. The
* proper calling convention for this method is $lib =
* Auth_OpenID_getMathLib().
*
* This function checks for the existence of specific long number
* implementations in the following order: GMP followed by BCmath.
*
* @return Auth_OpenID_MathWrapper $instance An instance of
* {@link Auth_OpenID_MathWrapper} or one of its subclasses
*
* @package OpenID
*/
function Auth_OpenID_getMathLib()
{
// The instance of Auth_OpenID_MathWrapper that we choose to
// supply will be stored here, so that subseqent calls to this
// method will return a reference to the same object.
static $lib = null;
if (isset($lib)) {
return $lib;
}
if (Auth_OpenID_noMathSupport()) {
$null = null;
return $null;
}
// If this method has not been called before, look at
// Auth_OpenID_math_extensions and try to find an extension that
// works.
$ext = Auth_OpenID_detectMathLibrary(Auth_OpenID_math_extensions());
if ($ext === false) {
$tried = array();
foreach (Auth_OpenID_math_extensions() as $extinfo) {
$tried[] = $extinfo['extension'];
}
$triedstr = implode(", ", $tried);
Auth_OpenID_setNoMathSupport();
$result = null;
return $result;
}
// Instantiate a new wrapper
$class = $ext['class'];
$lib = new $class();
return $lib;
}
function Auth_OpenID_setNoMathSupport()
{
if (!defined('Auth_OpenID_NO_MATH_SUPPORT')) {
define('Auth_OpenID_NO_MATH_SUPPORT', true);
}
}
function Auth_OpenID_noMathSupport()
{
return defined('Auth_OpenID_NO_MATH_SUPPORT');
}
openid-php-openid-782224d/Auth/OpenID/Consumer.php 0000664 0000000 0000000 00000231011 11366367341 0021642 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Require utility classes and functions for the consumer.
*/
require_once "Auth/OpenID.php";
require_once "Auth/OpenID/Message.php";
require_once "Auth/OpenID/HMAC.php";
require_once "Auth/OpenID/Association.php";
require_once "Auth/OpenID/CryptUtil.php";
require_once "Auth/OpenID/DiffieHellman.php";
require_once "Auth/OpenID/KVForm.php";
require_once "Auth/OpenID/Nonce.php";
require_once "Auth/OpenID/Discover.php";
require_once "Auth/OpenID/URINorm.php";
require_once "Auth/Yadis/Manager.php";
require_once "Auth/Yadis/XRI.php";
/**
* This is the status code returned when the complete method returns
* successfully.
*/
define('Auth_OpenID_SUCCESS', 'success');
/**
* Status to indicate cancellation of OpenID authentication.
*/
define('Auth_OpenID_CANCEL', 'cancel');
/**
* This is the status code completeAuth returns when the value it
* received indicated an invalid login.
*/
define('Auth_OpenID_FAILURE', 'failure');
/**
* This is the status code completeAuth returns when the
* {@link Auth_OpenID_Consumer} instance is in immediate mode, and the
* identity server sends back a URL to send the user to to complete his
* or her login.
*/
define('Auth_OpenID_SETUP_NEEDED', 'setup needed');
/**
* This is the status code beginAuth returns when the page fetched
* from the entered OpenID URL doesn't contain the necessary link tags
* to function as an identity page.
*/
define('Auth_OpenID_PARSE_ERROR', 'parse error');
/**
* An OpenID consumer implementation that performs discovery and does
* session management. See the Consumer.php file documentation for
* more information.
*
* @package OpenID
*/
class Auth_OpenID_Consumer {
/**
* @access private
*/
var $discoverMethod = 'Auth_OpenID_discover';
/**
* @access private
*/
var $session_key_prefix = "_openid_consumer_";
/**
* @access private
*/
var $_token_suffix = "last_token";
/**
* Initialize a Consumer instance.
*
* You should create a new instance of the Consumer object with
* every HTTP request that handles OpenID transactions.
*
* @param Auth_OpenID_OpenIDStore $store This must be an object
* that implements the interface in {@link
* Auth_OpenID_OpenIDStore}. Several concrete implementations are
* provided, to cover most common use cases. For stores backed by
* MySQL, PostgreSQL, or SQLite, see the {@link
* Auth_OpenID_SQLStore} class and its sublcasses. For a
* filesystem-backed store, see the {@link Auth_OpenID_FileStore}
* module. As a last resort, if it isn't possible for the server
* to store state at all, an instance of {@link
* Auth_OpenID_DumbStore} can be used.
*
* @param mixed $session An object which implements the interface
* of the {@link Auth_Yadis_PHPSession} class. Particularly, this
* object is expected to have these methods: get($key), set($key),
* $value), and del($key). This defaults to a session object
* which wraps PHP's native session machinery. You should only
* need to pass something here if you have your own sessioning
* implementation.
*
* @param str $consumer_cls The name of the class to instantiate
* when creating the internal consumer object. This is used for
* testing.
*/
function Auth_OpenID_Consumer($store, $session = null,
$consumer_cls = null)
{
if ($session === null) {
$session = new Auth_Yadis_PHPSession();
}
$this->session = $session;
if ($consumer_cls !== null) {
$this->consumer = new $consumer_cls($store);
} else {
$this->consumer = new Auth_OpenID_GenericConsumer($store);
}
$this->_token_key = $this->session_key_prefix . $this->_token_suffix;
}
/**
* Used in testing to define the discovery mechanism.
*
* @access private
*/
function getDiscoveryObject($session, $openid_url,
$session_key_prefix)
{
return new Auth_Yadis_Discovery($session, $openid_url,
$session_key_prefix);
}
/**
* Start the OpenID authentication process. See steps 1-2 in the
* overview at the top of this file.
*
* @param string $user_url Identity URL given by the user. This
* method performs a textual transformation of the URL to try and
* make sure it is normalized. For example, a user_url of
* example.com will be normalized to http://example.com/
* normalizing and resolving any redirects the server might issue.
*
* @param bool $anonymous True if the OpenID request is to be sent
* to the server without any identifier information. Use this
* when you want to transport data but don't want to do OpenID
* authentication with identifiers.
*
* @return Auth_OpenID_AuthRequest $auth_request An object
* containing the discovered information will be returned, with a
* method for building a redirect URL to the server, as described
* in step 3 of the overview. This object may also be used to add
* extension arguments to the request, using its 'addExtensionArg'
* method.
*/
function begin($user_url, $anonymous=false)
{
$openid_url = $user_url;
$disco = $this->getDiscoveryObject($this->session,
$openid_url,
$this->session_key_prefix);
// Set the 'stale' attribute of the manager. If discovery
// fails in a fatal way, the stale flag will cause the manager
// to be cleaned up next time discovery is attempted.
$m = $disco->getManager();
$loader = new Auth_Yadis_ManagerLoader();
if ($m) {
if ($m->stale) {
$disco->destroyManager();
} else {
$m->stale = true;
$disco->session->set($disco->session_key,
serialize($loader->toSession($m)));
}
}
$endpoint = $disco->getNextService($this->discoverMethod,
$this->consumer->fetcher);
// Reset the 'stale' attribute of the manager.
$m = $disco->getManager();
if ($m) {
$m->stale = false;
$disco->session->set($disco->session_key,
serialize($loader->toSession($m)));
}
if ($endpoint === null) {
return null;
} else {
return $this->beginWithoutDiscovery($endpoint,
$anonymous);
}
}
/**
* Start OpenID verification without doing OpenID server
* discovery. This method is used internally by Consumer.begin
* after discovery is performed, and exists to provide an
* interface for library users needing to perform their own
* discovery.
*
* @param Auth_OpenID_ServiceEndpoint $endpoint an OpenID service
* endpoint descriptor.
*
* @param bool anonymous Set to true if you want to perform OpenID
* without identifiers.
*
* @return Auth_OpenID_AuthRequest $auth_request An OpenID
* authentication request object.
*/
function beginWithoutDiscovery($endpoint, $anonymous=false)
{
$loader = new Auth_OpenID_ServiceEndpointLoader();
$auth_req = $this->consumer->begin($endpoint);
$this->session->set($this->_token_key,
$loader->toSession($auth_req->endpoint));
if (!$auth_req->setAnonymous($anonymous)) {
return new Auth_OpenID_FailureResponse(null,
"OpenID 1 requests MUST include the identifier " .
"in the request.");
}
return $auth_req;
}
/**
* Called to interpret the server's response to an OpenID
* request. It is called in step 4 of the flow described in the
* consumer overview.
*
* @param string $current_url The URL used to invoke the application.
* Extract the URL from your application's web
* request framework and specify it here to have it checked
* against the openid.current_url value in the response. If
* the current_url URL check fails, the status of the
* completion will be FAILURE.
*
* @param array $query An array of the query parameters (key =>
* value pairs) for this HTTP request. Defaults to null. If
* null, the GET or POST data are automatically gotten from the
* PHP environment. It is only useful to override $query for
* testing.
*
* @return Auth_OpenID_ConsumerResponse $response A instance of an
* Auth_OpenID_ConsumerResponse subclass. The type of response is
* indicated by the status attribute, which will be one of
* SUCCESS, CANCEL, FAILURE, or SETUP_NEEDED.
*/
function complete($current_url, $query=null)
{
if ($current_url && !is_string($current_url)) {
// This is ugly, but we need to complain loudly when
// someone uses the API incorrectly.
trigger_error("current_url must be a string; see NEWS file " .
"for upgrading notes.",
E_USER_ERROR);
}
if ($query === null) {
$query = Auth_OpenID::getQuery();
}
$loader = new Auth_OpenID_ServiceEndpointLoader();
$endpoint_data = $this->session->get($this->_token_key);
$endpoint =
$loader->fromSession($endpoint_data);
$message = Auth_OpenID_Message::fromPostArgs($query);
$response = $this->consumer->complete($message, $endpoint,
$current_url);
$this->session->del($this->_token_key);
if (in_array($response->status, array(Auth_OpenID_SUCCESS,
Auth_OpenID_CANCEL))) {
if ($response->identity_url !== null) {
$disco = $this->getDiscoveryObject($this->session,
$response->identity_url,
$this->session_key_prefix);
$disco->cleanup(true);
}
}
return $response;
}
}
/**
* A class implementing HMAC/DH-SHA1 consumer sessions.
*
* @package OpenID
*/
class Auth_OpenID_DiffieHellmanSHA1ConsumerSession {
var $session_type = 'DH-SHA1';
var $hash_func = 'Auth_OpenID_SHA1';
var $secret_size = 20;
var $allowed_assoc_types = array('HMAC-SHA1');
function Auth_OpenID_DiffieHellmanSHA1ConsumerSession($dh = null)
{
if ($dh === null) {
$dh = new Auth_OpenID_DiffieHellman();
}
$this->dh = $dh;
}
function getRequest()
{
$math = Auth_OpenID_getMathLib();
$cpub = $math->longToBase64($this->dh->public);
$args = array('dh_consumer_public' => $cpub);
if (!$this->dh->usingDefaultValues()) {
$args = array_merge($args, array(
'dh_modulus' =>
$math->longToBase64($this->dh->mod),
'dh_gen' =>
$math->longToBase64($this->dh->gen)));
}
return $args;
}
function extractSecret($response)
{
if (!$response->hasKey(Auth_OpenID_OPENID_NS,
'dh_server_public')) {
return null;
}
if (!$response->hasKey(Auth_OpenID_OPENID_NS,
'enc_mac_key')) {
return null;
}
$math = Auth_OpenID_getMathLib();
$spub = $math->base64ToLong($response->getArg(Auth_OpenID_OPENID_NS,
'dh_server_public'));
$enc_mac_key = base64_decode($response->getArg(Auth_OpenID_OPENID_NS,
'enc_mac_key'));
return $this->dh->xorSecret($spub, $enc_mac_key, $this->hash_func);
}
}
/**
* A class implementing HMAC/DH-SHA256 consumer sessions.
*
* @package OpenID
*/
class Auth_OpenID_DiffieHellmanSHA256ConsumerSession extends
Auth_OpenID_DiffieHellmanSHA1ConsumerSession {
var $session_type = 'DH-SHA256';
var $hash_func = 'Auth_OpenID_SHA256';
var $secret_size = 32;
var $allowed_assoc_types = array('HMAC-SHA256');
}
/**
* A class implementing plaintext consumer sessions.
*
* @package OpenID
*/
class Auth_OpenID_PlainTextConsumerSession {
var $session_type = 'no-encryption';
var $allowed_assoc_types = array('HMAC-SHA1', 'HMAC-SHA256');
function getRequest()
{
return array();
}
function extractSecret($response)
{
if (!$response->hasKey(Auth_OpenID_OPENID_NS, 'mac_key')) {
return null;
}
return base64_decode($response->getArg(Auth_OpenID_OPENID_NS,
'mac_key'));
}
}
/**
* Returns available session types.
*/
function Auth_OpenID_getAvailableSessionTypes()
{
$types = array(
'no-encryption' => 'Auth_OpenID_PlainTextConsumerSession',
'DH-SHA1' => 'Auth_OpenID_DiffieHellmanSHA1ConsumerSession',
'DH-SHA256' => 'Auth_OpenID_DiffieHellmanSHA256ConsumerSession');
return $types;
}
/**
* This class is the interface to the OpenID consumer logic.
* Instances of it maintain no per-request state, so they can be
* reused (or even used by multiple threads concurrently) as needed.
*
* @package OpenID
*/
class Auth_OpenID_GenericConsumer {
/**
* @access private
*/
var $discoverMethod = 'Auth_OpenID_discover';
/**
* This consumer's store object.
*/
var $store;
/**
* @access private
*/
var $_use_assocs;
/**
* @access private
*/
var $openid1_nonce_query_arg_name = 'janrain_nonce';
/**
* Another query parameter that gets added to the return_to for
* OpenID 1; if the user's session state is lost, use this claimed
* identifier to do discovery when verifying the response.
*/
var $openid1_return_to_identifier_name = 'openid1_claimed_id';
/**
* This method initializes a new {@link Auth_OpenID_Consumer}
* instance to access the library.
*
* @param Auth_OpenID_OpenIDStore $store This must be an object
* that implements the interface in {@link Auth_OpenID_OpenIDStore}.
* Several concrete implementations are provided, to cover most common use
* cases. For stores backed by MySQL, PostgreSQL, or SQLite, see
* the {@link Auth_OpenID_SQLStore} class and its sublcasses. For a
* filesystem-backed store, see the {@link Auth_OpenID_FileStore} module.
* As a last resort, if it isn't possible for the server to store
* state at all, an instance of {@link Auth_OpenID_DumbStore} can be used.
*
* @param bool $immediate This is an optional boolean value. It
* controls whether the library uses immediate mode, as explained
* in the module description. The default value is False, which
* disables immediate mode.
*/
function Auth_OpenID_GenericConsumer($store)
{
$this->store = $store;
$this->negotiator = Auth_OpenID_getDefaultNegotiator();
$this->_use_assocs = (is_null($this->store) ? false : true);
$this->fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
$this->session_types = Auth_OpenID_getAvailableSessionTypes();
}
/**
* Called to begin OpenID authentication using the specified
* {@link Auth_OpenID_ServiceEndpoint}.
*
* @access private
*/
function begin($service_endpoint)
{
$assoc = $this->_getAssociation($service_endpoint);
$r = new Auth_OpenID_AuthRequest($service_endpoint, $assoc);
$r->return_to_args[$this->openid1_nonce_query_arg_name] =
Auth_OpenID_mkNonce();
if ($r->message->isOpenID1()) {
$r->return_to_args[$this->openid1_return_to_identifier_name] =
$r->endpoint->claimed_id;
}
return $r;
}
/**
* Given an {@link Auth_OpenID_Message}, {@link
* Auth_OpenID_ServiceEndpoint} and optional return_to URL,
* complete OpenID authentication.
*
* @access private
*/
function complete($message, $endpoint, $return_to)
{
$mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode',
'');
$mode_methods = array(
'cancel' => '_complete_cancel',
'error' => '_complete_error',
'setup_needed' => '_complete_setup_needed',
'id_res' => '_complete_id_res',
);
$method = Auth_OpenID::arrayGet($mode_methods, $mode,
'_completeInvalid');
return call_user_func_array(array($this, $method),
array($message, &$endpoint, $return_to));
}
/**
* @access private
*/
function _completeInvalid($message, $endpoint, $unused)
{
$mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode',
'');
return new Auth_OpenID_FailureResponse($endpoint,
sprintf("Invalid openid.mode '%s'", $mode));
}
/**
* @access private
*/
function _complete_cancel($message, $endpoint, $unused)
{
return new Auth_OpenID_CancelResponse($endpoint);
}
/**
* @access private
*/
function _complete_error($message, $endpoint, $unused)
{
$error = $message->getArg(Auth_OpenID_OPENID_NS, 'error');
$contact = $message->getArg(Auth_OpenID_OPENID_NS, 'contact');
$reference = $message->getArg(Auth_OpenID_OPENID_NS, 'reference');
return new Auth_OpenID_FailureResponse($endpoint, $error,
$contact, $reference);
}
/**
* @access private
*/
function _complete_setup_needed($message, $endpoint, $unused)
{
if (!$message->isOpenID2()) {
return $this->_completeInvalid($message, $endpoint);
}
$user_setup_url = $message->getArg(Auth_OpenID_OPENID2_NS,
'user_setup_url');
return new Auth_OpenID_SetupNeededResponse($endpoint, $user_setup_url);
}
/**
* @access private
*/
function _complete_id_res($message, $endpoint, $return_to)
{
$user_setup_url = $message->getArg(Auth_OpenID_OPENID1_NS,
'user_setup_url');
if ($this->_checkSetupNeeded($message)) {
return new Auth_OpenID_SetupNeededResponse(
$endpoint, $user_setup_url);
} else {
return $this->_doIdRes($message, $endpoint, $return_to);
}
}
/**
* @access private
*/
function _checkSetupNeeded($message)
{
// In OpenID 1, we check to see if this is a cancel from
// immediate mode by the presence of the user_setup_url
// parameter.
if ($message->isOpenID1()) {
$user_setup_url = $message->getArg(Auth_OpenID_OPENID1_NS,
'user_setup_url');
if ($user_setup_url !== null) {
return true;
}
}
return false;
}
/**
* @access private
*/
function _doIdRes($message, $endpoint, $return_to)
{
// Checks for presence of appropriate fields (and checks
// signed list fields)
$result = $this->_idResCheckForFields($message);
if (Auth_OpenID::isFailure($result)) {
return $result;
}
if (!$this->_checkReturnTo($message, $return_to)) {
return new Auth_OpenID_FailureResponse(null,
sprintf("return_to does not match return URL. Expected %s, got %s",
$return_to,
$message->getArg(Auth_OpenID_OPENID_NS, 'return_to')));
}
// Verify discovery information:
$result = $this->_verifyDiscoveryResults($message, $endpoint);
if (Auth_OpenID::isFailure($result)) {
return $result;
}
$endpoint = $result;
$result = $this->_idResCheckSignature($message,
$endpoint->server_url);
if (Auth_OpenID::isFailure($result)) {
return $result;
}
$result = $this->_idResCheckNonce($message, $endpoint);
if (Auth_OpenID::isFailure($result)) {
return $result;
}
$signed_list_str = $message->getArg(Auth_OpenID_OPENID_NS, 'signed',
Auth_OpenID_NO_DEFAULT);
if (Auth_OpenID::isFailure($signed_list_str)) {
return $signed_list_str;
}
$signed_list = explode(',', $signed_list_str);
$signed_fields = Auth_OpenID::addPrefix($signed_list, "openid.");
return new Auth_OpenID_SuccessResponse($endpoint, $message,
$signed_fields);
}
/**
* @access private
*/
function _checkReturnTo($message, $return_to)
{
// Check an OpenID message and its openid.return_to value
// against a return_to URL from an application. Return True
// on success, False on failure.
// Check the openid.return_to args against args in the
// original message.
$result = Auth_OpenID_GenericConsumer::_verifyReturnToArgs(
$message->toPostArgs());
if (Auth_OpenID::isFailure($result)) {
return false;
}
// Check the return_to base URL against the one in the
// message.
$msg_return_to = $message->getArg(Auth_OpenID_OPENID_NS,
'return_to');
if (Auth_OpenID::isFailure($return_to)) {
// XXX log me
return false;
}
$return_to_parts = parse_url(Auth_OpenID_urinorm($return_to));
$msg_return_to_parts = parse_url(Auth_OpenID_urinorm($msg_return_to));
// If port is absent from both, add it so it's equal in the
// check below.
if ((!array_key_exists('port', $return_to_parts)) &&
(!array_key_exists('port', $msg_return_to_parts))) {
$return_to_parts['port'] = null;
$msg_return_to_parts['port'] = null;
}
// If path is absent from both, add it so it's equal in the
// check below.
if ((!array_key_exists('path', $return_to_parts)) &&
(!array_key_exists('path', $msg_return_to_parts))) {
$return_to_parts['path'] = null;
$msg_return_to_parts['path'] = null;
}
// The URL scheme, authority, and path MUST be the same
// between the two URLs.
foreach (array('scheme', 'host', 'port', 'path') as $component) {
// If the url component is absent in either URL, fail.
// There should always be a scheme, host, port, and path.
if (!array_key_exists($component, $return_to_parts)) {
return false;
}
if (!array_key_exists($component, $msg_return_to_parts)) {
return false;
}
if (Auth_OpenID::arrayGet($return_to_parts, $component) !==
Auth_OpenID::arrayGet($msg_return_to_parts, $component)) {
return false;
}
}
return true;
}
/**
* @access private
*/
function _verifyReturnToArgs($query)
{
// Verify that the arguments in the return_to URL are present in this
// response.
$message = Auth_OpenID_Message::fromPostArgs($query);
$return_to = $message->getArg(Auth_OpenID_OPENID_NS, 'return_to');
if (Auth_OpenID::isFailure($return_to)) {
return $return_to;
}
// XXX: this should be checked by _idResCheckForFields
if (!$return_to) {
return new Auth_OpenID_FailureResponse(null,
"Response has no return_to");
}
$parsed_url = parse_url($return_to);
$q = array();
if (array_key_exists('query', $parsed_url)) {
$rt_query = $parsed_url['query'];
$q = Auth_OpenID::parse_str($rt_query);
}
foreach ($q as $rt_key => $rt_value) {
if (!array_key_exists($rt_key, $query)) {
return new Auth_OpenID_FailureResponse(null,
sprintf("return_to parameter %s absent from query", $rt_key));
} else {
$value = $query[$rt_key];
if ($rt_value != $value) {
return new Auth_OpenID_FailureResponse(null,
sprintf("parameter %s value %s does not match " .
"return_to value %s", $rt_key,
$value, $rt_value));
}
}
}
// Make sure all non-OpenID arguments in the response are also
// in the signed return_to.
$bare_args = $message->getArgs(Auth_OpenID_BARE_NS);
foreach ($bare_args as $key => $value) {
if (Auth_OpenID::arrayGet($q, $key) != $value) {
return new Auth_OpenID_FailureResponse(null,
sprintf("Parameter %s = %s not in return_to URL",
$key, $value));
}
}
return true;
}
/**
* @access private
*/
function _idResCheckSignature($message, $server_url)
{
$assoc_handle = $message->getArg(Auth_OpenID_OPENID_NS,
'assoc_handle');
if (Auth_OpenID::isFailure($assoc_handle)) {
return $assoc_handle;
}
$assoc = $this->store->getAssociation($server_url, $assoc_handle);
if ($assoc) {
if ($assoc->getExpiresIn() <= 0) {
// XXX: It might be a good idea sometimes to re-start
// the authentication with a new association. Doing it
// automatically opens the possibility for
// denial-of-service by a server that just returns
// expired associations (or really short-lived
// associations)
return new Auth_OpenID_FailureResponse(null,
'Association with ' . $server_url . ' expired');
}
if (!$assoc->checkMessageSignature($message)) {
return new Auth_OpenID_FailureResponse(null,
"Bad signature");
}
} else {
// It's not an association we know about. Stateless mode
// is our only possible path for recovery. XXX - async
// framework will not want to block on this call to
// _checkAuth.
if (!$this->_checkAuth($message, $server_url)) {
return new Auth_OpenID_FailureResponse(null,
"Server denied check_authentication");
}
}
return null;
}
/**
* @access private
*/
function _verifyDiscoveryResults($message, $endpoint=null)
{
if ($message->getOpenIDNamespace() == Auth_OpenID_OPENID2_NS) {
return $this->_verifyDiscoveryResultsOpenID2($message,
$endpoint);
} else {
return $this->_verifyDiscoveryResultsOpenID1($message,
$endpoint);
}
}
/**
* @access private
*/
function _verifyDiscoveryResultsOpenID1($message, $endpoint)
{
$claimed_id = $message->getArg(Auth_OpenID_BARE_NS,
$this->openid1_return_to_identifier_name);
if (($endpoint === null) && ($claimed_id === null)) {
return new Auth_OpenID_FailureResponse($endpoint,
'When using OpenID 1, the claimed ID must be supplied, ' .
'either by passing it through as a return_to parameter ' .
'or by using a session, and supplied to the GenericConsumer ' .
'as the argument to complete()');
} else if (($endpoint !== null) && ($claimed_id === null)) {
$claimed_id = $endpoint->claimed_id;
}
$to_match = new Auth_OpenID_ServiceEndpoint();
$to_match->type_uris = array(Auth_OpenID_TYPE_1_1);
$to_match->local_id = $message->getArg(Auth_OpenID_OPENID1_NS,
'identity');
// Restore delegate information from the initiation phase
$to_match->claimed_id = $claimed_id;
if ($to_match->local_id === null) {
return new Auth_OpenID_FailureResponse($endpoint,
"Missing required field openid.identity");
}
$to_match_1_0 = $to_match->copy();
$to_match_1_0->type_uris = array(Auth_OpenID_TYPE_1_0);
if ($endpoint !== null) {
$result = $this->_verifyDiscoverySingle($endpoint, $to_match);
if (is_a($result, 'Auth_OpenID_TypeURIMismatch')) {
$result = $this->_verifyDiscoverySingle($endpoint,
$to_match_1_0);
}
if (Auth_OpenID::isFailure($result)) {
// oidutil.log("Error attempting to use stored
// discovery information: " + str(e))
// oidutil.log("Attempting discovery to
// verify endpoint")
} else {
return $endpoint;
}
}
// Endpoint is either bad (failed verification) or None
return $this->_discoverAndVerify($to_match->claimed_id,
array($to_match, $to_match_1_0));
}
/**
* @access private
*/
function _verifyDiscoverySingle($endpoint, $to_match)
{
// Every type URI that's in the to_match endpoint has to be
// present in the discovered endpoint.
foreach ($to_match->type_uris as $type_uri) {
if (!$endpoint->usesExtension($type_uri)) {
return new Auth_OpenID_TypeURIMismatch($endpoint,
"Required type ".$type_uri." not present");
}
}
// Fragments do not influence discovery, so we can't compare a
// claimed identifier with a fragment to discovered
// information.
list($defragged_claimed_id, $_) =
Auth_OpenID::urldefrag($to_match->claimed_id);
if ($defragged_claimed_id != $endpoint->claimed_id) {
return new Auth_OpenID_FailureResponse($endpoint,
sprintf('Claimed ID does not match (different subjects!), ' .
'Expected %s, got %s', $defragged_claimed_id,
$endpoint->claimed_id));
}
if ($to_match->getLocalID() != $endpoint->getLocalID()) {
return new Auth_OpenID_FailureResponse($endpoint,
sprintf('local_id mismatch. Expected %s, got %s',
$to_match->getLocalID(), $endpoint->getLocalID()));
}
// If the server URL is None, this must be an OpenID 1
// response, because op_endpoint is a required parameter in
// OpenID 2. In that case, we don't actually care what the
// discovered server_url is, because signature checking or
// check_auth should take care of that check for us.
if ($to_match->server_url === null) {
if ($to_match->preferredNamespace() != Auth_OpenID_OPENID1_NS) {
return new Auth_OpenID_FailureResponse($endpoint,
"Preferred namespace mismatch (bug)");
}
} else if ($to_match->server_url != $endpoint->server_url) {
return new Auth_OpenID_FailureResponse($endpoint,
sprintf('OP Endpoint mismatch. Expected %s, got %s',
$to_match->server_url, $endpoint->server_url));
}
return null;
}
/**
* @access private
*/
function _verifyDiscoveryResultsOpenID2($message, $endpoint)
{
$to_match = new Auth_OpenID_ServiceEndpoint();
$to_match->type_uris = array(Auth_OpenID_TYPE_2_0);
$to_match->claimed_id = $message->getArg(Auth_OpenID_OPENID2_NS,
'claimed_id');
$to_match->local_id = $message->getArg(Auth_OpenID_OPENID2_NS,
'identity');
$to_match->server_url = $message->getArg(Auth_OpenID_OPENID2_NS,
'op_endpoint');
if ($to_match->server_url === null) {
return new Auth_OpenID_FailureResponse($endpoint,
"OP Endpoint URL missing");
}
// claimed_id and identifier must both be present or both be
// absent
if (($to_match->claimed_id === null) &&
($to_match->local_id !== null)) {
return new Auth_OpenID_FailureResponse($endpoint,
'openid.identity is present without openid.claimed_id');
}
if (($to_match->claimed_id !== null) &&
($to_match->local_id === null)) {
return new Auth_OpenID_FailureResponse($endpoint,
'openid.claimed_id is present without openid.identity');
}
if ($to_match->claimed_id === null) {
// This is a response without identifiers, so there's
// really no checking that we can do, so return an
// endpoint that's for the specified `openid.op_endpoint'
return Auth_OpenID_ServiceEndpoint::fromOPEndpointURL(
$to_match->server_url);
}
if (!$endpoint) {
// The claimed ID doesn't match, so we have to do
// discovery again. This covers not using sessions, OP
// identifier endpoints and responses that didn't match
// the original request.
// oidutil.log('No pre-discovered information supplied.')
return $this->_discoverAndVerify($to_match->claimed_id,
array($to_match));
} else {
// The claimed ID matches, so we use the endpoint that we
// discovered in initiation. This should be the most
// common case.
$result = $this->_verifyDiscoverySingle($endpoint, $to_match);
if (Auth_OpenID::isFailure($result)) {
$endpoint = $this->_discoverAndVerify($to_match->claimed_id,
array($to_match));
if (Auth_OpenID::isFailure($endpoint)) {
return $endpoint;
}
}
}
// The endpoint we return should have the claimed ID from the
// message we just verified, fragment and all.
if ($endpoint->claimed_id != $to_match->claimed_id) {
$endpoint->claimed_id = $to_match->claimed_id;
}
return $endpoint;
}
/**
* @access private
*/
function _discoverAndVerify($claimed_id, $to_match_endpoints)
{
// oidutil.log('Performing discovery on %s' % (claimed_id,))
list($unused, $services) = call_user_func($this->discoverMethod,
$claimed_id,
&$this->fetcher);
if (!$services) {
return new Auth_OpenID_FailureResponse(null,
sprintf("No OpenID information found at %s",
$claimed_id));
}
return $this->_verifyDiscoveryServices($claimed_id, $services,
$to_match_endpoints);
}
/**
* @access private
*/
function _verifyDiscoveryServices($claimed_id,
$services, $to_match_endpoints)
{
// Search the services resulting from discovery to find one
// that matches the information from the assertion
foreach ($services as $endpoint) {
foreach ($to_match_endpoints as $to_match_endpoint) {
$result = $this->_verifyDiscoverySingle($endpoint,
$to_match_endpoint);
if (!Auth_OpenID::isFailure($result)) {
// It matches, so discover verification has
// succeeded. Return this endpoint.
return $endpoint;
}
}
}
return new Auth_OpenID_FailureResponse(null,
sprintf('No matching endpoint found after discovering %s: %s',
$claimed_id, $result->message));
}
/**
* Extract the nonce from an OpenID 1 response. Return the nonce
* from the BARE_NS since we independently check the return_to
* arguments are the same as those in the response message.
*
* See the openid1_nonce_query_arg_name class variable
*
* @returns $nonce The nonce as a string or null
*
* @access private
*/
function _idResGetNonceOpenID1($message, $endpoint)
{
return $message->getArg(Auth_OpenID_BARE_NS,
$this->openid1_nonce_query_arg_name);
}
/**
* @access private
*/
function _idResCheckNonce($message, $endpoint)
{
if ($message->isOpenID1()) {
// This indicates that the nonce was generated by the consumer
$nonce = $this->_idResGetNonceOpenID1($message, $endpoint);
$server_url = '';
} else {
$nonce = $message->getArg(Auth_OpenID_OPENID2_NS,
'response_nonce');
$server_url = $endpoint->server_url;
}
if ($nonce === null) {
return new Auth_OpenID_FailureResponse($endpoint,
"Nonce missing from response");
}
$parts = Auth_OpenID_splitNonce($nonce);
if ($parts === null) {
return new Auth_OpenID_FailureResponse($endpoint,
"Malformed nonce in response");
}
list($timestamp, $salt) = $parts;
if (!$this->store->useNonce($server_url, $timestamp, $salt)) {
return new Auth_OpenID_FailureResponse($endpoint,
"Nonce already used or out of range");
}
return null;
}
/**
* @access private
*/
function _idResCheckForFields($message)
{
$basic_fields = array('return_to', 'assoc_handle', 'sig', 'signed');
$basic_sig_fields = array('return_to', 'identity');
$require_fields = array(
Auth_OpenID_OPENID2_NS => array_merge($basic_fields,
array('op_endpoint')),
Auth_OpenID_OPENID1_NS => array_merge($basic_fields,
array('identity'))
);
$require_sigs = array(
Auth_OpenID_OPENID2_NS => array_merge($basic_sig_fields,
array('response_nonce',
'claimed_id',
'assoc_handle',
'op_endpoint')),
Auth_OpenID_OPENID1_NS => array_merge($basic_sig_fields,
array('nonce'))
);
foreach ($require_fields[$message->getOpenIDNamespace()] as $field) {
if (!$message->hasKey(Auth_OpenID_OPENID_NS, $field)) {
return new Auth_OpenID_FailureResponse(null,
"Missing required field '".$field."'");
}
}
$signed_list_str = $message->getArg(Auth_OpenID_OPENID_NS,
'signed',
Auth_OpenID_NO_DEFAULT);
if (Auth_OpenID::isFailure($signed_list_str)) {
return $signed_list_str;
}
$signed_list = explode(',', $signed_list_str);
foreach ($require_sigs[$message->getOpenIDNamespace()] as $field) {
// Field is present and not in signed list
if ($message->hasKey(Auth_OpenID_OPENID_NS, $field) &&
(!in_array($field, $signed_list))) {
return new Auth_OpenID_FailureResponse(null,
"'".$field."' not signed");
}
}
return null;
}
/**
* @access private
*/
function _checkAuth($message, $server_url)
{
$request = $this->_createCheckAuthRequest($message);
if ($request === null) {
return false;
}
$resp_message = $this->_makeKVPost($request, $server_url);
if (($resp_message === null) ||
(is_a($resp_message, 'Auth_OpenID_ServerErrorContainer'))) {
return false;
}
return $this->_processCheckAuthResponse($resp_message, $server_url);
}
/**
* @access private
*/
function _createCheckAuthRequest($message)
{
$signed = $message->getArg(Auth_OpenID_OPENID_NS, 'signed');
if ($signed) {
foreach (explode(',', $signed) as $k) {
$value = $message->getAliasedArg($k);
if ($value === null) {
return null;
}
}
}
$ca_message = $message->copy();
$ca_message->setArg(Auth_OpenID_OPENID_NS, 'mode',
'check_authentication');
return $ca_message;
}
/**
* @access private
*/
function _processCheckAuthResponse($response, $server_url)
{
$is_valid = $response->getArg(Auth_OpenID_OPENID_NS, 'is_valid',
'false');
$invalidate_handle = $response->getArg(Auth_OpenID_OPENID_NS,
'invalidate_handle');
if ($invalidate_handle !== null) {
$this->store->removeAssociation($server_url,
$invalidate_handle);
}
if ($is_valid == 'true') {
return true;
}
return false;
}
/**
* Adapt a POST response to a Message.
*
* @param $response Result of a POST to an OpenID endpoint.
*
* @access private
*/
static function _httpResponseToMessage($response, $server_url)
{
// Should this function be named Message.fromHTTPResponse instead?
$response_message = Auth_OpenID_Message::fromKVForm($response->body);
if ($response->status == 400) {
return Auth_OpenID_ServerErrorContainer::fromMessage(
$response_message);
} else if ($response->status != 200 and $response->status != 206) {
return null;
}
return $response_message;
}
/**
* @access private
*/
function _makeKVPost($message, $server_url)
{
$body = $message->toURLEncoded();
$resp = $this->fetcher->post($server_url, $body);
if ($resp === null) {
return null;
}
return $this->_httpResponseToMessage($resp, $server_url);
}
/**
* @access private
*/
function _getAssociation($endpoint)
{
if (!$this->_use_assocs) {
return null;
}
$assoc = $this->store->getAssociation($endpoint->server_url);
if (($assoc === null) ||
($assoc->getExpiresIn() <= 0)) {
$assoc = $this->_negotiateAssociation($endpoint);
if ($assoc !== null) {
$this->store->storeAssociation($endpoint->server_url,
$assoc);
}
}
return $assoc;
}
/**
* Handle ServerErrors resulting from association requests.
*
* @return $result If server replied with an C{unsupported-type}
* error, return a tuple of supported C{association_type},
* C{session_type}. Otherwise logs the error and returns null.
*
* @access private
*/
function _extractSupportedAssociationType($server_error, $endpoint,
$assoc_type)
{
// Any error message whose code is not 'unsupported-type'
// should be considered a total failure.
if (($server_error->error_code != 'unsupported-type') ||
($server_error->message->isOpenID1())) {
return null;
}
// The server didn't like the association/session type that we
// sent, and it sent us back a message that might tell us how
// to handle it.
// Extract the session_type and assoc_type from the error
// message
$assoc_type = $server_error->message->getArg(Auth_OpenID_OPENID_NS,
'assoc_type');
$session_type = $server_error->message->getArg(Auth_OpenID_OPENID_NS,
'session_type');
if (($assoc_type === null) || ($session_type === null)) {
return null;
} else if (!$this->negotiator->isAllowed($assoc_type,
$session_type)) {
return null;
} else {
return array($assoc_type, $session_type);
}
}
/**
* @access private
*/
function _negotiateAssociation($endpoint)
{
// Get our preferred session/association type from the negotiatior.
list($assoc_type, $session_type) = $this->negotiator->getAllowedType();
$assoc = $this->_requestAssociation(
$endpoint, $assoc_type, $session_type);
if (Auth_OpenID::isFailure($assoc)) {
return null;
}
if (is_a($assoc, 'Auth_OpenID_ServerErrorContainer')) {
$why = $assoc;
$supportedTypes = $this->_extractSupportedAssociationType(
$why, $endpoint, $assoc_type);
if ($supportedTypes !== null) {
list($assoc_type, $session_type) = $supportedTypes;
// Attempt to create an association from the assoc_type
// and session_type that the server told us it
// supported.
$assoc = $this->_requestAssociation(
$endpoint, $assoc_type, $session_type);
if (is_a($assoc, 'Auth_OpenID_ServerErrorContainer')) {
// Do not keep trying, since it rejected the
// association type that it told us to use.
// oidutil.log('Server %s refused its suggested association
// 'type: session_type=%s, assoc_type=%s'
// % (endpoint.server_url, session_type,
// assoc_type))
return null;
} else {
return $assoc;
}
} else {
return null;
}
} else {
return $assoc;
}
}
/**
* @access private
*/
function _requestAssociation($endpoint, $assoc_type, $session_type)
{
list($assoc_session, $args) = $this->_createAssociateRequest(
$endpoint, $assoc_type, $session_type);
$response_message = $this->_makeKVPost($args, $endpoint->server_url);
if ($response_message === null) {
// oidutil.log('openid.associate request failed: %s' % (why[0],))
return null;
} else if (is_a($response_message,
'Auth_OpenID_ServerErrorContainer')) {
return $response_message;
}
return $this->_extractAssociation($response_message, $assoc_session);
}
/**
* @access private
*/
function _extractAssociation($assoc_response, $assoc_session)
{
// Extract the common fields from the response, raising an
// exception if they are not found
$assoc_type = $assoc_response->getArg(
Auth_OpenID_OPENID_NS, 'assoc_type',
Auth_OpenID_NO_DEFAULT);
if (Auth_OpenID::isFailure($assoc_type)) {
return $assoc_type;
}
$assoc_handle = $assoc_response->getArg(
Auth_OpenID_OPENID_NS, 'assoc_handle',
Auth_OpenID_NO_DEFAULT);
if (Auth_OpenID::isFailure($assoc_handle)) {
return $assoc_handle;
}
// expires_in is a base-10 string. The Python parsing will
// accept literals that have whitespace around them and will
// accept negative values. Neither of these are really in-spec,
// but we think it's OK to accept them.
$expires_in_str = $assoc_response->getArg(
Auth_OpenID_OPENID_NS, 'expires_in',
Auth_OpenID_NO_DEFAULT);
if (Auth_OpenID::isFailure($expires_in_str)) {
return $expires_in_str;
}
$expires_in = Auth_OpenID::intval($expires_in_str);
if ($expires_in === false) {
$err = sprintf("Could not parse expires_in from association ".
"response %s", print_r($assoc_response, true));
return new Auth_OpenID_FailureResponse(null, $err);
}
// OpenID 1 has funny association session behaviour.
if ($assoc_response->isOpenID1()) {
$session_type = $this->_getOpenID1SessionType($assoc_response);
} else {
$session_type = $assoc_response->getArg(
Auth_OpenID_OPENID2_NS, 'session_type',
Auth_OpenID_NO_DEFAULT);
if (Auth_OpenID::isFailure($session_type)) {
return $session_type;
}
}
// Session type mismatch
if ($assoc_session->session_type != $session_type) {
if ($assoc_response->isOpenID1() &&
($session_type == 'no-encryption')) {
// In OpenID 1, any association request can result in
// a 'no-encryption' association response. Setting
// assoc_session to a new no-encryption session should
// make the rest of this function work properly for
// that case.
$assoc_session = new Auth_OpenID_PlainTextConsumerSession();
} else {
// Any other mismatch, regardless of protocol version
// results in the failure of the association session
// altogether.
return null;
}
}
// Make sure assoc_type is valid for session_type
if (!in_array($assoc_type, $assoc_session->allowed_assoc_types)) {
return null;
}
// Delegate to the association session to extract the secret
// from the response, however is appropriate for that session
// type.
$secret = $assoc_session->extractSecret($assoc_response);
if ($secret === null) {
return null;
}
return Auth_OpenID_Association::fromExpiresIn(
$expires_in, $assoc_handle, $secret, $assoc_type);
}
/**
* @access private
*/
function _createAssociateRequest($endpoint, $assoc_type, $session_type)
{
if (array_key_exists($session_type, $this->session_types)) {
$session_type_class = $this->session_types[$session_type];
if (is_callable($session_type_class)) {
$assoc_session = $session_type_class();
} else {
$assoc_session = new $session_type_class();
}
} else {
return null;
}
$args = array(
'mode' => 'associate',
'assoc_type' => $assoc_type);
if (!$endpoint->compatibilityMode()) {
$args['ns'] = Auth_OpenID_OPENID2_NS;
}
// Leave out the session type if we're in compatibility mode
// *and* it's no-encryption.
if ((!$endpoint->compatibilityMode()) ||
($assoc_session->session_type != 'no-encryption')) {
$args['session_type'] = $assoc_session->session_type;
}
$args = array_merge($args, $assoc_session->getRequest());
$message = Auth_OpenID_Message::fromOpenIDArgs($args);
return array($assoc_session, $message);
}
/**
* Given an association response message, extract the OpenID 1.X
* session type.
*
* This function mostly takes care of the 'no-encryption' default
* behavior in OpenID 1.
*
* If the association type is plain-text, this function will
* return 'no-encryption'
*
* @access private
* @return $typ The association type for this message
*/
function _getOpenID1SessionType($assoc_response)
{
// If it's an OpenID 1 message, allow session_type to default
// to None (which signifies "no-encryption")
$session_type = $assoc_response->getArg(Auth_OpenID_OPENID1_NS,
'session_type');
// Handle the differences between no-encryption association
// respones in OpenID 1 and 2:
// no-encryption is not really a valid session type for OpenID
// 1, but we'll accept it anyway, while issuing a warning.
if ($session_type == 'no-encryption') {
// oidutil.log('WARNING: OpenID server sent "no-encryption"'
// 'for OpenID 1.X')
} else if (($session_type == '') || ($session_type === null)) {
// Missing or empty session type is the way to flag a
// 'no-encryption' response. Change the session type to
// 'no-encryption' so that it can be handled in the same
// way as OpenID 2 'no-encryption' respones.
$session_type = 'no-encryption';
}
return $session_type;
}
}
/**
* This class represents an authentication request from a consumer to
* an OpenID server.
*
* @package OpenID
*/
class Auth_OpenID_AuthRequest {
/**
* Initialize an authentication request with the specified token,
* association, and endpoint.
*
* Users of this library should not create instances of this
* class. Instances of this class are created by the library when
* needed.
*/
function Auth_OpenID_AuthRequest($endpoint, $assoc)
{
$this->assoc = $assoc;
$this->endpoint = $endpoint;
$this->return_to_args = array();
$this->message = new Auth_OpenID_Message(
$endpoint->preferredNamespace());
$this->_anonymous = false;
}
/**
* Add an extension to this checkid request.
*
* $extension_request: An object that implements the extension
* request interface for adding arguments to an OpenID message.
*/
function addExtension($extension_request)
{
$extension_request->toMessage($this->message);
}
/**
* Add an extension argument to this OpenID authentication
* request.
*
* Use caution when adding arguments, because they will be
* URL-escaped and appended to the redirect URL, which can easily
* get quite long.
*
* @param string $namespace The namespace for the extension. For
* example, the simple registration extension uses the namespace
* 'sreg'.
*
* @param string $key The key within the extension namespace. For
* example, the nickname field in the simple registration
* extension's key is 'nickname'.
*
* @param string $value The value to provide to the server for
* this argument.
*/
function addExtensionArg($namespace, $key, $value)
{
return $this->message->setArg($namespace, $key, $value);
}
/**
* Set whether this request should be made anonymously. If a
* request is anonymous, the identifier will not be sent in the
* request. This is only useful if you are making another kind of
* request with an extension in this request.
*
* Anonymous requests are not allowed when the request is made
* with OpenID 1.
*/
function setAnonymous($is_anonymous)
{
if ($is_anonymous && $this->message->isOpenID1()) {
return false;
} else {
$this->_anonymous = $is_anonymous;
return true;
}
}
/**
* Produce a {@link Auth_OpenID_Message} representing this
* request.
*
* @param string $realm The URL (or URL pattern) that identifies
* your web site to the user when she is authorizing it.
*
* @param string $return_to The URL that the OpenID provider will
* send the user back to after attempting to verify her identity.
*
* Not specifying a return_to URL means that the user will not be
* returned to the site issuing the request upon its completion.
*
* @param bool $immediate If true, the OpenID provider is to send
* back a response immediately, useful for behind-the-scenes
* authentication attempts. Otherwise the OpenID provider may
* engage the user before providing a response. This is the
* default case, as the user may need to provide credentials or
* approve the request before a positive response can be sent.
*/
function getMessage($realm, $return_to=null, $immediate=false)
{
if ($return_to) {
$return_to = Auth_OpenID::appendArgs($return_to,
$this->return_to_args);
} else if ($immediate) {
// raise ValueError(
// '"return_to" is mandatory when
//using "checkid_immediate"')
return new Auth_OpenID_FailureResponse(null,
"'return_to' is mandatory when using checkid_immediate");
} else if ($this->message->isOpenID1()) {
// raise ValueError('"return_to" is
// mandatory for OpenID 1 requests')
return new Auth_OpenID_FailureResponse(null,
"'return_to' is mandatory for OpenID 1 requests");
} else if ($this->return_to_args) {
// raise ValueError('extra "return_to" arguments
// were specified, but no return_to was specified')
return new Auth_OpenID_FailureResponse(null,
"extra 'return_to' arguments where specified, " .
"but no return_to was specified");
}
if ($immediate) {
$mode = 'checkid_immediate';
} else {
$mode = 'checkid_setup';
}
$message = $this->message->copy();
if ($message->isOpenID1()) {
$realm_key = 'trust_root';
} else {
$realm_key = 'realm';
}
$message->updateArgs(Auth_OpenID_OPENID_NS,
array(
$realm_key => $realm,
'mode' => $mode,
'return_to' => $return_to));
if (!$this->_anonymous) {
if ($this->endpoint->isOPIdentifier()) {
// This will never happen when we're in compatibility
// mode, as long as isOPIdentifier() returns False
// whenever preferredNamespace() returns OPENID1_NS.
$claimed_id = $request_identity =
Auth_OpenID_IDENTIFIER_SELECT;
} else {
$request_identity = $this->endpoint->getLocalID();
$claimed_id = $this->endpoint->claimed_id;
}
// This is true for both OpenID 1 and 2
$message->setArg(Auth_OpenID_OPENID_NS, 'identity',
$request_identity);
if ($message->isOpenID2()) {
$message->setArg(Auth_OpenID_OPENID2_NS, 'claimed_id',
$claimed_id);
}
}
if ($this->assoc) {
$message->setArg(Auth_OpenID_OPENID_NS, 'assoc_handle',
$this->assoc->handle);
}
return $message;
}
function redirectURL($realm, $return_to = null,
$immediate = false)
{
$message = $this->getMessage($realm, $return_to, $immediate);
if (Auth_OpenID::isFailure($message)) {
return $message;
}
return $message->toURL($this->endpoint->server_url);
}
/**
* Get html for a form to submit this request to the IDP.
*
* form_tag_attrs: An array of attributes to be added to the form
* tag. 'accept-charset' and 'enctype' have defaults that can be
* overridden. If a value is supplied for 'action' or 'method', it
* will be replaced.
*/
function formMarkup($realm, $return_to=null, $immediate=false,
$form_tag_attrs=null)
{
$message = $this->getMessage($realm, $return_to, $immediate);
if (Auth_OpenID::isFailure($message)) {
return $message;
}
return $message->toFormMarkup($this->endpoint->server_url,
$form_tag_attrs);
}
/**
* Get a complete html document that will autosubmit the request
* to the IDP.
*
* Wraps formMarkup. See the documentation for that function.
*/
function htmlMarkup($realm, $return_to=null, $immediate=false,
$form_tag_attrs=null)
{
$form = $this->formMarkup($realm, $return_to, $immediate,
$form_tag_attrs);
if (Auth_OpenID::isFailure($form)) {
return $form;
}
return Auth_OpenID::autoSubmitHTML($form);
}
function shouldSendRedirect()
{
return $this->endpoint->compatibilityMode();
}
}
/**
* The base class for responses from the Auth_OpenID_Consumer.
*
* @package OpenID
*/
class Auth_OpenID_ConsumerResponse {
var $status = null;
function setEndpoint($endpoint)
{
$this->endpoint = $endpoint;
if ($endpoint === null) {
$this->identity_url = null;
} else {
$this->identity_url = $endpoint->claimed_id;
}
}
/**
* Return the display identifier for this response.
*
* The display identifier is related to the Claimed Identifier, but the
* two are not always identical. The display identifier is something the
* user should recognize as what they entered, whereas the response's
* claimed identifier (in the identity_url attribute) may have extra
* information for better persistence.
*
* URLs will be stripped of their fragments for display. XRIs will
* display the human-readable identifier (i-name) instead of the
* persistent identifier (i-number).
*
* Use the display identifier in your user interface. Use
* identity_url for querying your database or authorization server.
*
*/
function getDisplayIdentifier()
{
if ($this->endpoint !== null) {
return $this->endpoint->getDisplayIdentifier();
}
return null;
}
}
/**
* A response with a status of Auth_OpenID_SUCCESS. Indicates that
* this request is a successful acknowledgement from the OpenID server
* that the supplied URL is, indeed controlled by the requesting
* agent. This has three relevant attributes:
*
* claimed_id - The identity URL that has been authenticated
*
* signed_args - The arguments in the server's response that were
* signed and verified.
*
* status - Auth_OpenID_SUCCESS.
*
* @package OpenID
*/
class Auth_OpenID_SuccessResponse extends Auth_OpenID_ConsumerResponse {
var $status = Auth_OpenID_SUCCESS;
/**
* @access private
*/
function Auth_OpenID_SuccessResponse($endpoint, $message, $signed_args=null)
{
$this->endpoint = $endpoint;
$this->identity_url = $endpoint->claimed_id;
$this->signed_args = $signed_args;
$this->message = $message;
if ($this->signed_args === null) {
$this->signed_args = array();
}
}
/**
* Extract signed extension data from the server's response.
*
* @param string $prefix The extension namespace from which to
* extract the extension data.
*/
function extensionResponse($namespace_uri, $require_signed)
{
if ($require_signed) {
return $this->getSignedNS($namespace_uri);
} else {
return $this->message->getArgs($namespace_uri);
}
}
function isOpenID1()
{
return $this->message->isOpenID1();
}
function isSigned($ns_uri, $ns_key)
{
// Return whether a particular key is signed, regardless of
// its namespace alias
return in_array($this->message->getKey($ns_uri, $ns_key),
$this->signed_args);
}
function getSigned($ns_uri, $ns_key, $default = null)
{
// Return the specified signed field if available, otherwise
// return default
if ($this->isSigned($ns_uri, $ns_key)) {
return $this->message->getArg($ns_uri, $ns_key, $default);
} else {
return $default;
}
}
function getSignedNS($ns_uri)
{
$args = array();
$msg_args = $this->message->getArgs($ns_uri);
if (Auth_OpenID::isFailure($msg_args)) {
return null;
}
foreach ($msg_args as $key => $value) {
if (!$this->isSigned($ns_uri, $key)) {
unset($msg_args[$key]);
}
}
return $msg_args;
}
/**
* Get the openid.return_to argument from this response.
*
* This is useful for verifying that this request was initiated by
* this consumer.
*
* @return string $return_to The return_to URL supplied to the
* server on the initial request, or null if the response did not
* contain an 'openid.return_to' argument.
*/
function getReturnTo()
{
return $this->getSigned(Auth_OpenID_OPENID_NS, 'return_to');
}
}
/**
* A response with a status of Auth_OpenID_FAILURE. Indicates that the
* OpenID protocol has failed. This could be locally or remotely
* triggered. This has three relevant attributes:
*
* claimed_id - The identity URL for which authentication was
* attempted, if it can be determined. Otherwise, null.
*
* message - A message indicating why the request failed, if one is
* supplied. Otherwise, null.
*
* status - Auth_OpenID_FAILURE.
*
* @package OpenID
*/
class Auth_OpenID_FailureResponse extends Auth_OpenID_ConsumerResponse {
var $status = Auth_OpenID_FAILURE;
function Auth_OpenID_FailureResponse($endpoint, $message = null,
$contact = null, $reference = null)
{
$this->setEndpoint($endpoint);
$this->message = $message;
$this->contact = $contact;
$this->reference = $reference;
}
}
/**
* A specific, internal failure used to detect type URI mismatch.
*
* @package OpenID
*/
class Auth_OpenID_TypeURIMismatch extends Auth_OpenID_FailureResponse {
}
/**
* Exception that is raised when the server returns a 400 response
* code to a direct request.
*
* @package OpenID
*/
class Auth_OpenID_ServerErrorContainer {
function Auth_OpenID_ServerErrorContainer($error_text,
$error_code,
$message)
{
$this->error_text = $error_text;
$this->error_code = $error_code;
$this->message = $message;
}
/**
* @access private
*/
static function fromMessage($message)
{
$error_text = $message->getArg(
Auth_OpenID_OPENID_NS, 'error', '');
$error_code = $message->getArg(Auth_OpenID_OPENID_NS, 'error_code');
return new Auth_OpenID_ServerErrorContainer($error_text,
$error_code,
$message);
}
}
/**
* A response with a status of Auth_OpenID_CANCEL. Indicates that the
* user cancelled the OpenID authentication request. This has two
* relevant attributes:
*
* claimed_id - The identity URL for which authentication was
* attempted, if it can be determined. Otherwise, null.
*
* status - Auth_OpenID_SUCCESS.
*
* @package OpenID
*/
class Auth_OpenID_CancelResponse extends Auth_OpenID_ConsumerResponse {
var $status = Auth_OpenID_CANCEL;
function Auth_OpenID_CancelResponse($endpoint)
{
$this->setEndpoint($endpoint);
}
}
/**
* A response with a status of Auth_OpenID_SETUP_NEEDED. Indicates
* that the request was in immediate mode, and the server is unable to
* authenticate the user without further interaction.
*
* claimed_id - The identity URL for which authentication was
* attempted.
*
* setup_url - A URL that can be used to send the user to the server
* to set up for authentication. The user should be redirected in to
* the setup_url, either in the current window or in a new browser
* window. Null in OpenID 2.
*
* status - Auth_OpenID_SETUP_NEEDED.
*
* @package OpenID
*/
class Auth_OpenID_SetupNeededResponse extends Auth_OpenID_ConsumerResponse {
var $status = Auth_OpenID_SETUP_NEEDED;
function Auth_OpenID_SetupNeededResponse($endpoint,
$setup_url = null)
{
$this->setEndpoint($endpoint);
$this->setup_url = $setup_url;
}
}
openid-php-openid-782224d/Auth/OpenID/CryptUtil.php 0000664 0000000 0000000 00000006321 11366367341 0022012 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
if (!defined('Auth_OpenID_RAND_SOURCE')) {
/**
* The filename for a source of random bytes. Define this yourself
* if you have a different source of randomness.
*/
define('Auth_OpenID_RAND_SOURCE', '/dev/urandom');
}
class Auth_OpenID_CryptUtil {
/**
* Get the specified number of random bytes.
*
* Attempts to use a cryptographically secure (not predictable)
* source of randomness if available. If there is no high-entropy
* randomness source available, it will fail. As a last resort,
* for non-critical systems, define
* Auth_OpenID_RAND_SOURCE as null, and
* the code will fall back on a pseudo-random number generator.
*
* @param int $num_bytes The length of the return value
* @return string $bytes random bytes
*/
static function getBytes($num_bytes)
{
static $f = null;
$bytes = '';
if ($f === null) {
if (Auth_OpenID_RAND_SOURCE === null) {
$f = false;
} else {
$f = @fopen(Auth_OpenID_RAND_SOURCE, "r");
if ($f === false) {
$msg = 'Define Auth_OpenID_RAND_SOURCE as null to ' .
' continue with an insecure random number generator.';
trigger_error($msg, E_USER_ERROR);
}
}
}
if ($f === false) {
// pseudorandom used
$bytes = '';
for ($i = 0; $i < $num_bytes; $i += 4) {
$bytes .= pack('L', mt_rand());
}
$bytes = substr($bytes, 0, $num_bytes);
} else {
$bytes = fread($f, $num_bytes);
}
return $bytes;
}
/**
* Produce a string of length random bytes, chosen from chrs. If
* $chrs is null, the resulting string may contain any characters.
*
* @param integer $length The length of the resulting
* randomly-generated string
* @param string $chrs A string of characters from which to choose
* to build the new string
* @return string $result A string of randomly-chosen characters
* from $chrs
*/
static function randomString($length, $population = null)
{
if ($population === null) {
return Auth_OpenID_CryptUtil::getBytes($length);
}
$popsize = strlen($population);
if ($popsize > 256) {
$msg = 'More than 256 characters supplied to ' . __FUNCTION__;
trigger_error($msg, E_USER_ERROR);
}
$duplicate = 256 % $popsize;
$str = "";
for ($i = 0; $i < $length; $i++) {
do {
$n = ord(Auth_OpenID_CryptUtil::getBytes(1));
} while ($n < $duplicate);
$n %= $popsize;
$str .= $population[$n];
}
return $str;
}
}
openid-php-openid-782224d/Auth/OpenID/DatabaseConnection.php 0000664 0000000 0000000 00000007560 11366367341 0023605 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* An empty base class intended to emulate PEAR connection
* functionality in applications that supply their own database
* abstraction mechanisms. See {@link Auth_OpenID_SQLStore} for more
* information. You should subclass this class if you need to create
* an SQL store that needs to access its database using an
* application's database abstraction layer instead of a PEAR database
* connection. Any subclass of Auth_OpenID_DatabaseConnection MUST
* adhere to the interface specified here.
*
* @package OpenID
*/
class Auth_OpenID_DatabaseConnection {
/**
* Sets auto-commit mode on this database connection.
*
* @param bool $mode True if auto-commit is to be used; false if
* not.
*/
function autoCommit($mode)
{
}
/**
* Run an SQL query with the specified parameters, if any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return mixed $result The result of calling this connection's
* internal query function. The type of result depends on the
* underlying database engine. This method is usually used when
* the result of a query is not important, like a DDL query.
*/
function query($sql, $params = array())
{
}
/**
* Starts a transaction on this connection, if supported.
*/
function begin()
{
}
/**
* Commits a transaction on this connection, if supported.
*/
function commit()
{
}
/**
* Performs a rollback on this connection, if supported.
*/
function rollback()
{
}
/**
* Run an SQL query and return the first column of the first row
* of the result set, if any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return mixed $result The value of the first column of the
* first row of the result set. False if no such result was
* found.
*/
function getOne($sql, $params = array())
{
}
/**
* Run an SQL query and return the first row of the result set, if
* any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return array $result The first row of the result set, if any,
* keyed on column name. False if no such result was found.
*/
function getRow($sql, $params = array())
{
}
/**
* Run an SQL query with the specified parameters, if any.
*
* @param string $sql An SQL string with placeholders. The
* placeholders are assumed to be specific to the database engine
* for this connection.
*
* @param array $params An array of parameters to insert into the
* SQL string using this connection's escaping mechanism.
*
* @return array $result An array of arrays representing the
* result of the query; each array is keyed on column name.
*/
function getAll($sql, $params = array())
{
}
}
openid-php-openid-782224d/Auth/OpenID/DiffieHellman.php 0000664 0000000 0000000 00000005610 11366367341 0022542 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
require_once 'Auth/OpenID.php';
require_once 'Auth/OpenID/BigMath.php';
function Auth_OpenID_getDefaultMod()
{
return '155172898181473697471232257763715539915724801'.
'966915404479707795314057629378541917580651227423'.
'698188993727816152646631438561595825688188889951'.
'272158842675419950341258706556549803580104870537'.
'681476726513255747040765857479291291572334510643'.
'245094715007229621094194349783925984760375594985'.
'848253359305585439638443';
}
function Auth_OpenID_getDefaultGen()
{
return '2';
}
/**
* The Diffie-Hellman key exchange class. This class relies on
* {@link Auth_OpenID_MathLibrary} to perform large number operations.
*
* @access private
* @package OpenID
*/
class Auth_OpenID_DiffieHellman {
var $mod;
var $gen;
var $private;
var $lib = null;
function Auth_OpenID_DiffieHellman($mod = null, $gen = null,
$private = null, $lib = null)
{
if ($lib === null) {
$this->lib = Auth_OpenID_getMathLib();
} else {
$this->lib = $lib;
}
if ($mod === null) {
$this->mod = $this->lib->init(Auth_OpenID_getDefaultMod());
} else {
$this->mod = $mod;
}
if ($gen === null) {
$this->gen = $this->lib->init(Auth_OpenID_getDefaultGen());
} else {
$this->gen = $gen;
}
if ($private === null) {
$r = $this->lib->rand($this->mod);
$this->private = $this->lib->add($r, 1);
} else {
$this->private = $private;
}
$this->public = $this->lib->powmod($this->gen, $this->private,
$this->mod);
}
function getSharedSecret($composite)
{
return $this->lib->powmod($composite, $this->private, $this->mod);
}
function getPublicKey()
{
return $this->public;
}
function usingDefaultValues()
{
return ($this->mod == Auth_OpenID_getDefaultMod() &&
$this->gen == Auth_OpenID_getDefaultGen());
}
function xorSecret($composite, $secret, $hash_func)
{
$dh_shared = $this->getSharedSecret($composite);
$dh_shared_str = $this->lib->longToBinary($dh_shared);
$hash_dh_shared = $hash_func($dh_shared_str);
$xsecret = "";
for ($i = 0; $i < Auth_OpenID::bytes($secret); $i++) {
$xsecret .= chr(ord($secret[$i]) ^ ord($hash_dh_shared[$i]));
}
return $xsecret;
}
}
openid-php-openid-782224d/Auth/OpenID/Discover.php 0000664 0000000 0000000 00000044203 11366367341 0021632 0 ustar 00root root 0000000 0000000 claimed_id = null;
$this->server_url = null;
$this->type_uris = array();
$this->local_id = null;
$this->canonicalID = null;
$this->used_yadis = false; // whether this came from an XRDS
$this->display_identifier = null;
}
function getDisplayIdentifier()
{
if ($this->display_identifier) {
return $this->display_identifier;
}
if (! $this->claimed_id) {
return $this->claimed_id;
}
$parsed = parse_url($this->claimed_id);
$scheme = $parsed['scheme'];
$host = $parsed['host'];
$path = $parsed['path'];
if (array_key_exists('query', $parsed)) {
$query = $parsed['query'];
$no_frag = "$scheme://$host$path?$query";
} else {
$no_frag = "$scheme://$host$path";
}
return $no_frag;
}
function usesExtension($extension_uri)
{
return in_array($extension_uri, $this->type_uris);
}
function preferredNamespace()
{
if (in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris) ||
in_array(Auth_OpenID_TYPE_2_0, $this->type_uris)) {
return Auth_OpenID_OPENID2_NS;
} else {
return Auth_OpenID_OPENID1_NS;
}
}
/*
* Query this endpoint to see if it has any of the given type
* URIs. This is useful for implementing other endpoint classes
* that e.g. need to check for the presence of multiple versions
* of a single protocol.
*
* @param $type_uris The URIs that you wish to check
*
* @return all types that are in both in type_uris and
* $this->type_uris
*/
function matchTypes($type_uris)
{
$result = array();
foreach ($type_uris as $test_uri) {
if ($this->supportsType($test_uri)) {
$result[] = $test_uri;
}
}
return $result;
}
function supportsType($type_uri)
{
// Does this endpoint support this type?
return ((in_array($type_uri, $this->type_uris)) ||
(($type_uri == Auth_OpenID_TYPE_2_0) &&
$this->isOPIdentifier()));
}
function compatibilityMode()
{
return $this->preferredNamespace() != Auth_OpenID_OPENID2_NS;
}
function isOPIdentifier()
{
return in_array(Auth_OpenID_TYPE_2_0_IDP, $this->type_uris);
}
static function fromOPEndpointURL($op_endpoint_url)
{
// Construct an OP-Identifier OpenIDServiceEndpoint object for
// a given OP Endpoint URL
$obj = new Auth_OpenID_ServiceEndpoint();
$obj->server_url = $op_endpoint_url;
$obj->type_uris = array(Auth_OpenID_TYPE_2_0_IDP);
return $obj;
}
function parseService($yadis_url, $uri, $type_uris, $service_element)
{
// Set the state of this object based on the contents of the
// service element. Return true if successful, false if not
// (if findOPLocalIdentifier returns false).
$this->type_uris = $type_uris;
$this->server_url = $uri;
$this->used_yadis = true;
if (!$this->isOPIdentifier()) {
$this->claimed_id = $yadis_url;
$this->local_id = Auth_OpenID_findOPLocalIdentifier(
$service_element,
$this->type_uris);
if ($this->local_id === false) {
return false;
}
}
return true;
}
function getLocalID()
{
// Return the identifier that should be sent as the
// openid.identity_url parameter to the server.
if ($this->local_id === null && $this->canonicalID === null) {
return $this->claimed_id;
} else {
if ($this->local_id) {
return $this->local_id;
} else {
return $this->canonicalID;
}
}
}
/*
* Parse the given document as XRDS looking for OpenID consumer services.
*
* @return array of Auth_OpenID_ServiceEndpoint or null if the
* document cannot be parsed.
*/
function consumerFromXRDS($uri, $xrds_text)
{
$xrds =& Auth_Yadis_XRDS::parseXRDS($xrds_text);
if ($xrds) {
$yadis_services =
$xrds->services(array('filter_MatchesAnyOpenIDConsumerType'));
return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
}
return null;
}
/*
* Parse the given document as XRDS looking for OpenID services.
*
* @return array of Auth_OpenID_ServiceEndpoint or null if the
* document cannot be parsed.
*/
static function fromXRDS($uri, $xrds_text)
{
$xrds = Auth_Yadis_XRDS::parseXRDS($xrds_text);
if ($xrds) {
$yadis_services =
$xrds->services(array('filter_MatchesAnyOpenIDType'));
return Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services);
}
return null;
}
/*
* Create endpoints from a DiscoveryResult.
*
* @param discoveryResult Auth_Yadis_DiscoveryResult
* @return array of Auth_OpenID_ServiceEndpoint or null if
* endpoints cannot be created.
*/
static function fromDiscoveryResult($discoveryResult)
{
if ($discoveryResult->isXRDS()) {
return Auth_OpenID_ServiceEndpoint::fromXRDS(
$discoveryResult->normalized_uri,
$discoveryResult->response_text);
} else {
return Auth_OpenID_ServiceEndpoint::fromHTML(
$discoveryResult->normalized_uri,
$discoveryResult->response_text);
}
}
static function fromHTML($uri, $html)
{
$discovery_types = array(
array(Auth_OpenID_TYPE_2_0,
'openid2.provider', 'openid2.local_id'),
array(Auth_OpenID_TYPE_1_1,
'openid.server', 'openid.delegate')
);
$services = array();
foreach ($discovery_types as $triple) {
list($type_uri, $server_rel, $delegate_rel) = $triple;
$urls = Auth_OpenID_legacy_discover($html, $server_rel,
$delegate_rel);
if ($urls === false) {
continue;
}
list($delegate_url, $server_url) = $urls;
$service = new Auth_OpenID_ServiceEndpoint();
$service->claimed_id = $uri;
$service->local_id = $delegate_url;
$service->server_url = $server_url;
$service->type_uris = array($type_uri);
$services[] = $service;
}
return $services;
}
function copy()
{
$x = new Auth_OpenID_ServiceEndpoint();
$x->claimed_id = $this->claimed_id;
$x->server_url = $this->server_url;
$x->type_uris = $this->type_uris;
$x->local_id = $this->local_id;
$x->canonicalID = $this->canonicalID;
$x->used_yadis = $this->used_yadis;
return $x;
}
}
function Auth_OpenID_findOPLocalIdentifier($service, $type_uris)
{
// Extract a openid:Delegate value from a Yadis Service element.
// If no delegate is found, returns null. Returns false on
// discovery failure (when multiple delegate/localID tags have
// different values).
$service->parser->registerNamespace('openid',
Auth_OpenID_XMLNS_1_0);
$service->parser->registerNamespace('xrd',
Auth_Yadis_XMLNS_XRD_2_0);
$parser = $service->parser;
$permitted_tags = array();
if (in_array(Auth_OpenID_TYPE_1_1, $type_uris) ||
in_array(Auth_OpenID_TYPE_1_0, $type_uris)) {
$permitted_tags[] = 'openid:Delegate';
}
if (in_array(Auth_OpenID_TYPE_2_0, $type_uris)) {
$permitted_tags[] = 'xrd:LocalID';
}
$local_id = null;
foreach ($permitted_tags as $tag_name) {
$tags = $service->getElements($tag_name);
foreach ($tags as $tag) {
$content = $parser->content($tag);
if ($local_id === null) {
$local_id = $content;
} else if ($local_id != $content) {
return false;
}
}
}
return $local_id;
}
function filter_MatchesAnyOpenIDType($service)
{
$uris = $service->getTypes();
foreach ($uris as $uri) {
if (in_array($uri, Auth_OpenID_getOpenIDTypeURIs())) {
return true;
}
}
return false;
}
function filter_MatchesAnyOpenIDConsumerType(&$service)
{
$uris = $service->getTypes();
foreach ($uris as $uri) {
if (in_array($uri, Auth_OpenID_getOpenIDConsumerTypeURIs())) {
return true;
}
}
return false;
}
function Auth_OpenID_bestMatchingService($service, $preferred_types)
{
// Return the index of the first matching type, or something
// higher if no type matches.
//
// This provides an ordering in which service elements that
// contain a type that comes earlier in the preferred types list
// come before service elements that come later. If a service
// element has more than one type, the most preferred one wins.
foreach ($preferred_types as $index => $typ) {
if (in_array($typ, $service->type_uris)) {
return $index;
}
}
return count($preferred_types);
}
function Auth_OpenID_arrangeByType($service_list, $preferred_types)
{
// Rearrange service_list in a new list so services are ordered by
// types listed in preferred_types. Return the new list.
// Build a list with the service elements in tuples whose
// comparison will prefer the one with the best matching service
$prio_services = array();
foreach ($service_list as $index => $service) {
$prio_services[] = array(Auth_OpenID_bestMatchingService($service,
$preferred_types),
$index, $service);
}
sort($prio_services);
// Now that the services are sorted by priority, remove the sort
// keys from the list.
foreach ($prio_services as $index => $s) {
$prio_services[$index] = $prio_services[$index][2];
}
return $prio_services;
}
// Extract OP Identifier services. If none found, return the rest,
// sorted with most preferred first according to
// OpenIDServiceEndpoint.openid_type_uris.
//
// openid_services is a list of OpenIDServiceEndpoint objects.
//
// Returns a list of OpenIDServiceEndpoint objects."""
function Auth_OpenID_getOPOrUserServices($openid_services)
{
$op_services = Auth_OpenID_arrangeByType($openid_services,
array(Auth_OpenID_TYPE_2_0_IDP));
$openid_services = Auth_OpenID_arrangeByType($openid_services,
Auth_OpenID_getOpenIDTypeURIs());
if ($op_services) {
return $op_services;
} else {
return $openid_services;
}
}
function Auth_OpenID_makeOpenIDEndpoints($uri, $yadis_services)
{
$s = array();
if (!$yadis_services) {
return $s;
}
foreach ($yadis_services as $service) {
$type_uris = $service->getTypes();
$uris = $service->getURIs();
// If any Type URIs match and there is an endpoint URI
// specified, then this is an OpenID endpoint
if ($type_uris &&
$uris) {
foreach ($uris as $service_uri) {
$openid_endpoint = new Auth_OpenID_ServiceEndpoint();
if ($openid_endpoint->parseService($uri,
$service_uri,
$type_uris,
$service)) {
$s[] = $openid_endpoint;
}
}
}
}
return $s;
}
function Auth_OpenID_discoverWithYadis($uri, $fetcher,
$endpoint_filter='Auth_OpenID_getOPOrUserServices',
$discover_function=null)
{
// Discover OpenID services for a URI. Tries Yadis and falls back
// on old-style discovery if Yadis fails.
// Might raise a yadis.discover.DiscoveryFailure if no document
// came back for that URI at all. I don't think falling back to
// OpenID 1.0 discovery on the same URL will help, so don't bother
// to catch it.
if ($discover_function === null) {
$discover_function = array('Auth_Yadis_Yadis', 'discover');
}
$openid_services = array();
$response = call_user_func_array($discover_function,
array($uri, $fetcher));
$yadis_url = $response->normalized_uri;
$yadis_services = array();
if ($response->isFailure() && !$response->isXRDS()) {
return array($uri, array());
}
$openid_services = Auth_OpenID_ServiceEndpoint::fromXRDS(
$yadis_url,
$response->response_text);
if (!$openid_services) {
if ($response->isXRDS()) {
return Auth_OpenID_discoverWithoutYadis($uri,
$fetcher);
}
// Try to parse the response as HTML to get OpenID 1.0/1.1
//
$openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
$yadis_url,
$response->response_text);
}
$openid_services = call_user_func_array($endpoint_filter,
array($openid_services));
return array($yadis_url, $openid_services);
}
function Auth_OpenID_discoverURI($uri, $fetcher)
{
$uri = Auth_OpenID::normalizeUrl($uri);
return Auth_OpenID_discoverWithYadis($uri, $fetcher);
}
function Auth_OpenID_discoverWithoutYadis($uri, $fetcher)
{
$http_resp = @$fetcher->get($uri);
if ($http_resp->status != 200 and $http_resp->status != 206) {
return array($uri, array());
}
$identity_url = $http_resp->final_url;
// Try to parse the response as HTML to get OpenID 1.0/1.1
$openid_services = Auth_OpenID_ServiceEndpoint::fromHTML(
$identity_url,
$http_resp->body);
return array($identity_url, $openid_services);
}
function Auth_OpenID_discoverXRI($iname, $fetcher)
{
$resolver = new Auth_Yadis_ProxyResolver($fetcher);
list($canonicalID, $yadis_services) =
$resolver->query($iname,
Auth_OpenID_getOpenIDTypeURIs(),
array('filter_MatchesAnyOpenIDType'));
$openid_services = Auth_OpenID_makeOpenIDEndpoints($iname,
$yadis_services);
$openid_services = Auth_OpenID_getOPOrUserServices($openid_services);
for ($i = 0; $i < count($openid_services); $i++) {
$openid_services[$i]->canonicalID = $canonicalID;
$openid_services[$i]->claimed_id = $canonicalID;
$openid_services[$i]->display_identifier = $iname;
}
// FIXME: returned xri should probably be in some normal form
return array($iname, $openid_services);
}
function Auth_OpenID_discover($uri, $fetcher)
{
// If the fetcher (i.e., PHP) doesn't support SSL, we can't do
// discovery on an HTTPS URL.
if ($fetcher->isHTTPS($uri) && !$fetcher->supportsSSL()) {
return array($uri, array());
}
if (Auth_Yadis_identifierScheme($uri) == 'XRI') {
$result = Auth_OpenID_discoverXRI($uri, $fetcher);
} else {
$result = Auth_OpenID_discoverURI($uri, $fetcher);
}
// If the fetcher doesn't support SSL, we can't interact with
// HTTPS server URLs; remove those endpoints from the list.
if (!$fetcher->supportsSSL()) {
$http_endpoints = array();
list($new_uri, $endpoints) = $result;
foreach ($endpoints as $e) {
if (!$fetcher->isHTTPS($e->server_url)) {
$http_endpoints[] = $e;
}
}
$result = array($new_uri, $http_endpoints);
}
return $result;
}
openid-php-openid-782224d/Auth/OpenID/DumbStore.php 0000664 0000000 0000000 00000005315 11366367341 0021761 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Import the interface for creating a new store class.
*/
require_once 'Auth/OpenID/Interface.php';
require_once 'Auth/OpenID/HMAC.php';
/**
* This is a store for use in the worst case, when you have no way of
* saving state on the consumer site. Using this store makes the
* consumer vulnerable to replay attacks, as it's unable to use
* nonces. Avoid using this store if it is at all possible.
*
* Most of the methods of this class are implementation details.
* Users of this class need to worry only about the constructor.
*
* @package OpenID
*/
class Auth_OpenID_DumbStore extends Auth_OpenID_OpenIDStore {
/**
* Creates a new {@link Auth_OpenID_DumbStore} instance. For the security
* of the tokens generated by the library, this class attempts to
* at least have a secure implementation of getAuthKey.
*
* When you create an instance of this class, pass in a secret
* phrase. The phrase is hashed with sha1 to make it the correct
* length and form for an auth key. That allows you to use a long
* string as the secret phrase, which means you can make it very
* difficult to guess.
*
* Each {@link Auth_OpenID_DumbStore} instance that is created for use by
* your consumer site needs to use the same $secret_phrase.
*
* @param string secret_phrase The phrase used to create the auth
* key returned by getAuthKey
*/
function Auth_OpenID_DumbStore($secret_phrase)
{
$this->auth_key = Auth_OpenID_SHA1($secret_phrase);
}
/**
* This implementation does nothing.
*/
function storeAssociation($server_url, $association)
{
}
/**
* This implementation always returns null.
*/
function getAssociation($server_url, $handle = null)
{
return null;
}
/**
* This implementation always returns false.
*/
function removeAssociation($server_url, $handle)
{
return false;
}
/**
* In a system truly limited to dumb mode, nonces must all be
* accepted. This therefore always returns true, which makes
* replay attacks feasible.
*/
function useNonce($server_url, $timestamp, $salt)
{
return true;
}
/**
* This method returns the auth key generated by the constructor.
*/
function getAuthKey()
{
return $this->auth_key;
}
}
openid-php-openid-782224d/Auth/OpenID/Extension.php 0000664 0000000 0000000 00000002573 11366367341 0022034 0 ustar 00root root 0000000 0000000 isOpenID1();
$added = $message->namespaces->addAlias($this->ns_uri,
$this->ns_alias,
$implicit);
if ($added === null) {
if ($message->namespaces->getAlias($this->ns_uri) !=
$this->ns_alias) {
return null;
}
}
$message->updateArgs($this->ns_uri,
$this->getExtensionArgs());
return $message;
}
}
openid-php-openid-782224d/Auth/OpenID/FileStore.php 0000664 0000000 0000000 00000043323 11366367341 0021752 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Require base class for creating a new interface.
*/
require_once 'Auth/OpenID.php';
require_once 'Auth/OpenID/Interface.php';
require_once 'Auth/OpenID/HMAC.php';
require_once 'Auth/OpenID/Nonce.php';
/**
* This is a filesystem-based store for OpenID associations and
* nonces. This store should be safe for use in concurrent systems on
* both windows and unix (excluding NFS filesystems). There are a
* couple race conditions in the system, but those failure cases have
* been set up in such a way that the worst-case behavior is someone
* having to try to log in a second time.
*
* Most of the methods of this class are implementation details.
* People wishing to just use this store need only pay attention to
* the constructor.
*
* @package OpenID
*/
class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore {
/**
* Initializes a new {@link Auth_OpenID_FileStore}. This
* initializes the nonce and association directories, which are
* subdirectories of the directory passed in.
*
* @param string $directory This is the directory to put the store
* directories in.
*/
function Auth_OpenID_FileStore($directory)
{
if (!Auth_OpenID::ensureDir($directory)) {
trigger_error('Not a directory and failed to create: '
. $directory, E_USER_ERROR);
}
$directory = realpath($directory);
$this->directory = $directory;
$this->active = true;
$this->nonce_dir = $directory . DIRECTORY_SEPARATOR . 'nonces';
$this->association_dir = $directory . DIRECTORY_SEPARATOR .
'associations';
// Temp dir must be on the same filesystem as the assciations
// $directory.
$this->temp_dir = $directory . DIRECTORY_SEPARATOR . 'temp';
$this->max_nonce_age = 6 * 60 * 60; // Six hours, in seconds
if (!$this->_setup()) {
trigger_error('Failed to initialize OpenID file store in ' .
$directory, E_USER_ERROR);
}
}
function destroy()
{
Auth_OpenID_FileStore::_rmtree($this->directory);
$this->active = false;
}
/**
* Make sure that the directories in which we store our data
* exist.
*
* @access private
*/
function _setup()
{
return (Auth_OpenID::ensureDir($this->nonce_dir) &&
Auth_OpenID::ensureDir($this->association_dir) &&
Auth_OpenID::ensureDir($this->temp_dir));
}
/**
* Create a temporary file on the same filesystem as
* $this->association_dir.
*
* The temporary directory should not be cleaned if there are any
* processes using the store. If there is no active process using
* the store, it is safe to remove all of the files in the
* temporary directory.
*
* @return array ($fd, $filename)
* @access private
*/
function _mktemp()
{
$name = Auth_OpenID_FileStore::_mkstemp($dir = $this->temp_dir);
$file_obj = @fopen($name, 'wb');
if ($file_obj !== false) {
return array($file_obj, $name);
} else {
Auth_OpenID_FileStore::_removeIfPresent($name);
}
}
function cleanupNonces()
{
global $Auth_OpenID_SKEW;
$nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
$now = time();
$removed = 0;
// Check all nonces for expiry
foreach ($nonces as $nonce_fname) {
$base = basename($nonce_fname);
$parts = explode('-', $base, 2);
$timestamp = $parts[0];
$timestamp = intval($timestamp, 16);
if (abs($timestamp - $now) > $Auth_OpenID_SKEW) {
Auth_OpenID_FileStore::_removeIfPresent($nonce_fname);
$removed += 1;
}
}
return $removed;
}
/**
* Create a unique filename for a given server url and
* handle. This implementation does not assume anything about the
* format of the handle. The filename that is returned will
* contain the domain name from the server URL for ease of human
* inspection of the data directory.
*
* @return string $filename
*/
function getAssociationFilename($server_url, $handle)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
if (strpos($server_url, '://') === false) {
trigger_error(sprintf("Bad server URL: %s", $server_url),
E_USER_WARNING);
return null;
}
list($proto, $rest) = explode('://', $server_url, 2);
$parts = explode('/', $rest);
$domain = Auth_OpenID_FileStore::_filenameEscape($parts[0]);
$url_hash = Auth_OpenID_FileStore::_safe64($server_url);
if ($handle) {
$handle_hash = Auth_OpenID_FileStore::_safe64($handle);
} else {
$handle_hash = '';
}
$filename = sprintf('%s-%s-%s-%s', $proto, $domain, $url_hash,
$handle_hash);
return $this->association_dir. DIRECTORY_SEPARATOR . $filename;
}
/**
* Store an association in the association directory.
*/
function storeAssociation($server_url, $association)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return false;
}
$association_s = $association->serialize();
$filename = $this->getAssociationFilename($server_url,
$association->handle);
list($tmp_file, $tmp) = $this->_mktemp();
if (!$tmp_file) {
trigger_error("_mktemp didn't return a valid file descriptor",
E_USER_WARNING);
return false;
}
fwrite($tmp_file, $association_s);
fflush($tmp_file);
fclose($tmp_file);
if (@rename($tmp, $filename)) {
return true;
} else {
// In case we are running on Windows, try unlinking the
// file in case it exists.
@unlink($filename);
// Now the target should not exist. Try renaming again,
// giving up if it fails.
if (@rename($tmp, $filename)) {
return true;
}
}
// If there was an error, don't leave the temporary file
// around.
Auth_OpenID_FileStore::_removeIfPresent($tmp);
return false;
}
/**
* Retrieve an association. If no handle is specified, return the
* association with the most recent issue time.
*
* @return mixed $association
*/
function getAssociation($server_url, $handle = null)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
if ($handle === null) {
$handle = '';
}
// The filename with the empty handle is a prefix of all other
// associations for the given server URL.
$filename = $this->getAssociationFilename($server_url, $handle);
if ($handle) {
return $this->_getAssociation($filename);
} else {
$association_files =
Auth_OpenID_FileStore::_listdir($this->association_dir);
$matching_files = array();
// strip off the path to do the comparison
$name = basename($filename);
foreach ($association_files as $association_file) {
$base = basename($association_file);
if (strpos($base, $name) === 0) {
$matching_files[] = $association_file;
}
}
$matching_associations = array();
// read the matching files and sort by time issued
foreach ($matching_files as $full_name) {
$association = $this->_getAssociation($full_name);
if ($association !== null) {
$matching_associations[] = array($association->issued,
$association);
}
}
$issued = array();
$assocs = array();
foreach ($matching_associations as $key => $assoc) {
$issued[$key] = $assoc[0];
$assocs[$key] = $assoc[1];
}
array_multisort($issued, SORT_DESC, $assocs, SORT_DESC,
$matching_associations);
// return the most recently issued one.
if ($matching_associations) {
list($issued, $assoc) = $matching_associations[0];
return $assoc;
} else {
return null;
}
}
}
/**
* @access private
*/
function _getAssociation($filename)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
$assoc_file = @fopen($filename, 'rb');
if ($assoc_file === false) {
return null;
}
$assoc_s = fread($assoc_file, filesize($filename));
fclose($assoc_file);
if (!$assoc_s) {
return null;
}
$association =
Auth_OpenID_Association::deserialize('Auth_OpenID_Association',
$assoc_s);
if (!$association) {
Auth_OpenID_FileStore::_removeIfPresent($filename);
return null;
}
if ($association->getExpiresIn() == 0) {
Auth_OpenID_FileStore::_removeIfPresent($filename);
return null;
} else {
return $association;
}
}
/**
* Remove an association if it exists. Do nothing if it does not.
*
* @return bool $success
*/
function removeAssociation($server_url, $handle)
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
$assoc = $this->getAssociation($server_url, $handle);
if ($assoc === null) {
return false;
} else {
$filename = $this->getAssociationFilename($server_url, $handle);
return Auth_OpenID_FileStore::_removeIfPresent($filename);
}
}
/**
* Return whether this nonce is present. As a side effect, mark it
* as no longer present.
*
* @return bool $present
*/
function useNonce($server_url, $timestamp, $salt)
{
global $Auth_OpenID_SKEW;
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
if ( abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
return false;
}
if ($server_url) {
list($proto, $rest) = explode('://', $server_url, 2);
} else {
$proto = '';
$rest = '';
}
$parts = explode('/', $rest, 2);
$domain = $this->_filenameEscape($parts[0]);
$url_hash = $this->_safe64($server_url);
$salt_hash = $this->_safe64($salt);
$filename = sprintf('%08x-%s-%s-%s-%s', $timestamp, $proto,
$domain, $url_hash, $salt_hash);
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $filename;
$result = @fopen($filename, 'x');
if ($result === false) {
return false;
} else {
fclose($result);
return true;
}
}
/**
* Remove expired entries from the database. This is potentially
* expensive, so only run when it is acceptable to take time.
*
* @access private
*/
function _allAssocs()
{
$all_associations = array();
$association_filenames =
Auth_OpenID_FileStore::_listdir($this->association_dir);
foreach ($association_filenames as $association_filename) {
$association_file = fopen($association_filename, 'rb');
if ($association_file !== false) {
$assoc_s = fread($association_file,
filesize($association_filename));
fclose($association_file);
// Remove expired or corrupted associations
$association =
Auth_OpenID_Association::deserialize(
'Auth_OpenID_Association', $assoc_s);
if ($association === null) {
Auth_OpenID_FileStore::_removeIfPresent(
$association_filename);
} else {
if ($association->getExpiresIn() == 0) {
$all_associations[] = array($association_filename,
$association);
}
}
}
}
return $all_associations;
}
function clean()
{
if (!$this->active) {
trigger_error("FileStore no longer active", E_USER_ERROR);
return null;
}
$nonces = Auth_OpenID_FileStore::_listdir($this->nonce_dir);
$now = time();
// Check all nonces for expiry
foreach ($nonces as $nonce) {
if (!Auth_OpenID_checkTimestamp($nonce, $now)) {
$filename = $this->nonce_dir . DIRECTORY_SEPARATOR . $nonce;
Auth_OpenID_FileStore::_removeIfPresent($filename);
}
}
foreach ($this->_allAssocs() as $pair) {
list($assoc_filename, $assoc) = $pair;
if ($assoc->getExpiresIn() == 0) {
Auth_OpenID_FileStore::_removeIfPresent($assoc_filename);
}
}
}
/**
* @access private
*/
function _rmtree($dir)
{
if ($dir[strlen($dir) - 1] != DIRECTORY_SEPARATOR) {
$dir .= DIRECTORY_SEPARATOR;
}
if ($handle = opendir($dir)) {
while ($item = readdir($handle)) {
if (!in_array($item, array('.', '..'))) {
if (is_dir($dir . $item)) {
if (!Auth_OpenID_FileStore::_rmtree($dir . $item)) {
return false;
}
} else if (is_file($dir . $item)) {
if (!unlink($dir . $item)) {
return false;
}
}
}
}
closedir($handle);
if (!@rmdir($dir)) {
return false;
}
return true;
} else {
// Couldn't open directory.
return false;
}
}
/**
* @access private
*/
function _mkstemp($dir)
{
foreach (range(0, 4) as $i) {
$name = tempnam($dir, "php_openid_filestore_");
if ($name !== false) {
return $name;
}
}
return false;
}
/**
* @access private
*/
static function _mkdtemp($dir)
{
foreach (range(0, 4) as $i) {
$name = $dir . strval(DIRECTORY_SEPARATOR) . strval(getmypid()) .
"-" . strval(rand(1, time()));
if (!mkdir($name, 0700)) {
return false;
} else {
return $name;
}
}
return false;
}
/**
* @access private
*/
function _listdir($dir)
{
$handle = opendir($dir);
$files = array();
while (false !== ($filename = readdir($handle))) {
if (!in_array($filename, array('.', '..'))) {
$files[] = $dir . DIRECTORY_SEPARATOR . $filename;
}
}
return $files;
}
/**
* @access private
*/
function _isFilenameSafe($char)
{
$_Auth_OpenID_filename_allowed = Auth_OpenID_letters .
Auth_OpenID_digits . ".";
return (strpos($_Auth_OpenID_filename_allowed, $char) !== false);
}
/**
* @access private
*/
function _safe64($str)
{
$h64 = base64_encode(Auth_OpenID_SHA1($str));
$h64 = str_replace('+', '_', $h64);
$h64 = str_replace('/', '.', $h64);
$h64 = str_replace('=', '', $h64);
return $h64;
}
/**
* @access private
*/
function _filenameEscape($str)
{
$filename = "";
$b = Auth_OpenID::toBytes($str);
for ($i = 0; $i < count($b); $i++) {
$c = $b[$i];
if (Auth_OpenID_FileStore::_isFilenameSafe($c)) {
$filename .= $c;
} else {
$filename .= sprintf("_%02X", ord($c));
}
}
return $filename;
}
/**
* Attempt to remove a file, returning whether the file existed at
* the time of the call.
*
* @access private
* @return bool $result True if the file was present, false if not.
*/
function _removeIfPresent($filename)
{
return @unlink($filename);
}
function cleanupAssociations()
{
$removed = 0;
foreach ($this->_allAssocs() as $pair) {
list($assoc_filename, $assoc) = $pair;
if ($assoc->getExpiresIn() == 0) {
$this->_removeIfPresent($assoc_filename);
$removed += 1;
}
}
return $removed;
}
}
openid-php-openid-782224d/Auth/OpenID/HMAC.php 0000664 0000000 0000000 00000005244 11366367341 0020566 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
require_once 'Auth/OpenID.php';
/**
* SHA1_BLOCKSIZE is this module's SHA1 blocksize used by the fallback
* implementation.
*/
define('Auth_OpenID_SHA1_BLOCKSIZE', 64);
function Auth_OpenID_SHA1($text)
{
if (function_exists('hash') &&
function_exists('hash_algos') &&
(in_array('sha1', hash_algos()))) {
// PHP 5 case (sometimes): 'hash' available and 'sha1' algo
// supported.
return hash('sha1', $text, true);
} else if (function_exists('sha1')) {
// PHP 4 case: 'sha1' available.
$hex = sha1($text);
$raw = '';
for ($i = 0; $i < 40; $i += 2) {
$hexcode = substr($hex, $i, 2);
$charcode = (int)base_convert($hexcode, 16, 10);
$raw .= chr($charcode);
}
return $raw;
} else {
// Explode.
trigger_error('No SHA1 function found', E_USER_ERROR);
}
}
/**
* Compute an HMAC/SHA1 hash.
*
* @access private
* @param string $key The HMAC key
* @param string $text The message text to hash
* @return string $mac The MAC
*/
function Auth_OpenID_HMACSHA1($key, $text)
{
if (Auth_OpenID::bytes($key) > Auth_OpenID_SHA1_BLOCKSIZE) {
$key = Auth_OpenID_SHA1($key, true);
}
$key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x00));
$ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE);
$opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE);
$hash1 = Auth_OpenID_SHA1(($key ^ $ipad) . $text, true);
$hmac = Auth_OpenID_SHA1(($key ^ $opad) . $hash1, true);
return $hmac;
}
if (function_exists('hash') &&
function_exists('hash_algos') &&
(in_array('sha256', hash_algos()))) {
function Auth_OpenID_SHA256($text)
{
// PHP 5 case: 'hash' available and 'sha256' algo supported.
return hash('sha256', $text, true);
}
define('Auth_OpenID_SHA256_SUPPORTED', true);
} else {
define('Auth_OpenID_SHA256_SUPPORTED', false);
}
if (function_exists('hash_hmac') &&
function_exists('hash_algos') &&
(in_array('sha256', hash_algos()))) {
function Auth_OpenID_HMACSHA256($key, $text)
{
// Return raw MAC (not hex string).
return hash_hmac('sha256', $text, $key, true);
}
define('Auth_OpenID_HMACSHA256_SUPPORTED', true);
} else {
define('Auth_OpenID_HMACSHA256_SUPPORTED', false);
}
openid-php-openid-782224d/Auth/OpenID/Interface.php 0000664 0000000 0000000 00000015426 11366367341 0021761 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* This is the interface for the store objects the OpenID library
* uses. It is a single class that provides all of the persistence
* mechanisms that the OpenID library needs, for both servers and
* consumers. If you want to create an SQL-driven store, please see
* then {@link Auth_OpenID_SQLStore} class.
*
* Change: Version 2.0 removed the storeNonce, getAuthKey, and isDumb
* methods, and changed the behavior of the useNonce method to support
* one-way nonces.
*
* @package OpenID
* @author JanRain, Inc.
*/
class Auth_OpenID_OpenIDStore {
/**
* This method puts an Association object into storage,
* retrievable by server URL and handle.
*
* @param string $server_url The URL of the identity server that
* this association is with. Because of the way the server portion
* of the library uses this interface, don't assume there are any
* limitations on the character set of the input string. In
* particular, expect to see unescaped non-url-safe characters in
* the server_url field.
*
* @param Association $association The Association to store.
*/
function storeAssociation($server_url, $association)
{
trigger_error("Auth_OpenID_OpenIDStore::storeAssociation ".
"not implemented", E_USER_ERROR);
}
/*
* Remove expired nonces from the store.
*
* Discards any nonce from storage that is old enough that its
* timestamp would not pass useNonce().
*
* This method is not called in the normal operation of the
* library. It provides a way for store admins to keep their
* storage from filling up with expired data.
*
* @return the number of nonces expired
*/
function cleanupNonces()
{
trigger_error("Auth_OpenID_OpenIDStore::cleanupNonces ".
"not implemented", E_USER_ERROR);
}
/*
* Remove expired associations from the store.
*
* This method is not called in the normal operation of the
* library. It provides a way for store admins to keep their
* storage from filling up with expired data.
*
* @return the number of associations expired.
*/
function cleanupAssociations()
{
trigger_error("Auth_OpenID_OpenIDStore::cleanupAssociations ".
"not implemented", E_USER_ERROR);
}
/*
* Shortcut for cleanupNonces(), cleanupAssociations().
*
* This method is not called in the normal operation of the
* library. It provides a way for store admins to keep their
* storage from filling up with expired data.
*/
function cleanup()
{
return array($this->cleanupNonces(),
$this->cleanupAssociations());
}
/**
* Report whether this storage supports cleanup
*/
function supportsCleanup()
{
return true;
}
/**
* This method returns an Association object from storage that
* matches the server URL and, if specified, handle. It returns
* null if no such association is found or if the matching
* association is expired.
*
* If no handle is specified, the store may return any association
* which matches the server URL. If multiple associations are
* valid, the recommended return value for this method is the one
* most recently issued.
*
* This method is allowed (and encouraged) to garbage collect
* expired associations when found. This method must not return
* expired associations.
*
* @param string $server_url The URL of the identity server to get
* the association for. Because of the way the server portion of
* the library uses this interface, don't assume there are any
* limitations on the character set of the input string. In
* particular, expect to see unescaped non-url-safe characters in
* the server_url field.
*
* @param mixed $handle This optional parameter is the handle of
* the specific association to get. If no specific handle is
* provided, any valid association matching the server URL is
* returned.
*
* @return Association The Association for the given identity
* server.
*/
function getAssociation($server_url, $handle = null)
{
trigger_error("Auth_OpenID_OpenIDStore::getAssociation ".
"not implemented", E_USER_ERROR);
}
/**
* This method removes the matching association if it's found, and
* returns whether the association was removed or not.
*
* @param string $server_url The URL of the identity server the
* association to remove belongs to. Because of the way the server
* portion of the library uses this interface, don't assume there
* are any limitations on the character set of the input
* string. In particular, expect to see unescaped non-url-safe
* characters in the server_url field.
*
* @param string $handle This is the handle of the association to
* remove. If there isn't an association found that matches both
* the given URL and handle, then there was no matching handle
* found.
*
* @return mixed Returns whether or not the given association existed.
*/
function removeAssociation($server_url, $handle)
{
trigger_error("Auth_OpenID_OpenIDStore::removeAssociation ".
"not implemented", E_USER_ERROR);
}
/**
* Called when using a nonce.
*
* This method should return C{True} if the nonce has not been
* used before, and store it for a while to make sure nobody
* tries to use the same value again. If the nonce has already
* been used, return C{False}.
*
* Change: In earlier versions, round-trip nonces were used and a
* nonce was only valid if it had been previously stored with
* storeNonce. Version 2.0 uses one-way nonces, requiring a
* different implementation here that does not depend on a
* storeNonce call. (storeNonce is no longer part of the
* interface.
*
* @param string $nonce The nonce to use.
*
* @return bool Whether or not the nonce was valid.
*/
function useNonce($server_url, $timestamp, $salt)
{
trigger_error("Auth_OpenID_OpenIDStore::useNonce ".
"not implemented", E_USER_ERROR);
}
/**
* Removes all entries from the store; implementation is optional.
*/
function reset()
{
}
}
openid-php-openid-782224d/Auth/OpenID/KVForm.php 0000664 0000000 0000000 00000004735 11366367341 0021226 0 ustar 00root root 0000000 0000000
* @copyright 2005-2008 Janrain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
*/
/**
* Container for key-value/comma-newline OpenID format and parsing
*/
class Auth_OpenID_KVForm {
/**
* Convert an OpenID colon/newline separated string into an
* associative array
*
* @static
* @access private
*/
static function toArray($kvs, $strict=false)
{
$lines = explode("\n", $kvs);
$last = array_pop($lines);
if ($last !== '') {
array_push($lines, $last);
if ($strict) {
return false;
}
}
$values = array();
for ($lineno = 0; $lineno < count($lines); $lineno++) {
$line = $lines[$lineno];
$kv = explode(':', $line, 2);
if (count($kv) != 2) {
if ($strict) {
return false;
}
continue;
}
$key = $kv[0];
$tkey = trim($key);
if ($tkey != $key) {
if ($strict) {
return false;
}
}
$value = $kv[1];
$tval = trim($value);
if ($tval != $value) {
if ($strict) {
return false;
}
}
$values[$tkey] = $tval;
}
return $values;
}
/**
* Convert an array into an OpenID colon/newline separated string
*
* @static
* @access private
*/
static function fromArray($values)
{
if ($values === null) {
return null;
}
ksort($values);
$serialized = '';
foreach ($values as $key => $value) {
if (is_array($value)) {
list($key, $value) = array($value[0], $value[1]);
}
if (strpos($key, ':') !== false) {
return null;
}
if (strpos($key, "\n") !== false) {
return null;
}
if (strpos($value, "\n") !== false) {
return null;
}
$serialized .= "$key:$value\n";
}
return $serialized;
}
}
openid-php-openid-782224d/Auth/OpenID/MDB2Store.php 0000664 0000000 0000000 00000033557 11366367341 0021567 0 ustar 00root root 0000000 0000000
* @copyright 2005 Janrain, Inc.
* @license http://www.gnu.org/copyleft/lesser.html LGPL
*/
require_once 'MDB2.php';
/**
* @access private
*/
require_once 'Auth/OpenID/Interface.php';
/**
* @access private
*/
require_once 'Auth/OpenID.php';
/**
* @access private
*/
require_once 'Auth/OpenID/Nonce.php';
/**
* This store uses a PEAR::MDB2 connection to store persistence
* information.
*
* The table names used are determined by the class variables
* associations_table_name and nonces_table_name. To change the name
* of the tables used, pass new table names into the constructor.
*
* To create the tables with the proper schema, see the createTables
* method.
*
* @package OpenID
*/
class Auth_OpenID_MDB2Store extends Auth_OpenID_OpenIDStore {
/**
* This creates a new MDB2Store instance. It requires an
* established database connection be given to it, and it allows
* overriding the default table names.
*
* @param connection $connection This must be an established
* connection to a database of the correct type for the SQLStore
* subclass you're using. This must be a PEAR::MDB2 connection
* handle.
*
* @param associations_table: This is an optional parameter to
* specify the name of the table used for storing associations.
* The default value is 'oid_associations'.
*
* @param nonces_table: This is an optional parameter to specify
* the name of the table used for storing nonces. The default
* value is 'oid_nonces'.
*/
function Auth_OpenID_MDB2Store($connection,
$associations_table = null,
$nonces_table = null)
{
$this->associations_table_name = "oid_associations";
$this->nonces_table_name = "oid_nonces";
// Check the connection object type to be sure it's a PEAR
// database connection.
if (!is_object($connection) ||
!is_subclass_of($connection, 'mdb2_driver_common')) {
trigger_error("Auth_OpenID_MDB2Store expected PEAR connection " .
"object (got ".get_class($connection).")",
E_USER_ERROR);
return;
}
$this->connection = $connection;
// Be sure to set the fetch mode so the results are keyed on
// column name instead of column index.
$this->connection->setFetchMode(MDB2_FETCHMODE_ASSOC);
if (PEAR::isError($this->connection->loadModule('Extended'))) {
trigger_error("Unable to load MDB2_Extended module", E_USER_ERROR);
return;
}
if ($associations_table) {
$this->associations_table_name = $associations_table;
}
if ($nonces_table) {
$this->nonces_table_name = $nonces_table;
}
$this->max_nonce_age = 6 * 60 * 60;
}
function tableExists($table_name)
{
return !PEAR::isError($this->connection->query(
sprintf("SELECT * FROM %s LIMIT 0",
$table_name)));
}
function createTables()
{
$n = $this->create_nonce_table();
$a = $this->create_assoc_table();
if (!$n || !$a) {
return false;
}
return true;
}
function create_nonce_table()
{
if (!$this->tableExists($this->nonces_table_name)) {
switch ($this->connection->phptype) {
case "mysql":
case "mysqli":
// Custom SQL for MySQL to use InnoDB and variable-
// length keys
$r = $this->connection->exec(
sprintf("CREATE TABLE %s (\n".
" server_url VARCHAR(2047) NOT NULL DEFAULT '',\n".
" timestamp INTEGER NOT NULL,\n".
" salt CHAR(40) NOT NULL,\n".
" UNIQUE (server_url(255), timestamp, salt)\n".
") TYPE=InnoDB",
$this->nonces_table_name));
if (PEAR::isError($r)) {
return false;
}
break;
default:
if (PEAR::isError(
$this->connection->loadModule('Manager'))) {
return false;
}
$fields = array(
"server_url" => array(
"type" => "text",
"length" => 2047,
"notnull" => true
),
"timestamp" => array(
"type" => "integer",
"notnull" => true
),
"salt" => array(
"type" => "text",
"length" => 40,
"fixed" => true,
"notnull" => true
)
);
$constraint = array(
"unique" => 1,
"fields" => array(
"server_url" => true,
"timestamp" => true,
"salt" => true
)
);
$r = $this->connection->createTable($this->nonces_table_name,
$fields);
if (PEAR::isError($r)) {
return false;
}
$r = $this->connection->createConstraint(
$this->nonces_table_name,
$this->nonces_table_name . "_constraint",
$constraint);
if (PEAR::isError($r)) {
return false;
}
break;
}
}
return true;
}
function create_assoc_table()
{
if (!$this->tableExists($this->associations_table_name)) {
switch ($this->connection->phptype) {
case "mysql":
case "mysqli":
// Custom SQL for MySQL to use InnoDB and variable-
// length keys
$r = $this->connection->exec(
sprintf("CREATE TABLE %s(\n".
" server_url VARCHAR(2047) NOT NULL DEFAULT '',\n".
" handle VARCHAR(255) NOT NULL,\n".
" secret BLOB NOT NULL,\n".
" issued INTEGER NOT NULL,\n".
" lifetime INTEGER NOT NULL,\n".
" assoc_type VARCHAR(64) NOT NULL,\n".
" PRIMARY KEY (server_url(255), handle)\n".
") TYPE=InnoDB",
$this->associations_table_name));
if (PEAR::isError($r)) {
return false;
}
break;
default:
if (PEAR::isError(
$this->connection->loadModule('Manager'))) {
return false;
}
$fields = array(
"server_url" => array(
"type" => "text",
"length" => 2047,
"notnull" => true
),
"handle" => array(
"type" => "text",
"length" => 255,
"notnull" => true
),
"secret" => array(
"type" => "blob",
"length" => "255",
"notnull" => true
),
"issued" => array(
"type" => "integer",
"notnull" => true
),
"lifetime" => array(
"type" => "integer",
"notnull" => true
),
"assoc_type" => array(
"type" => "text",
"length" => 64,
"notnull" => true
)
);
$options = array(
"primary" => array(
"server_url" => true,
"handle" => true
)
);
$r = $this->connection->createTable(
$this->associations_table_name,
$fields,
$options);
if (PEAR::isError($r)) {
return false;
}
break;
}
}
return true;
}
function storeAssociation($server_url, $association)
{
$fields = array(
"server_url" => array(
"value" => $server_url,
"key" => true
),
"handle" => array(
"value" => $association->handle,
"key" => true
),
"secret" => array(
"value" => $association->secret,
"type" => "blob"
),
"issued" => array(
"value" => $association->issued
),
"lifetime" => array(
"value" => $association->lifetime
),
"assoc_type" => array(
"value" => $association->assoc_type
)
);
return !PEAR::isError($this->connection->replace(
$this->associations_table_name,
$fields));
}
function cleanupNonces()
{
global $Auth_OpenID_SKEW;
$v = time() - $Auth_OpenID_SKEW;
return $this->connection->exec(
sprintf("DELETE FROM %s WHERE timestamp < %d",
$this->nonces_table_name, $v));
}
function cleanupAssociations()
{
return $this->connection->exec(
sprintf("DELETE FROM %s WHERE issued + lifetime < %d",
$this->associations_table_name, time()));
}
function getAssociation($server_url, $handle = null)
{
$sql = "";
$params = null;
$types = array(
"text",
"blob",
"integer",
"integer",
"text"
);
if ($handle !== null) {
$sql = sprintf("SELECT handle, secret, issued, lifetime, assoc_type " .
"FROM %s WHERE server_url = ? AND handle = ?",
$this->associations_table_name);
$params = array($server_url, $handle);
} else {
$sql = sprintf("SELECT handle, secret, issued, lifetime, assoc_type " .
"FROM %s WHERE server_url = ? ORDER BY issued DESC",
$this->associations_table_name);
$params = array($server_url);
}
$assoc = $this->connection->getRow($sql, $types, $params);
if (!$assoc || PEAR::isError($assoc)) {
return null;
} else {
$association = new Auth_OpenID_Association($assoc['handle'],
stream_get_contents(
$assoc['secret']),
$assoc['issued'],
$assoc['lifetime'],
$assoc['assoc_type']);
fclose($assoc['secret']);
return $association;
}
}
function removeAssociation($server_url, $handle)
{
$r = $this->connection->execParam(
sprintf("DELETE FROM %s WHERE server_url = ? AND handle = ?",
$this->associations_table_name),
array($server_url, $handle));
if (PEAR::isError($r) || $r == 0) {
return false;
}
return true;
}
function useNonce($server_url, $timestamp, $salt)
{
global $Auth_OpenID_SKEW;
if (abs($timestamp - time()) > $Auth_OpenID_SKEW ) {
return false;
}
$fields = array(
"timestamp" => $timestamp,
"salt" => $salt
);
if (!empty($server_url)) {
$fields["server_url"] = $server_url;
}
$r = $this->connection->autoExecute(
$this->nonces_table_name,
$fields,
MDB2_AUTOQUERY_INSERT);
if (PEAR::isError($r)) {
return false;
}
return true;
}
/**
* Resets the store by removing all records from the store's
* tables.
*/
function reset()
{
$this->connection->query(sprintf("DELETE FROM %s",
$this->associations_table_name));
$this->connection->query(sprintf("DELETE FROM %s",
$this->nonces_table_name));
}
}
?>
openid-php-openid-782224d/Auth/OpenID/MemcachedStore.php 0000664 0000000 0000000 00000014607 11366367341 0022744 0 ustar 00root root 0000000 0000000
* @copyright 2008 JanRain, Inc.
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
* Contributed by Open Web Technologies
*/
/**
* Import the interface for creating a new store class.
*/
require_once 'Auth/OpenID/Interface.php';
/**
* This is a memcached-based store for OpenID associations and
* nonces.
*
* As memcache has limit of 250 chars for key length,
* server_url, handle and salt are hashed with sha1().
*
* Most of the methods of this class are implementation details.
* People wishing to just use this store need only pay attention to
* the constructor.
*
* @package OpenID
*/
class Auth_OpenID_MemcachedStore extends Auth_OpenID_OpenIDStore {
/**
* Initializes a new {@link Auth_OpenID_MemcachedStore} instance.
* Just saves memcached object as property.
*
* @param resource connection Memcache connection resourse
*/
function Auth_OpenID_MemcachedStore($connection, $compress = false)
{
$this->connection = $connection;
$this->compress = $compress ? MEMCACHE_COMPRESSED : 0;
}
/**
* Store association until its expiration time in memcached.
* Overwrites any existing association with same server_url and
* handle. Handles list of associations for every server.
*/
function storeAssociation($server_url, $association)
{
// create memcached keys for association itself
// and list of associations for this server
$associationKey = $this->associationKey($server_url,
$association->handle);
$serverKey = $this->associationServerKey($server_url);
// get list of associations
$serverAssociations = $this->connection->get($serverKey);
// if no such list, initialize it with empty array
if (!$serverAssociations) {
$serverAssociations = array();
}
// and store given association key in it
$serverAssociations[$association->issued] = $associationKey;
// save associations' keys list
$this->connection->set(
$serverKey,
$serverAssociations,
$this->compress
);
// save association itself
$this->connection->set(
$associationKey,
$association,
$this->compress,
$association->issued + $association->lifetime);
}
/**
* Read association from memcached. If no handle given
* and multiple associations found, returns latest issued
*/
function getAssociation($server_url, $handle = null)
{
// simple case: handle given
if ($handle !== null) {
// get association, return null if failed
$association = $this->connection->get(
$this->associationKey($server_url, $handle));
return $association ? $association : null;
}
// no handle given, working with list
// create key for list of associations
$serverKey = $this->associationServerKey($server_url);
// get list of associations
$serverAssociations = $this->connection->get($serverKey);
// return null if failed or got empty list
if (!$serverAssociations) {
return null;
}
// get key of most recently issued association
$keys = array_keys($serverAssociations);
sort($keys);
$lastKey = $serverAssociations[array_pop($keys)];
// get association, return null if failed
$association = $this->connection->get($lastKey);
return $association ? $association : null;
}
/**
* Immediately delete association from memcache.
*/
function removeAssociation($server_url, $handle)
{
// create memcached keys for association itself
// and list of associations for this server
$serverKey = $this->associationServerKey($server_url);
$associationKey = $this->associationKey($server_url,
$handle);
// get list of associations
$serverAssociations = $this->connection->get($serverKey);
// return null if failed or got empty list
if (!$serverAssociations) {
return false;
}
// ensure that given association key exists in list
$serverAssociations = array_flip($serverAssociations);
if (!array_key_exists($associationKey, $serverAssociations)) {
return false;
}
// remove given association key from list
unset($serverAssociations[$associationKey]);
$serverAssociations = array_flip($serverAssociations);
// save updated list
$this->connection->set(
$serverKey,
$serverAssociations,
$this->compress
);
// delete association
return $this->connection->delete($associationKey);
}
/**
* Create nonce for server and salt, expiring after
* $Auth_OpenID_SKEW seconds.
*/
function useNonce($server_url, $timestamp, $salt)
{
global $Auth_OpenID_SKEW;
// save one request to memcache when nonce obviously expired
if (abs($timestamp - time()) > $Auth_OpenID_SKEW) {
return false;
}
// returns false when nonce already exists
// otherwise adds nonce
return $this->connection->add(
'openid_nonce_' . sha1($server_url) . '_' . sha1($salt),
1, // any value here
$this->compress,
$Auth_OpenID_SKEW);
}
/**
* Memcache key is prefixed with 'openid_association_' string.
*/
function associationKey($server_url, $handle = null)
{
return 'openid_association_' . sha1($server_url) . '_' . sha1($handle);
}
/**
* Memcache key is prefixed with 'openid_association_' string.
*/
function associationServerKey($server_url)
{
return 'openid_association_server_' . sha1($server_url);
}
/**
* Report that this storage doesn't support cleanup
*/
function supportsCleanup()
{
return false;
}
}
openid-php-openid-782224d/Auth/OpenID/Message.php 0000664 0000000 0000000 00000063603 11366367341 0021445 0 ustar 00root root 0000000 0000000 keys = array();
$this->values = array();
if (is_array($classic_array)) {
foreach ($classic_array as $key => $value) {
$this->set($key, $value);
}
}
}
/**
* Returns true if $thing is an Auth_OpenID_Mapping object; false
* if not.
*/
static function isA($thing)
{
return (is_object($thing) &&
strtolower(get_class($thing)) == 'auth_openid_mapping');
}
/**
* Returns an array of the keys in the mapping.
*/
function keys()
{
return $this->keys;
}
/**
* Returns an array of values in the mapping.
*/
function values()
{
return $this->values;
}
/**
* Returns an array of (key, value) pairs in the mapping.
*/
function items()
{
$temp = array();
for ($i = 0; $i < count($this->keys); $i++) {
$temp[] = array($this->keys[$i],
$this->values[$i]);
}
return $temp;
}
/**
* Returns the "length" of the mapping, or the number of keys.
*/
function len()
{
return count($this->keys);
}
/**
* Sets a key-value pair in the mapping. If the key already
* exists, its value is replaced with the new value.
*/
function set($key, $value)
{
$index = array_search($key, $this->keys);
if ($index !== false) {
$this->values[$index] = $value;
} else {
$this->keys[] = $key;
$this->values[] = $value;
}
}
/**
* Gets a specified value from the mapping, associated with the
* specified key. If the key does not exist in the mapping,
* $default is returned instead.
*/
function get($key, $default = null)
{
$index = array_search($key, $this->keys);
if ($index !== false) {
return $this->values[$index];
} else {
return $default;
}
}
/**
* @access private
*/
function _reflow()
{
// PHP is broken yet again. Sort the arrays to remove the
// hole in the numeric indexes that make up the array.
$old_keys = $this->keys;
$old_values = $this->values;
$this->keys = array();
$this->values = array();
foreach ($old_keys as $k) {
$this->keys[] = $k;
}
foreach ($old_values as $v) {
$this->values[] = $v;
}
}
/**
* Deletes a key-value pair from the mapping with the specified
* key.
*/
function del($key)
{
$index = array_search($key, $this->keys);
if ($index !== false) {
unset($this->keys[$index]);
unset($this->values[$index]);
$this->_reflow();
return true;
}
return false;
}
/**
* Returns true if the specified value has a key in the mapping;
* false if not.
*/
function contains($value)
{
return (array_search($value, $this->keys) !== false);
}
}
/**
* Maintains a bijective map between namespace uris and aliases.
*
* @package OpenID
*/
class Auth_OpenID_NamespaceMap {
function Auth_OpenID_NamespaceMap()
{
$this->alias_to_namespace = new Auth_OpenID_Mapping();
$this->namespace_to_alias = new Auth_OpenID_Mapping();
$this->implicit_namespaces = array();
}
function getAlias($namespace_uri)
{
return $this->namespace_to_alias->get($namespace_uri);
}
function getNamespaceURI($alias)
{
return $this->alias_to_namespace->get($alias);
}
function iterNamespaceURIs()
{
// Return an iterator over the namespace URIs
return $this->namespace_to_alias->keys();
}
function iterAliases()
{
// Return an iterator over the aliases"""
return $this->alias_to_namespace->keys();
}
function iteritems()
{
return $this->namespace_to_alias->items();
}
function isImplicit($namespace_uri)
{
return in_array($namespace_uri, $this->implicit_namespaces);
}
function addAlias($namespace_uri, $desired_alias, $implicit=false)
{
// Add an alias from this namespace URI to the desired alias
global $Auth_OpenID_OPENID_PROTOCOL_FIELDS;
// Check that desired_alias is not an openid protocol field as
// per the spec.
if (in_array($desired_alias, $Auth_OpenID_OPENID_PROTOCOL_FIELDS)) {
Auth_OpenID::log("\"%s\" is not an allowed namespace alias",
$desired_alias);
return null;
}
// Check that desired_alias does not contain a period as per
// the spec.
if (strpos($desired_alias, '.') !== false) {
Auth_OpenID::log('"%s" must not contain a dot', $desired_alias);
return null;
}
// Check that there is not a namespace already defined for the
// desired alias
$current_namespace_uri =
$this->alias_to_namespace->get($desired_alias);
if (($current_namespace_uri !== null) &&
($current_namespace_uri != $namespace_uri)) {
Auth_OpenID::log('Cannot map "%s" because previous mapping exists',
$namespace_uri);
return null;
}
// Check that there is not already a (different) alias for
// this namespace URI
$alias = $this->namespace_to_alias->get($namespace_uri);
if (($alias !== null) && ($alias != $desired_alias)) {
Auth_OpenID::log('Cannot map %s to alias %s. ' .
'It is already mapped to alias %s',
$namespace_uri, $desired_alias, $alias);
return null;
}
assert((Auth_OpenID_NULL_NAMESPACE === $desired_alias) ||
is_string($desired_alias));
$this->alias_to_namespace->set($desired_alias, $namespace_uri);
$this->namespace_to_alias->set($namespace_uri, $desired_alias);
if ($implicit) {
array_push($this->implicit_namespaces, $namespace_uri);
}
return $desired_alias;
}
function add($namespace_uri)
{
// Add this namespace URI to the mapping, without caring what
// alias it ends up with
// See if this namespace is already mapped to an alias
$alias = $this->namespace_to_alias->get($namespace_uri);
if ($alias !== null) {
return $alias;
}
// Fall back to generating a numerical alias
$i = 0;
while (1) {
$alias = 'ext' . strval($i);
if ($this->addAlias($namespace_uri, $alias) === null) {
$i += 1;
} else {
return $alias;
}
}
// Should NEVER be reached!
return null;
}
function contains($namespace_uri)
{
return $this->isDefined($namespace_uri);
}
function isDefined($namespace_uri)
{
return $this->namespace_to_alias->contains($namespace_uri);
}
}
/**
* In the implementation of this object, null represents the global
* namespace as well as a namespace with no key.
*
* @package OpenID
*/
class Auth_OpenID_Message {
function Auth_OpenID_Message($openid_namespace = null)
{
// Create an empty Message
$this->allowed_openid_namespaces = array(
Auth_OpenID_OPENID1_NS,
Auth_OpenID_THE_OTHER_OPENID1_NS,
Auth_OpenID_OPENID2_NS);
$this->args = new Auth_OpenID_Mapping();
$this->namespaces = new Auth_OpenID_NamespaceMap();
if ($openid_namespace === null) {
$this->_openid_ns_uri = null;
} else {
$implicit = Auth_OpenID_isOpenID1($openid_namespace);
$this->setOpenIDNamespace($openid_namespace, $implicit);
}
}
function isOpenID1()
{
return Auth_OpenID_isOpenID1($this->getOpenIDNamespace());
}
function isOpenID2()
{
return $this->getOpenIDNamespace() == Auth_OpenID_OPENID2_NS;
}
static function fromPostArgs($args)
{
// Construct a Message containing a set of POST arguments
$obj = new Auth_OpenID_Message();
// Partition into "openid." args and bare args
$openid_args = array();
foreach ($args as $key => $value) {
if (is_array($value)) {
return null;
}
$parts = explode('.', $key, 2);
if (count($parts) == 2) {
list($prefix, $rest) = $parts;
} else {
$prefix = null;
}
if ($prefix != 'openid') {
$obj->args->set(array(Auth_OpenID_BARE_NS, $key), $value);
} else {
$openid_args[$rest] = $value;
}
}
if ($obj->_fromOpenIDArgs($openid_args)) {
return $obj;
} else {
return null;
}
}
static function fromOpenIDArgs($openid_args)
{
// Takes an array.
// Construct a Message from a parsed KVForm message
$obj = new Auth_OpenID_Message();
if ($obj->_fromOpenIDArgs($openid_args)) {
return $obj;
} else {
return null;
}
}
/**
* @access private
*/
function _fromOpenIDArgs($openid_args)
{
global $Auth_OpenID_registered_aliases;
// Takes an Auth_OpenID_Mapping instance OR an array.
if (!Auth_OpenID_Mapping::isA($openid_args)) {
$openid_args = new Auth_OpenID_Mapping($openid_args);
}
$ns_args = array();
// Resolve namespaces
foreach ($openid_args->items() as $pair) {
list($rest, $value) = $pair;
$parts = explode('.', $rest, 2);
if (count($parts) == 2) {
list($ns_alias, $ns_key) = $parts;
} else {
$ns_alias = Auth_OpenID_NULL_NAMESPACE;
$ns_key = $rest;
}
if ($ns_alias == 'ns') {
if ($this->namespaces->addAlias($value, $ns_key) === null) {
return false;
}
} else if (($ns_alias == Auth_OpenID_NULL_NAMESPACE) &&
($ns_key == 'ns')) {
// null namespace
if ($this->setOpenIDNamespace($value, false) === false) {
return false;
}
} else {
$ns_args[] = array($ns_alias, $ns_key, $value);
}
}
if (!$this->getOpenIDNamespace()) {
if ($this->setOpenIDNamespace(Auth_OpenID_OPENID1_NS, true) ===
false) {
return false;
}
}
// Actually put the pairs into the appropriate namespaces
foreach ($ns_args as $triple) {
list($ns_alias, $ns_key, $value) = $triple;
$ns_uri = $this->namespaces->getNamespaceURI($ns_alias);
if ($ns_uri === null) {
$ns_uri = $this->_getDefaultNamespace($ns_alias);
if ($ns_uri === null) {
$ns_uri = Auth_OpenID_OPENID_NS;
$ns_key = sprintf('%s.%s', $ns_alias, $ns_key);
} else {
$this->namespaces->addAlias($ns_uri, $ns_alias, true);
}
}
$this->setArg($ns_uri, $ns_key, $value);
}
return true;
}
function _getDefaultNamespace($mystery_alias)
{
global $Auth_OpenID_registered_aliases;
if ($this->isOpenID1()) {
return @$Auth_OpenID_registered_aliases[$mystery_alias];
}
return null;
}
function setOpenIDNamespace($openid_ns_uri, $implicit)
{
if (!in_array($openid_ns_uri, $this->allowed_openid_namespaces)) {
Auth_OpenID::log('Invalid null namespace: "%s"', $openid_ns_uri);
return false;
}
$succeeded = $this->namespaces->addAlias($openid_ns_uri,
Auth_OpenID_NULL_NAMESPACE,
$implicit);
if ($succeeded === false) {
return false;
}
$this->_openid_ns_uri = $openid_ns_uri;
return true;
}
function getOpenIDNamespace()
{
return $this->_openid_ns_uri;
}
static function fromKVForm($kvform_string)
{
// Create a Message from a KVForm string
return Auth_OpenID_Message::fromOpenIDArgs(
Auth_OpenID_KVForm::toArray($kvform_string));
}
function copy()
{
return $this;
}
function toPostArgs()
{
// Return all arguments with openid. in front of namespaced
// arguments.
$args = array();
// Add namespace definitions to the output
foreach ($this->namespaces->iteritems() as $pair) {
list($ns_uri, $alias) = $pair;
if ($this->namespaces->isImplicit($ns_uri)) {
continue;
}
if ($alias == Auth_OpenID_NULL_NAMESPACE) {
$ns_key = 'openid.ns';
} else {
$ns_key = 'openid.ns.' . $alias;
}
$args[$ns_key] = $ns_uri;
}
foreach ($this->args->items() as $pair) {
list($ns_parts, $value) = $pair;
list($ns_uri, $ns_key) = $ns_parts;
$key = $this->getKey($ns_uri, $ns_key);
$args[$key] = $value;
}
return $args;
}
function toArgs()
{
// Return all namespaced arguments, failing if any
// non-namespaced arguments exist.
$post_args = $this->toPostArgs();
$kvargs = array();
foreach ($post_args as $k => $v) {
if (strpos($k, 'openid.') !== 0) {
// raise ValueError(
// 'This message can only be encoded as a POST, because it '
// 'contains arguments that are not prefixed with "openid."')
return null;
} else {
$kvargs[substr($k, 7)] = $v;
}
}
return $kvargs;
}
function toFormMarkup($action_url, $form_tag_attrs = null,
$submit_text = "Continue")
{
$form = "\n";
return $form;
}
function toURL($base_url)
{
// Generate a GET URL with the parameters in this message
// attached as query parameters.
return Auth_OpenID::appendArgs($base_url, $this->toPostArgs());
}
function toKVForm()
{
// Generate a KVForm string that contains the parameters in
// this message. This will fail if the message contains
// arguments outside of the 'openid.' prefix.
return Auth_OpenID_KVForm::fromArray($this->toArgs());
}
function toURLEncoded()
{
// Generate an x-www-urlencoded string
$args = array();
foreach ($this->toPostArgs() as $k => $v) {
$args[] = array($k, $v);
}
sort($args);
return Auth_OpenID::httpBuildQuery($args);
}
/**
* @access private
*/
function _fixNS($namespace)
{
// Convert an input value into the internally used values of
// this object
if ($namespace == Auth_OpenID_OPENID_NS) {
if ($this->_openid_ns_uri === null) {
return new Auth_OpenID_FailureResponse(null,
'OpenID namespace not set');
} else {
$namespace = $this->_openid_ns_uri;
}
}
if (($namespace != Auth_OpenID_BARE_NS) &&
(!is_string($namespace))) {
//TypeError
$err_msg = sprintf("Namespace must be Auth_OpenID_BARE_NS, ".
"Auth_OpenID_OPENID_NS or a string. got %s",
print_r($namespace, true));
return new Auth_OpenID_FailureResponse(null, $err_msg);
}
if (($namespace != Auth_OpenID_BARE_NS) &&
(strpos($namespace, ':') === false)) {
// fmt = 'OpenID 2.0 namespace identifiers SHOULD be URIs. Got %r'
// warnings.warn(fmt % (namespace,), DeprecationWarning)
if ($namespace == 'sreg') {
// fmt = 'Using %r instead of "sreg" as namespace'
// warnings.warn(fmt % (SREG_URI,), DeprecationWarning,)
return Auth_OpenID_SREG_URI;
}
}
return $namespace;
}
function hasKey($namespace, $ns_key)
{
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
// XXX log me
return false;
} else {
return $this->args->contains(array($namespace, $ns_key));
}
}
function getKey($namespace, $ns_key)
{
// Get the key for a particular namespaced argument
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
}
if ($namespace == Auth_OpenID_BARE_NS) {
return $ns_key;
}
$ns_alias = $this->namespaces->getAlias($namespace);
// No alias is defined, so no key can exist
if ($ns_alias === null) {
return null;
}
if ($ns_alias == Auth_OpenID_NULL_NAMESPACE) {
$tail = $ns_key;
} else {
$tail = sprintf('%s.%s', $ns_alias, $ns_key);
}
return 'openid.' . $tail;
}
function getArg($namespace, $key, $default = null)
{
// Get a value for a namespaced key.
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
} else {
if ((!$this->args->contains(array($namespace, $key))) &&
($default == Auth_OpenID_NO_DEFAULT)) {
$err_msg = sprintf("Namespace %s missing required field %s",
$namespace, $key);
return new Auth_OpenID_FailureResponse(null, $err_msg);
} else {
return $this->args->get(array($namespace, $key), $default);
}
}
}
function getArgs($namespace)
{
// Get the arguments that are defined for this namespace URI
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
} else {
$stuff = array();
foreach ($this->args->items() as $pair) {
list($key, $value) = $pair;
list($pair_ns, $ns_key) = $key;
if ($pair_ns == $namespace) {
$stuff[$ns_key] = $value;
}
}
return $stuff;
}
}
function updateArgs($namespace, $updates)
{
// Set multiple key/value pairs in one call
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
} else {
foreach ($updates as $k => $v) {
$this->setArg($namespace, $k, $v);
}
return true;
}
}
function setArg($namespace, $key, $value)
{
// Set a single argument in this namespace
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
} else {
$this->args->set(array($namespace, $key), $value);
if ($namespace !== Auth_OpenID_BARE_NS) {
$this->namespaces->add($namespace);
}
return true;
}
}
function delArg($namespace, $key)
{
$namespace = $this->_fixNS($namespace);
if (Auth_OpenID::isFailure($namespace)) {
return $namespace;
} else {
return $this->args->del(array($namespace, $key));
}
}
function getAliasedArg($aliased_key, $default = null)
{
if ($aliased_key == 'ns') {
// Return the namespace URI for the OpenID namespace
return $this->getOpenIDNamespace();
}
$parts = explode('.', $aliased_key, 2);
if (count($parts) != 2) {
$ns = null;
} else {
list($alias, $key) = $parts;
if ($alias == 'ns') {
// Return the namespace URI for a namespace alias
// parameter.
return $this->namespaces->getNamespaceURI($key);
} else {
$ns = $this->namespaces->getNamespaceURI($alias);
}
}
if ($ns === null) {
$key = $aliased_key;
$ns = $this->getOpenIDNamespace();
}
return $this->getArg($ns, $key, $default);
}
}
openid-php-openid-782224d/Auth/OpenID/MySQLStore.php 0000664 0000000 0000000 00000004057 11366367341 0022041 0 ustar 00root root 0000000 0000000 sql['nonce_table'] =
"CREATE TABLE %s (\n".
" server_url VARCHAR(2047) NOT NULL,\n".
" timestamp INTEGER NOT NULL,\n".
" salt CHAR(40) NOT NULL,\n".
" UNIQUE (server_url(255), timestamp, salt)\n".
") ENGINE=InnoDB";
$this->sql['assoc_table'] =
"CREATE TABLE %s (\n".
" server_url BLOB NOT NULL,\n".
" handle VARCHAR(255) NOT NULL,\n".
" secret BLOB NOT NULL,\n".
" issued INTEGER NOT NULL,\n".
" lifetime INTEGER NOT NULL,\n".
" assoc_type VARCHAR(64) NOT NULL,\n".
" PRIMARY KEY (server_url(255), handle)\n".
") ENGINE=InnoDB";
$this->sql['set_assoc'] =
"REPLACE INTO %s (server_url, handle, secret, issued,\n".
" lifetime, assoc_type) VALUES (?, ?, !, ?, ?, ?)";
$this->sql['get_assocs'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ?";
$this->sql['get_assoc'] =
"SELECT handle, secret, issued, lifetime, assoc_type FROM %s ".
"WHERE server_url = ? AND handle = ?";
$this->sql['remove_assoc'] =
"DELETE FROM %s WHERE server_url = ? AND handle = ?";
$this->sql['add_nonce'] =
"INSERT INTO %s (server_url, timestamp, salt) VALUES (?, ?, ?)";
$this->sql['clean_nonce'] =
"DELETE FROM %s WHERE timestamp < ?";
$this->sql['clean_assoc'] =
"DELETE FROM %s WHERE issued + lifetime < ?";
}
/**
* @access private
*/
function blobEncode($blob)
{
return "0x" . bin2hex($blob);
}
}
openid-php-openid-782224d/Auth/OpenID/Nonce.php 0000664 0000000 0000000 00000005475 11366367341 0021126 0 ustar 00root root 0000000 0000000 preferred_auth_policies = $preferred_auth_policies;
$this->max_auth_age = $max_auth_age;
}
/**
* Add an acceptable authentication policy URI to this request
*
* This method is intended to be used by the relying party to add
* acceptable authentication types to the request.
*
* policy_uri: The identifier for the preferred type of
* authentication.
*/
function addPolicyURI($policy_uri)
{
if (!in_array($policy_uri, $this->preferred_auth_policies)) {
$this->preferred_auth_policies[] = $policy_uri;
}
}
function getExtensionArgs()
{
$ns_args = array(
'preferred_auth_policies' =>
implode(' ', $this->preferred_auth_policies)
);
if ($this->max_auth_age !== null) {
$ns_args['max_auth_age'] = strval($this->max_auth_age);
}
return $ns_args;
}
/**
* Instantiate a Request object from the arguments in a checkid_*
* OpenID message
*/
static function fromOpenIDRequest($request)
{
$obj = new Auth_OpenID_PAPE_Request();
$args = $request->message->getArgs(Auth_OpenID_PAPE_NS_URI);
if ($args === null || $args === array()) {
return null;
}
$obj->parseExtensionArgs($args);
return $obj;
}
/**
* Set the state of this request to be that expressed in these
* PAPE arguments
*
* @param args: The PAPE arguments without a namespace
*/
function parseExtensionArgs($args)
{
// preferred_auth_policies is a space-separated list of policy
// URIs
$this->preferred_auth_policies = array();
$policies_str = Auth_OpenID::arrayGet($args, 'preferred_auth_policies');
if ($policies_str) {
foreach (explode(' ', $policies_str) as $uri) {
if (!in_array($uri, $this->preferred_auth_policies)) {
$this->preferred_auth_policies[] = $uri;
}
}
}
// max_auth_age is base-10 integer number of seconds
$max_auth_age_str = Auth_OpenID::arrayGet($args, 'max_auth_age');
if ($max_auth_age_str) {
$this->max_auth_age = Auth_OpenID::intval($max_auth_age_str);
} else {
$this->max_auth_age = null;
}
}
/**
* Given a list of authentication policy URIs that a provider
* supports, this method returns the subsequence of those types
* that are preferred by the relying party.
*
* @param supported_types: A sequence of authentication policy
* type URIs that are supported by a provider
*
* @return array The sub-sequence of the supported types that are
* preferred by the relying party. This list will be ordered in
* the order that the types appear in the supported_types
* sequence, and may be empty if the provider does not prefer any
* of the supported authentication types.
*/
function preferredTypes($supported_types)
{
$result = array();
foreach ($supported_types as $st) {
if (in_array($st, $this->preferred_auth_policies)) {
$result[] = $st;
}
}
return $result;
}
}
/**
* A Provider Authentication Policy response, sent from a provider to
* a relying party
*/
class Auth_OpenID_PAPE_Response extends Auth_OpenID_Extension {
var $ns_alias = 'pape';
var $ns_uri = Auth_OpenID_PAPE_NS_URI;
function Auth_OpenID_PAPE_Response($auth_policies=null, $auth_time=null,
$nist_auth_level=null)
{
if ($auth_policies) {
$this->auth_policies = $auth_policies;
} else {
$this->auth_policies = array();
}
$this->auth_time = $auth_time;
$this->nist_auth_level = $nist_auth_level;
}
/**
* Add a authentication policy to this response
*
* This method is intended to be used by the provider to add a
* policy that the provider conformed to when authenticating the
* user.
*
* @param policy_uri: The identifier for the preferred type of
* authentication.
*/
function addPolicyURI($policy_uri)
{
if (!in_array($policy_uri, $this->auth_policies)) {
$this->auth_policies[] = $policy_uri;
}
}
/**
* Create an Auth_OpenID_PAPE_Response object from a successful
* OpenID library response.
*
* @param success_response $success_response A SuccessResponse
* from Auth_OpenID_Consumer::complete()
*
* @returns: A provider authentication policy response from the
* data that was supplied with the id_res response.
*/
static function fromSuccessResponse($success_response)
{
$obj = new Auth_OpenID_PAPE_Response();
// PAPE requires that the args be signed.
$args = $success_response->getSignedNS(Auth_OpenID_PAPE_NS_URI);
if ($args === null || $args === array()) {
return null;
}
$result = $obj->parseExtensionArgs($args);
if ($result === false) {
return null;
} else {
return $obj;
}
}
/**
* Parse the provider authentication policy arguments into the
* internal state of this object
*
* @param args: unqualified provider authentication policy
* arguments
*
* @param strict: Whether to return false when bad data is
* encountered
*
* @return null The data is parsed into the internal fields of
* this object.
*/
function parseExtensionArgs($args, $strict=false)
{
$policies_str = Auth_OpenID::arrayGet($args, 'auth_policies');
if ($policies_str && $policies_str != "none") {
$this->auth_policies = explode(" ", $policies_str);
}
$nist_level_str = Auth_OpenID::arrayGet($args, 'nist_auth_level');
if ($nist_level_str !== null) {
$nist_level = Auth_OpenID::intval($nist_level_str);
if ($nist_level === false) {
if ($strict) {
return false;
} else {
$nist_level = null;
}
}
if (0 <= $nist_level && $nist_level < 5) {
$this->nist_auth_level = $nist_level;
} else if ($strict) {
return false;
}
}
$auth_time = Auth_OpenID::arrayGet($args, 'auth_time');
if ($auth_time !== null) {
if (preg_match(PAPE_TIME_VALIDATOR, $auth_time)) {
$this->auth_time = $auth_time;
} else if ($strict) {
return false;
}
}
}
function getExtensionArgs()
{
$ns_args = array();
if (count($this->auth_policies) > 0) {
$ns_args['auth_policies'] = implode(' ', $this->auth_policies);
} else {
$ns_args['auth_policies'] = 'none';
}
if ($this->nist_auth_level !== null) {
if (!in_array($this->nist_auth_level, range(0, 4), true)) {
return false;
}
$ns_args['nist_auth_level'] = strval($this->nist_auth_level);
}
if ($this->auth_time !== null) {
if (!preg_match(PAPE_TIME_VALIDATOR, $this->auth_time)) {
return false;
}
$ns_args['auth_time'] = $this->auth_time;
}
return $ns_args;
}
}
openid-php-openid-782224d/Auth/OpenID/Parse.php 0000664 0000000 0000000 00000027240 11366367341 0021130 0 ustar 00root root 0000000 0000000 tags
* in the head of HTML or XHTML documents and parses out their
* attributes according to the OpenID spec. It is a liberal parser,
* but it requires these things from the data in order to work:
*
* - There must be an open tag
*
* - There must be an open tag inside of the tag
*
* - Only s that are found inside of the tag are parsed
* (this is by design)
*
* - The parser follows the OpenID specification in resolving the
* attributes of the link tags. This means that the attributes DO
* NOT get resolved as they would by an XML or HTML parser. In
* particular, only certain entities get replaced, and href
* attributes do not get resolved relative to a base URL.
*
* From http://openid.net/specs.bml:
*
* - The openid.server URL MUST be an absolute URL. OpenID consumers
* MUST NOT attempt to resolve relative URLs.
*
* - The openid.server URL MUST NOT include entities other than &,
* <, >, and ".
*
* The parser ignores SGML comments and . Both kinds
* of quoting are allowed for attributes.
*
* The parser deals with invalid markup in these ways:
*
* - Tag names are not case-sensitive
*
* - The tag is accepted even when it is not at the top level
*
* - The tag is accepted even when it is not a direct child of
* the tag, but a tag must be an ancestor of the
* tag
*
* - tags are accepted even when they are not direct children
* of the tag, but a tag must be an ancestor of the
* tag
*
* - If there is no closing tag for an open or tag, the
* remainder of the document is viewed as being inside of the
* tag. If there is no closing tag for a tag, the link tag is
* treated as a short tag. Exceptions to this rule are that
* closes and or closes
*
* - Attributes of the tag are not required to be quoted.
*
* - In the case of duplicated attribute names, the attribute coming
* last in the tag will be the value returned.
*
* - Any text that does not parse as an attribute within a link tag
* will be ignored. (e.g. will
* ignore pumpkin)
*
* - If there are more than one or tag, the parser only
* looks inside of the first one.
*
* - The contents of
Name: Link inside comment inside head inside html
Name: Link inside of head after short head
Name: Plain vanilla
Link:
Name: Ignore tags in the namespace
Link*:
Name: Short link tag
Link:
Name: Spaces in the HTML tag
Link:
Name: Spaces in the head tag
Link:
Name: Spaces in the link tag
Link:
Name: No whitespace
Link:
Name: Closed head tag
Link:
Name: One good, one bad (after close head)
Link:
Name: One good, one bad (after open body)
Link:
Name: ill formed (missing close head)
Link:
Name: Ill formed (no close head, link after )
Link:
Name: Ignore random tags inside of html
Link:
Name: case-folding
Link*:
Name: unexpected tags
Link:
Name: un-closed script tags
Link*:
EOF