Updating Janrain OpenID auth library

Source: https://github.com/openid/php-openid
This commit is contained in:
Mikael Nordfeldth 2013-09-24 01:49:34 +02:00
parent f01c478aab
commit 49b755912f
17 changed files with 738 additions and 73 deletions

View File

@ -374,42 +374,7 @@ class Auth_OpenID_Association {
} }
$calculated_sig = $this->getMessageSignature($message); $calculated_sig = $this->getMessageSignature($message);
return Auth_OpenID_CryptUtil::constEq($calculated_sig, $sig);
return $this->constantTimeCompare($calculated_sig, $sig);
}
/**
* String comparison function which will complete in a constant time
* for strings of any given matching length, to help prevent an attacker
* from distinguishing how much of a signature token they have guessed
* correctly.
*
* For this usage, it's assumed that the length of the string is known,
* so we may safely short-circuit on mismatched lengths which will be known
* to be invalid by the attacker.
*
* http://lists.openid.net/pipermail/openid-security/2010-July/001156.html
* http://rdist.root.org/2010/01/07/timing-independent-array-comparison/
*/
private function constantTimeCompare($a, $b)
{
$len = strlen($a);
if (strlen($b) !== $len) {
// Short-circuit on length mismatch; attackers will already know
// the correct target length so this is safe.
return false;
}
if ($len == 0) {
// 0-length valid input shouldn't really happen. :)
return true;
}
$result = 0;
for ($i = 0; $i < strlen($a); $i++) {
// We use scary bitwise operations to avoid logical short-circuits
// in lower-level code.
$result |= ord($a{$i}) ^ ord($b{$i});
}
return ($result == 0);
} }
} }

View File

@ -365,7 +365,6 @@ function Auth_OpenID_detectMathLibrary($exts)
{ {
$loaded = false; $loaded = false;
$hasDl = function_exists('dl');
foreach ($exts as $extension) { foreach ($exts as $extension) {
if (extension_loaded($extension['extension'])) { if (extension_loaded($extension['extension'])) {
return $extension; return $extension;

View File

@ -957,6 +957,10 @@ class Auth_OpenID_GenericConsumer {
} }
if (!$assoc->checkMessageSignature($message)) { if (!$assoc->checkMessageSignature($message)) {
// If we get a "bad signature" here, it means that the association
// is unrecoverabley corrupted in some way. Any futher attempts
// to login with this association is likely to fail. Drop it.
$this->store->removeAssociation($server_url, $assoc_handle);
return new Auth_OpenID_FailureResponse(null, return new Auth_OpenID_FailureResponse(null,
"Bad signature"); "Bad signature");
} }
@ -1179,9 +1183,11 @@ class Auth_OpenID_GenericConsumer {
function _discoverAndVerify($claimed_id, $to_match_endpoints) function _discoverAndVerify($claimed_id, $to_match_endpoints)
{ {
// oidutil.log('Performing discovery on %s' % (claimed_id,)) // oidutil.log('Performing discovery on %s' % (claimed_id,))
list($unused, $services) = call_user_func($this->discoverMethod, list($unused, $services) = call_user_func_array($this->discoverMethod,
$claimed_id, array(
&$this->fetcher); $claimed_id,
&$this->fetcher,
));
if (!$services) { if (!$services) {
return new Auth_OpenID_FailureResponse(null, return new Auth_OpenID_FailureResponse(null,

View File

@ -104,5 +104,19 @@ class Auth_OpenID_CryptUtil {
return $str; return $str;
} }
static function constEq($s1, $s2)
{
if (strlen($s1) != strlen($s2)) {
return false;
}
$result = true;
$length = strlen($s1);
for ($i = 0; $i < $length; $i++) {
$result &= ($s1[$i] == $s2[$i]);
}
return $result;
}
} }

View File

@ -39,7 +39,7 @@ class Auth_OpenID_Extension {
* *
* Returns the message with the extension arguments added. * Returns the message with the extension arguments added.
*/ */
function toMessage($message) function toMessage($message, $request = null)
{ {
$implicit = $message->isOpenID1(); $implicit = $message->isOpenID1();
$added = $message->namespaces->addAlias($this->ns_uri, $added = $message->namespaces->addAlias($this->ns_uri,
@ -53,8 +53,13 @@ class Auth_OpenID_Extension {
} }
} }
$message->updateArgs($this->ns_uri, if ($request !== null) {
$this->getExtensionArgs()); $message->updateArgs($this->ns_uri,
$this->getExtensionArgs($request));
} else {
$message->updateArgs($this->ns_uri,
$this->getExtensionArgs());
}
return $message; return $message;
} }
} }

View File

@ -300,13 +300,22 @@ class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore {
return null; return null;
} }
if (file_exists($filename) !== true) {
return null;
}
$assoc_file = @fopen($filename, 'rb'); $assoc_file = @fopen($filename, 'rb');
if ($assoc_file === false) { if ($assoc_file === false) {
return null; return null;
} }
$assoc_s = fread($assoc_file, filesize($filename)); $filesize = filesize($filename);
if ($filesize === false || $filesize <= 0) {
return null;
}
$assoc_s = fread($assoc_file, $filesize);
fclose($assoc_file); fclose($assoc_file);
if (!$assoc_s) { if (!$assoc_s) {

View File

@ -60,6 +60,13 @@ function Auth_OpenID_HMACSHA1($key, $text)
$key = Auth_OpenID_SHA1($key, true); $key = Auth_OpenID_SHA1($key, true);
} }
if (function_exists('hash_hmac') &&
function_exists('hash_algos') &&
(in_array('sha1', hash_algos()))) {
return hash_hmac('sha1', $text, $key, true);
}
// Home-made solution
$key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x00)); $key = str_pad($key, Auth_OpenID_SHA1_BLOCKSIZE, chr(0x00));
$ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE); $ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE);
$opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE); $opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE);

