* @copyright 2005 Janrain, Inc. * @license http://www.gnu.org/copyleft/lesser.html LGPL */ session_start(); require_once 'Auth/OpenID/CryptUtil.php'; require_once 'Services/Yadis/HTTPFetcher.php'; require_once 'Auth/OpenID/DiffieHellman.php'; require_once 'Auth/OpenID/FileStore.php'; require_once 'Auth/OpenID/KVForm.php'; require_once 'Auth/OpenID/Consumer.php'; require_once 'Auth/OpenID/Server.php'; require_once 'Auth/OpenID/Nonce.php'; require_once 'Tests/Auth/OpenID/MemStore.php'; require_once 'PHPUnit.php'; class Auth_OpenID_TestConsumer extends Auth_OpenID_GenericConsumer { /** * Use a small (insecure) modulus for this test so that it runs quickly */ function _createDiffieHellman() { return new Auth_OpenID_DiffieHellman('1235514290909'); } } $_Auth_OpenID_assocs = array( array('another 20-byte key.', 'Snarky'), array(str_repeat("\x00", 20), 'Zeros'), ); function Auth_OpenID_parse($qs) { $result = array(); $parts = explode("&", $qs); foreach ($parts as $pair) { list($key, $value) = explode("=", $pair, 2); assert(!array_key_exists($key, $result)); $result[$key] = urldecode($value); } return $result; } function Auth_OpenID_associate($qs, $assoc_secret, $assoc_handle) { $query_data = Auth_OpenID_parse($qs); assert($query_data['openid.mode'] == 'associate'); assert($query_data['openid.assoc_type'] == 'HMAC-SHA1'); $reply_dict = array( 'assoc_type' => 'HMAC-SHA1', 'assoc_handle' => $assoc_handle, 'expires_in' => '600', ); if (defined('Auth_OpenID_NO_MATH_SUPPORT')) { assert(count($query_data) == 2); $reply_dict['mac_key'] = $assoc_secret; } else { assert((count($query_data) == 6) || (count($query_data) == 4)); assert($query_data['openid.mode'] == 'associate'); assert($query_data['openid.session_type'] == 'DH-SHA1'); $dh_args = Auth_OpenID_DiffieHellman:: serverAssociate($query_data, $assoc_secret); $reply_dict = array_merge($reply_dict, $dh_args); } return Auth_OpenID_KVForm::fromArray($reply_dict); } class Auth_OpenID_TestFetcher extends Services_Yadis_HTTPFetcher { function Auth_OpenID_TestFetcher($user_url, $user_page, $assoc_secret, $assoc_handle) { $this->get_responses = array($user_url => new Services_Yadis_HTTPResponse($user_url, 200, array(), $user_page)); $this->assoc_secret = $assoc_secret; $this->assoc_handle = $assoc_handle; $this->num_assocs = 0; } function response($url, $body) { if ($body === null) { return new Services_Yadis_HTTPResponse($url, 404, array(), 'Not found'); } else { return new Services_Yadis_HTTPResponse($url, 200, array(), $body); } } function get($url) { if (array_key_exists($url, $this->get_responses)) { return $this->get_responses[$url]; } else { return $this->response($url, null); } } function _checkAuth($url, $body) { $query_data = Auth_OpenID_parse($body); $expected = array( 'openid.mode' => 'check_authentication', 'openid.signed' => 'assoc_handle,sig,signed', 'openid.sig' => 'fake', 'openid.assoc_handle' => $this->assoc_handle, ); if ($query_data == $expected) { return new Services_Yadis_HTTPResponse($url, 200, array(), "is_valid:true\n"); } else { return new Services_Yadis_HTTPResponse($url, 400, array(), "error:bad check_authentication query\n"); } } function post($url, $body) { if (strpos($body, 'openid.mode=associate') !== false) { $response = Auth_OpenID_associate($body, $this->assoc_secret, $this->assoc_handle); $this->num_assocs++; return $this->response($url, $response); } elseif (strpos($body, 'openid.mode=check_authentication') !== false) { return $this->_checkAuth($url, $body); } else { return $this->response($url, null); } } } $_Auth_OpenID_user_page_pat = " A user page %s blah blah "; $_Auth_OpenID_server_url = "http://server.example.com/"; $_Auth_OpenID_consumer_url = "http://consumer.example.com/"; class Tests_Auth_OpenID_Consumer extends PHPUnit_TestCase { function _run(&$consumer, $user_url, $mode, $delegate_url, &$fetcher, &$store, $immediate) { global $_Auth_OpenID_consumer_url, $_Auth_OpenID_server_url; $endpoint = new Auth_OpenID_ServiceEndpoint(); $endpoint->identity_url = $user_url; $endpoint->server_url = $_Auth_OpenID_server_url; $endpoint->delegate = $delegate_url; $result = $consumer->begin($endpoint); $return_to = $_Auth_OpenID_consumer_url; $trust_root = $_Auth_OpenID_consumer_url; $redirect_url = $result->redirectURL($trust_root, $return_to, $immediate); $parsed = parse_url($redirect_url); $qs = $parsed['query']; $q = Auth_OpenID_parse($qs); $new_return_to = $q['openid.return_to']; unset($q['openid.return_to']); $expected = array( 'openid.mode' => $mode, 'openid.identity' => $delegate_url, 'openid.trust_root' => $trust_root ); if ($consumer->_use_assocs) { $expected['openid.assoc_handle'] = $fetcher->assoc_handle; } $this->assertEquals($expected, $q); $this->assertEquals(0, strpos($redirect_url, $_Auth_OpenID_server_url)); $this->assertEquals(0, strpos($new_return_to, $return_to)); $query = array( 'nonce' => $result->return_to_args['nonce'], 'openid.mode'=> 'id_res', 'openid.return_to'=> $new_return_to, 'openid.identity'=> $delegate_url, 'openid.assoc_handle'=> $fetcher->assoc_handle, ); if ($consumer->_use_assocs) { $assoc = $store->getAssociation($_Auth_OpenID_server_url, $fetcher->assoc_handle); $assoc->addSignature(array('mode', 'return_to', 'identity'), $query); } else { $query['openid.signed'] = 'assoc_handle,sig,signed'; $query['openid.assoc_handle'] = $fetcher->assoc_handle; $query['openid.sig'] = 'fake'; } $result = $consumer->complete($query, $result->endpoint); $this->assertEquals(Auth_OpenID_SUCCESS, $result->status); $this->assertEquals($result->identity_url, $user_url); } function _test_success($user_url, $delegate_url, $links, $immediate = false) { global $_Auth_OpenID_filestore_base_dir, $_Auth_OpenID_server_url, $_Auth_OpenID_user_page_pat, $_Auth_OpenID_assocs; $store = new Tests_Auth_OpenID_MemStore(); if ($immediate) { $mode = 'checkid_immediate'; } else { $mode = 'checkid_setup'; } $user_page = sprintf($_Auth_OpenID_user_page_pat, $links); $fetcher = new Auth_OpenID_TestFetcher($user_url, $user_page, $_Auth_OpenID_assocs[0][0], $_Auth_OpenID_assocs[0][1]); $consumer = new Auth_OpenID_TestConsumer($store); $consumer->fetcher =& $fetcher; $expected_num_assocs = 0; $this->assertEquals($expected_num_assocs, $fetcher->num_assocs); $this->_run($consumer, $user_url, $mode, $delegate_url, $fetcher, $store, $immediate); if ($consumer->_use_assocs) { $expected_num_assocs += 1; } $this->assertEquals($expected_num_assocs, $fetcher->num_assocs); // Test that doing it again uses the existing association $this->_run($consumer, $user_url, $mode, $delegate_url, $fetcher, $store, $immediate); $this->assertEquals($expected_num_assocs, $fetcher->num_assocs); // Another association is created if we remove the existing one $store->removeAssociation($_Auth_OpenID_server_url, $fetcher->assoc_handle); $this->_run($consumer, $user_url, $mode, $delegate_url, $fetcher, $store, $immediate); if ($consumer->_use_assocs) { $expected_num_assocs += 1; } $this->assertEquals($expected_num_assocs, $fetcher->num_assocs); // Test that doing it again uses the existing association $this->_run($consumer, $user_url, $mode, $delegate_url, $fetcher, $store, $immediate); $this->assertEquals($expected_num_assocs, $fetcher->num_assocs); } function test_success() { global $_Auth_OpenID_server_url; $user_url = 'http://www.example.com/user.html'; $links = sprintf('', $_Auth_OpenID_server_url); $delegate_url = 'http://consumer.example.com/user'; $delegate_links = sprintf(''. '', $_Auth_OpenID_server_url, $delegate_url); $this->_test_success($user_url, $user_url, $links); $this->_test_success($user_url, $user_url, $links, true); $this->_test_success($user_url, $delegate_url, $delegate_links); $this->_test_success($user_url, $delegate_url, $delegate_links, true); } } class _TestIdRes extends PHPUnit_TestCase { var $consumer_class = 'Auth_OpenID_GenericConsumer'; function setUp() { $this->store = new Tests_Auth_OpenID_MemStore(); $cl = $this->consumer_class; $this->consumer = new $cl($this->store); $this->return_to = "nonny"; $this->endpoint = new Auth_OpenID_ServiceEndpoint(); $this->server_id = "sirod"; $this->server_url = "serlie"; $this->consumer_id = "consu"; $this->endpoint->identity_url = $this->consumer_id; $this->endpoint->server_url = $this->server_url; $this->endpoint->delegate = $this->server_id; } } class Tests_Auth_OpenID_Consumer_TestSetupNeeded extends _TestIdRes { function test_setupNeeded() { $setup_url = "http://unittest/setup-here"; $query = array( 'openid.mode' => 'id_res', 'openid.user_setup_url' => $setup_url); $ret = $this->consumer->_doIdRes($query, $this->endpoint); $this->assertEquals($ret->status, Auth_OpenID_SETUP_NEEDED); $this->assertEquals($ret->setup_url, $setup_url); } } define('E_CHECK_AUTH_HAPPENED', 'checkauth occurred'); define('E_MOCK_FETCHER_EXCEPTION', 'mock fetcher exception'); define('E_ASSERTION_ERROR', 'assertion error'); class _CheckAuthDetectingConsumer extends Auth_OpenID_GenericConsumer { function _checkAuth($query, $server_url) { __raiseError(E_CHECK_AUTH_HAPPENED); } } class Tests_Auth_OpenID_Consumer_CheckNonceTest extends _TestIdRes { function test_consumerNonce() { $this->return_to = sprintf('http://rt.unittest/?nonce=%s', Auth_OpenID_mkNonce()); $this->response = new Auth_OpenID_SuccessResponse($this->endpoint, array('openid.return_to' => $this->return_to)); $ret = $this->consumer->_checkNonce(null, $this->response); $this->assertEquals($ret->status, Auth_OpenID_SUCCESS); $this->assertEquals($ret->identity_url, $this->consumer_id); } function test_serverNonce() { $this->response = new Auth_OpenID_SuccessResponse($this->endpoint, array('openid.nonce' => Auth_OpenID_mkNonce())); $ret = $this->consumer->_checkNonce($this->server_url, $this->response); $this->assertEquals($ret->status, Auth_OpenID_SUCCESS); $this->assertEquals($ret->identity_url, $this->consumer_id); } function test_badNonce() { // remove the nonce from the store $nonce = Auth_OpenID_mkNonce(); list($timestamp, $salt) = Auth_OpenID_splitNonce($nonce); $this->store->useNonce($this->server_url, $timestamp, $salt); $this->response = new Auth_OpenID_SuccessResponse($this->endpoint, array('openid.nonce' => $nonce)); $ret = $this->consumer->_checkNonce($this->server_url, $this->response); $this->assertEquals($ret->status, Auth_OpenID_FAILURE); $this->assertEquals($ret->identity_url, $this->consumer_id); $this->assertTrue(strpos($ret->message, 'Nonce missing from store') === 0); } function test_tamperedNonce() { // Malformed nonce $this->response = new Auth_OpenID_SuccessResponse($this->endpoint, array('openid.nonce' => 'malformed')); $ret = $this->consumer->_checkNonce($this->server_url, $this->response); $this->assertEquals($ret->status, Auth_OpenID_FAILURE); $this->assertEquals($ret->identity_url, $this->consumer_id); $this->assertTrue(strpos($ret->message, 'Malformed nonce') === 0, $ret->message); } function test_missingNonce() { // no nonce parameter on the return_to $this->response = new Auth_OpenID_SuccessResponse($this->endpoint, array('openid.return_to' => $this->return_to)); $ret = $this->consumer->_checkNonce($this->server_url, $this->response); $this->assertEquals($ret->status, Auth_OpenID_FAILURE); $this->assertEquals($ret->identity_url, $this->consumer_id); $this->assertTrue(strpos($ret->message, 'Nonce missing from return_to') === 0); } } class Tests_Auth_OpenID_Consumer_TestCheckAuthTriggered extends _TestIdRes { var $consumer_class = '_CheckAuthDetectingConsumer'; function _doIdRes($query) { return $this->consumer->_doIdRes($query, $this->endpoint); } function test_checkAuthTriggered() { $query = array('openid.return_to' => $this->return_to, 'openid.identity' => $this->server_id, 'openid.assoc_handle' =>'not_found'); $result = $this->_doIdRes($query); $error = __getError(); if ($error === null) { $this->fail('_checkAuth did not happen.'); } } function test_checkAuthTriggeredWithAssoc() { // Store an association for this server that does not match // the handle that is in the query $issued = time(); $lifetime = 1000; $assoc = new Auth_OpenID_Association( 'handle', 'secret', $issued, $lifetime, 'HMAC-SHA1'); $this->store->storeAssociation($this->server_url, $assoc); $query = array( 'openid.return_to' => $this->return_to, 'openid.identity' => $this->server_id, 'openid.assoc_handle' =>'not_found'); $result = $this->_doIdRes($query); $error = __getError(); if ($error === null) { $this->fail('_checkAuth did not happen.'); } } function test_expiredAssoc() { // Store an expired association for the server with the handle // that is in the query $issued = time() - 10; $lifetime = 0; $handle = 'handle'; $assoc = new Auth_OpenID_Association( $handle, 'secret', $issued, $lifetime, 'HMAC-SHA1'); $this->assertTrue($assoc->getExpiresIn() <= 0); $this->store->storeAssociation($this->server_url, $assoc); $query = array( 'openid.return_to' => $this->return_to, 'openid.identity' => $this->server_id, 'openid.assoc_handle' => $handle); $info = $this->_doIdRes($query); $this->assertEquals('failure', $info->status); $this->assertEquals($this->consumer_id, $info->identity_url); $this->assertTrue(strpos($info->message, 'expired') !== false); } function test_newerAssoc() { // Store an expired association for the server with the handle // that is in the query $lifetime = 1000; $good_issued = time() - 10; $good_handle = 'handle'; $good_assoc = new Auth_OpenID_Association( $good_handle, 'secret', $good_issued, $lifetime, 'HMAC-SHA1'); $this->store->storeAssociation($this->server_url, $good_assoc); $bad_issued = time() - 5; $bad_handle = 'handle2'; $bad_assoc = new Auth_OpenID_Association( $bad_handle, 'secret', $bad_issued, $lifetime, 'HMAC-SHA1'); $this->store->storeAssociation($this->server_url, $bad_assoc); $query = array( 'openid.return_to' => $this->return_to, 'openid.identity' => $this->server_id, 'openid.assoc_handle' => $good_handle); $good_assoc->addSignature(array('return_to', 'identity'), $query); $info = $this->_doIdRes($query); $this->assertEquals($info->status, 'success'); $this->assertEquals($this->consumer_id, $info->identity_url); } } class _MockFetcher { function _MockFetcher($response = null) { // response is (code, url, body) $this->response = $response; $this->fetches = array(); } function post($url, $body) { $this->fetches[] = array($url, $body, array()); return $this->response; } function get($url) { $this->fetches[] = array($url, null, array()); return $this->response; } } class Tests_Auth_OpenID_Complete extends _TestIdRes { function test_cancel() { $query = array('openid.mode' => 'cancel'); $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_CANCEL); $this->assertTrue($r->identity_url == $this->endpoint->identity_url); } function test_error() { $msg = 'an error message'; $query = array('openid.mode' =>'error', 'openid.error' => $msg); $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_FAILURE); $this->assertTrue($r->identity_url == $this->endpoint->identity_url); $this->assertEquals($r->message, $msg); } function test_noMode() { $query = array(); $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_FAILURE); $this->assertTrue($r->identity_url == $this->endpoint->identity_url); } function test_idResMissingField() { $query = array('openid.mode' => 'id_res'); $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_FAILURE); $this->assertEquals($r->identity_url, $this->consumer_id); } function test_idResURLMismatch() { $query = array('openid.mode' => 'id_res', 'openid.return_to' => 'return_to (just anything)', 'openid.identity' => 'something wrong (not this->consumer_id)', 'openid.assoc_handle' => 'does not matter'); $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_FAILURE); $this->assertEquals($r->identity_url, $this->consumer_id); $this->assertTrue(strpos($r->message, 'delegate') !== false); } } class Tests_Auth_OpenID_CheckAuthResponse extends _TestIdRes { function _createAssoc() { $issued = time(); $lifetime = 1000; $assoc = new Auth_OpenID_Association( 'handle', 'secret', $issued, $lifetime, 'HMAC-SHA1'); $store =& $this->consumer->store; $store->storeAssociation($this->server_url, $assoc); $assoc2 = $store->getAssociation($this->server_url); $this->assertEquals($assoc, $assoc2); } function test_goodResponse() { // successful response to check_authentication $response = array('is_valid' => 'true'); $r = $this->consumer->_processCheckAuthResponse($response, $this->server_url); $this->assertTrue($r); } function test_missingAnswer() { // check_authentication returns false when the server sends no // answer $response = array(); $r = $this->consumer->_processCheckAuthResponse($response, $this->server_url); $this->assertFalse($r); } function test_badResponse() { // check_authentication returns false when is_valid is false $response = array('is_valid' => 'false'); $r = $this->consumer->_processCheckAuthResponse($response, $this->server_url); $this->assertFalse($r); } function test_badResponseInvalidate() { // Make sure that the handle is invalidated when is_valid is // false $this->_createAssoc(); $response = array('is_valid' => 'false', 'invalidate_handle' => 'handle'); $r = $this->consumer->_processCheckAuthResponse($response, $this->server_url); $this->assertFalse($r); $this->assertTrue( $this->consumer->store->getAssociation($this->server_url) === null); } function test_invalidateMissing() { // invalidate_handle with a handle that is not present $response = array('is_valid' => 'true', 'invalidate_handle' => 'missing'); $r = $this->consumer->_processCheckAuthResponse($response, $this->server_url); $this->assertTrue($r); } function test_invalidatePresent() { // invalidate_handle with a handle that exists""" $this->_createAssoc(); $response = array('is_valid' => 'true', 'invalidate_handle' => 'handle'); $r = $this->consumer->_processCheckAuthResponse($response, $this->server_url); $this->assertTrue($r); $this->assertTrue( $this->consumer->store->getAssociation($this->server_url) === null); } } class _IdResFetchFailingConsumer extends Auth_OpenID_GenericConsumer { var $message = 'fetch failed'; function _doIdRes($query, $endpoint) { return new Auth_OpenID_FailureResponse($endpoint, $this->message); } } class Tests_Auth_OpenID_FetchErrorInIdRes extends _TestIdRes { var $consumer_class = '_IdResFetchFailingConsumer'; function test_idResFailure() { $query = array('openid.mode' => 'id_res'); $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_FAILURE); $this->assertEquals($r->identity_url, $this->consumer_id); $this->assertEquals($this->consumer->message, $r->message); } } class _ExceptionRaisingMockFetcher { function get($url) { __raiseError(E_MOCK_FETCHER_EXCEPTION); } function post($url, $body) { __raiseError(E_MOCK_FETCHER_EXCEPTION); } } class _BadArgCheckingConsumer extends Auth_OpenID_GenericConsumer { function _makeKVPost($args, $tmp) { if ($args != array( 'openid.mode' => 'check_authentication', 'openid.signed' => 'foo')) { __raiseError(E_ASSERTION_ERROR); } return null; } } class Tests_Auth_OpenID_Consumer_TestCheckAuth extends _TestIdRes { function setUp() { $this->store = new Tests_Auth_OpenID_MemStore(); $this->consumer = new Auth_OpenID_GenericConsumer($this->store); $this->fetcher = new _MockFetcher(); $this->consumer->fetcher =& $this->fetcher; } function test_checkauth_error() { global $_Auth_OpenID_server_url; $this->fetcher->response = new Services_Yadis_HTTPResponse("http://some_url", 404, array(), "blah:blah\n"); $query = array('openid.signed' => 'stuff, things'); $r = $this->consumer->_checkAuth($query, $_Auth_OpenID_server_url); if ($r !== false) { $this->fail("Expected _checkAuth result to be false"); } } function test_bad_args() { $query = array('openid.signed' => 'foo', 'closid.foo' => 'something'); $consumer = new _BadArgCheckingConsumer($this->store); $consumer->_checkAuth($query, 'does://not.matter'); $this->assertEquals(__getError(), E_ASSERTION_ERROR); } } class Tests_Auth_OpenID_Consumer_TestFetchAssoc extends PHPUnit_TestCase { function setUp() { $this->store = new Tests_Auth_OpenID_MemStore(); $this->fetcher = new _MockFetcher(); $this->consumer = new Auth_OpenID_GenericConsumer($this->store); $this->consumer->fetcher =& $this->fetcher; } function test_kvpost_error() { $this->fetcher->response = new Services_Yadis_HTTPResponse("http://some_url", 404, array(), "blah:blah\n"); $r = $this->consumer->_makeKVPost(array('openid.mode' => 'associate'), "http://server_url"); if ($r !== null) { $this->fail("Expected _makeKVPost result to be null"); } } function test_error_exception() { $this->consumer->fetcher = new _ExceptionRaisingMockFetcher(); $this->consumer->_makeKVPost(array('openid.mode' => 'associate'), "http://server_url"); if (__getError() !== E_MOCK_FETCHER_EXCEPTION) { $this->fail("Expected ExceptionRaisingMockFetcher to " . "raise E_MOCK_FETCHER_EXCEPTION"); } // exception fetching returns no association $this->assertEquals(@$this->consumer->_getAssociation('some://url'), null); $this->consumer->_checkAuth(array('openid.signed' => ''), 'some://url'); if (__getError() !== E_MOCK_FETCHER_EXCEPTION) { $this->fail("Expected ExceptionRaisingMockFetcher to " . "raise E_MOCK_FETCHER_EXCEPTION (_checkAuth)"); } } } class Tests_Auth_OpenID_AuthRequest extends PHPUnit_TestCase { function setUp() { $this->endpoint = new Auth_OpenID_ServiceEndpoint(); $this->endpoint->delegate = 'http://server.unittest/joe'; $this->endpoint->server_url = 'http://server.unittest/'; $this->assoc =& $this; $this->assoc->handle = 'assoc@handle'; $this->authreq = new Auth_OpenID_AuthRequest($this->endpoint, $this->assoc); } function test_addExtensionArg() { $this->authreq->addExtensionArg('bag', 'color', 'brown'); $this->authreq->addExtensionArg('bag', 'material', 'paper'); $this->assertEquals($this->authreq->extra_args, array('openid.bag.color' => 'brown', 'openid.bag.material' => 'paper')); $url = $this->authreq->redirectURL('http://7.utest/', 'http://7.utest/r'); $this->failUnless(strpos($url, 'openid.bag.color=brown') !== false, 'extension arg not found in '.$url); $this->failUnless(strpos($url, 'openid.bag.material=paper') !== false, 'extension arg not found in '.$url); } } class Tests_Auth_OpenID_SuccessResponse extends PHPUnit_TestCase { function setUp() { $this->endpoint = new Auth_OpenID_ServiceEndpoint(); $this->endpoint->identity_url = 'identity_url'; } function test_extensionResponse() { $resp = SuccessResponse($this->endpoint, array( 'openid.unittest.one' => '1', 'openid.unittest.two' =>'2', 'openid.sreg.nickname' => 'j3h', 'openid.return_to' => 'return_to')); $utargs = $resp->extensionResponse('unittest'); $this->assertEquals($utargs, array('one' => '1', 'two' => '2')); $sregargs = $resp->extensionResponse('sreg'); $this->assertEquals($sregargs, array('nickname' => 'j3h')); } function test_noReturnTo() { $resp = SuccessResponse($this->endpoint, array()); $this->failUnless($resp->getReturnTo() === null); } function test_returnTo() { $resp = SuccessResponse($this->endpoint, array('openid.return_to' => 'return_to')); $this->assertEquals($resp->getReturnTo(), 'return_to'); } } class Tests_Auth_OpenID_ParseAssociation extends _TestIdRes { var $secret = ''; function setUp() { parent::setUp(); $this->secret = str_repeat('x', 20); } function test_missing() { // Missing required arguments $result = $this->consumer->_parseAssociation(array(), null, 'server_url'); $this->assertTrue($result === null); } function _setUpDH() { list($sess, $args) = $this->consumer->_createAssociateRequest($this->server_url); $server_sess = Auth_OpenID_DiffieHellmanServerSession::fromQuery($args); $server_resp = $server_sess->answer($this->secret); $server_resp['assoc_type'] = 'HMAC-SHA1'; $server_resp['assoc_handle'] = 'handle'; $server_resp['expires_in'] = '1000'; $server_resp['session_type'] = 'DH-SHA1'; return array($sess, $server_resp); } function test_plainSuccess() { $sess = new Auth_OpenID_PlainTextConsumerSession(); $server_resp = array('mac_key' => 'AAAAAAAAAAAAAAAAAAAAAAAAAAA=', 'assoc_type' => 'HMAC-SHA1', 'assoc_handle' => 'ahandle', 'expires_in' => '1000' ); $ret = $this->consumer->_parseAssociation($server_resp, $sess, 'server_url'); $this->assertEquals($ret->secret, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" . "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"); } function test_DHSuccess() { if (defined('Auth_OpenID_NO_MATH_SUPPORT')) { print "No math support: not running test_DHSuccess\n"; return; } list($sess, $server_resp) = $this->_setUpDH(); $ret = $this->consumer->_parseAssociation($server_resp, $sess, 'server_url'); $this->assertTrue($ret !== null); $this->assertEquals($ret->assoc_type, 'HMAC-SHA1'); $this->assertEquals($ret->secret, $this->secret); $this->assertEquals($ret->handle, 'handle'); $this->assertEquals($ret->lifetime, 1000); } function test_badAssocType() { $sess = new Auth_OpenID_PlainTextConsumerSession(); $server_resp = array('mac_key' => 'XXXXXXXXXXXXXXXXXXXX', 'assoc_handle' => 'ahandle', 'assoc_type' => 'Crazy Low Prices!!!', 'expires_in' => '1000' ); $ret = $this->consumer->_parseAssociation($server_resp, $sess, 'server_url'); $this->assertTrue($ret === null); } function test_badExpiresIn() { $sess = new Auth_OpenID_PlainTextConsumerSession(); $server_resp = array('mac_key' => 'XXXXXXXXXXXXXXXXXXXX', 'assoc_handle' => 'ahandle', 'assoc_type' => 'HMAC-SHA1', 'expires_in' => 'Crazy Low Prices!!!' ); $ret = $this->consumer->_parseAssociation($server_resp, $sess, 'server_url'); $this->assertTrue($ret === null); } function test_badSessionType() { $sess = new Auth_OpenID_PlainTextConsumerSession(); $server_resp = array('mac_key' => 'XXXXXXXXXXXXXXXXXXXX', 'assoc_handle' => 'ahandle', 'assoc_type' => 'HMAC-SHA1', 'expires_in' => '1000', 'session_type' => '|/iA6rA' ); $ret = $this->consumer->_parseAssociation($server_resp, $sess, 'server_url'); $this->assertTrue($ret === null); } function test_plainFallback() { if (defined('Auth_OpenID_NO_MATH_SUPPORT')) { print "No math support: not running test_plainFallback\n"; return; } $sess = new Auth_OpenID_DiffieHellmanConsumerSession(); $server_resp = array( 'assoc_type' => 'HMAC-SHA1', 'assoc_handle' => 'handle', 'expires_in' => '1000', 'mac_key' => base64_encode($this->secret)); $ret = $this->consumer->_parseAssociation($server_resp, $sess, 'server_url'); $this->assertTrue($ret !== null); $this->assertEquals($ret->assoc_type, 'HMAC-SHA1'); $this->assertEquals($ret->secret, $this->secret); $this->assertEquals($ret->handle, 'handle'); $this->assertEquals($ret->lifetime, 1000); } function test_plainFallbackFailure() { if (defined('Auth_OpenID_NO_MATH_SUPPORT')) { print "No math support: not running test_plainFallbackFailure\n"; return; } $sess = new Auth_OpenID_DiffieHellmanConsumerSession(); // missing mac_key $server_resp = array( 'assoc_type' => 'HMAC-SHA1', 'assoc_handle' => 'handle', 'expires_in' => '1000'); $ret = $this->consumer->_parseAssociation($server_resp, $sess, 'server_url'); $this->assertTrue($ret === null); } function test_badDHValues() { if (defined('Auth_OpenID_NO_MATH_SUPPORT')) { return; } list($sess, $server_resp) = $this->_setUpDH(); $server_resp['enc_mac_key'] = "\x00\x00\x00"; $ret = $this->consumer->_parseAssociation($server_resp, $sess, 'server_url'); $this->assertTrue($ret === null); } } class _StubConsumer { function _StubConsumer() { $this->assoc = null; $this->response = null; $this->endpoint = null; $this->fetcher = new _MockFetcher(); } function begin($service) { $auth_req = new Auth_OpenID_AuthRequest($this->assoc, $service); $this->endpoint = $service; return $auth_req; } function complete($query, $endpoint) { return $this->response; } } class Tests_Auth_OpenID_ConsumerTest2 extends PHPUnit_TestCase { function setUp() { foreach ($_SESSION as $k => $v) { unset($_SESSION[$k]); } $this->endpoint = new Auth_OpenID_ServiceEndpoint(); $this->identity_url = 'http://identity.url/'; $this->endpoint->identity_url = $this->identity_url; $this->store = null; $this->session = new Services_Yadis_PHPSession(); $this->consumer =& new Auth_OpenID_Consumer($this->store, &$this->session); $this->consumer->consumer =& new _StubConsumer(); $this->discovery =& new Services_Yadis_Discovery(&$this->session, $this->identity_url, $this->consumer->session_key_prefix); } function test_beginWithoutDiscovery() { // Does this really test anything non-trivial? $result = $this->consumer->beginWithoutDiscovery($this->endpoint); // The result is an auth request $this->assertTrue(strtolower(get_class($result)) == 'auth_openid_authrequest'); $loader = new Auth_OpenID_ServiceEndpointLoader(); // Side-effect of calling beginWithoutDiscovery is setting the // session value to the endpoint attribute of the result $this->assertTrue( $loader->fromSession( $this->session->get($this->consumer->_token_key)) == $result->endpoint); // The endpoint that we passed in is the endpoint on the // auth_request $this->assertTrue($result->endpoint == $this->endpoint); } function test_completeEmptySession() { $response = $this->consumer->complete(array()); $this->assertEquals($response->status, Auth_OpenID_FAILURE); $this->assertTrue($response->identity_url === null); } function _doResp($auth_req, $exp_resp) { // complete a transaction, using the expected response from // the generic consumer. $this->consumer->consumer->response = $exp_resp; // endpoint is stored in the session // $this->assertTrue($this->session->data); $this->assertTrue($_SESSION); $resp = $this->consumer->complete(array()); // All responses should have the same identity URL, and the // session should be cleaned out $this->assertTrue($resp->identity_url == $this->identity_url); $this->assertFalse(in_array($this->consumer->_token_key, $_SESSION)); // this->session->data)); // Expected status response $this->assertEquals($resp->status, $exp_resp->status); return $resp; } function _doRespNoDisco($exp_resp) { // Set up a transaction without discovery $auth_req = $this->consumer->beginWithoutDiscovery($this->endpoint); $resp = $this->_doResp($auth_req, $exp_resp); // There should be nothing left in the session once we have // completed. $this->assertFalse($this->session->contents()); return $resp; } function test_noDiscoCompleteSuccessWithToken() { $this->_doRespNoDisco(new Auth_OpenID_SuccessResponse($this->endpoint, array())); } function test_noDiscoCompleteCancelWithToken() { $this->_doRespNoDisco(new Auth_OpenID_CancelResponse($this->endpoint)); } function test_noDiscoCompleteFailure() { $msg = 'failed!'; $resp = $this->_doRespNoDisco(new Auth_OpenID_FailureResponse($this->endpoint, $msg)); $this->assertTrue($resp->message == $msg); } function test_noDiscoCompleteSetupNeeded() { $setup_url = 'http://setup.url/'; $resp = $this->_doRespNoDisco( new Auth_OpenID_SetupNeededResponse($this->endpoint, $setup_url)); $this->assertTrue($resp->setup_url == $setup_url); } // To test that discovery is cleaned up, we need to initialize a // Yadis manager, and have it put its values in the session. function _doRespDisco($is_clean, $exp_resp) { // Set up and execute a transaction, with discovery $this->discovery->createManager(array($this->endpoint), $this->identity_url); $auth_req = $this->consumer->begin($this->identity_url); $resp = $this->_doResp($auth_req, $exp_resp); $manager = $this->discovery->getManager(); if ($is_clean) { $this->assertTrue($this->discovery->getManager() === null); } else { $this->assertFalse($this->discovery->getManager() === null); } return $resp; } // Cancel and success DO clean up the discovery process function test_completeSuccess() { $this->_doRespDisco(true, new Auth_OpenID_SuccessResponse($this->endpoint, array())); } function test_completeCancel() { $this->_doRespDisco(true, new Auth_OpenID_CancelResponse($this->endpoint)); } // Failure and setup_needed don't clean up the discovery process function test_completeFailure() { $msg = 'failed!'; $resp = $this->_doRespDisco(false, new Auth_OpenID_FailureResponse($this->endpoint, $msg)); $this->assertTrue($resp->message == $msg); } function test_completeSetupNeeded() { $setup_url = 'http://setup.url/'; $resp = $this->_doRespDisco(false, new Auth_OpenID_SetupNeededResponse($this->endpoint, $setup_url)); $this->assertTrue($resp->status == Auth_OpenID_SETUP_NEEDED); $this->assertTrue($resp->setup_url == $setup_url); } function test_begin() { $this->discovery->createManager(array($this->endpoint), $this->identity_url); // Should not raise an exception $auth_req = $this->consumer->begin($this->identity_url); $this->assertTrue(strtolower(get_class($auth_req)) === 'auth_openid_authrequest'); $this->assertTrue($auth_req->endpoint == $this->endpoint); $this->assertTrue($auth_req->endpoint == $this->consumer->consumer->endpoint); $this->assertTrue($auth_req->assoc == $this->consumer->consumer->assoc); } } // Add other test cases to be run. $Tests_Auth_OpenID_Consumer_other = array( new Tests_Auth_OpenID_Consumer_TestSetupNeeded(), new Tests_Auth_OpenID_Consumer_TestCheckAuth(), new Tests_Auth_OpenID_Consumer_TestCheckAuthTriggered(), new Tests_Auth_OpenID_Consumer_TestFetchAssoc(), new Tests_Auth_OpenID_Consumer_CheckNonceTest(), new Tests_Auth_OpenID_Complete(), new Tests_Auth_OpenID_CheckAuthResponse(), new Tests_Auth_OpenID_FetchErrorInIdRes(), new Tests_Auth_OpenID_ParseAssociation(), new Tests_Auth_OpenID_ConsumerTest2() ); ?>