2554 lines
90 KiB
PHP
2554 lines
90 KiB
PHP
|
<?php
|
||
|
|
||
|
/**
|
||
|
* Tests for the OpenID consumer.
|
||
|
*
|
||
|
* 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_once 'Auth/OpenID/CryptUtil.php';
|
||
|
require_once 'Auth/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 'Auth/OpenID/SReg.php';
|
||
|
require_once 'Auth/OpenID/Message.php';
|
||
|
require_once 'Tests/Auth/OpenID/MemStore.php';
|
||
|
|
||
|
/*
|
||
|
* Convenience function to create a SuccessResponse with the given
|
||
|
* arguments, all signed.
|
||
|
*/
|
||
|
function mkSuccess($endpoint, $q)
|
||
|
{
|
||
|
$signed_list = array();
|
||
|
foreach (array_keys($q) as $k) {
|
||
|
$signed_list[] = 'openid.' . $k;
|
||
|
}
|
||
|
return new Auth_OpenID_SuccessResponse($endpoint,
|
||
|
Auth_OpenID_Message::fromOpenIDArgs($q),
|
||
|
$signed_list);
|
||
|
}
|
||
|
|
||
|
class FastConsumerSession extends Auth_OpenID_DiffieHellmanSHA1ConsumerSession {
|
||
|
function FastConsumerSession($dh = null)
|
||
|
{
|
||
|
if ($dh === null) {
|
||
|
$dh = new Auth_OpenID_DiffieHellman(100389557, 2);
|
||
|
}
|
||
|
|
||
|
$this->dh = $dh;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function setConsumerSession($con)
|
||
|
{
|
||
|
$con->session_types = array('DH-SHA1' => 'FastConsumerSession');
|
||
|
}
|
||
|
|
||
|
global $_Auth_OpenID_assocs;
|
||
|
$_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[urldecode($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);
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query_data);
|
||
|
$session = Auth_OpenID_PlainTextServerSession::fromMessage($message);
|
||
|
} else {
|
||
|
assert((count($query_data) == 6) || (count($query_data) == 4));
|
||
|
assert($query_data['openid.mode'] == 'associate');
|
||
|
assert($query_data['openid.session_type'] == 'DH-SHA1');
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query_data);
|
||
|
|
||
|
$session = Auth_OpenID_DiffieHellmanSHA1ServerSession::fromMessage($message);
|
||
|
$reply_dict['session_type'] = 'DH-SHA1';
|
||
|
|
||
|
}
|
||
|
|
||
|
$reply_dict = array_merge($reply_dict, $session->answer($assoc_secret));
|
||
|
return Auth_OpenID_KVForm::fromArray($reply_dict);
|
||
|
}
|
||
|
|
||
|
class Auth_OpenID_TestFetcher extends Auth_Yadis_HTTPFetcher {
|
||
|
function Auth_OpenID_TestFetcher($user_url, $user_page,
|
||
|
$assoc_secret, $assoc_handle)
|
||
|
{
|
||
|
$this->get_responses = array($user_url =>
|
||
|
new Auth_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 Auth_Yadis_HTTPResponse($url, 404, array(), 'Not found');
|
||
|
} else {
|
||
|
return new Auth_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 Auth_Yadis_HTTPResponse($url, 200, array(), "is_valid:true\n");
|
||
|
} else {
|
||
|
return new Auth_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);
|
||
|
}
|
||
|
|
||
|
return $this->response($url, null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
global $_Auth_OpenID_user_page_pat;
|
||
|
$_Auth_OpenID_user_page_pat = "<html>
|
||
|
<head>
|
||
|
<title>A user page</title>
|
||
|
%s
|
||
|
</head>
|
||
|
<body>
|
||
|
blah blah
|
||
|
</body>
|
||
|
</html>";
|
||
|
|
||
|
global $_Auth_OpenID_server_url;
|
||
|
$_Auth_OpenID_server_url = "http://server.example.com/";
|
||
|
|
||
|
global $_Auth_OpenID_consumer_url;
|
||
|
$_Auth_OpenID_consumer_url = "http://consumer.example.com/";
|
||
|
|
||
|
class Tests_Auth_OpenID_Consumer extends PHPUnit_Framework_TestCase {
|
||
|
|
||
|
function _run($consumer, $user_url, $mode, $delegate_url,
|
||
|
$fetcher, $store, $immediate)
|
||
|
{
|
||
|
global $_Auth_OpenID_consumer_url,
|
||
|
$_Auth_OpenID_server_url;
|
||
|
|
||
|
if (!defined('Auth_OpenID_NO_MATH_SUPPORT')) {
|
||
|
setConsumerSession($consumer);
|
||
|
}
|
||
|
|
||
|
$endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$endpoint->claimed_id = $user_url;
|
||
|
$endpoint->server_url = $_Auth_OpenID_server_url;
|
||
|
$endpoint->local_id = $delegate_url;
|
||
|
$endpoint->type_uris = array(Auth_OpenID_TYPE_1_1);
|
||
|
|
||
|
$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));
|
||
|
|
||
|
$parsed = parse_url($new_return_to);
|
||
|
$query = Auth_OpenID_parse($parsed['query']);
|
||
|
|
||
|
$query = array_merge($query, array(
|
||
|
'openid.mode'=> 'id_res',
|
||
|
'openid.return_to'=> $new_return_to,
|
||
|
'openid.identity'=> $delegate_url,
|
||
|
'openid.assoc_handle'=> $fetcher->assoc_handle,
|
||
|
));
|
||
|
|
||
|
if (!$consumer->_use_assocs) {
|
||
|
$query['openid.signed'] =
|
||
|
'assoc_handle,mode,signed,identity';
|
||
|
$query['openid.assoc_handle'] = $fetcher->assoc_handle;
|
||
|
$query['openid.sig'] = 'fake';
|
||
|
}
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
if ($consumer->_use_assocs) {
|
||
|
$assoc = $store->getAssociation($_Auth_OpenID_server_url,
|
||
|
$fetcher->assoc_handle);
|
||
|
$message = $assoc->signMessage($message);
|
||
|
}
|
||
|
|
||
|
$result = $consumer->complete($message, $result->endpoint, $new_return_to);
|
||
|
|
||
|
$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_GenericConsumer($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('<link rel="openid.server" href="%s" />',
|
||
|
$_Auth_OpenID_server_url);
|
||
|
|
||
|
$delegate_url = 'http://consumer.example.com/user';
|
||
|
$delegate_links = sprintf('<link rel="openid.server" href="%s" />'.
|
||
|
'<link rel="openid.delegate" href="%s" />',
|
||
|
$_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 ConfigurableConsumer extends Auth_OpenID_GenericConsumer {
|
||
|
var $return_to_check_disabled = false;
|
||
|
|
||
|
function disableReturnToChecking() {
|
||
|
$this->return_to_check_disabled = true;
|
||
|
}
|
||
|
|
||
|
function complete($message, $endpoint, $return_to) {
|
||
|
if ($this->return_to_check_disabled) {
|
||
|
$return_to = null;
|
||
|
}
|
||
|
|
||
|
return parent::complete($message, $endpoint, $return_to);
|
||
|
}
|
||
|
|
||
|
function _checkReturnTo($unused, $unused2) {
|
||
|
if ($this->return_to_check_disabled) {
|
||
|
return true;
|
||
|
} else {
|
||
|
return parent::_checkReturnTo($unused, $unused2);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class _TestIdRes extends PHPUnit_Framework_TestCase {
|
||
|
var $consumer_class = 'ConfigurableConsumer';
|
||
|
|
||
|
function setUp()
|
||
|
{
|
||
|
$this->store = new Tests_Auth_OpenID_MemStore();
|
||
|
$cl = $this->consumer_class;
|
||
|
$this->consumer = new $cl($this->store);
|
||
|
$this->return_to = "http://some.host/path";
|
||
|
$this->endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
|
||
|
$this->server_id = "sirod";
|
||
|
$this->server_url = "serlie";
|
||
|
$this->consumer_id = "consu";
|
||
|
|
||
|
$this->endpoint->claimed_id = $this->consumer_id;
|
||
|
$this->endpoint->server_url = $this->server_url;
|
||
|
$this->endpoint->local_id = $this->server_id;
|
||
|
$this->endpoint->type_uris = array(Auth_OpenID_TYPE_1_1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_Consumer_TestSetupNeeded extends _TestIdRes {
|
||
|
function failUnlessSetupNeeded($expected_setup_url, $message)
|
||
|
{
|
||
|
if ($this->consumer._checkSetupNeeded($message)) {
|
||
|
$this->assertEquals($expected_setup_url,
|
||
|
$message->getArg(Auth_OpenID_OPENID_NS,
|
||
|
'user_setup_url'));
|
||
|
} else {
|
||
|
$this->fail("Expected to find an immediate-mode response");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function test_setupNeededOpenID1()
|
||
|
{
|
||
|
// The minimum conditions necessary to trigger Setup Needed
|
||
|
$setup_url = 'http://unittest/setup-here';
|
||
|
$message = Auth_OpenID_Message::fromPostArgs(array(
|
||
|
'opaenid.mode' => 'id_res',
|
||
|
'openid.user_setup_url' => $setup_url
|
||
|
));
|
||
|
$this->assertTrue($message->isOpenID1());
|
||
|
$this->failUnlessSetupNeeded($setup_url, $message);
|
||
|
}
|
||
|
|
||
|
function test_setupNeededOpenID1_extra()
|
||
|
{
|
||
|
// Extra stuff along with setup_url still trigger Setup Needed
|
||
|
$setup_url = 'http://unittest/setup-here';
|
||
|
$message = Auth_OpenID_Message::fromPostArgs(array(
|
||
|
'openid.mode' => 'id_res',
|
||
|
'openid.user_setup_url' => $setup_url,
|
||
|
'openid.identity' => 'bogus'
|
||
|
));
|
||
|
$this->assertTrue($message->isOpenID1());
|
||
|
$this->failUnlessSetupNeeded($setup_url, $message);
|
||
|
}
|
||
|
|
||
|
function test_noSetupNeededOpenID1()
|
||
|
{
|
||
|
// When the user_setup_url is missing on an OpenID 1 message,
|
||
|
// we assume that it's not a cancel response to
|
||
|
// checkid_immediate
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs(array('mode' => 'id_res'));
|
||
|
$this->assertTrue($message->isOpenID1());
|
||
|
|
||
|
// No SetupNeededError raised
|
||
|
$this->consumer->_checkSetupNeeded($message);
|
||
|
}
|
||
|
|
||
|
function test_setupNeededOpenID2()
|
||
|
{
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs(array(
|
||
|
'mode' => 'setup_needed',
|
||
|
'ns' => Auth_OpenID_OPENID2_NS
|
||
|
));
|
||
|
$this->assertTrue($message->isOpenID2());
|
||
|
$response = $this->consumer->complete($message, null, null);
|
||
|
$this->assertEquals('setup_needed', $response->status);
|
||
|
$this->assertEquals(null, $response->setup_url);
|
||
|
}
|
||
|
|
||
|
function test_setupNeededDoesntWorkForOpenID1()
|
||
|
{
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs(array(
|
||
|
'mode' => 'setup_needed'));
|
||
|
|
||
|
$this->assertFalse($this->consumer._checkSetupNeeded($message));
|
||
|
|
||
|
$response = $this->consumer->complete($message, null, null);
|
||
|
$this->assertEquals('failure', $response->status);
|
||
|
$this->assertTrue(strpos($response->message, 'Invalid openid.mode') === 0);
|
||
|
}
|
||
|
|
||
|
function test_noSetupNeededOpenID2()
|
||
|
{
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs(array(
|
||
|
'mode' => 'id_res',
|
||
|
'game' => 'puerto_rico',
|
||
|
'ns' => Auth_OpenID_OPENID2_NS
|
||
|
));
|
||
|
$this->assertTrue($message->isOpenID2());
|
||
|
|
||
|
$this->assertFalse($this->consumer._checkSetupNeeded($message));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class IdResCheckForFieldsTest extends _TestIdRes {
|
||
|
function setUp() {
|
||
|
# Argh.
|
||
|
$v = null;
|
||
|
$this->consumer = new Auth_OpenID_GenericConsumer($v);
|
||
|
}
|
||
|
|
||
|
function successTest($openid_args, $signed_list) {
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs($openid_args);
|
||
|
$message->setArg(Auth_OpenID_OPENID_NS, 'signed', implode(',', $signed_list));
|
||
|
$result = $this->consumer->_idResCheckForFields($message);
|
||
|
$this->assertFalse(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
|
||
|
function test_openid1Success() {
|
||
|
$this->successTest(
|
||
|
array('return_to' =>'return',
|
||
|
'assoc_handle' =>'assoc handle',
|
||
|
'sig' =>'a signature',
|
||
|
'identity' =>'someone',
|
||
|
),
|
||
|
array('return_to', 'identity'));
|
||
|
}
|
||
|
|
||
|
function test_openid2Success() {
|
||
|
$this->successTest(
|
||
|
array('ns' => Auth_OpenID_OPENID2_NS,
|
||
|
'return_to' =>'return',
|
||
|
'assoc_handle' =>'assoc handle',
|
||
|
'sig' =>'a signature',
|
||
|
'op_endpoint' =>'my favourite server',
|
||
|
'response_nonce' =>'use only once',
|
||
|
),
|
||
|
array('return_to', 'response_nonce', 'assoc_handle', 'op_endpoint'));
|
||
|
}
|
||
|
|
||
|
function test_openid2Success_identifiers() {
|
||
|
$this->successTest(
|
||
|
array('ns' =>Auth_OpenID_OPENID2_NS,
|
||
|
'return_to' =>'return',
|
||
|
'assoc_handle' =>'assoc handle',
|
||
|
'sig' =>'a signature',
|
||
|
'claimed_id' =>'i claim to be me',
|
||
|
'identity' =>'my server knows me as me',
|
||
|
'op_endpoint' =>'my favourite server',
|
||
|
'response_nonce' =>'use only once',
|
||
|
),
|
||
|
array('return_to', 'response_nonce', 'identity',
|
||
|
'claimed_id', 'assoc_handle', 'op_endpoint'));
|
||
|
}
|
||
|
|
||
|
function endswith($str, $it) {
|
||
|
$it_len = strlen($it);
|
||
|
$total = strlen($str);
|
||
|
return (strpos($str, $it) === $total - $it_len);
|
||
|
}
|
||
|
|
||
|
function missingFieldTest($openid_args) {
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs($openid_args);
|
||
|
$result = $this->consumer->_idResCheckForFields($message);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
$this->assertTrue(strpos($result->message, 'Missing required') === 0);
|
||
|
}
|
||
|
|
||
|
function missingSignedTest($openid_args) {
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs($openid_args);
|
||
|
$result = $this->consumer->_idResCheckForFields($message);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
if (Auth_OpenID::isFailure($result)) {
|
||
|
$this->assertTrue($this->endswith($result->message, 'not signed'),
|
||
|
$result->message);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function test_openid1Missing_returnToSig() {
|
||
|
$this->missingSignedTest(
|
||
|
array('return_to' =>'return',
|
||
|
'assoc_handle' =>'assoc handle',
|
||
|
'sig' =>'a signature',
|
||
|
'identity' =>'someone',
|
||
|
'signed' => 'identity,assoc_handle'));
|
||
|
}
|
||
|
|
||
|
function test_openid2Missing_opEndpointSig() {
|
||
|
$this->missingSignedTest(
|
||
|
array('ns' => Auth_OpenID_OPENID2_NS,
|
||
|
'return_to' =>'return',
|
||
|
'assoc_handle' =>'assoc handle',
|
||
|
'sig' =>'a signature',
|
||
|
'identity' =>'someone',
|
||
|
'op_endpoint' => 'the endpoint',
|
||
|
'signed' => 'identity,return_to,assoc_handle'));
|
||
|
}
|
||
|
|
||
|
function test_openid1Missing_identitySig() {
|
||
|
$this->missingSignedTest(
|
||
|
array('return_to' =>'return',
|
||
|
'assoc_handle' =>'assoc handle',
|
||
|
'sig' =>'a signature',
|
||
|
'identity' =>'someone',
|
||
|
'signed' => 'eturn_to'));
|
||
|
}
|
||
|
|
||
|
function test_openid1MissingReturnTo() {
|
||
|
$this->missingFieldTest(
|
||
|
array('assoc_handle' =>'assoc handle',
|
||
|
'sig' =>'a signature',
|
||
|
'identity' =>'someone',
|
||
|
'signed' => 'return_to,identity'));
|
||
|
}
|
||
|
|
||
|
function test_openid1MissingAssocHandle() {
|
||
|
$this->missingFieldTest(
|
||
|
array('return_to' =>'return',
|
||
|
'sig' =>'a signature',
|
||
|
'identity' =>'someone',
|
||
|
'signed' => 'return_to,identity'
|
||
|
));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
define('E_CHECK_AUTH_HAPPENED', 'checkauth occurred');
|
||
|
define('E_MOCK_FETCHER_EXCEPTION', 'mock fetcher exception');
|
||
|
define('E_ASSERTION_ERROR', 'assertion error');
|
||
|
|
||
|
class _CheckAuthDetectingConsumer extends ConfigurableConsumer {
|
||
|
function _verifyDiscoveryResults($message, $endpoint)
|
||
|
{
|
||
|
return $endpoint;
|
||
|
}
|
||
|
|
||
|
function _idResCheckNonce($message, $endpoint)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function _checkAuth($query, $server_url)
|
||
|
{
|
||
|
__raiseError(E_CHECK_AUTH_HAPPENED);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
global $GOODSIG;
|
||
|
$GOODSIG = "[A Good Signature]";
|
||
|
|
||
|
class GoodAssociation {
|
||
|
var $expiresIn = 3600;
|
||
|
var $handle = "-blah-";
|
||
|
|
||
|
function getExpiresIn()
|
||
|
{
|
||
|
return $this->expiresIn;
|
||
|
}
|
||
|
|
||
|
function checkMessageSignature($message)
|
||
|
{
|
||
|
global $GOODSIG;
|
||
|
return $message->getArg(Auth_OpenID_OPENID_NS, 'sig') == $GOODSIG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class GoodAssocStore extends Tests_Auth_OpenID_MemStore {
|
||
|
function getAssociation($server_url, $handle = null)
|
||
|
{
|
||
|
return new GoodAssociation();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class TestIdResCheckSignature extends _TestIdRes {
|
||
|
function setUp()
|
||
|
{
|
||
|
global $GOODSIG;
|
||
|
|
||
|
parent::setUp();
|
||
|
$this->assoc = new GoodAssociation();
|
||
|
$this->assoc->handle = "{not_dumb}";
|
||
|
$this->store->storeAssociation($this->endpoint->server_url, $this->assoc);
|
||
|
|
||
|
$this->message = Auth_OpenID_Message::fromPostArgs(array(
|
||
|
'openid.mode'=> 'id_res',
|
||
|
'openid.identity'=> '=example',
|
||
|
'openid.sig'=> $GOODSIG,
|
||
|
'openid.assoc_handle'=> $this->assoc->handle,
|
||
|
'openid.signed'=> 'mode,identity,assoc_handle,signed',
|
||
|
'frobboz'=> 'banzit'));
|
||
|
}
|
||
|
|
||
|
function test_sign()
|
||
|
{
|
||
|
// assoc_handle to assoc with good sig
|
||
|
$this->consumer->_idResCheckSignature($this->message,
|
||
|
$this->endpoint->server_url);
|
||
|
}
|
||
|
|
||
|
function test_signFailsWithBadSig()
|
||
|
{
|
||
|
$this->message.setArg(Auth_OpenID_OPENID_NS, 'sig', 'BAD SIGNATURE');
|
||
|
$result = $this->consumer->_idResCheckSignature($this->message, $this->endpoint->server_url);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class StatelessConsumer1 extends ConfigurableConsumer {
|
||
|
function _processCheckAuthResponse($response, $server_url)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function _makeKVPost($args, $server_url)
|
||
|
{
|
||
|
return array();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_Stateless1 extends _TestIdRes {
|
||
|
var $consumer_class = "StatelessConsumer1";
|
||
|
|
||
|
function setUp()
|
||
|
{
|
||
|
global $GOODSIG;
|
||
|
|
||
|
parent::setUp();
|
||
|
$this->assoc = new GoodAssociation();
|
||
|
$this->assoc->handle = "{not_dumb}";
|
||
|
$this->store->storeAssociation($this->endpoint->server_url, $this->assoc);
|
||
|
|
||
|
$this->message = Auth_OpenID_Message::fromPostArgs(array(
|
||
|
'openid.mode'=> 'id_res',
|
||
|
'openid.identity'=> '=example',
|
||
|
'openid.sig'=> $GOODSIG,
|
||
|
'openid.assoc_handle'=> $this->assoc->handle,
|
||
|
'openid.signed'=> 'mode,identity,assoc_handle,signed',
|
||
|
'frobboz'=> 'banzit'));
|
||
|
}
|
||
|
|
||
|
function test_stateless()
|
||
|
{
|
||
|
// assoc_handle missing assoc, consumer._checkAuth returns
|
||
|
// goodthings
|
||
|
$this->message->setArg(Auth_OpenID_OPENID_NS, "assoc_handle", "dumbHandle");
|
||
|
$this->consumer->_idResCheckSignature($this->message,
|
||
|
$this->endpoint->server_url);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class StatelessConsumer2 extends ConfigurableConsumer {
|
||
|
function _checkAuth($_, $__)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_Stateless2 extends _TestIdRes {
|
||
|
var $consumer_class = "StatelessConsumer2";
|
||
|
|
||
|
function setUp()
|
||
|
{
|
||
|
global $GOODSIG;
|
||
|
|
||
|
parent::setUp();
|
||
|
$this->assoc = new GoodAssociation();
|
||
|
$this->assoc->handle = "{not_dumb}";
|
||
|
$this->store->storeAssociation($this->endpoint->server_url, $this->assoc);
|
||
|
|
||
|
$this->message = Auth_OpenID_Message::fromPostArgs(array(
|
||
|
'openid.mode'=> 'id_res',
|
||
|
'openid.identity'=> '=example',
|
||
|
'openid.sig'=> $GOODSIG,
|
||
|
'openid.assoc_handle'=> $this->assoc->handle,
|
||
|
'openid.signed'=> 'mode,identity,assoc_handle,signed',
|
||
|
'frobboz'=> 'banzit'));
|
||
|
}
|
||
|
|
||
|
function test_statelessRaisesError()
|
||
|
{
|
||
|
// assoc_handle missing assoc, consumer._checkAuth returns
|
||
|
// goodthings
|
||
|
$this->message->setArg(Auth_OpenID_OPENID_NS, "assoc_handle",
|
||
|
"dumbHandle");
|
||
|
$result = $this->consumer->_idResCheckSignature($this->message,
|
||
|
$this->endpoint->server_url);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_Consumer_CheckNonceTest extends _TestIdRes {
|
||
|
function setUp()
|
||
|
{
|
||
|
parent::setUp();
|
||
|
$this->consumer->openid1_nonce_query_arg_name = 'nonce';
|
||
|
}
|
||
|
|
||
|
function test_openid1Success()
|
||
|
{
|
||
|
// use consumer-generated nonce
|
||
|
$nonce_value = Auth_OpenID_mkNonce();
|
||
|
$this->return_to = sprintf('http://rt.unittest/?nonce=%s',
|
||
|
$nonce_value);
|
||
|
$this->response = Auth_OpenID_Message::fromOpenIDArgs(
|
||
|
array('return_to' => $this->return_to));
|
||
|
$this->response->setArg(Auth_OpenID_BARE_NS, 'nonce', $nonce_value);
|
||
|
|
||
|
$result = $this->consumer->_idResCheckNonce($this->response, $this->endpoint);
|
||
|
$this->assertFalse(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
|
||
|
function test_openid1Missing()
|
||
|
{
|
||
|
// use consumer-generated nonce
|
||
|
$this->response = Auth_OpenID_Message::fromOpenIDArgs(array());
|
||
|
$n = $this->consumer->_idResGetNonceOpenID1($this->response, $this->endpoint);
|
||
|
$this->assertTrue($n === null);
|
||
|
}
|
||
|
|
||
|
function test_consumerNonceOpenID2()
|
||
|
{
|
||
|
// OpenID 2 does not use consumer-generated nonce
|
||
|
$this->return_to = sprintf('http://rt.unittest/?nonce=%s',
|
||
|
Auth_OpenID_mkNonce());
|
||
|
$this->response = Auth_OpenID_Message::fromOpenIDArgs(
|
||
|
array('return_to' => $this->return_to,
|
||
|
'ns' => Auth_OpenID_OPENID2_NS));
|
||
|
$result = $this->consumer->_idResCheckNonce($this->response, $this->endpoint);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
|
||
|
function test_serverNonce()
|
||
|
{
|
||
|
// use server-generated nonce
|
||
|
$this->response = Auth_OpenID_Message::fromOpenIDArgs(
|
||
|
array('ns' => Auth_OpenID_OPENID2_NS,
|
||
|
'response_nonce' => Auth_OpenID_mkNonce()));
|
||
|
$this->consumer->_idResCheckNonce($this->response, $this->endpoint);
|
||
|
}
|
||
|
|
||
|
function test_serverNonceOpenID1()
|
||
|
{
|
||
|
// OpenID 1 does not use server-generated nonce
|
||
|
$this->response = Auth_OpenID_Message::fromOpenIDArgs(
|
||
|
array('ns' => Auth_OpenID_OPENID1_NS,
|
||
|
'return_to'=> 'http://return.to/',
|
||
|
'response_nonce'=> Auth_OpenID_mkNonce()));
|
||
|
$result = $this->consumer->_idResCheckNonce($this->response, $this->endpoint);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
|
||
|
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);
|
||
|
|
||
|
$response = Auth_OpenID_Message::fromOpenIDArgs(array(
|
||
|
'response_nonce' => $nonce,
|
||
|
'ns' => Auth_OpenID_OPENID2_NS
|
||
|
));
|
||
|
|
||
|
$result = $this->consumer->_idResCheckNonce($response,
|
||
|
$this->endpoint);
|
||
|
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
|
||
|
function test_tamperedNonce()
|
||
|
{
|
||
|
// Malformed nonce
|
||
|
$query = array('response_nonce' => 'malformed',
|
||
|
'ns' => Auth_OpenID_OPENID2_NS);
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$result = $this->consumer->_idResCheckNonce($message,
|
||
|
$this->endpoint);
|
||
|
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
|
||
|
function test_missingNonce()
|
||
|
{
|
||
|
// no nonce parameter on the return_to
|
||
|
$query = array('openid.return_to' => $this->return_to);
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$result = $this->consumer->_idResCheckNonce($message,
|
||
|
$this->endpoint);
|
||
|
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_Consumer_TestCheckAuthTriggered extends _TestIdRes {
|
||
|
var $consumer_class = '_CheckAuthDetectingConsumer';
|
||
|
|
||
|
function _doIdRes($message, $endpoint, $return_to)
|
||
|
{
|
||
|
return $this->consumer->_doIdRes($message, $endpoint, $return_to);
|
||
|
}
|
||
|
|
||
|
function test_checkAuthTriggered()
|
||
|
{
|
||
|
$query = array('openid.return_to' => $this->return_to,
|
||
|
'openid.identity' => $this->server_id,
|
||
|
'openid.assoc_handle' =>'not_found',
|
||
|
'openid.sig' => 'bogus',
|
||
|
'openid.signed' => 'identity,return_to');
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
|
||
|
$result = $this->_doIdRes($message, $this->endpoint, null);
|
||
|
|
||
|
$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',
|
||
|
'openid.sig' => 'bogus',
|
||
|
'openid.signed' => 'return_to,identity');
|
||
|
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$result = $this->_doIdRes($message, $this->endpoint, null);
|
||
|
$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.sig' => 'bogus',
|
||
|
'openid.signed' => 'identity,return_to',
|
||
|
'openid.assoc_handle' => $handle);
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
|
||
|
$info = $this->_doIdRes($message, $this->endpoint, null);
|
||
|
|
||
|
$this->assertEquals('failure', $info->status);
|
||
|
|
||
|
$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);
|
||
|
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
$message = $good_assoc->signMessage($message);
|
||
|
|
||
|
$info = $this->_doIdRes($message, $this->endpoint, null);
|
||
|
|
||
|
$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');
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
|
||
|
$r = $this->consumer->complete($message, $this->endpoint, null);
|
||
|
$this->assertEquals($r->status, Auth_OpenID_CANCEL);
|
||
|
$this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
|
||
|
}
|
||
|
|
||
|
function test_cancel_with_return_to() {
|
||
|
$message = Auth_OpenID_Message::fromPostArgs(array('openid.mode' => 'cancel'));
|
||
|
$r = $this->consumer->complete($message, $this->endpoint, $this->return_to);
|
||
|
$this->assertEquals($r->status, Auth_OpenID_CANCEL);
|
||
|
$this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
|
||
|
}
|
||
|
|
||
|
function test_errorWithNoOptionalKeys()
|
||
|
{
|
||
|
$msg = 'an error message';
|
||
|
$contact = 'some contact info here';
|
||
|
$message = Auth_OpenID_Message::fromPostArgs(array('openid.mode'=> 'error',
|
||
|
'openid.error'=> $msg,
|
||
|
'openid.contact'=> $contact));
|
||
|
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
|
||
|
$r = $this->consumer->complete($message, $this->endpoint, null);
|
||
|
$this->assertEquals($r->status, Auth_OpenID_FAILURE);
|
||
|
$this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
|
||
|
$this->assertTrue($r->contact == $contact);
|
||
|
$this->assertTrue($r->reference === null);
|
||
|
$this->assertEquals($r->message, $msg);
|
||
|
}
|
||
|
|
||
|
function test_errorWithOptionalKeys()
|
||
|
{
|
||
|
$msg = 'an error message';
|
||
|
$contact = 'me';
|
||
|
$reference = 'support ticket';
|
||
|
$message = Auth_OpenID_Message::fromPostArgs(array('openid.mode'=> 'error',
|
||
|
'openid.error'=> $msg, 'openid.reference'=> $reference,
|
||
|
'openid.contact'=> $contact, 'openid.ns'=> Auth_OpenID_OPENID2_NS
|
||
|
));
|
||
|
$r = $this->consumer->complete($message, $this->endpoint, null);
|
||
|
$this->assertEquals($r->status, Auth_OpenID_FAILURE);
|
||
|
$this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
|
||
|
$this->assertTrue($r->contact == $contact);
|
||
|
$this->assertTrue($r->reference == $reference);
|
||
|
$this->assertEquals($r->message, $msg);
|
||
|
}
|
||
|
|
||
|
function test_error()
|
||
|
{
|
||
|
$msg = 'an error message';
|
||
|
$query = array('openid.mode' =>'error',
|
||
|
'openid.error' => $msg);
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
|
||
|
$r = $this->consumer->complete($message, $this->endpoint, null);
|
||
|
$this->assertEquals($r->status, Auth_OpenID_FAILURE);
|
||
|
$this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
|
||
|
$this->assertEquals($r->message, $msg);
|
||
|
}
|
||
|
|
||
|
function test_noMode()
|
||
|
{
|
||
|
$query = array();
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
$r = $this->consumer->complete($message, $this->endpoint, null);
|
||
|
$this->assertEquals($r->status, Auth_OpenID_FAILURE);
|
||
|
$this->assertTrue($r->identity_url == $this->endpoint->claimed_id);
|
||
|
}
|
||
|
|
||
|
function test_idResMissingField()
|
||
|
{
|
||
|
$query = array('openid.mode' => 'id_res');
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
$r = $this->consumer->complete($message, $this->endpoint, null);
|
||
|
$this->assertTrue(Auth_openID::isFailure($r));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class _VerifiedError extends Auth_OpenID_FailureResponse {
|
||
|
}
|
||
|
|
||
|
class Consumer_idResURLMismatch extends ConfigurableConsumer {
|
||
|
function _discoverAndVerify($to_match)
|
||
|
{
|
||
|
return new _VerifiedError(null, 'verified error');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_idResURLMismatch extends _TestIdRes {
|
||
|
var $consumer_class = 'Consumer_idResURLMismatch';
|
||
|
|
||
|
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',
|
||
|
'openid.signed' => 'identity,return_to',
|
||
|
'openid.sig' => 'bogus');
|
||
|
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
$r = $this->consumer->complete($message, $this->endpoint, null);
|
||
|
$this->assertTrue(is_a($r, '_VerifiedError'));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class SetupNeededConsumer extends Auth_OpenID_GenericConsumer {
|
||
|
function _checkSetupNeeded($message)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_SetupNeeded extends _TestIdRes {
|
||
|
function test_setupNeededIdRes()
|
||
|
{
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs(array('mode'=> 'id_res'));
|
||
|
$response = $this->consumer->complete($message, null, null);
|
||
|
$this->assertEquals(Auth_OpenID_SETUP_NEEDED,
|
||
|
$response->status);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class TempConsumer extends ConfigurableConsumer {
|
||
|
function _verifyDiscoveryResults($message, $endpoint)
|
||
|
{
|
||
|
return $endpoint;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class TestCompleteMissingSig extends PHPUnit_Framework_TestCase {
|
||
|
|
||
|
function setUp()
|
||
|
{
|
||
|
global $GOODSIG;
|
||
|
|
||
|
$this->store = new GoodAssocStore();
|
||
|
$this->consumer = new ConfigurableConsumer($this->store);
|
||
|
$this->server_url = "http://idp.unittest/";
|
||
|
|
||
|
$claimed_id = 'bogus.claimed';
|
||
|
|
||
|
$this->message = Auth_OpenID_Message::fromOpenIDArgs(
|
||
|
array('mode'=> 'id_res',
|
||
|
'return_to'=> 'return_to (just anything)',
|
||
|
'identity'=> $claimed_id,
|
||
|
'assoc_handle'=> 'does not matter',
|
||
|
'sig'=> $GOODSIG,
|
||
|
'response_nonce'=> Auth_OpenID_mkNonce(),
|
||
|
'signed'=> 'identity,return_to,response_nonce,assoc_handle,claimed_id,op_endpoint',
|
||
|
'claimed_id'=> $claimed_id,
|
||
|
'op_endpoint'=> $this->server_url,
|
||
|
'ns' => Auth_OpenID_OPENID2_NS));
|
||
|
|
||
|
$this->endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$this->endpoint->server_url = $this->server_url;
|
||
|
$this->endpoint->claimed_id = $claimed_id;
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
}
|
||
|
|
||
|
function test_idResMissingNoSigs()
|
||
|
{
|
||
|
$c = new TempConsumer($this->store);
|
||
|
$c->disableReturnToChecking();
|
||
|
$r = $c->complete($this->message, $this->endpoint, null);
|
||
|
$this->failUnlessSuccess($r);
|
||
|
}
|
||
|
|
||
|
function test_idResNoIdentity()
|
||
|
{
|
||
|
$this->message->delArg(Auth_OpenID_OPENID_NS, 'identity');
|
||
|
$this->message->delArg(Auth_OpenID_OPENID_NS, 'claimed_id');
|
||
|
$this->endpoint->claimed_id = null;
|
||
|
$this->message->setArg(Auth_OpenID_OPENID_NS,
|
||
|
'signed', 'return_to,response_nonce,assoc_handle,op_endpoint');
|
||
|
$r = $this->consumer->complete($this->message, $this->endpoint, null);
|
||
|
$this->failUnlessSuccess($r);
|
||
|
}
|
||
|
|
||
|
function test_idResMissingIdentitySig()
|
||
|
{
|
||
|
$this->message->setArg(Auth_OpenID_OPENID_NS,
|
||
|
'signed',
|
||
|
'return_to,response_nonce,assoc_handle,claimed_id,op_endpoint');
|
||
|
$r = $this->consumer->complete($this->message, $this->endpoint, null);
|
||
|
$this->assertEquals($r->status, Auth_OpenID_FAILURE);
|
||
|
}
|
||
|
|
||
|
function test_idResMissingReturnToSig()
|
||
|
{
|
||
|
$this->message->setArg(Auth_OpenID_OPENID_NS,
|
||
|
'signed',
|
||
|
'identity,response_nonce,assoc_handle,claimed_id');
|
||
|
$r = $this->consumer->complete($this->message, $this->endpoint, null);
|
||
|
$this->assertEquals($r->status, Auth_OpenID_FAILURE);
|
||
|
}
|
||
|
|
||
|
function test_idResMissingAssocHandleSig()
|
||
|
{
|
||
|
$this->message->setArg(Auth_OpenID_OPENID_NS, 'signed',
|
||
|
'identity,response_nonce,return_to,claimed_id');
|
||
|
$r = $this->consumer->complete($this->message, $this->endpoint, null);
|
||
|
$this->assertEquals($r->status, Auth_OpenID_FAILURE);
|
||
|
}
|
||
|
|
||
|
function test_idResMissingClaimedIDSig()
|
||
|
{
|
||
|
$this->message->setArg(Auth_OpenID_OPENID_NS, 'signed',
|
||
|
'identity,response_nonce,return_to,assoc_handle');
|
||
|
$r = $this->consumer->complete($this->message, $this->endpoint, null);
|
||
|
$this->assertEquals($r->status, Auth_OpenID_FAILURE);
|
||
|
}
|
||
|
|
||
|
function failUnlessSuccess($response)
|
||
|
{
|
||
|
if ($response->status != Auth_OpenID_SUCCESS) {
|
||
|
$this->fail(sprintf("Non-successful response: %s", $response->status));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class TestReturnToArgs extends PHPUnit_Framework_TestCase {
|
||
|
function setUp()
|
||
|
{
|
||
|
$store = null;
|
||
|
$this->consumer = new Auth_OpenID_GenericConsumer($store);
|
||
|
}
|
||
|
|
||
|
function test_returnToArgsUnexpectedArg()
|
||
|
{
|
||
|
$query = array(
|
||
|
'openid.mode' => 'id_res',
|
||
|
'openid.return_to' => 'http://example.com/',
|
||
|
'foo' => 'bar');
|
||
|
|
||
|
// no return value, success is assumed if there are no
|
||
|
// exceptions.
|
||
|
$this->assertTrue(Auth_OpenID::isFailure(
|
||
|
$this->consumer->_verifyReturnToArgs($query)));
|
||
|
}
|
||
|
|
||
|
function test_returnToArgsOkay()
|
||
|
{
|
||
|
$query = array(
|
||
|
'openid.mode'=> 'id_res',
|
||
|
'openid.return_to'=> 'http://example.com/?foo=bar',
|
||
|
'foo'=> 'bar'
|
||
|
);
|
||
|
// no return value, success is assumed if there are no exceptions.
|
||
|
$result = $this->consumer->_verifyReturnToArgs($query);
|
||
|
|
||
|
$this->assertFalse(Auth_OpenID::isFailure($result));
|
||
|
$this->assertTrue($result);
|
||
|
}
|
||
|
|
||
|
function test_returnToMismatch()
|
||
|
{
|
||
|
$query = array(
|
||
|
'openid.mode' => 'id_res',
|
||
|
'openid.return_to' => 'http://example.com/?foo=bar');
|
||
|
|
||
|
// fail, query has no key 'foo'.
|
||
|
$result = $this->consumer->_verifyReturnToArgs($query);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
|
||
|
$query['foo'] = 'baz';
|
||
|
// fail, values for 'foo' do not match.
|
||
|
$result = $this->consumer->_verifyReturnToArgs($query);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
|
||
|
function test_noReturnTo()
|
||
|
{
|
||
|
$query = array('openid.mode'=> 'id_res');
|
||
|
$result = $this->consumer->_verifyReturnToArgs($query);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
|
||
|
function test_completeBadReturnTo()
|
||
|
{
|
||
|
// Test GenericConsumer.complete()'s handling of bad return_to
|
||
|
// values.
|
||
|
$return_to = "http://some.url/path?foo=bar";
|
||
|
|
||
|
// Scheme, authority, and path differences are checked by
|
||
|
// GenericConsumer._checkReturnTo. Query args checked by
|
||
|
// GenericConsumer._verifyReturnToArgs.
|
||
|
$bad_return_tos = array(
|
||
|
// Scheme only
|
||
|
"https://some.url/path?foo=bar",
|
||
|
// Authority only
|
||
|
"http://some.url.invalid/path?foo=bar",
|
||
|
// Path only
|
||
|
"http://some.url/path_extra?foo=bar",
|
||
|
// Query args differ
|
||
|
"http://some.url/path?foo=bar2",
|
||
|
"http://some.url/path?foo2=bar"
|
||
|
);
|
||
|
|
||
|
$m = new Auth_OpenID_Message(Auth_OpenID_OPENID1_NS);
|
||
|
$m->setArg(Auth_OpenID_OPENID_NS, 'mode', 'cancel');
|
||
|
$m->setArg(Auth_OpenID_BARE_NS, 'foo', 'bar');
|
||
|
$endpoint = null;
|
||
|
|
||
|
foreach ($bad_return_tos as $bad) {
|
||
|
$m->setArg(Auth_OpenID_OPENID_NS, 'return_to', $bad);
|
||
|
$this->assertFalse($this->consumer->_checkReturnTo($m, $return_to));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function test_completeGoodReturnTo()
|
||
|
{
|
||
|
// Test GenericConsumer.complete()'s handling of good
|
||
|
// return_to values.
|
||
|
$return_to = "http://some.url/path";
|
||
|
|
||
|
$good_return_tos = array(
|
||
|
array($return_to,
|
||
|
array()),
|
||
|
array($return_to . "?another=arg",
|
||
|
array(array(
|
||
|
array(Auth_OpenID_BARE_NS, 'another'),
|
||
|
'arg'))),
|
||
|
array($return_to . "?another=arg#fragment",
|
||
|
array(array(
|
||
|
array(Auth_OpenID_BARE_NS, 'another'),
|
||
|
'arg'))),
|
||
|
array("HTTP://some.url/path",array()),
|
||
|
array("http://some.URL/path",array()),
|
||
|
array("http://some.url:80/path",array()),
|
||
|
array("http://some.url/./path",array())
|
||
|
);
|
||
|
|
||
|
$endpoint = null;
|
||
|
|
||
|
foreach ($good_return_tos as $pair) {
|
||
|
list($good_return_to, $extra) = $pair;
|
||
|
$m = new Auth_OpenID_Message(Auth_OpenID_OPENID1_NS);
|
||
|
$m->setArg(Auth_OpenID_OPENID_NS, 'mode', 'cancel');
|
||
|
|
||
|
for ($i = 0; $i < count($extra); $i++) {
|
||
|
list($ckey, $value) = $extra[$i];
|
||
|
$ns = $ckey[0];
|
||
|
$key = $ckey[1];
|
||
|
$m->setArg($ns, $key, $value);
|
||
|
}
|
||
|
|
||
|
$m->setArg(Auth_OpenID_OPENID_NS, 'return_to', $good_return_to);
|
||
|
$result = $this->consumer->complete($m, $endpoint, $return_to);
|
||
|
$this->assertTrue(is_a($result, 'Auth_OpenID_CancelResponse'));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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');
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs($response);
|
||
|
$r = $this->consumer->_processCheckAuthResponse($message, $this->server_url);
|
||
|
$this->assertTrue($r);
|
||
|
}
|
||
|
|
||
|
function test_missingAnswer()
|
||
|
{
|
||
|
// check_authentication returns false when the server sends no
|
||
|
// answer
|
||
|
$response = array();
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($response);
|
||
|
$r = $this->consumer->_processCheckAuthResponse($message, $this->server_url);
|
||
|
$this->assertFalse($r);
|
||
|
}
|
||
|
|
||
|
function test_badResponse()
|
||
|
{
|
||
|
// check_authentication returns false when is_valid is false
|
||
|
$response = array('is_valid' => 'false');
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs($response);
|
||
|
|
||
|
$r = $this->consumer->_processCheckAuthResponse($message, $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');
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs($response);
|
||
|
|
||
|
$r = $this->consumer->_processCheckAuthResponse($message,
|
||
|
$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');
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs($response);
|
||
|
|
||
|
$r = $this->consumer->_processCheckAuthResponse($message, $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');
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromOpenIDArgs($response);
|
||
|
|
||
|
$r = $this->consumer->_processCheckAuthResponse($message, $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($message, $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');
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
$r = $this->consumer->complete($message, $this->endpoint, null);
|
||
|
$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);
|
||
|
|
||
|
return new Auth_Yadis_HTTPResponse($url, 400,
|
||
|
array(), '');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class _BadArgCheckingConsumer extends Auth_OpenID_GenericConsumer {
|
||
|
function _makeKVPost($message, $tmp)
|
||
|
{
|
||
|
$args = $message->toPostArgs();
|
||
|
|
||
|
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 Auth_Yadis_HTTPResponse("http://some_url",
|
||
|
404,
|
||
|
array(),
|
||
|
"blah:blah\n");
|
||
|
$query = array('openid.signed' => 'stuff, things');
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$r = $this->consumer->_checkAuth($message, $_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);
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$this->assertFalse($consumer->_checkAuth($message, 'does://not.matter'));
|
||
|
}
|
||
|
|
||
|
function test_signedList()
|
||
|
{
|
||
|
$signed = 'identity,mode,ns.sreg,sreg.email';
|
||
|
$query = Auth_OpenID_Message::fromOpenIDArgs(array(
|
||
|
'mode'=> 'id_res',
|
||
|
'sig'=> 'rabbits',
|
||
|
'identity'=> '=example',
|
||
|
'assoc_handle'=> 'munchkins',
|
||
|
'ns.sreg' => 'urn:sreg',
|
||
|
'sreg.email' => 'bogus@example.com',
|
||
|
'signed'=> $signed,
|
||
|
'foo'=> 'bar'));
|
||
|
|
||
|
$args = $this->consumer->_createCheckAuthRequest($query);
|
||
|
$this->assertTrue($args->isOpenID1());
|
||
|
$signed_list = explode(',',$signed);
|
||
|
foreach ($signed_list as $k) {
|
||
|
$this->assertTrue($args->getAliasedArg($k));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
function test_112()
|
||
|
{
|
||
|
$args = array('openid.assoc_handle' => 'fa1f5ff0-cde4-11dc-a183-3714bfd55ca8',
|
||
|
'openid.claimed_id' => 'http://binkley.lan/user/test01',
|
||
|
'openid.identity' => 'http://test01.binkley.lan/',
|
||
|
'openid.mode' => 'id_res',
|
||
|
'openid.ns' => 'http://specs.openid.net/auth/2.0',
|
||
|
'openid.ns.pape' => 'http://specs.openid.net/extensions/pape/1.0',
|
||
|
'openid.op_endpoint' => 'http://binkley.lan/server',
|
||
|
'openid.pape.auth_policies' => 'none',
|
||
|
'openid.pape.auth_time' => '2008-01-28T20 =>42 =>36Z',
|
||
|
'openid.pape.nist_auth_level' => '0',
|
||
|
'openid.response_nonce' => '2008-01-28T21 =>07 =>04Z99Q=',
|
||
|
'openid.return_to' => 'http://binkley.lan =>8001/process?janrain_nonce=2008-01-28T21%3A07%3A02Z0tMIKx',
|
||
|
'openid.sig' => 'YJlWH4U6SroB1HoPkmEKx9AyGGg=',
|
||
|
'openid.signed' => 'assoc_handle,identity,response_nonce,return_to,claimed_id,op_endpoint,pape.auth_time,ns.pape,pape.nist_auth_level,pape.auth_policies'
|
||
|
);
|
||
|
$this->assertEquals(Auth_OpenID_OPENID2_NS, $args['openid.ns']);
|
||
|
$incoming = Auth_OpenID_Message::fromPostArgs($args);
|
||
|
$this->assertTrue($incoming->isOpenID2());
|
||
|
$car = $this->consumer->_createCheckAuthRequest($incoming);
|
||
|
$expected_args = $args;
|
||
|
$expected_args['openid.mode'] = 'check_authentication';
|
||
|
$expected = Auth_OpenID_Message::fromPostArgs($expected_args);
|
||
|
$this->assertTrue($expected->isOpenID2());
|
||
|
$this->assertEquals($expected, $car);
|
||
|
$this->assertEquals($expected_args, $car->toPostArgs());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_Consumer_TestFetchAssoc extends PHPUnit_Framework_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 Auth_Yadis_HTTPResponse("http://some_url",
|
||
|
404,
|
||
|
array(),
|
||
|
"blah:blah\n");
|
||
|
$query = array('openid.mode' => 'associate');
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$r = $this->consumer->_makeKVPost($message,
|
||
|
"http://server_url");
|
||
|
if ($r !== null) {
|
||
|
$this->fail("Expected _makeKVPost result to be null");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function test_error_404()
|
||
|
{
|
||
|
// 404 from a kv post raises HTTPFetchingError
|
||
|
$this->fetcher->response = new Auth_Yadis_HTTPResponse(
|
||
|
"http://some_url", 404, array('Hea'=> 'der'), 'blah:blah\n');
|
||
|
|
||
|
$result = $this->consumer->_makeKVPost(
|
||
|
Auth_OpenID_Message::fromPostArgs(array('mode'=>'associate')),
|
||
|
"http://server_url");
|
||
|
|
||
|
$this->assertTrue($result === null);
|
||
|
}
|
||
|
|
||
|
function test_error_exception()
|
||
|
{
|
||
|
$this->consumer->fetcher = new _ExceptionRaisingMockFetcher();
|
||
|
|
||
|
$query = array('openid.mode' => 'associate');
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$this->consumer->_makeKVPost($message,
|
||
|
"http://server_url");
|
||
|
|
||
|
if (__getError() !== E_MOCK_FETCHER_EXCEPTION) {
|
||
|
$this->fail("Expected ExceptionRaisingMockFetcher to " .
|
||
|
"raise E_MOCK_FETCHER_EXCEPTION");
|
||
|
}
|
||
|
|
||
|
$endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$endpoint->server_url = 'some://url';
|
||
|
|
||
|
// exception fetching returns no association
|
||
|
$this->assertEquals($this->consumer->_getAssociation($endpoint),
|
||
|
null);
|
||
|
|
||
|
$query = array('openid.signed' => '');
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$this->consumer->_checkAuth($message,
|
||
|
'some://url');
|
||
|
|
||
|
if (__getError() !== E_MOCK_FETCHER_EXCEPTION) {
|
||
|
$this->fail("Expected ExceptionRaisingMockFetcher to " .
|
||
|
"raise E_MOCK_FETCHER_EXCEPTION (_checkAuth)");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_AuthRequestHTMLMarkup extends PHPUnit_Framework_TestCase {
|
||
|
function setUp()
|
||
|
{
|
||
|
$this->endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$this->endpoint->claimed_id = 'identity_url';
|
||
|
|
||
|
$this->request = new Auth_OpenID_AuthRequest($this->endpoint, null);
|
||
|
}
|
||
|
|
||
|
function test_htmlMarkup()
|
||
|
{
|
||
|
$html = $this->request->htmlMarkup('http://realm.com/',
|
||
|
'http://realm.com/return_to');
|
||
|
$this->assertTrue(strpos($html,"<html>") !== false);
|
||
|
$this->assertTrue(strpos($html,"</html>") !== false);
|
||
|
$this->assertTrue(strpos($html,"<body onload") !== false);
|
||
|
$this->assertTrue(strpos($html,"</body>") !== false);
|
||
|
$this->assertTrue(strpos($html,"<form") !== false);
|
||
|
$this->assertTrue(strpos($html,"</form>") !== false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_SuccessResponse extends PHPUnit_Framework_TestCase {
|
||
|
function setUp()
|
||
|
{
|
||
|
$this->endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$this->endpoint->claimed_id = 'identity_url';
|
||
|
}
|
||
|
|
||
|
function test_extensionResponse()
|
||
|
{
|
||
|
$uri = "http://bogus.unittest/1.0";
|
||
|
|
||
|
$query = array(
|
||
|
'openid.ns.unittest' => $uri,
|
||
|
'openid.unittest.one' => '1',
|
||
|
'openid.unittest.two' =>'2',
|
||
|
'openid.sreg.nickname' => 'j3h',
|
||
|
'openid.return_to' => 'return_to');
|
||
|
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
$resp = new Auth_OpenID_SuccessResponse($this->endpoint, $message);
|
||
|
|
||
|
$utargs = $resp->extensionResponse($uri, false);
|
||
|
$this->assertEquals($utargs, array('one' => '1', 'two' => '2'));
|
||
|
$sregargs = $resp->extensionResponse(Auth_OpenID_SREG_NS_URI, false);
|
||
|
$this->assertEquals($sregargs, array('nickname' => 'j3h'));
|
||
|
}
|
||
|
|
||
|
function test_extensionResponseSigned()
|
||
|
{
|
||
|
$args = array(
|
||
|
'ns.sreg' => 'urn:sreg',
|
||
|
'ns.unittest' => 'urn:unittest',
|
||
|
'unittest.one' => '1',
|
||
|
'unittest.two' => '2',
|
||
|
'sreg.nickname' => 'j3h',
|
||
|
'sreg.dob' => 'yesterday',
|
||
|
'return_to' => 'return_to',
|
||
|
'signed' => 'sreg.nickname,unittest.one,sreg.dob');
|
||
|
|
||
|
$signed_list = array('openid.sreg.nickname',
|
||
|
'openid.unittest.one',
|
||
|
'openid.sreg.dob',
|
||
|
'openid.ns.sreg');
|
||
|
|
||
|
$msg = Auth_OpenID_Message::fromOpenIDArgs($args);
|
||
|
$resp = new Auth_OpenID_SuccessResponse($this->endpoint, $msg, $signed_list);
|
||
|
|
||
|
// All args in this NS are signed, so expect all.
|
||
|
$sregargs = $resp->extensionResponse('urn:sreg', true);
|
||
|
$this->assertEquals($sregargs,
|
||
|
array('nickname' => 'j3h',
|
||
|
'dob' => 'yesterday'));
|
||
|
|
||
|
// Not all args in this NS are signed, so expect null when
|
||
|
// asking for them.
|
||
|
$utargs = $resp->extensionResponse('urn:unittest', true);
|
||
|
$this->assertEquals($utargs, null);
|
||
|
}
|
||
|
|
||
|
function test_noReturnTo()
|
||
|
{
|
||
|
$message = Auth_OpenID_Message::fromPostArgs(array());
|
||
|
$resp = new Auth_OpenID_SuccessResponse($this->endpoint, $message);
|
||
|
$this->assertTrue($resp->getReturnTo() === null);
|
||
|
}
|
||
|
|
||
|
function test_returnTo()
|
||
|
{
|
||
|
$query = array('openid.return_to' => 'return_to');
|
||
|
$message = Auth_OpenID_Message::fromPostArgs($query);
|
||
|
|
||
|
$resp = new Auth_OpenID_SuccessResponse($this->endpoint,
|
||
|
$message, array('openid.return_to'));
|
||
|
|
||
|
$this->assertEquals($resp->getReturnTo(), 'return_to');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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($service, $this->assoc);
|
||
|
$this->endpoint = $service;
|
||
|
return $auth_req;
|
||
|
}
|
||
|
|
||
|
function complete($message, $endpoint, $return_to)
|
||
|
{
|
||
|
return $this->response;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_DiscoFailure extends PHPUnit_Framework_TestCase {
|
||
|
var $consumerClass = null;
|
||
|
|
||
|
function setUp()
|
||
|
{
|
||
|
foreach ($_SESSION as $k => $v) {
|
||
|
unset($_SESSION[$k]);
|
||
|
}
|
||
|
|
||
|
$this->endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$this->claimed_id = 'http://identity.url/';
|
||
|
$this->endpoint->claimed_id = $this->claimed_id;
|
||
|
$this->store = null;
|
||
|
$this->session = new Auth_Yadis_PHPSession();
|
||
|
$cls = $this->consumerClass;
|
||
|
$this->consumer = new $cls($this->store, $this->session);
|
||
|
$this->consumer->consumer = new _StubConsumer();
|
||
|
$this->discovery = new Auth_Yadis_Discovery($this->session,
|
||
|
$this->claimed_id,
|
||
|
$this->consumer->session_key_prefix);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Consumer_completeEmptySession extends Auth_OpenID_GenericConsumer {
|
||
|
var $test_case = null;
|
||
|
var $text = "failed complete";
|
||
|
|
||
|
function complete($message, $endpoint, $return_to)
|
||
|
{
|
||
|
$this->test_case->assertTrue($endpoint === null);
|
||
|
return new Auth_OpenID_FailureResponse($endpoint, $this->text);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_ConsumerTest2 extends PHPUnit_Framework_TestCase {
|
||
|
function setUp()
|
||
|
{
|
||
|
foreach ($_SESSION as $k => $v) {
|
||
|
unset($_SESSION[$k]);
|
||
|
}
|
||
|
|
||
|
$this->endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$this->claimed_id = 'http://identity.url/';
|
||
|
$this->endpoint->claimed_id = $this->claimed_id;
|
||
|
$this->store = null;
|
||
|
$this->session = new Auth_Yadis_PHPSession();
|
||
|
$this->consumer = new Auth_OpenID_Consumer($this->store, $this->session);
|
||
|
$this->consumer->consumer = new _StubConsumer();
|
||
|
$this->discovery = new Auth_Yadis_Discovery($this->session,
|
||
|
$this->claimed_id,
|
||
|
$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()
|
||
|
{
|
||
|
$this->consumer->consumer = new Consumer_completeEmptySession($this->store);
|
||
|
$this->consumer->consumer->test_case =& $this;
|
||
|
|
||
|
$response = $this->consumer->complete(null);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($response));
|
||
|
$this->assertEquals($this->consumer->consumer->text, $response->message);
|
||
|
$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(null);
|
||
|
|
||
|
// All responses should have the same identity URL, and the
|
||
|
// session should be cleaned out
|
||
|
if ($this->endpoint->claimed_id != Auth_OpenID_IDENTIFIER_SELECT) {
|
||
|
$this->assertTrue($resp->identity_url == $this->claimed_id);
|
||
|
}
|
||
|
|
||
|
$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;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Be sure that the session gets cleaned up when the response is
|
||
|
* successful and has a different URL than the one in the request.
|
||
|
*/
|
||
|
function test_successDifferentURL()
|
||
|
{
|
||
|
// Set up a request endpoint describing an IDP URL
|
||
|
$this->identity_url = 'http://idp.url/';
|
||
|
$this->endpoint->claimed_id = $this->endpoint->local_id = Auth_OpenID_IDENTIFIER_SELECT;
|
||
|
|
||
|
// Use a response endpoint with a different URL (asserted by
|
||
|
// the IDP)
|
||
|
$resp_endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$resp_endpoint->claimed_id = "http://user.url/";
|
||
|
|
||
|
$resp = $this->_doRespDisco(
|
||
|
true,
|
||
|
mkSuccess($resp_endpoint, array()));
|
||
|
$this->assertTrue($this->discovery->getManager(true) === null);
|
||
|
}
|
||
|
|
||
|
function test_noDiscoCompleteSuccessWithToken()
|
||
|
{
|
||
|
$message = Auth_OpenID_Message::fromPostArgs(array());
|
||
|
$this->_doRespNoDisco(new Auth_OpenID_SuccessResponse($this->endpoint,
|
||
|
$message));
|
||
|
}
|
||
|
|
||
|
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->claimed_id);
|
||
|
$auth_req = $this->consumer->begin($this->claimed_id);
|
||
|
$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()
|
||
|
{
|
||
|
$message = Auth_OpenID_Message::fromPostArgs(array());
|
||
|
$this->_doRespDisco(true,
|
||
|
new Auth_OpenID_SuccessResponse($this->endpoint,
|
||
|
$message));
|
||
|
}
|
||
|
|
||
|
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->claimed_id);
|
||
|
// Should not raise an exception
|
||
|
$auth_req = $this->consumer->begin($this->claimed_id);
|
||
|
$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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class IDPDrivenTest_Consumer1 extends ConfigurableConsumer {
|
||
|
var $iverified = array();
|
||
|
var $endpoint = null;
|
||
|
var $failure_cb = null;
|
||
|
var $check_endpoint = null;
|
||
|
|
||
|
function _idResCheckNonce($message, $endpoint)
|
||
|
{
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
function _verifyDiscoveryResults($identifier, $endpoint)
|
||
|
{
|
||
|
call_user_func($this->failure_cb,
|
||
|
$endpoint === $this->check_endpoint);
|
||
|
$this->iverified[] = $this->endpoint;
|
||
|
return $this->endpoint;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class IDPDrivenTest_Consumer2 extends ConfigurableConsumer {
|
||
|
function verifyDiscoveryResults($identifier, $endp)
|
||
|
{
|
||
|
return new Auth_OpenID_FailureResponse(null,
|
||
|
"Bogus");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class IDPDrivenTest extends PHPUnit_Framework_TestCase {
|
||
|
function setUp()
|
||
|
{
|
||
|
$this->store = new GoodAssocStore();
|
||
|
$this->consumer = new ConfigurableConsumer($this->store);
|
||
|
$this->endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$this->endpoint->server_url = "http://idp.unittest/";
|
||
|
}
|
||
|
|
||
|
function test_idpDrivenBegin()
|
||
|
{
|
||
|
// Testing here that the token-handling doesn't explode...
|
||
|
$this->assertTrue($this->consumer->begin($this->endpoint) !== null);
|
||
|
}
|
||
|
|
||
|
function test_idpDrivenComplete()
|
||
|
{
|
||
|
global $GOODSIG;
|
||
|
|
||
|
$this->consumer = new IDPDrivenTest_Consumer1($this->store);
|
||
|
$this->consumer->failure_cb = array($this, "assertTrue");
|
||
|
$this->consumer->check_endpoint =& $this->endpoint;
|
||
|
|
||
|
$identifier = '=directed_identifier';
|
||
|
$message = Auth_OpenID_Message::fromPostArgs(array(
|
||
|
'openid.identity'=> '=directed_identifier',
|
||
|
'openid.return_to'=> 'x',
|
||
|
'openid.assoc_handle'=> 'z',
|
||
|
'openid.signed'=> 'identity,return_to',
|
||
|
'openid.sig'=> $GOODSIG));
|
||
|
|
||
|
$endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$endpoint->claimed_id = $identifier;
|
||
|
$endpoint->server_url = $this->endpoint->server_url;
|
||
|
$endpoint->local_id = $identifier;
|
||
|
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
|
||
|
$this->consumer->endpoint =& $endpoint;
|
||
|
$response = $this->consumer->_doIdRes($message, $this->endpoint, null);
|
||
|
|
||
|
$this->failUnlessSuccess($response);
|
||
|
|
||
|
$this->assertEquals($response->identity_url, "=directed_identifier");
|
||
|
|
||
|
// assert that discovery attempt happens and returns good
|
||
|
$this->assertEquals($this->consumer->iverified, array($endpoint));
|
||
|
}
|
||
|
|
||
|
function test_idpDrivenCompleteFraud()
|
||
|
{
|
||
|
global $GOODSIG;
|
||
|
|
||
|
$this->consumer = new IDPDrivenTest_Consumer2($this->store);
|
||
|
|
||
|
// crap with an identifier that doesn't match discovery info
|
||
|
$message = Auth_OpenID_Message::fromPostArgs(array(
|
||
|
'openid.identity'=> '=directed_identifier',
|
||
|
'openid.return_to'=> 'x',
|
||
|
'openid.assoc_handle'=> 'z',
|
||
|
'openid.signed'=> 'identity,return_to',
|
||
|
'openid.sig'=> $GOODSIG));
|
||
|
|
||
|
$this->consumer->disableReturnToChecking();
|
||
|
|
||
|
$result = $this->consumer->_doIdRes($message, $this->endpoint, null);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
|
||
|
function failUnlessSuccess($response)
|
||
|
{
|
||
|
if ($response->status != Auth_OpenID_SUCCESS) {
|
||
|
$this->fail("Non-successful response (status is ".$response->status.")");
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
global $__test_otherServer_text;
|
||
|
$__test_otherServer_text = "__test_otherServer";
|
||
|
class TestDiscoveryVerification_test_otherServer extends Auth_OpenID_GenericConsumer {
|
||
|
function _discoverAndVerify($to_match)
|
||
|
{
|
||
|
global $__test_otherServer_text;
|
||
|
return new Auth_OpenID_FailureResponse(null, $__test_otherServer_text);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class TestDiscoveryVerification extends PHPUnit_Framework_TestCase {
|
||
|
var $services = array();
|
||
|
|
||
|
function discoveryFunc($identifier)
|
||
|
{
|
||
|
return array($identifier, $this->services);
|
||
|
}
|
||
|
|
||
|
function setUp()
|
||
|
{
|
||
|
$this->store = new GoodAssocStore();
|
||
|
$this->consumer = new Auth_OpenID_GenericConsumer($this->store);
|
||
|
$this->consumer->discoverMethod = array($this,
|
||
|
'discoveryFunc');
|
||
|
|
||
|
$this->identifier = "http://idp.unittest/1337";
|
||
|
$this->server_url = "http://endpoint.unittest/";
|
||
|
|
||
|
$this->message = Auth_OpenID_Message::fromPostArgs(array(
|
||
|
'openid.ns'=> Auth_OpenID_OPENID2_NS,
|
||
|
'openid.identity'=> $this->identifier,
|
||
|
'openid.claimed_id'=> $this->identifier,
|
||
|
'openid.op_endpoint'=> $this->server_url));
|
||
|
|
||
|
$this->endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$this->endpoint->server_url = $this->server_url;
|
||
|
}
|
||
|
|
||
|
function test_theGoodStuff()
|
||
|
{
|
||
|
$endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);
|
||
|
$endpoint->claimed_id = $this->identifier;
|
||
|
$endpoint->server_url = $this->server_url;
|
||
|
$endpoint->local_id = $this->identifier;
|
||
|
$this->services = array($endpoint);
|
||
|
$r = $this->consumer->_verifyDiscoveryResults($this->message, $endpoint);
|
||
|
|
||
|
$this->assertEquals($r, $endpoint);
|
||
|
}
|
||
|
|
||
|
function test_otherServer()
|
||
|
{
|
||
|
global $__test_otherServer_text;
|
||
|
|
||
|
// setup
|
||
|
$this->consumer = new TestDiscoveryVerification_test_otherServer($this->store);
|
||
|
$this->consumer->discoverMethod = array($this,
|
||
|
'discoveryFunc');
|
||
|
|
||
|
// a set of things without the stuff
|
||
|
$endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);
|
||
|
$endpoint->claimed_id = $this->identifier;
|
||
|
$endpoint->server_url = "http://the-MOON.unittest/";
|
||
|
$endpoint->local_id = $this->identifier;
|
||
|
$this->services = array($endpoint);
|
||
|
|
||
|
$result = $this->consumer->_verifyDiscoveryResults(
|
||
|
$this->message, $endpoint);
|
||
|
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
$this->assertTrue(strpos($result->message, $__test_otherServer_text) !== false);
|
||
|
}
|
||
|
|
||
|
function test_foreignDelegate()
|
||
|
{
|
||
|
global $__test_otherServer_text;
|
||
|
|
||
|
// setup
|
||
|
$this->consumer = new TestDiscoveryVerification_test_otherServer($this->store);
|
||
|
$this->consumer->discoverMethod = array($this,
|
||
|
'discoveryFunc');
|
||
|
|
||
|
// a set of things with the server stuff but other delegate
|
||
|
$endpoint = new Auth_OpenID_ServiceEndpoint();
|
||
|
$endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);
|
||
|
$endpoint->claimed_id = $this->identifier;
|
||
|
$endpoint->server_url = $this->server_url;
|
||
|
$endpoint->local_id = "http://unittest/juan-carlos";
|
||
|
|
||
|
$result = $this->consumer->_verifyDiscoveryResults(
|
||
|
$this->message, $endpoint);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
$this->assertTrue(strpos($result->message, $__test_otherServer_text) !== false);
|
||
|
}
|
||
|
|
||
|
function test_nothingDiscovered()
|
||
|
{
|
||
|
// a set of no things.
|
||
|
$this->services = array();
|
||
|
$result = $this->consumer->_verifyDiscoveryResults(
|
||
|
$this->message, $this->endpoint);
|
||
|
$this->assertTrue(Auth_OpenID::isFailure($result));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class DummyEndpoint {
|
||
|
var $use_compatibility = false;
|
||
|
|
||
|
function compatibilityMode()
|
||
|
{
|
||
|
return $this->use_compatibility;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class TestCreateAssociationRequest extends PHPUnit_Framework_TestCase {
|
||
|
function setUp()
|
||
|
{
|
||
|
$this->endpoint = new DummyEndpoint();
|
||
|
$s = null;
|
||
|
$this->consumer = new Auth_OpenID_GenericConsumer($s);
|
||
|
$this->assoc_type = 'HMAC-SHA1';
|
||
|
}
|
||
|
|
||
|
function test_noEncryptionSendsType()
|
||
|
{
|
||
|
$session_type = 'no-encryption';
|
||
|
list($session, $args) = $this->consumer->_createAssociateRequest(
|
||
|
$this->endpoint, $this->assoc_type, $session_type);
|
||
|
|
||
|
$this->assertTrue(is_a($session, 'Auth_OpenID_PlainTextConsumerSession'));
|
||
|
|
||
|
$expected = Auth_OpenID_Message::fromOpenIDArgs(
|
||
|
array('ns' => Auth_OpenID_OPENID2_NS,
|
||
|
'session_type'=>$session_type,
|
||
|
'mode'=>'associate',
|
||
|
'assoc_type'=>$this->assoc_type));
|
||
|
|
||
|
$this->assertEquals($expected->toPostArgs(),
|
||
|
$args->toPostArgs());
|
||
|
}
|
||
|
|
||
|
function test_noEncryptionSendsTypeHMACSHA256()
|
||
|
{
|
||
|
if (!Auth_OpenID_HMACSHA256_SUPPORTED) {
|
||
|
$this->pass();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
$session_type = 'no-encryption';
|
||
|
$this->assoc_type = 'HMAC-SHA256';
|
||
|
|
||
|
list($session, $args) = $this->consumer->_createAssociateRequest(
|
||
|
$this->endpoint, $this->assoc_type, $session_type);
|
||
|
|
||
|
$this->assertTrue(is_a($session, 'Auth_OpenID_PlainTextConsumerSession'));
|
||
|
|
||
|
$expected = Auth_OpenID_Message::fromOpenIDArgs(
|
||
|
array('ns' => Auth_OpenID_OPENID2_NS,
|
||
|
'session_type'=>$session_type,
|
||
|
'mode'=>'associate',
|
||
|
'assoc_type'=>$this->assoc_type));
|
||
|
|
||
|
$this->assertEquals($expected->toPostArgs(),
|
||
|
$args->toPostArgs());
|
||
|
|
||
|
$response = Auth_OpenID_Message::fromOpenIDArgs(
|
||
|
array('ns' => Auth_OpenID_OPENID2_NS,
|
||
|
'session_type'=>$session_type,
|
||
|
'assoc_type'=>$this->assoc_type,
|
||
|
'expires_in' => '10000000000',
|
||
|
'mac_key' => 'ZM9v',
|
||
|
'assoc_handle' => 'turnme'
|
||
|
)
|
||
|
);
|
||
|
|
||
|
$assoc = $this->consumer->_extractAssociation($response, $session);
|
||
|
|
||
|
$this->assertTrue($assoc !== null);
|
||
|
$this->assertTrue(is_a($assoc, 'Auth_OpenID_Association'));
|
||
|
$this->assertTrue($assoc->assoc_type = $this->assoc_type);
|
||
|
$this->assertTrue($assoc->session_type = $session_type);
|
||
|
}
|
||
|
|
||
|
function test_noEncryptionCompatibility()
|
||
|
{
|
||
|
$this->endpoint->use_compatibility = true;
|
||
|
$session_type = 'no-encryption';
|
||
|
list($session, $args) = $this->consumer->_createAssociateRequest(
|
||
|
$this->endpoint, $this->assoc_type, $session_type);
|
||
|
|
||
|
$this->assertTrue(is_a($session, 'Auth_OpenID_PlainTextConsumerSession'));
|
||
|
$this->assertEquals(Auth_OpenID_Message::fromOpenIDArgs(array('mode'=>'associate',
|
||
|
'assoc_type'=>$this->assoc_type)),
|
||
|
$args);
|
||
|
}
|
||
|
|
||
|
function test_dhSHA1Compatibility()
|
||
|
{
|
||
|
// Set the consumer's session type to a fast session since we
|
||
|
// need it here.
|
||
|
setConsumerSession($this->consumer);
|
||
|
|
||
|
$this->endpoint->use_compatibility = true;
|
||
|
$session_type = 'DH-SHA1';
|
||
|
list($session, $args) = $this->consumer->_createAssociateRequest(
|
||
|
$this->endpoint, $this->assoc_type, $session_type);
|
||
|
|
||
|
$this->assertTrue(is_a($session,
|
||
|
'Auth_OpenID_DiffieHellmanSHA1ConsumerSession'));
|
||
|
|
||
|
// This is a random base-64 value, so just check that it's
|
||
|
// present.
|
||
|
$this->assertTrue($args->hasKey(Auth_OpenID_OPENID1_NS, 'dh_consumer_public'));
|
||
|
$args->delArg(Auth_OpenID_OPENID1_NS, 'dh_consumer_public');
|
||
|
|
||
|
// OK, session_type is set here and not for no-encryption
|
||
|
// compatibility
|
||
|
$expected = Auth_OpenID_Message::fromOpenIDArgs(array('mode'=>'associate',
|
||
|
'session_type'=>'DH-SHA1',
|
||
|
'assoc_type'=>$this->assoc_type,
|
||
|
'dh_modulus'=> 'BfvStQ==',
|
||
|
'dh_gen'=> 'Ag=='));
|
||
|
|
||
|
$this->assertEquals($expected->toPostArgs(),
|
||
|
$args->toPostArgs());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class TestDiffieHellmanResponseParameters extends PHPUnit_Framework_TestCase {
|
||
|
var $session_cls = null;
|
||
|
var $message_namespace = null;
|
||
|
|
||
|
function setUp()
|
||
|
{
|
||
|
// Pre-compute DH with small prime so tests run quickly.
|
||
|
$this->server_dh = new Auth_OpenID_DiffieHellman(100389557, 2);
|
||
|
$this->consumer_dh = new Auth_OpenID_DiffieHellman(100389557, 2);
|
||
|
|
||
|
$lib = Auth_OpenID_getMathLib();
|
||
|
|
||
|
$cls = $this->session_cls;
|
||
|
$this->consumer_session = new $cls($this->consumer_dh);
|
||
|
|
||
|
// base64(btwoc(g ^ xb mod p))
|
||
|
$this->dh_server_public = $lib->longToBase64($this->server_dh->public);
|
||
|
|
||
|
$this->secret = Auth_OpenID_CryptUtil::randomString(
|
||
|
$this->consumer_session->secret_size);
|
||
|
|
||
|
$this->enc_mac_key = base64_encode(
|
||
|
$this->server_dh->xorSecret($this->consumer_dh->public,
|
||
|
$this->secret,
|
||
|
$this->consumer_session->hash_func));
|
||
|
|
||
|
$this->msg = new Auth_OpenID_Message($this->message_namespace);
|
||
|
}
|
||
|
|
||
|
function testExtractSecret()
|
||
|
{
|
||
|
$this->msg->setArg(Auth_OpenID_OPENID_NS, 'dh_server_public',
|
||
|
$this->dh_server_public);
|
||
|
|
||
|
$this->msg->setArg(Auth_OpenID_OPENID_NS, 'enc_mac_key',
|
||
|
$this->enc_mac_key);
|
||
|
|
||
|
$extracted = $this->consumer_session->extractSecret($this->msg);
|
||
|
$this->assertEquals($extracted, $this->secret);
|
||
|
}
|
||
|
|
||
|
function testAbsentServerPublic()
|
||
|
{
|
||
|
$this->msg->setArg(Auth_OpenID_OPENID_NS, 'enc_mac_key',
|
||
|
$this->enc_mac_key);
|
||
|
|
||
|
$this->assertTrue($this->consumer_session->extractSecret($this->msg) === null);
|
||
|
}
|
||
|
|
||
|
function testAbsentMacKey()
|
||
|
{
|
||
|
$this->msg->setArg(Auth_OpenID_OPENID_NS, 'dh_server_public',
|
||
|
$this->dh_server_public);
|
||
|
|
||
|
$this->assertTrue($this->consumer_session->extractSecret($this->msg) === null);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
function testInvalidBase64Public()
|
||
|
{
|
||
|
$this->msg->setArg(Auth_OpenID_OPENID_NS, 'dh_server_public',
|
||
|
'n o t b a s e 6 4.');
|
||
|
|
||
|
$this->msg->setArg(Auth_OpenID_OPENID_NS, 'enc_mac_key',
|
||
|
$this->enc_mac_key);
|
||
|
|
||
|
$this->assertTrue($this->consumer_session->extractSecret($this->msg) === null);
|
||
|
}
|
||
|
|
||
|
function testInvalidBase64MacKey()
|
||
|
{
|
||
|
$this->msg->setArg(Auth_OpenID_OPENID_NS, 'dh_server_public',
|
||
|
$this->dh_server_public);
|
||
|
|
||
|
$this->msg->setArg(Auth_OpenID_OPENID_NS, 'enc_mac_key',
|
||
|
'n o t base 64');
|
||
|
|
||
|
$this->assertTrue($this->consumer_session->extractSecret($this->msg) === null);
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
class TestOpenID1SHA1 extends TestDiffieHellmanResponseParameters {
|
||
|
var $session_cls = 'Auth_OpenID_DiffieHellmanSHA1ConsumerSession';
|
||
|
var $message_namespace = Auth_OpenID_OPENID1_NS;
|
||
|
}
|
||
|
|
||
|
class TestOpenID2SHA1 extends TestDiffieHellmanResponseParameters {
|
||
|
var $session_cls = 'Auth_OpenID_DiffieHellmanSHA1ConsumerSession';
|
||
|
var $message_namespace = Auth_OpenID_OPENID2_NS;
|
||
|
}
|
||
|
|
||
|
if (!defined('Auth_OpenID_NO_MATH_SUPPORT') &&
|
||
|
Auth_OpenID_SHA256_SUPPORTED) {
|
||
|
class TestOpenID2SHA256 extends TestDiffieHellmanResponseParameters {
|
||
|
var $session_cls = 'Auth_OpenID_DiffieHellmanSHA256ConsumerSession';
|
||
|
var $message_namespace = Auth_OpenID_OPENID2_NS;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Tests_Auth_OpenID_KVPost extends PHPUnit_Framework_TestCase {
|
||
|
function setUp()
|
||
|
{
|
||
|
$this->server_url = 'http://unittest/bogus';
|
||
|
}
|
||
|
|
||
|
function test_200()
|
||
|
{
|
||
|
$response = new Auth_Yadis_HTTPResponse();
|
||
|
$response->status = 200;
|
||
|
$response->body = "foo:bar\nbaz:quux\n";
|
||
|
$r = Auth_OpenID_GenericConsumer::_httpResponseToMessage($response, $this->server_url);
|
||
|
$expected_msg = Auth_OpenID_Message::fromOpenIDArgs(array('foo' => 'bar', 'baz' => 'quux'));
|
||
|
$this->assertEquals($expected_msg, $r);
|
||
|
}
|
||
|
|
||
|
function test_400()
|
||
|
{
|
||
|
$response = new Auth_Yadis_HTTPResponse();
|
||
|
$response->status = 400;
|
||
|
$response->body = "error:bonk\nerror_code:7\n";
|
||
|
$result = Auth_OpenID_GenericConsumer::_httpResponseToMessage($response, $this->server_url);
|
||
|
|
||
|
$this->assertTrue(is_a($result, 'Auth_OpenID_ServerErrorContainer'));
|
||
|
$this->assertEquals($result->error_text, 'bonk');
|
||
|
$this->assertEquals($result->error_code, '7');
|
||
|
}
|
||
|
|
||
|
function test_500()
|
||
|
{
|
||
|
// 500 as an example of any non-200, non-400 code.
|
||
|
$response = new Auth_Yadis_HTTPResponse();
|
||
|
$response->status = 500;
|
||
|
$response->body = "foo:bar\nbaz:quux\n";
|
||
|
$result = Auth_OpenID_GenericConsumer::_httpResponseToMessage($response, $this->server_url);
|
||
|
$this->assertTrue($result === null);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add other test cases to be run.
|
||
|
global $Tests_Auth_OpenID_Consumer_other;
|
||
|
$Tests_Auth_OpenID_Consumer_other = array(
|
||
|
// new Tests_Auth_OpenID_Consumer_TestSetupNeeded(),
|
||
|
new Tests_Auth_OpenID_AuthRequestHTMLMarkup(),
|
||
|
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_SuccessResponse(),
|
||
|
new Tests_Auth_OpenID_CheckAuthResponse(),
|
||
|
new Tests_Auth_OpenID_FetchErrorInIdRes(),
|
||
|
new Tests_Auth_OpenID_ConsumerTest2(),
|
||
|
new Tests_Auth_OpenID_Stateless1(),
|
||
|
new Tests_Auth_OpenID_Stateless2(),
|
||
|
new TestCompleteMissingSig(),
|
||
|
new TestReturnToArgs(),
|
||
|
new IDPDrivenTest(),
|
||
|
new TestDiscoveryVerification(),
|
||
|
new Tests_Auth_OpenID_KVPost(),
|
||
|
new Tests_idResURLMismatch(),
|
||
|
new IdResCheckForFieldsTest(),
|
||
|
);
|
||
|
|
||
|
if (!defined('Auth_OpenID_NO_MATH_SUPPORT')) {
|
||
|
$Tests_Auth_OpenID_Consumer_other[] = new TestCreateAssociationRequest();
|
||
|
$Tests_Auth_OpenID_Consumer_other[] = new TestOpenID1SHA1();
|
||
|
$Tests_Auth_OpenID_Consumer_other[] = new TestOpenID2SHA1();
|
||
|
}
|
||
|
|
||
|
if (!defined('Auth_OpenID_NO_MATH_SUPPORT') &&
|
||
|
Auth_OpenID_SHA256_SUPPORTED) {
|
||
|
$Tests_Auth_OpenID_Consumer_other[] = new TestOpenID2SHA256();
|
||
|
}
|
||
|
|
||
|
|