View File

@ -0,0 +1,413 @@
<?php
/**
* SQL-backed OpenID stores for use with PEAR::MDB2.
*
* PHP versions 4 and 5
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author JanRain, Inc. <openid@janrain.com>
* @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));
}
}
?>

View File

@ -675,7 +675,7 @@ class Auth_OpenID_Message {
if ($form_tag_attrs) { if ($form_tag_attrs) {
foreach ($form_tag_attrs as $name => $attr) { foreach ($form_tag_attrs as $name => $attr) {
$form .= sprintf(" %s=\"%s\"", $name, $attr); $form .= sprintf(" %s=\"%s\"", $name, htmlspecialchars($attr));
} }
} }
@ -684,11 +684,11 @@ class Auth_OpenID_Message {
foreach ($this->toPostArgs() as $name => $value) { foreach ($this->toPostArgs() as $name => $value) {
$form .= sprintf( $form .= sprintf(
"<input type=\"hidden\" name=\"%s\" value=\"%s\" />\n", "<input type=\"hidden\" name=\"%s\" value=\"%s\" />\n",
$name, $value); htmlspecialchars($name), htmlspecialchars($value));
} }
$form .= sprintf("<input type=\"submit\" value=\"%s\" />\n", $form .= sprintf("<input type=\"submit\" value=\"%s\" />\n",
$submit_text); htmlspecialchars($submit_text));
$form .= "</form>\n"; $form .= "</form>\n";

View File

@ -32,7 +32,7 @@ class Auth_OpenID_MySQLStore extends Auth_OpenID_SQLStore {
$this->sql['assoc_table'] = $this->sql['assoc_table'] =
"CREATE TABLE %s (\n". "CREATE TABLE %s (\n".
" server_url BLOB NOT NULL,\n". " server_url VARCHAR(2047) NOT NULL,\n".
" handle VARCHAR(255) NOT NULL,\n". " handle VARCHAR(255) NOT NULL,\n".
" secret BLOB NOT NULL,\n". " secret BLOB NOT NULL,\n".
" issued INTEGER NOT NULL,\n". " issued INTEGER NOT NULL,\n".

View File

@ -219,7 +219,11 @@ class Auth_OpenID_Parse {
function match($regexp, $text, &$match) function match($regexp, $text, &$match)
{ {
if (!is_callable('mb_ereg_search_init')) { if (!is_callable('mb_ereg_search_init')) {
return preg_match($regexp, $text, $match); if (!preg_match($regexp, $text, $match)) {
return false;
}
$match = $match[0];
return true;
} }
$regexp = substr($regexp, 1, strlen($regexp) - 2 - strlen($this->_re_flags)); $regexp = substr($regexp, 1, strlen($regexp) - 2 - strlen($this->_re_flags));
@ -227,7 +231,7 @@ class Auth_OpenID_Parse {
if (!mb_ereg_search($regexp)) { if (!mb_ereg_search($regexp)) {
return false; return false;
} }
list($match) = mb_ereg_search_getregs(); $match = mb_ereg_search_getregs();
return true; return true;
} }
@ -269,7 +273,7 @@ class Auth_OpenID_Parse {
// Try to find the <HEAD> tag. // Try to find the <HEAD> tag.
$head_re = $this->headFind(); $head_re = $this->headFind();
$head_match = ''; $head_match = array();
if (!$this->match($head_re, $stripped, $head_match)) { if (!$this->match($head_re, $stripped, $head_match)) {
ini_set( 'pcre.backtrack_limit', $old_btlimit ); ini_set( 'pcre.backtrack_limit', $old_btlimit );
return array(); return array();
@ -278,7 +282,7 @@ class Auth_OpenID_Parse {
$link_data = array(); $link_data = array();
$link_matches = array(); $link_matches = array();
if (!preg_match_all($this->_link_find, $head_match, if (!preg_match_all($this->_link_find, $head_match[0],
$link_matches)) { $link_matches)) {
ini_set( 'pcre.backtrack_limit', $old_btlimit ); ini_set( 'pcre.backtrack_limit', $old_btlimit );
return array(); return array();

View File

@ -0,0 +1,208 @@
<?php
/**
* Supplies Redis server store backend for OpenID servers and consumers.
* Uses Predis library {@see https://github.com/nrk/predis}.
* Requires PHP >= 5.3.
*
* LICENSE: See the COPYING file included in this distribution.
*
* @package OpenID
* @author Ville Mattila <ville@eventio.fi>
* @copyright 2008 JanRain Inc., 2013 Eventio Oy / Ville Mattila
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache
* Contributed by Eventio Oy <http://www.eventio.fi/>
*/
/**
* Import the interface for creating a new store class.
*/
require_once 'Auth/OpenID/Interface.php';
/**
* Supplies Redis server store backend for OpenID servers and consumers.
* Uses Predis library {@see https://github.com/nrk/predis}.
* Requires PHP >= 5.3.
*
* @package OpenID
*/
class Auth_OpenID_PredisStore extends Auth_OpenID_OpenIDStore {
/**
* @var \Predis\Client
*/
protected $redis;
/**
* Prefix for Redis keys
* @var string
*/
protected $prefix;
/**
* Initializes a new {@link Auth_OpenID_PredisStore} instance.
*
* @param \Predis\Client $redis Predis client object
* @param string $prefix Prefix for all keys stored to the Redis
*/
function Auth_OpenID_PredisStore(\Predis\Client $redis, $prefix = '')
{
$this->prefix = $prefix;
$this->redis = $redis;
}
/**
* Store association until its expiration time in Redis server.
* Overwrites any existing association with same server_url and
* handle. Handles list of associations for every server.
*/
function storeAssociation($server_url, $association)
{
// create Redis keys for association itself
// and list of associations for this server
$associationKey = $this->associationKey($server_url,
$association->handle);
$serverKey = $this->associationServerKey($server_url);
// save association to server's associations' keys list
$this->redis->lpush(
$serverKey,
$associationKey
);
// Will touch the association list expiration, to avoid filling up
$newExpiration = ($association->issued + $association->lifetime);
$expirationKey = $serverKey.'_expires_at';
$expiration = $this->redis->get($expirationKey);
if (!$expiration || $newExpiration > $expiration) {
$this->redis->set($expirationKey, $newExpiration);
$this->redis->expireat($serverKey, $newExpiration);
$this->redis->expireat($expirationKey, $newExpiration);
}
// save association itself, will automatically expire
$this->redis->setex(
$associationKey,
$newExpiration - time(),
serialize($association)
);
}
/**
* Read association from Redis. If no handle given
* and multiple associations found, returns latest issued
*/
function getAssociation($server_url, $handle = null)
{
// simple case: handle given
if ($handle !== null) {
return $this->getAssociationFromServer(
$this->associationKey($server_url, $handle)
);
}
// no handle given, receiving the latest issued
$serverKey = $this->associationServerKey($server_url);
$lastKey = $this->redis->lpop($serverKey);
if (!$lastKey) { return null; }
// get association, return null if failed
return $this->getAssociationFromServer($lastKey);
}
/**
* Function to actually receive and unserialize the association
* from the server.
*/
private function getAssociationFromServer($associationKey)
{
$association = $this->redis->get($associationKey);
return $association ? unserialize($association) : null;
}
/**
* Immediately delete association from Redis.
*/
function removeAssociation($server_url, $handle)
{
// create Redis keys
$serverKey = $this->associationServerKey($server_url);
$associationKey = $this->associationKey($server_url,
$handle);
// Removing the association from the server's association list
$removed = $this->redis->lrem($serverKey, 0, $associationKey);
if ($removed < 1) {
return false;
}
// Delete the association itself
return $this->redis->del($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;
}
// SETNX will set the value only of the key doesn't exist yet.
$nonceKey = $this->nonceKey($server_url, $salt);
$added = $this->predis->setnx($nonceKey);
if ($added) {
// Will set expiration
$this->predis->expire($nonceKey, $Auth_OpenID_SKEW);
return true;
} else {
return false;
}
}
/**
* Build up nonce key
*/
private function nonceKey($server_url, $salt)
{
return $this->prefix .
'openid_nonce_' .
sha1($server_url) . '_' . sha1($salt);
}
/**
* Key is prefixed with $prefix and 'openid_association_' string
*/
function associationKey($server_url, $handle = null)
{
return $this->prefix .
'openid_association_' .
sha1($server_url) . '_' . sha1($handle);
}
/**
* Key is prefixed with $prefix and 'openid_association_server_' string
*/
function associationServerKey($server_url)
{
return $this->prefix .
'openid_association_server_' .
sha1($server_url);
}
/**
* Report that this storage doesn't support cleanup
*/
function supportsCleanup()
{
return false;
}
}

