diff --git a/extlib/Auth/OpenID/Association.php b/extlib/Auth/OpenID/Association.php index 7fdf399a3c..2729138ebb 100644 --- a/extlib/Auth/OpenID/Association.php +++ b/extlib/Auth/OpenID/Association.php @@ -374,42 +374,7 @@ class Auth_OpenID_Association { } $calculated_sig = $this->getMessageSignature($message); - - 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); + return Auth_OpenID_CryptUtil::constEq($calculated_sig, $sig); } } diff --git a/extlib/Auth/OpenID/BigMath.php b/extlib/Auth/OpenID/BigMath.php index 7fca2dc43e..58b46bf27b 100644 --- a/extlib/Auth/OpenID/BigMath.php +++ b/extlib/Auth/OpenID/BigMath.php @@ -365,7 +365,6 @@ function Auth_OpenID_detectMathLibrary($exts) { $loaded = false; - $hasDl = function_exists('dl'); foreach ($exts as $extension) { if (extension_loaded($extension['extension'])) { return $extension; diff --git a/extlib/Auth/OpenID/Consumer.php b/extlib/Auth/OpenID/Consumer.php index 021c038988..d562e33f35 100644 --- a/extlib/Auth/OpenID/Consumer.php +++ b/extlib/Auth/OpenID/Consumer.php @@ -957,6 +957,10 @@ class Auth_OpenID_GenericConsumer { } 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, "Bad signature"); } @@ -1179,9 +1183,11 @@ class Auth_OpenID_GenericConsumer { 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); + list($unused, $services) = call_user_func_array($this->discoverMethod, + array( + $claimed_id, + &$this->fetcher, + )); if (!$services) { return new Auth_OpenID_FailureResponse(null, diff --git a/extlib/Auth/OpenID/CryptUtil.php b/extlib/Auth/OpenID/CryptUtil.php index a926267779..3c60cea170 100644 --- a/extlib/Auth/OpenID/CryptUtil.php +++ b/extlib/Auth/OpenID/CryptUtil.php @@ -104,5 +104,19 @@ class Auth_OpenID_CryptUtil { 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; + } } diff --git a/extlib/Auth/OpenID/Extension.php b/extlib/Auth/OpenID/Extension.php index c4e38c0380..542a1da261 100644 --- a/extlib/Auth/OpenID/Extension.php +++ b/extlib/Auth/OpenID/Extension.php @@ -39,7 +39,7 @@ class Auth_OpenID_Extension { * * Returns the message with the extension arguments added. */ - function toMessage($message) + function toMessage($message, $request = null) { $implicit = $message->isOpenID1(); $added = $message->namespaces->addAlias($this->ns_uri, @@ -53,8 +53,13 @@ class Auth_OpenID_Extension { } } - $message->updateArgs($this->ns_uri, - $this->getExtensionArgs()); + if ($request !== null) { + $message->updateArgs($this->ns_uri, + $this->getExtensionArgs($request)); + } else { + $message->updateArgs($this->ns_uri, + $this->getExtensionArgs()); + } return $message; } } diff --git a/extlib/Auth/OpenID/FileStore.php b/extlib/Auth/OpenID/FileStore.php index 074421a0bb..7eec791d24 100644 --- a/extlib/Auth/OpenID/FileStore.php +++ b/extlib/Auth/OpenID/FileStore.php @@ -300,13 +300,22 @@ class Auth_OpenID_FileStore extends Auth_OpenID_OpenIDStore { return null; } + if (file_exists($filename) !== true) { + return null; + } + $assoc_file = @fopen($filename, 'rb'); if ($assoc_file === false) { 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); if (!$assoc_s) { diff --git a/extlib/Auth/OpenID/HMAC.php b/extlib/Auth/OpenID/HMAC.php index e9779bd4e0..e6c4bdfd9d 100644 --- a/extlib/Auth/OpenID/HMAC.php +++ b/extlib/Auth/OpenID/HMAC.php @@ -60,6 +60,13 @@ function Auth_OpenID_HMACSHA1($key, $text) $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)); $ipad = str_repeat(chr(0x36), Auth_OpenID_SHA1_BLOCKSIZE); $opad = str_repeat(chr(0x5c), Auth_OpenID_SHA1_BLOCKSIZE); diff --git a/extlib/Auth/OpenID/MDB2Store.php b/extlib/Auth/OpenID/MDB2Store.php new file mode 100644 index 0000000000..fb27d5c4d5 --- /dev/null +++ b/extlib/Auth/OpenID/MDB2Store.php @@ -0,0 +1,413 @@ + + * @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)); + } + +} + +?> diff --git a/extlib/Auth/OpenID/Message.php b/extlib/Auth/OpenID/Message.php index 9aa1fa4684..16ec1c1db4 100644 --- a/extlib/Auth/OpenID/Message.php +++ b/extlib/Auth/OpenID/Message.php @@ -675,7 +675,7 @@ class Auth_OpenID_Message { if ($form_tag_attrs) { 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) { $form .= sprintf( "\n", - $name, $value); + htmlspecialchars($name), htmlspecialchars($value)); } $form .= sprintf("\n", - $submit_text); + htmlspecialchars($submit_text)); $form .= "\n"; diff --git a/extlib/Auth/OpenID/MySQLStore.php b/extlib/Auth/OpenID/MySQLStore.php index 810f059f1d..a5299b3a5c 100644 --- a/extlib/Auth/OpenID/MySQLStore.php +++ b/extlib/Auth/OpenID/MySQLStore.php @@ -32,7 +32,7 @@ class Auth_OpenID_MySQLStore extends Auth_OpenID_SQLStore { $this->sql['assoc_table'] = "CREATE TABLE %s (\n". - " server_url BLOB NOT NULL,\n". + " server_url VARCHAR(2047) NOT NULL,\n". " handle VARCHAR(255) NOT NULL,\n". " secret BLOB NOT NULL,\n". " issued INTEGER NOT NULL,\n". diff --git a/extlib/Auth/OpenID/Parse.php b/extlib/Auth/OpenID/Parse.php index 6c2e721691..0461bdcff7 100644 --- a/extlib/Auth/OpenID/Parse.php +++ b/extlib/Auth/OpenID/Parse.php @@ -219,7 +219,11 @@ class Auth_OpenID_Parse { function match($regexp, $text, &$match) { 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)); @@ -227,7 +231,7 @@ class Auth_OpenID_Parse { if (!mb_ereg_search($regexp)) { return false; } - list($match) = mb_ereg_search_getregs(); + $match = mb_ereg_search_getregs(); return true; } @@ -269,7 +273,7 @@ class Auth_OpenID_Parse { // Try to find the tag. $head_re = $this->headFind(); - $head_match = ''; + $head_match = array(); if (!$this->match($head_re, $stripped, $head_match)) { ini_set( 'pcre.backtrack_limit', $old_btlimit ); return array(); @@ -278,7 +282,7 @@ class Auth_OpenID_Parse { $link_data = 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)) { ini_set( 'pcre.backtrack_limit', $old_btlimit ); return array(); diff --git a/extlib/Auth/OpenID/PredisStore.php b/extlib/Auth/OpenID/PredisStore.php new file mode 100644 index 0000000000..7108c2faf9 --- /dev/null +++ b/extlib/Auth/OpenID/PredisStore.php @@ -0,0 +1,208 @@ += 5.3. + * + * LICENSE: See the COPYING file included in this distribution. + * + * @package OpenID + * @author Ville Mattila + * @copyright 2008 JanRain Inc., 2013 Eventio Oy / Ville Mattila + * @license http://www.apache.org/licenses/LICENSE-2.0 Apache + * Contributed by Eventio Oy + */ + +/** + * 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; + } + +} + diff --git a/extlib/Auth/OpenID/SQLStore.php b/extlib/Auth/OpenID/SQLStore.php index c04059732c..2dc731a777 100644 --- a/extlib/Auth/OpenID/SQLStore.php +++ b/extlib/Auth/OpenID/SQLStore.php @@ -166,7 +166,7 @@ class Auth_OpenID_SQLStore extends Auth_OpenID_OpenIDStore { */ function isError($value) { - return PEAR::isError($value); + return @PEAR::isError($value); } /** diff --git a/extlib/Auth/OpenID/Server.php b/extlib/Auth/OpenID/Server.php index cc8ba961c2..9887d1e8d8 100644 --- a/extlib/Auth/OpenID/Server.php +++ b/extlib/Auth/OpenID/Server.php @@ -817,11 +817,11 @@ class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request { */ function returnToVerified() { - $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); + $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); return call_user_func_array($this->verifyReturnTo, array($this->trust_root, $this->return_to, $fetcher)); } - + static function fromMessage($message, $server) { $mode = $message->getArg(Auth_OpenID_OPENID_NS, 'mode'); @@ -1704,7 +1704,7 @@ class Auth_OpenID_Server { { if (method_exists($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; } diff --git a/extlib/Auth/Yadis/Manager.php b/extlib/Auth/Yadis/Manager.php index ee6f68bcb6..15e69079bb 100644 --- a/extlib/Auth/Yadis/Manager.php +++ b/extlib/Auth/Yadis/Manager.php @@ -37,7 +37,7 @@ class Auth_Yadis_PHPSession { */ function get($name, $default=null) { - if (array_key_exists($name, $_SESSION)) { + if (isset($_SESSION) && array_key_exists($name, $_SESSION)) { return $_SESSION[$name]; } else { return $default; @@ -411,9 +411,11 @@ class Auth_Yadis_Discovery { if (!$manager || (!$manager->services)) { $this->destroyManager(); - list($yadis_url, $services) = call_user_func($discover_cb, - $this->url, - &$fetcher); + list($yadis_url, $services) = call_user_func_array($discover_cb, + array( + $this->url, + &$fetcher, + )); $manager = $this->createManager($services, $yadis_url); } diff --git a/extlib/Auth/Yadis/ParanoidHTTPFetcher.php b/extlib/Auth/Yadis/ParanoidHTTPFetcher.php index 4da7c94c0d..125029c4cb 100644 --- a/extlib/Auth/Yadis/ParanoidHTTPFetcher.php +++ b/extlib/Auth/Yadis/ParanoidHTTPFetcher.php @@ -129,8 +129,20 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher { curl_setopt($c, CURLOPT_URL, $url); if (defined('Auth_OpenID_VERIFY_HOST')) { - curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); - curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); + // set SSL verification options only if Auth_OpenID_VERIFY_HOST + // 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); @@ -153,6 +165,7 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher { curl_close($c); if (defined('Auth_OpenID_VERIFY_HOST') && + Auth_OpenID_VERIFY_HOST == true && $this->isHTTPS($url)) { Auth_OpenID::log('OpenID: Verified SSL host %s using '. '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, $new_headers, $body); } @@ -194,6 +203,10 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher { 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_POSTFIELDS, $body); curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout); @@ -202,8 +215,17 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher { array($this, "_writeData")); if (defined('Auth_OpenID_VERIFY_HOST')) { - curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); - curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); + // set SSL verification options only if Auth_OpenID_VERIFY_HOST + // 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); @@ -217,7 +239,9 @@ class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher { 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 '. '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, $new_headers, $body); } diff --git a/extlib/Auth/Yadis/XML.php b/extlib/Auth/Yadis/XML.php index cf1f5c41b2..39a9942220 100644 --- a/extlib/Auth/Yadis/XML.php +++ b/extlib/Auth/Yadis/XML.php @@ -234,7 +234,19 @@ class Auth_Yadis_dom extends Auth_Yadis_XMLParser { 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; }