diff options
-rw-r--r-- | Auth/OpenID/Message.php | 64 | ||||
-rw-r--r-- | Auth/OpenID/Server.php | 6 | ||||
-rw-r--r-- | Tests/Auth/OpenID/Consumer.php | 31 | ||||
-rw-r--r-- | Tests/Auth/OpenID/Message.php | 103 | ||||
-rw-r--r-- | Tests/Auth/OpenID/Server.php | 45 |
5 files changed, 213 insertions, 36 deletions
diff --git a/Auth/OpenID/Message.php b/Auth/OpenID/Message.php index 08693ce..fd23e67 100644 --- a/Auth/OpenID/Message.php +++ b/Auth/OpenID/Message.php @@ -12,6 +12,7 @@ require_once 'Auth/OpenID.php'; require_once 'Auth/OpenID/KVForm.php'; require_once 'Auth/Yadis/XML.php'; +require_once 'Auth/OpenID/Consumer.php'; // For Auth_OpenID_FailureResponse // This doesn't REALLY belong here, but where is better? define('Auth_OpenID_IDENTIFIER_SELECT', @@ -23,6 +24,13 @@ define('Auth_OpenID_SREG_URI', 'http://openid.net/sreg/1.0'); // The OpenID 1.X namespace URI define('Auth_OpenID_OPENID1_NS', 'http://openid.net/signon/1.0'); +define('Auth_OpenID_THE_OTHER_OPENID1_NS', 'http://openid.net/signon/1.1'); + +function Auth_OpenID_isOpenID1($ns) +{ + return ($ns == Auth_OpenID_THE_OTHER_OPENID1_NS) || + ($ns == Auth_OpenID_OPENID1_NS); +} // The OpenID 2.0 namespace URI define('Auth_OpenID_OPENID2_NS', 'http://specs.openid.net/auth/2.0'); @@ -313,14 +321,15 @@ class Auth_OpenID_NamespaceMap { // Check that desired_alias is not an openid protocol field as // per the spec. if (in_array($desired_alias, $Auth_OpenID_OPENID_PROTOCOL_FIELDS)) { - // "%r is not an allowed namespace alias" % (desired_alias,); + Auth_OpenID::log("\"%s\" is not an allowed namespace alias", + $desired_alias); return null; } // Check that desired_alias does not contain a period as per // the spec. if (strpos($desired_alias, '.') !== false) { - // "%r must not contain a dot" % (desired_alias,) + Auth_OpenID::log('"%s" must not contain a dot', $desired_alias); return null; } @@ -331,7 +340,8 @@ class Auth_OpenID_NamespaceMap { if (($current_namespace_uri !== null) && ($current_namespace_uri != $namespace_uri)) { - // Cannot map because previous mapping exists + Auth_OpenID::log('Cannot map "%s" because previous mapping exists', + $namespace_uri); return null; } @@ -340,9 +350,9 @@ class Auth_OpenID_NamespaceMap { $alias = $this->namespace_to_alias->get($namespace_uri); if (($alias !== null) && ($alias != $desired_alias)) { - // fmt = ('Cannot map %r to alias %r. ' - // 'It is already mapped to alias %r') - // raise KeyError(fmt % (namespace_uri, desired_alias, alias)) + Auth_OpenID::log('Cannot map %s to alias %s. ' . + 'It is already mapped to alias %s', + $namespace_uri, $desired_alias, $alias); return null; } @@ -409,6 +419,7 @@ class Auth_OpenID_Message { // Create an empty Message $this->allowed_openid_namespaces = array( Auth_OpenID_OPENID1_NS, + Auth_OpenID_THE_OTHER_OPENID1_NS, Auth_OpenID_OPENID2_NS); $this->args = new Auth_OpenID_Mapping(); @@ -416,13 +427,14 @@ class Auth_OpenID_Message { if ($openid_namespace === null) { $this->_openid_ns_uri = null; } else { - $this->setOpenIDNamespace($openid_namespace); + $implicit = Auth_OpenID_isOpenID1($openid_namespace); + $this->setOpenIDNamespace($openid_namespace, $implicit); } } function isOpenID1() { - return $this->getOpenIDNamespace() == Auth_OpenID_OPENID1_NS; + return Auth_OpenID_isOpenID1($this->getOpenIDNamespace()); } function isOpenID2() @@ -513,8 +525,7 @@ class Auth_OpenID_Message { } else if (($ns_alias == Auth_OpenID_NULL_NAMESPACE) && ($ns_key == 'ns')) { // null namespace - if ($this->namespaces->addAlias($value, - Auth_OpenID_NULL_NAMESPACE) === null) { + if ($this->setOpenIDNamespace($value, false) === false) { return false; } } else { @@ -522,11 +533,12 @@ class Auth_OpenID_Message { } } - // Ensure that there is an OpenID namespace definition - $openid_ns_uri = - $this->namespaces->getNamespaceURI(Auth_OpenID_NULL_NAMESPACE); - - $this->setOpenIDNamespace($openid_ns_uri); + if (!$this->getOpenIDNamespace()) { + if ($this->setOpenIDNamespace(Auth_OpenID_OPENID1_NS, true) === + false) { + return false; + } + } // Actually put the pairs into the appropriate namespaces foreach ($ns_args as $triple) { @@ -535,6 +547,7 @@ class Auth_OpenID_Message { if ($ns_uri === null) { $ns_uri = $this->_getDefaultNamespace($ns_alias); if ($ns_uri === null) { + $ns_uri = Auth_OpenID_OPENID_NS; $ns_key = sprintf('%s.%s', $ns_alias, $ns_key); } else { @@ -557,24 +570,23 @@ class Auth_OpenID_Message { return null; } - function setOpenIDNamespace($openid_ns_uri=null) + function setOpenIDNamespace($openid_ns_uri, $implicit) { - if ($openid_ns_uri === null) { - $openid_ns_uri = Auth_OpenID_OPENID1_NS; - $implicit = true; - } else { - $implicit = false; + if (!in_array($openid_ns_uri, $this->allowed_openid_namespaces)) { + Auth_OpenID::log('Invalid null namespace: "%s"', $openid_ns_uri); + return false; } - if (!in_array($openid_ns_uri, $this->allowed_openid_namespaces)) { - // raise ValueError('Invalid null namespace: %r' % (openid_ns_uri,)) + $succeeded = $this->namespaces->addAlias($openid_ns_uri, + Auth_OpenID_NULL_NAMESPACE, + $implicit); + if ($succeeded === false) { return false; } - $this->namespaces->addAlias($openid_ns_uri, - Auth_OpenID_NULL_NAMESPACE, - $implicit); $this->_openid_ns_uri = $openid_ns_uri; + + return true; } function getOpenIDNamespace() diff --git a/Auth/OpenID/Server.php b/Auth/OpenID/Server.php index 81bd3f1..e746bcc 100644 --- a/Auth/OpenID/Server.php +++ b/Auth/OpenID/Server.php @@ -1059,10 +1059,14 @@ class Auth_OpenID_CheckIDRequest extends Auth_OpenID_Request { $response->fields->updateArgs(Auth_OpenID_OPENID_NS, array('mode' => $mode, - 'op_endpoint' => $server_url, 'return_to' => $this->return_to, 'response_nonce' => Auth_OpenID_mkNonce())); + if (!$this->message->isOpenID1()) { + $response->fields->setArg(Auth_OpenID_OPENID_NS, + 'op_endpoint', $server_url); + } + if ($response_identity !== null) { $response->fields->setArg( Auth_OpenID_OPENID_NS, diff --git a/Tests/Auth/OpenID/Consumer.php b/Tests/Auth/OpenID/Consumer.php index 3f6f9b7..82903d6 100644 --- a/Tests/Auth/OpenID/Consumer.php +++ b/Tests/Auth/OpenID/Consumer.php @@ -228,7 +228,6 @@ class Tests_Auth_OpenID_Consumer extends PHPUnit_TestCase { 'openid.mode' => $mode, 'openid.identity' => $delegate_url, 'openid.trust_root' => $trust_root, - 'openid.ns' => Auth_OpenID_OPENID1_NS ); if ($consumer->_use_assocs) { @@ -1556,6 +1555,36 @@ class Tests_Auth_OpenID_Consumer_TestCheckAuth extends _TestIdRes { $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_TestCase { diff --git a/Tests/Auth/OpenID/Message.php b/Tests/Auth/OpenID/Message.php index e19a69c..7f86848 100644 --- a/Tests/Auth/OpenID/Message.php +++ b/Tests/Auth/OpenID/Message.php @@ -70,7 +70,8 @@ class Tests_Auth_OpenID_EmptyMessage extends MessageTest { { $key = $this->msg->getKey(Auth_OpenID_OPENID_NS, 'foo'); $this->assertTrue(Auth_OpenID::isFailure($key)); - $this->msg->setOpenIDNamespace(); + + $this->msg->setOpenIDNamespace(Auth_OpenID_OPENID1_NS, false); $key = $this->msg->getKey(Auth_OpenID_OPENID_NS, 'foo'); $this->assertEquals('openid.foo', $key); } @@ -553,7 +554,7 @@ class Tests_Auth_OpenID_OpenID1Message extends MessageTest { } } -class Tests_Auth_OpenID_OpenID1ExplicitMessage extends MessageTest { +class Tests_Auth_OpenID_OpenID1ExplicitMessage extends PHPUnit_TestCase { function setUp() { $this->msg = Auth_OpenID_Message::fromPostArgs(array('openid.mode' => 'error', @@ -564,7 +565,8 @@ class Tests_Auth_OpenID_OpenID1ExplicitMessage extends MessageTest { function test_isOpenID1() { $this->assertTrue($this->msg->isOpenID1()); - $this->assertFalse($this->msg->namespaces->isImplicit(Auth_OpenID_OPENID1_NS)); + $this->assertFalse( + $this->msg->namespaces->isImplicit(Auth_OpenID_OPENID1_NS)); } function test_isOpenID2() @@ -1100,6 +1102,101 @@ class Tests_Auth_OpenID_GeneralMessageTest extends PHPUnit_TestCase { $this->_checkForm($html, $m, $this->action_url, $tag_attrs, $this->submit_text); } + + function test_setOpenIDNamespace_invalid() + { + $m = new Auth_OpenID_Message(); + $invalid_things = array( + // Empty string is not okay here. + '', + // Good guess! But wrong. + 'http://openid.net/signon/2.0', + // What? + 'http://specs%\\\r2Eopenid.net/auth/2.0', + // Too much escapings! + 'http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0', + // This is a Type URI, not a openid.ns value. + 'http://specs.openid.net/auth/2.0/signon', + ); + + foreach ($invalid_things as $x) { + $this->assertTrue($m->setOpenIDNamespace($x, true) === false); + } + } + + function test_isOpenID1() + { + $v1_namespaces = array( + // Yes, there are two of them. + 'http://openid.net/signon/1.1', + 'http://openid.net/signon/1.0', + ); + + foreach ($v1_namespaces as $ns) { + $m = new Auth_OpenID_Message($ns); + $this->assertTrue($m->isOpenID1(), + "$ns not recognized as OpenID 1"); + $this->assertEquals($ns, $m->getOpenIDNamespace()); + $this->assertTrue($m->namespaces->isImplicit($ns)); + } + } + + function test_isOpenID2() + { + $ns = 'http://specs.openid.net/auth/2.0'; + $m = new Auth_OpenID_Message($ns); + $this->assertTrue($m->isOpenID2()); + $this->assertFalse( + $m->namespaces->isImplicit(Auth_OpenID_NULL_NAMESPACE)); + $this->assertEquals($ns, $m->getOpenIDNamespace()); + } + + function test_setOpenIDNamespace_explicit() + { + $m = new Auth_OpenID_Message(); + $m->setOpenIDNamespace(Auth_OpenID_THE_OTHER_OPENID1_NS, false); + $this->assertFalse($m->namespaces->isImplicit( + Auth_OpenID_THE_OTHER_OPENID1_NS)); + } + + function test_setOpenIDNamespace_implicit() + { + $m = new Auth_OpenID_Message(); + $m->setOpenIDNamespace(Auth_OpenID_THE_OTHER_OPENID1_NS, true); + $this->assertTrue( + $m->namespaces->isImplicit(Auth_OpenID_THE_OTHER_OPENID1_NS)); + } + + + function test_explicitOpenID11NSSerialzation() + { + $m = new Auth_OpenID_Message(); + $m->setOpenIDNamespace(Auth_OpenID_THE_OTHER_OPENID1_NS, false); + + $post_args = $m->toPostArgs(); + $this->assertEquals($post_args, + array('openid.ns' => + Auth_OpenID_THE_OTHER_OPENID1_NS)); + } + + function test_fromPostArgs_ns11() + { + // An example of the stuff that some Drupal installations send us, + // which includes openid.ns but is 1.1. + $query = array( + 'openid.assoc_handle' => '', + 'openid.claimed_id' => 'http://foobar.invalid/', + 'openid.identity' => 'http://foobar.myopenid.com', + 'openid.mode' => 'checkid_setup', + 'openid.ns' => 'http://openid.net/signon/1.1', + 'openid.ns.sreg' => 'http://openid.net/extensions/sreg/1.1', + 'openid.return_to' => 'http://drupal.invalid/return_to', + 'openid.sreg.required' => 'nickname,email', + 'openid.trust_root' => 'http://drupal.invalid', + ); + $m = Auth_OpenID_Message::fromPostArgs($query); + $this->assertTrue($m->isOpenID1()); + } } class Tests_Auth_OpenID_NamespaceMap extends PHPUnit_TestCase { diff --git a/Tests/Auth/OpenID/Server.php b/Tests/Auth/OpenID/Server.php index a52f21a..d73cb8b 100644 --- a/Tests/Auth/OpenID/Server.php +++ b/Tests/Auth/OpenID/Server.php @@ -75,8 +75,7 @@ class Tests_Auth_OpenID_Test_ServerError extends PHPUnit_TestCase { $this->assertTrue($e->hasReturnTo()); $expected_args = array( 'openid.mode' => 'error', - 'openid.error' => 'plucky', - 'openid.ns' => Auth_OpenID_OPENID1_NS); + 'openid.error' => 'plucky'); $encoded = $e->encodeToURL(); if (Auth_OpenID_isError($encoded)) { @@ -155,8 +154,7 @@ class Tests_Auth_OpenID_Test_ServerError extends PHPUnit_TestCase { $e = new Auth_OpenID_ServerError($args, "plucky"); $this->assertTrue($e->hasReturnTo()); $expected_args = array('openid.mode' => 'error', - 'openid.error' => 'plucky', - 'openid.ns' => Auth_OpenID_OPENID1_NS); + 'openid.error' => 'plucky'); $this->assertTrue($e->whichEncoding() == Auth_OpenID_ENCODE_URL); @@ -1247,6 +1245,41 @@ class Tests_Auth_OpenID_CheckID extends PHPUnit_TestCase { $this->assertTrue(is_a($result, 'Auth_OpenID_ServerError')); } + function test_answerAllowNoEndpointOpenID1() + { + $identity = 'http://bambam.unittest/'; + $reqmessage = Auth_OpenID_Message::fromOpenIDArgs(array( + 'identity' => $identity, + 'trust_root' => 'http://bar.unittest/', + 'return_to' => 'http://bar.unittest/999', + )); + $this->server->op_endpoint = null; + $this->request = Auth_OpenID_CheckIDRequest::fromMessage($reqmessage, $this->server); + $answer = $this->request->answer(true); + + $expected_list = array('mode' => 'id_res', + 'return_to' => $this->request->return_to, + 'identity' => $identity, + ); + + foreach ($expected_list as $k => $expected) { + $actual = $answer->fields->getArg(Auth_OpenID_OPENID_NS, $k); + $this->assertEquals($expected, $actual); + } + + $this->assertTrue($answer->fields->hasKey(Auth_OpenID_OPENID_NS, + 'response_nonce')); + $this->assertTrue($answer->fields->getOpenIDNamespace(), + Auth_OpenID_OPENID1_NS); + $this->assertTrue( + $answer->fields->namespaces->isImplicit(Auth_OpenID_OPENID1_NS)); + + // One for nonce (OpenID v1 namespace is implicit) + $this->assertEquals(count($answer->fields->toPostArgs()), + count($expected_list) + 1, + var_export($answer->fields->toPostArgs(), true)); + } + function test_answerAllowWithDelegatedIdentityOpenID2() { // Answer an IDENTIFIER_SELECT case with a delegated @@ -1392,9 +1425,11 @@ class Tests_Auth_OpenID_CheckID extends PHPUnit_TestCase { $answer = $this->request->answer(false, $server_url); $this->assertEquals($answer->request, $this->request); - $this->assertEquals(count($answer->fields->toPostArgs()), 3); + $this->assertEquals(count($answer->fields->toPostArgs()), 2); $this->assertEquals($answer->fields->getOpenIDNamespace(), Auth_OpenID_OPENID1_NS); + $this->assertTrue( + $answer->fields->namespaces->isImplicit(Auth_OpenID_OPENID1_NS)); $this->assertEquals($answer->fields->getArg(Auth_OpenID_OPENID_NS, 'mode'), 'id_res'); $this->assertTrue(strpos($answer->fields->getArg(Auth_OpenID_OPENID_NS, |