View File

@ -166,7 +166,7 @@ class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore {
*/ */
function isError($value) function isError($value)
{ {
return PEAR::isError($value); return @PEAR::isError($value);
} }
/** /**

View File

@ -817,11 +817,11 @@ class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request {
*/ */
function returnToVerified() function returnToVerified()
{ {
$fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); $fetcher = Auth_Yadis_Yadis::getHTTPFetcher();
return call_user_func_array($this->verifyReturnTo, return call_user_func_array($this->verifyReturnTo,
array($this->trust_root, $this->return_to, $fetcher)); array($this->trust_root, $this->return_to, $fetcher));
} }
static function fromMessage($message, $server) static function fromMessage($message, $server)
{ {
$mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode'); $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode');
@ -1704,7 +1704,7 @@ class Auth_OpenID_Server {
{ {
if (method_exists($this, "openid_" . $request->mode)) { if (method_exists($this, "openid_" . $request->mode)) {
$handler = array($this, "openid_" . $request->mode); $handler = array($this, "openid_" . $request->mode);
return call_user_func($handler, &$request); return call_user_func_array($handler, array($request));
} }
return null; return null;
} }

View File

@ -37,7 +37,7 @@ class Auth_Yadis_PHPSession {
*/ */
function get($name, $default=null) function get($name, $default=null)
{ {
if (array_key_exists($name, $_SESSION)) { if (isset($_SESSION) && array_key_exists($name, $_SESSION)) {
return $_SESSION[$name]; return $_SESSION[$name];
} else { } else {
return $default; return $default;
@ -411,9 +411,11 @@ class Auth_Yadis_Discovery {
if (!$manager || (!$manager->services)) { if (!$manager || (!$manager->services)) {
$this->destroyManager(); $this->destroyManager();
list($yadis_url, $services) = call_user_func($discover_cb, list($yadis_url, $services) = call_user_func_array($discover_cb,
$this->url, array(
&$fetcher); $this->url,
&$fetcher,
));
$manager = $this->createManager($services, $yadis_url); $manager = $this->createManager($services, $yadis_url);
} }

View File

@ -129,8 +129,20 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
curl_setopt($c, CURLOPT_URL, $url); curl_setopt($c, CURLOPT_URL, $url);
if (defined('Auth_OpenID_VERIFY_HOST')) { if (defined('Auth_OpenID_VERIFY_HOST')) {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); // set SSL verification options only if Auth_OpenID_VERIFY_HOST
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); // is explicitly set, otherwise use system default.
if (Auth_OpenID_VERIFY_HOST) {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
if (defined('Auth_OpenID_CAINFO')) {
curl_setopt($c, CURLOPT_CAINFO, Auth_OpenID_CAINFO);
}
} else {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
}
}
if (defined('Auth_OpenID_HTTP_PROXY')) {
curl_setopt($c, CURLOPT_PROXY, Auth_OpenID_HTTP_PROXY);
} }
curl_exec($c); curl_exec($c);
@ -153,6 +165,7 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
curl_close($c); curl_close($c);
if (defined('Auth_OpenID_VERIFY_HOST') && if (defined('Auth_OpenID_VERIFY_HOST') &&
Auth_OpenID_VERIFY_HOST == true &&
$this->isHTTPS($url)) { $this->isHTTPS($url)) {
Auth_OpenID::log('OpenID: Verified SSL host %s using '. Auth_OpenID::log('OpenID: Verified SSL host %s using '.
'curl/get', $url); 'curl/get', $url);
@ -166,10 +179,6 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
} }
} }
Auth_OpenID::log(
"Successfully fetched '%s': GET response code %s",
$url, $code);
return new Auth_Yadis_HTTPResponse($url, $code, return new Auth_Yadis_HTTPResponse($url, $code,
$new_headers, $body); $new_headers, $body);
} }
@ -194,6 +203,10 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
curl_setopt($c, CURLOPT_NOSIGNAL, true); curl_setopt($c, CURLOPT_NOSIGNAL, true);
} }
if (defined('Auth_OpenID_HTTP_PROXY')) {
curl_setopt($c, CURLOPT_PROXY, Auth_OpenID_HTTP_PROXY);
}
curl_setopt($c, CURLOPT_POST, true); curl_setopt($c, CURLOPT_POST, true);
curl_setopt($c, CURLOPT_POSTFIELDS, $body); curl_setopt($c, CURLOPT_POSTFIELDS, $body);
curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout); curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout);
@ -202,8 +215,17 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
array($this, "_writeData")); array($this, "_writeData"));
if (defined('Auth_OpenID_VERIFY_HOST')) { if (defined('Auth_OpenID_VERIFY_HOST')) {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); // set SSL verification options only if Auth_OpenID_VERIFY_HOST
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); // is explicitly set, otherwise use system default.
if (Auth_OpenID_VERIFY_HOST) {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2);
if (defined('Auth_OpenID_CAINFO')) {
curl_setopt($c, CURLOPT_CAINFO, Auth_OpenID_CAINFO);
}
} else {
curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false);
}
} }
curl_exec($c); curl_exec($c);
@ -217,7 +239,9 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
return null; return null;
} }
if (defined('Auth_OpenID_VERIFY_HOST') && $this->isHTTPS($url)) { if (defined('Auth_OpenID_VERIFY_HOST') &&
Auth_OpenID_VERIFY_HOST == true &&
$this->isHTTPS($url)) {
Auth_OpenID::log('OpenID: Verified SSL host %s using '. Auth_OpenID::log('OpenID: Verified SSL host %s using '.
'curl/post', $url); 'curl/post', $url);
} }
@ -235,9 +259,6 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher {
} }
Auth_OpenID::log("Successfully fetched '%s': POST response code %s",
$url, $code);
return new Auth_Yadis_HTTPResponse($url, $code, return new Auth_Yadis_HTTPResponse($url, $code,
$new_headers, $body); $new_headers, $body);
} }

View File

@ -234,7 +234,19 @@ class Auth_Yadis_dom extends Auth_Yadis_XMLParser {
return false; return false;
} }
if (!@$this->doc->loadXML($xml_string)) { // libxml_disable_entity_loader (PHP 5 >= 5.2.11)
if (function_exists('libxml_disable_entity_loader') && function_exists('libxml_use_internal_errors')) {
// disable external entities and libxml errors
$loader = libxml_disable_entity_loader(true);
$errors = libxml_use_internal_errors(true);
$parse_result = @$this->doc->loadXML($xml_string);
libxml_disable_entity_loader($loader);
libxml_use_internal_errors($errors);
} else {
$parse_result = @$this->doc->loadXML($xml_string);
}
if (!$parse_result) {
return false; return false;
} }