123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 |
- <?php
- /**
- * A test script for the OpenIDStore classes.
- *
- * PHP versions 4 and 5
- *
- * LICENSE: See the COPYING file included in this distribution.
- *
- * @package OpenID
- * @author JanRain, Inc. <openid@janrain.com>
- * @copyright 2005-2008 Janrain, Inc.
- * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
- */
- /**
- * Require classes and functions to run the Store tests.
- */
- require_once 'Auth/OpenID/Association.php';
- require_once 'Auth/OpenID/CryptUtil.php';
- require_once 'Auth/OpenID/Nonce.php';
- require_once 'Auth/OpenID.php';
- require_once 'PHPUnit.php';
- function _Auth_OpenID_mkdtemp()
- {
- if (strpos(PHP_OS, 'WIN') === 0) {
- $dir = $_ENV['TMP'];
- if (!isset($dir)) {
- $dir = 'C:\Windows\Temp';
- }
- } else {
- $dir = @$_ENV['TMPDIR'];
- if (!isset($dir)) {
- $dir = '/tmp';
- }
- }
- return Auth_OpenID_FileStore::_mkdtemp($dir);
- }
- /**
- * This is the host where the SQL stores' databases should be created
- * and destroyed.
- */
- global $_Auth_OpenID_db_test_host;
- $_Auth_OpenID_db_test_host = 'dbtest';
- /**
- * Generate a sufficently unique database name so many hosts can run
- * SQL store tests on the server at the same time and not step on each
- * other.
- */
- function _Auth_OpenID_getTmpDbName()
- {
- $hostname = php_uname('n');
- $hostname = str_replace('.', '_', $hostname);
- $hostname = str_replace('-', '_', $hostname);
- $hostname = strtolower($hostname);
- return sprintf("%s_%d_%s_openid_test",
- $hostname,
- getmypid(),
- strval(rand(1, time())));
- }
- /**
- * Superclass that has methods for testing OpenID stores. Subclass this to
- * test your own store implementation.
- *
- * @package OpenID
- */
- class Tests_Auth_OpenID_Store extends PHPUnit_TestCase {
- /**
- * Prepares for the SQL store tests.
- */
- function setUp()
- {
- $this->letters = Auth_OpenID_letters;
- $this->digits = Auth_OpenID_digits;
- $this->punct = Auth_OpenID_punct;
- $this->allowed_nonce = $this->letters . $this->digits;
- $this->allowed_handle = $this->letters . $this->digits . $this->punct;
- }
- /**
- * Generates an association with the specified parameters.
- */
- function genAssoc($now, $issued = 0, $lifetime = 600)
- {
- $sec = Auth_OpenID_CryptUtil::randomString(20);
- $hdl = Auth_OpenID_CryptUtil::randomString(128, $this->allowed_handle);
- return new Auth_OpenID_Association($hdl, $sec, $now + $issued,
- $lifetime, 'HMAC-SHA1');
- }
- /**
- * @access private
- */
- function _checkRetrieve(&$store, $url, $handle, $expected, $name = null)
- {
- $retrieved_assoc = $store->getAssociation($url, $handle);
- if ($expected === null) {
- $this->assertTrue($retrieved_assoc === null);
- } else {
- $this->assertTrue($expected->equal($retrieved_assoc), $name);
- }
- }
- function _checkRemove(&$store, $url, $handle, $expected, $name = null)
- {
- $present = $store->removeAssociation($url, $handle);
- $this->assertTrue((!$expected && !$present) ||
- ($expected && $present),
- $name);
- }
- /**
- * Make sure a given store has a minimum of API compliance. Call
- * this function with an empty store.
- *
- * Raises AssertionError if the store does not work as expected.
- *
- * OpenIDStore -> NoneType
- */
- function _testStore(&$store)
- {
- // Association functions
- $now = time();
- $server_url = 'http://www.myopenid.com/openid';
- $assoc = $this->genAssoc($now);
- $this->_checkRetrieve($store, $server_url, null, null,
- 'Make sure that a missing association returns no result');
- $store->storeAssociation($server_url, $assoc);
- $this->_checkRetrieve($store, $server_url, null, $assoc,
- 'Check that after storage, getting returns the same result');
- $this->_checkRetrieve($store, $server_url, null, $assoc,
- 'more than once');
- $store->storeAssociation($server_url, $assoc);
- $this->_checkRetrieve($store, $server_url, null, $assoc,
- 'Storing more than once has no ill effect');
- // Removing an association that does not exist returns not present
- $this->_checkRemove($store, $server_url, $assoc->handle . 'x', false,
- "Remove nonexistent association (1)");
- // Removing an association that does not exist returns not present
- $this->_checkRemove($store, $server_url . 'x', $assoc->handle, false,
- "Remove nonexistent association (2)");
- // Removing an association that is present returns present
- $this->_checkRemove($store, $server_url, $assoc->handle, true,
- "Remove existent association");
- // but not present on subsequent calls
- $this->_checkRemove($store, $server_url, $assoc->handle, false,
- "Remove nonexistent association after removal");
- // Put assoc back in the store
- $store->storeAssociation($server_url, $assoc);
- // More recent and expires after assoc
- $assoc2 = $this->genAssoc($now, $issued = 1);
- $store->storeAssociation($server_url, $assoc2);
- $this->_checkRetrieve($store, $server_url, null, $assoc2,
- 'After storing an association with a different handle, but the
- same $server_url, the handle with the later expiration is
- returned.');
- $this->_checkRetrieve($store, $server_url, $assoc->handle, $assoc,
- 'We can still retrieve the older association');
- $this->_checkRetrieve($store, $server_url, $assoc2->handle, $assoc2,
- 'Plus we can retrieve the association with the later expiration
- explicitly');
- $assoc3 = $this->genAssoc($now, $issued = 2, $lifetime = 100);
- $store->storeAssociation($server_url, $assoc3);
- // More recent issued time, so assoc3 is expected.
- $this->_checkRetrieve($store, $server_url, null, $assoc3, "(1)");
- $this->_checkRetrieve($store, $server_url, $assoc->handle,
- $assoc, "(2)");
- $this->_checkRetrieve($store, $server_url, $assoc2->handle,
- $assoc2, "(3)");
- $this->_checkRetrieve($store, $server_url, $assoc3->handle,
- $assoc3, "(4)");
- $this->_checkRemove($store, $server_url, $assoc2->handle, true, "(5)");
- $this->_checkRetrieve($store, $server_url, null, $assoc3, "(6)");
- $this->_checkRetrieve($store, $server_url, $assoc->handle,
- $assoc, "(7)");
- $this->_checkRetrieve($store, $server_url, $assoc2->handle,
- null, "(8)");
- $this->_checkRetrieve($store, $server_url, $assoc3->handle,
- $assoc3, "(9)");
- $this->_checkRemove($store, $server_url, $assoc2->handle,
- false, "(10)");
- $this->_checkRemove($store, $server_url, $assoc3->handle,
- true, "(11)");
- $this->_checkRetrieve($store, $server_url, null, $assoc, "(12)");
- $this->_checkRetrieve($store, $server_url, $assoc->handle,
- $assoc, "(13)");
- $this->_checkRetrieve($store, $server_url, $assoc2->handle,
- null, "(14)");
- $this->_checkRetrieve($store, $server_url, $assoc3->handle,
- null, "(15)");
- $this->_checkRemove($store, $server_url, $assoc2->handle,
- false, "(16)");
- $this->_checkRemove($store, $server_url, $assoc->handle,
- true, "(17)");
- $this->_checkRemove($store, $server_url, $assoc3->handle,
- false, "(18)");
- $this->_checkRetrieve($store, $server_url, null, null, "(19)");
- $this->_checkRetrieve($store, $server_url, $assoc->handle,
- null, "(20)");
- $this->_checkRetrieve($store, $server_url, $assoc2->handle,
- null, "(21)");
- $this->_checkRetrieve($store, $server_url,$assoc3->handle,
- null, "(22)");
- $this->_checkRemove($store, $server_url, $assoc2->handle,
- false, "(23)");
- $this->_checkRemove($store, $server_url, $assoc->handle,
- false, "(24)");
- $this->_checkRemove($store, $server_url, $assoc3->handle,
- false, "(25)");
- // Put associations into store, for two different server URLs
- $assoc1 = $this->genAssoc($now);
- $assoc2 = $this->genAssoc($now + 2);
- $server_url1 = "http://one.example.com/one";
- $server_url2 = "http://two.localhost.localdomain/two";
- $store->storeAssociation($server_url1, $assoc1);
- $store->storeAssociation($server_url2, $assoc2);
- // Ask for each one, make sure we get it
- $this->_checkRetrieve($store, $server_url1, $assoc1->handle,
- $assoc1, "(26)");
- $this->_checkRetrieve($store, $server_url2, $assoc2->handle,
- $assoc2, "(27)");
- $store->storeAssociation($server_url1, $assoc1);
- $store->storeAssociation($server_url2, $assoc2);
- // Ask for each one, make sure we get it
- $this->_checkRetrieve($store, $server_url1, null,
- $assoc1, "(28)");
- $this->_checkRetrieve($store, $server_url2, null,
- $assoc2, "(29)");
- // test expired associations
- // assoc 1: server 1, valid
- // assoc 2: server 1, expired
- // assoc 3: server 2, expired
- // assoc 4: server 3, valid
- $assocValid1 = $this->genAssoc($now, -3600, 7200);
- $assocValid2 = $this->genAssoc($now, -5);
- $assocExpired1 = $this->genAssoc($now, -7200, 3600);
- $assocExpired2 = $this->genAssoc($now, -7200, 3600);
- if (!$store->supportsCleanup()) {
- return;
- }
-
- $store->cleanupAssociations();
- $store->storeAssociation($server_url . '1', $assocValid1);
- $store->storeAssociation($server_url . '1', $assocExpired1);
- $store->storeAssociation($server_url . '2', $assocExpired2);
- $store->storeAssociation($server_url . '3', $assocValid2);
- $cleaned = $store->cleanupAssociations();
- $this->assertEquals(2, $cleaned);
- }
- function _checkUseNonce(&$store, $nonce, $expected, $server_url, $msg=null)
- {
- list($stamp, $salt) = Auth_OpenID_splitNonce($nonce);
- $actual = $store->useNonce($server_url, $stamp, $salt);
- $this->assertEquals(intval($expected), intval($actual), "_checkUseNonce failed: $server_url, $msg");
- }
- function _testNonce(&$store)
- {
- // Nonce functions
- $server_url = 'http://www.myopenid.com/openid';
- foreach (array($server_url, '') as $url) {
- // Random nonce (not in store)
- $nonce1 = Auth_OpenID_mkNonce();
- // A nonce is not by default
- $this->_checkUseNonce($store, $nonce1, true, $url, "blergx");
- // Once stored, cannot be stored again
- $this->_checkUseNonce($store, $nonce1, false, $url, 2);
- // And using again has the same effect
- $this->_checkUseNonce($store, $nonce1, false, $url, 3);
- // Nonces from when the universe was an hour old should
- // not pass these days.
- $old_nonce = Auth_OpenID_mkNonce(3600);
- $this->_checkUseNonce($store, $old_nonce, false, $url,
- "Old nonce ($old_nonce) passed.");
- }
- }
- function _testNonceCleanup(&$store) {
- if (!$store->supportsCleanup()) {
- return;
- }
-
- $server_url = 'http://www.myopenid.com/openid';
- $now = time();
- $old_nonce1 = Auth_OpenID_mkNonce($now - 20000);
- $old_nonce2 = Auth_OpenID_mkNonce($now - 10000);
- $recent_nonce = Auth_OpenID_mkNonce($now - 600);
- global $Auth_OpenID_SKEW;
- $orig_skew = $Auth_OpenID_SKEW;
- $Auth_OpenID_SKEW = 0;
- $store->cleanupNonces();
- // Set SKEW high so stores will keep our nonces.
- $Auth_OpenID_SKEW = 100000;
- $params = Auth_OpenID_splitNonce($old_nonce1);
- array_unshift($params, $server_url);
- $this->assertTrue(call_user_func_array(array(&$store, 'useNonce'), $params));
- $params = Auth_OpenID_splitNonce($old_nonce2);
- array_unshift($params, $server_url);
- $this->assertTrue(call_user_func_array(array(&$store, 'useNonce'), $params));
- $params = Auth_OpenID_splitNonce($recent_nonce);
- array_unshift($params, $server_url);
- $this->assertTrue(call_user_func_array(array(&$store, 'useNonce'), $params));
- $Auth_OpenID_SKEW = 3600;
- $cleaned = $store->cleanupNonces();
- $this->assertEquals(2, $cleaned); // , "Cleaned %r nonces." % (cleaned,)
- $Auth_OpenID_SKEW = 100000;
- // A roundabout method of checking that the old nonces were
- // cleaned is to see if we're allowed to add them again.
- $params = Auth_OpenID_splitNonce($old_nonce1);
- array_unshift($params, $server_url);
- $this->assertTrue(call_user_func_array(array(&$store, 'useNonce'), $params));
- $params = Auth_OpenID_splitNonce($old_nonce2);
- array_unshift($params, $server_url);
- $this->assertTrue(call_user_func_array(array(&$store, 'useNonce'), $params));
- // The recent nonce wasn't cleaned, so it should still fail.
- $params = Auth_OpenID_splitNonce($recent_nonce);
- array_unshift($params, $server_url);
- $this->assertFalse(call_user_func_array(array(&$store, 'useNonce'), $params));
- $Auth_OpenID_SKEW = $orig_skew;
- }
- }
- /**
- * Class that tests all of the stores included with the OpenID library
- *
- * @package OpenID
- */
- class Tests_Auth_OpenID_Included_StoreTest extends Tests_Auth_OpenID_Store {
- function test_memstore()
- {
- require_once 'Tests/Auth/OpenID/MemStore.php';
- $store = new Tests_Auth_OpenID_MemStore();
- $this->_testStore($store);
- $this->_testNonce($store);
- $this->_testNonceCleanup($store);
- }
- function test_filestore()
- {
- require_once 'Auth/OpenID/FileStore.php';
- $temp_dir = _Auth_OpenID_mkdtemp();
- if (!$temp_dir) {
- trigger_error('Could not create temporary directory ' .
- 'with Auth_OpenID_FileStore::_mkdtemp',
- E_USER_WARNING);
- return null;
- }
- $store = new Auth_OpenID_FileStore($temp_dir);
- $this->_testStore($store);
- $this->_testNonce($store);
- $this->_testNonceCleanup($store);
- $store->destroy();
- }
- function test_postgresqlstore()
- {
- // If the postgres extension isn't loaded or loadable, succeed
- // because we can't run the test.
- if (!(extension_loaded('pgsql') ||
- @dl('pgsql.so') ||
- @dl('php_pgsql.dll'))) {
- print "(not testing PostGreSQL store)";
- $this->pass();
- return;
- }
- require_once 'Auth/OpenID/PostgreSQLStore.php';
- require_once 'DB.php';
- global $_Auth_OpenID_db_test_host;
- $temp_db_name = _Auth_OpenID_getTmpDbName();
- $connect_db_name = 'test_master';
- $dsn = array(
- 'phptype' => 'pgsql',
- 'username' => 'openid_test',
- 'password' => '',
- 'hostspec' => $_Auth_OpenID_db_test_host,
- 'database' => $connect_db_name
- );
- $allowed_failures = 5;
- $result = null;
- $sleep_time = 1.0;
- $sql = sprintf("CREATE DATABASE %s", $temp_db_name);
- for ($failures = 0; $failures < $allowed_failures; $failures++) {
- $template_db =& DB::connect($dsn);
- if (PEAR::isError($template_db)) {
- $result =& $template_db;
- } else {
- // Try to create the test database.
- $result = $template_db->query($sql);
- $template_db->disconnect();
- unset($template_db);
- if (!PEAR::isError($result)) {
- break;
- }
- }
- $sleep_time *= ((mt_rand(1, 100) / 100.0) + 1.5);
- print "Failed to create database $temp_db_name.\n".
- "Waiting $sleep_time before trying again\n";
- $int_sleep = floor($sleep_time);
- $frac_sleep = $sleep_time - $int_sleep;
- sleep($int_sleep);
- usleep($frac_sleep * 1000000.0);
- }
- if ($failures == $allowed_failures) {
- $this->pass("Temporary database creation failed after $failures ".
- " tries ('$temp_db_name'): " . $result->getMessage());
- return;
- }
- // Disconnect from template1 and reconnect to the temporary
- // testing database.
- $dsn['database'] = $temp_db_name;
- $db =& DB::connect($dsn);
- if (PEAR::isError($db)) {
- $this->fail("Temporary database connection failed " .
- " ('$temp_db_name'): " . $db->getMessage());
- return;
- }
- $store =& new Auth_OpenID_PostgreSQLStore($db);
- $this->assertFalse($store->tableExists($store->nonces_table_name));
- $this->assertFalse($store->tableExists($store->associations_table_name));
- $store->createTables();
- $this->assertTrue($store->tableExists($store->nonces_table_name));
- $this->assertTrue($store->tableExists($store->associations_table_name));
- $this->_testStore($store);
- $this->_testNonce($store);
- $this->_testNonceCleanup($store);
- $db->disconnect();
- unset($db);
- // Connect to template1 again so we can drop the temporary
- // database.
- $dsn['database'] = $connect_db_name;
- $template_db =& DB::connect($dsn);
- if (PEAR::isError($template_db)) {
- $this->fail("Template database connection (to drop " .
- "temporary database) failed: " .
- $template_db->getMessage());
- return;
- }
- $result = $template_db->query(sprintf("DROP DATABASE %s",
- $temp_db_name));
- if (PEAR::isError($result)) {
- $this->fail("Dropping temporary database failed: " .
- $result->getMessage());
- return;
- }
- $template_db->disconnect();
- unset($template_db);
- }
- function test_sqlitestore()
- {
- // If the sqlite extension isn't loaded or loadable, succeed
- // because we can't run the test.
- if (!(extension_loaded('sqlite') ||
- @dl('sqlite.so') ||
- @dl('php_sqlite.dll'))) {
- print "(not testing SQLite store)";
- $this->pass();
- return;
- }
- require_once 'Auth/OpenID/SQLiteStore.php';
- require_once 'DB.php';
- $temp_dir = _Auth_OpenID_mkdtemp();
- if (!$temp_dir) {
- trigger_error('Could not create temporary directory ' .
- 'with Auth_OpenID_FileStore::_mkdtemp',
- E_USER_WARNING);
- return null;
- }
- $dsn = 'sqlite:///' . urlencode($temp_dir) . '/php_openid_storetest.db';
- $db =& DB::connect($dsn);
- if (PEAR::isError($db)) {
- $this->pass("SQLite database connection failed: " .
- $db->getMessage());
- } else {
- $store =& new Auth_OpenID_SQLiteStore($db);
- $this->assertTrue($store->createTables(), "Table creation failed");
- $this->_testStore($store);
- $this->_testNonce($store);
- $this->_testNonceCleanup($store);
- }
- $db->disconnect();
- unset($db);
- unset($store);
- unlink($temp_dir . '/php_openid_storetest.db');
- rmdir($temp_dir);
- }
- function test_mysqlstore()
- {
- // If the mysql extension isn't loaded or loadable, succeed
- // because we can't run the test.
- if (!(extension_loaded('mysql') ||
- @dl('mysql.' . PHP_SHLIB_SUFFIX))) {
- print "(not testing MySQL store)";
- $this->pass();
- return;
- }
- require_once 'Auth/OpenID/MySQLStore.php';
- require_once 'DB.php';
- global $_Auth_OpenID_db_test_host;
- $dsn = array(
- 'phptype' => 'mysql',
- 'username' => 'openid_test',
- 'password' => '',
- 'hostspec' => $_Auth_OpenID_db_test_host
- );
- $db =& DB::connect($dsn);
- if (PEAR::isError($db)) {
- print "MySQL database connection failed: " .
- $db->getMessage();
- $this->pass();
- return;
- }
- $temp_db_name = _Auth_OpenID_getTmpDbName();
- $result = $db->query("CREATE DATABASE $temp_db_name");
- if (PEAR::isError($result)) {
- $this->pass("Error creating MySQL temporary database: " .
- $result->getMessage());
- return;
- }
- $db->query("USE $temp_db_name");
- $store =& new Auth_OpenID_MySQLStore($db);
- $store->createTables();
- $this->_testStore($store);
- $this->_testNonce($store);
- $this->_testNonceCleanup($store);
- $db->query("DROP DATABASE $temp_db_name");
- }
- }
- /**
- * This is the host that the store test will use
- */
- global $_Auth_OpenID_memcache_test_host;
- $_Auth_OpenID_memcache_test_host = 'localhost';
- class Tests_Auth_OpenID_MemcachedStore_Test extends Tests_Auth_OpenID_Store {
- function test_memcache()
- {
- // If the memcache extension isn't loaded or loadable, succeed
- // because we can't run the test.
- if (!(extension_loaded('memcache') ||
- @dl('memcache.so') ||
- @dl('php_memcache.dll'))) {
- print "(skipping memcache store tests)";
- $this->pass();
- return;
- }
- require_once 'Auth/OpenID/MemcachedStore.php';
- global $_Auth_OpenID_memcache_test_host;
- $memcached = new Memcache();
- if (!$memcached->connect($_Auth_OpenID_memcache_test_host)) {
- print "(skipping memcache store tests - couldn't connect)";
- $this->pass();
- } else {
- $store = new Auth_OpenID_MemcachedStore($memcached);
- $this->_testStore($store);
- $this->_testNonce($store);
- $this->_testNonceCleanup($store);
- $memcached->close();
- }
- }
- }
- class Tests_Auth_OpenID_StoreTest extends PHPUnit_TestSuite {
- function getName()
- {
- return "Tests_Auth_OpenID_StoreTest";
- }
- function Tests_Auth_OpenID_StoreTest()
- {
- $this->addTestSuite('Tests_Auth_OpenID_Included_StoreTest');
- $this->addTestSuite('Tests_Auth_OpenID_MemcachedStore_Test');
- }
- }
- ?>
|