diff options
author | tailor <cygnus@janrain.com> | 2006-08-18 19:53:02 +0000 |
---|---|---|
committer | tailor <cygnus@janrain.com> | 2006-08-18 19:53:02 +0000 |
commit | 4d7517d2e8f8ff565628176ceacb00b904816eb3 (patch) | |
tree | 829971ee10aad9a7c4e0be9f885a333700c71655 | |
parent | e864c7aa4f77b774cdc3fe64baf7a1533a4828b8 (diff) | |
download | php-openid-4d7517d2e8f8ff565628176ceacb00b904816eb3.zip php-openid-4d7517d2e8f8ff565628176ceacb00b904816eb3.tar.gz php-openid-4d7517d2e8f8ff565628176ceacb00b904816eb3.tar.bz2 |
[project @ Ported patch to remove token]
-rw-r--r-- | Auth/OpenID/Consumer.php | 177 | ||||
-rw-r--r-- | Tests/Auth/OpenID/Consumer.php | 75 |
2 files changed, 86 insertions, 166 deletions
diff --git a/Auth/OpenID/Consumer.php b/Auth/OpenID/Consumer.php index 3566b7b..dea5326 100644 --- a/Auth/OpenID/Consumer.php +++ b/Auth/OpenID/Consumer.php @@ -353,7 +353,7 @@ class Auth_OpenID_Consumer { function &beginWithoutDiscovery($endpoint) { $auth_req = $this->consumer->begin($endpoint); - $this->session->set($this->_token_key, $auth_req->token); + $this->session->set($this->_token_key, $auth_req->endpoint); return $auth_req; } @@ -374,13 +374,13 @@ class Auth_OpenID_Consumer { { $query = Auth_OpenID::fixArgs($query); - $token = $this->session->get($this->_token_key); + $endpoint = $this->session->get($this->_token_key); - if ($token === null) { + if ($endpoint === null) { $response = new Auth_OpenID_FailureResponse(null, 'No session state found'); } else { - $response = $this->consumer->complete($query, $token); + $response = $this->consumer->complete($query, $endpoint); $this->session->del($this->_token_key); } @@ -429,15 +429,6 @@ class Auth_OpenID_GenericConsumer { var $nonce_chrs = Auth_OpenID_DEFAULT_NONCE_CHRS; /** - * How long should an authentication session stay good? - * - * In units of sections. Shorter times mean less opportunity for - * attackers, longer times mean less chance of a user's session - * timing out. - */ - var $token_lifetime = Auth_OpenID_DEFAULT_TOKEN_LIFETIME; - - /** * This method initializes a new {@link Auth_OpenID_Consumer} * instance to access the library. * @@ -477,43 +468,32 @@ class Auth_OpenID_GenericConsumer { function begin($service_endpoint) { $nonce = $this->_createNonce(); - $token = $this->_genToken($service_endpoint->identity_url, - $service_endpoint->getServerID(), - $service_endpoint->server_url); $assoc = $this->_getAssociation($service_endpoint->server_url); - $r = new Auth_OpenID_AuthRequest($token, $assoc, $service_endpoint); + $r = new Auth_OpenID_AuthRequest($assoc, $service_endpoint); $r->return_to_args['nonce'] = $nonce; return $r; } - function complete($query, $token) + function complete($query, $endpoint) { $mode = Auth_OpenID::arrayGet($query, 'openid.mode', '<no mode specified>'); - $pieces = $this->_splitToken($token); - if ($pieces === null) { - $pieces = array(null, null, null); - } - - list($identity_url, $delegate, $server_url) = $pieces; - if ($mode == Auth_OpenID_CANCEL) { - return new Auth_OpenID_CancelResponse($identity_url); + return new Auth_OpenID_CancelResponse($endpoint); } else if ($mode == 'error') { $error = Auth_OpenID::arrayGet($query, 'openid.error'); - return new Auth_OpenID_FailureResponse($identity_url, $error); + return new Auth_OpenID_FailureResponse($endpoint, $error); } else if ($mode == 'id_res') { - if ($identity_url === null) { + if ($endpoint->identity_url === null) { return new Auth_OpenID_FailureResponse($identity_url, - "No session state found"); + "No session state found"); } - $response = $this->_doIdRes($query, $identity_url, $delegate, - $server_url); + $response = $this->_doIdRes($query, $endpoint); if ($response === null) { - return new Auth_OpenID_FailureResponse($identity_url, + return new Auth_OpenID_FailureResponse($endpoint, "HTTP request failed"); } if ($response->status == Auth_OpenID_SUCCESS) { @@ -524,7 +504,7 @@ class Auth_OpenID_GenericConsumer { return $response; } } else { - return new Auth_OpenID_FailureResponse($identity_url, + return new Auth_OpenID_FailureResponse($endpoint, sprintf("Invalid openid.mode '%s'", $mode)); } @@ -533,13 +513,13 @@ class Auth_OpenID_GenericConsumer { /** * @access private */ - function _doIdRes($query, $consumer_id, $server_id, $server_url) + function _doIdRes($query, $endpoint) { $user_setup_url = Auth_OpenID::arrayGet($query, 'openid.user_setup_url'); if ($user_setup_url !== null) { - return new Auth_OpenID_SetupNeededResponse($consumer_id, + return new Auth_OpenID_SetupNeededResponse($endpoint, $user_setup_url); } @@ -549,55 +529,65 @@ class Auth_OpenID_GenericConsumer { 'openid.assoc_handle', null); if (($return_to === null) || - ($server_id === null) || + ($server_id2 === null) || ($assoc_handle === null)) { - return new Auth_OpenID_FailureResponse($consumer_id, + return new Auth_OpenID_FailureResponse($endpoint, "Missing required field"); } - if ($server_id != $server_id2) { - return new Auth_OpenID_FailureResponse($consumer_id, + if ($endpoint->delegate != $server_id2) { + return new Auth_OpenID_FailureResponse($endpoint, "Server ID (delegate) mismatch"); } $signed = Auth_OpenID::arrayGet($query, 'openid.signed'); - $assoc = $this->store->getAssociation($server_url, $assoc_handle); + $assoc = $this->store->getAssociation($endpoint->server_url, + $assoc_handle); if ($assoc === null) { // It's not an association we know about. Dumb mode is // our only possible path for recovery. - if ($this->_checkAuth($query, $server_url)) { - return new Auth_OpenID_SuccessResponse($consumer_id, $query, + if ($this->_checkAuth($query, $endpoint->server_url)) { + return new Auth_OpenID_SuccessResponse($endpoint, $query, $signed); } else { - return new Auth_OpenID_FailureResponse($consumer_id, + return new Auth_OpenID_FailureResponse($endpoint, "Server denied check_authentication"); } } if ($assoc->getExpiresIn() <= 0) { - $msg = sprintf("Association with %s expired", $server_url); - return new Auth_OpenID_FailureResponse($consumer_id, $msg); + $msg = sprintf("Association with %s expired", + $endpoint->server_url); + return new Auth_OpenID_FailureResponse($endpoint, $msg); } // Check the signature $sig = Auth_OpenID::arrayGet($query, 'openid.sig', null); if (($sig === null) || ($signed === null)) { - return new Auth_OpenID_FailureResponse($consumer_id, + return new Auth_OpenID_FailureResponse($endpoint, "Missing argument signature"); } $signed_list = explode(",", $signed); + + //Fail if the identity field is present but not signed + if (($endpoint->identity_url !== null) && + (!in_array('identity', $signed_list))) { + $msg = '"openid.identity" not signed'; + return new Auth_OpenID_FailureResponse($endpoint, $msg); + } + $v_sig = $assoc->signDict($signed_list, $query); if ($v_sig != $sig) { - return new Auth_OpenID_FailureResponse($consumer_id, + return new Auth_OpenID_FailureResponse($endpoint, "Bad signature"); } - return Auth_OpenID_SuccessResponse::fromQuery($consumer_id, + return Auth_OpenID_SuccessResponse::fromQuery($endpoint, $query, $signed); } @@ -715,9 +705,8 @@ class Auth_OpenID_GenericConsumer { foreach ($query as $k => $v) { if ($k == 'nonce') { if ($v != $nonce) { - return new Auth_OpenID_FailureResponse( - $response->identity_url, - "Nonce mismatch"); + return new Auth_OpenID_FailureResponse($response, + "Nonce mismatch"); } else { $found = true; break; @@ -726,13 +715,13 @@ class Auth_OpenID_GenericConsumer { } if (!$found) { - return new Auth_OpenID_FailureResponse($response->identity_url, + return new Auth_OpenID_FailureResponse($response, sprintf("Nonce missing from return_to: %s", $response->getReturnTo())); } if (!$this->store->useNonce($nonce)) { - return new Auth_OpenID_FailureResponse($response->identity_url, + return new Auth_OpenID_FailureResponse($response, "Nonce missing from store"); } @@ -770,7 +759,7 @@ class Auth_OpenID_GenericConsumer { $assoc = $this->store->getAssociation($server_url); if (($assoc === null) || - ($replace && ($assoc->getExpiresIn() < $this->token_lifetime))) { + ($replace && ($assoc->getExpiresIn() <= 0))) { $args = array( 'openid.mode' => 'associate', @@ -790,55 +779,6 @@ class Auth_OpenID_GenericConsumer { /** * @access private */ - function _genToken($consumer_id, $server_id, $server_url) - { - $timestamp = strval(time()); - $elements = array($timestamp, $consumer_id, $server_id, $server_url); - - $joined = implode("\x00", $elements); - $sig = Auth_OpenID_HMACSHA1($this->store->getAuthKey(), - $joined); - - return base64_encode($sig . $joined); - } - - /** - * @access private - */ - function _splitToken($token) - { - $token = base64_decode($token); - if (strlen($token) < 20) { - return null; - } - - $sig = substr($token, 0, 20); - $joined = substr($token, 20); - $check_sig = Auth_OpenID_HMACSHA1($this->store->getAuthKey(), $joined); - if ($check_sig != $sig) { - return null; - } - - $split = explode("\x00", $joined); - if (count($split) != 4) { - return null; - } - - $ts = intval($split[0]); - if ($ts == 0) { - return null; - } - - if ($ts + $this->token_lifetime < time()) { - return null; - } - - return array_slice($split, 1); - } - - /** - * @access private - */ function _fetchAssociation($dh, $server_url, $body) { $ret = @$this->fetcher->post($server_url, $body); @@ -938,13 +878,12 @@ class Auth_OpenID_AuthRequest { * class. Instances of this class are created by the library when * needed. */ - function Auth_OpenID_AuthRequest($token, $assoc, $endpoint) + function Auth_OpenID_AuthRequest($assoc, $endpoint) { $this->assoc = $assoc; $this->endpoint = $endpoint; $this->extra_args = array(); $this->return_to_args = array(); - $this->token = $token; } /** @@ -1042,16 +981,17 @@ class Auth_OpenID_SuccessResponse extends Auth_OpenID_ConsumerResponse { /** * @access private */ - function Auth_OpenID_SuccessResponse($identity_url, $signed_args) + function Auth_OpenID_SuccessResponse($endpoint, $signed_args) { - $this->identity_url = $identity_url; + $this->endpoint = $endpoint; + $this->identity_url = $endpoint->identity_url; $this->signed_args = $signed_args; } /** * @access private */ - function fromQuery($identity_url, $query, $signed) + function fromQuery($endpoint, $query, $signed) { $signed_args = array(); foreach (explode(",", $signed) as $field_name) { @@ -1059,7 +999,7 @@ class Auth_OpenID_SuccessResponse extends Auth_OpenID_ConsumerResponse { $signed_args[$field_name] = Auth_OpenID::arrayGet($query, $field_name, ''); } - return new Auth_OpenID_SuccessResponse($identity_url, $signed_args); + return new Auth_OpenID_SuccessResponse($endpoint, $signed_args); } /** @@ -1117,9 +1057,14 @@ class Auth_OpenID_SuccessResponse extends Auth_OpenID_ConsumerResponse { class Auth_OpenID_FailureResponse extends Auth_OpenID_ConsumerResponse { var $status = Auth_OpenID_FAILURE; - function Auth_OpenID_FailureResponse($identity_url = null, $message = null) + function Auth_OpenID_FailureResponse($endpoint, $message = null) { - $this->identity_url = $identity_url; + $this->endpoint = $endpoint; + if ($endpoint !== null) { + $this->identity_url = $endpoint->identity_url; + } else { + $this->identity_url = null; + } $this->message = $message; } } @@ -1139,9 +1084,10 @@ class Auth_OpenID_FailureResponse extends Auth_OpenID_ConsumerResponse { class Auth_OpenID_CancelResponse extends Auth_OpenID_ConsumerResponse { var $status = Auth_OpenID_CANCEL; - function Auth_OpenID_CancelResponse($identity_url = null) + function Auth_OpenID_CancelResponse($endpoint) { - $this->identity_url = $identity_url; + $this->endpoint = $endpoint; + $this->identity_url = $endpoint->identity_url; } } @@ -1165,10 +1111,11 @@ class Auth_OpenID_CancelResponse extends Auth_OpenID_ConsumerResponse { class Auth_OpenID_SetupNeededResponse extends Auth_OpenID_ConsumerResponse { var $status = Auth_OpenID_SETUP_NEEDED; - function Auth_OpenID_SetupNeededResponse($identity_url = null, + function Auth_OpenID_SetupNeededResponse($endpoint, $setup_url = null) { - $this->identity_url = $identity_url; + $this->endpoint = $endpoint; + $this->identity_url = $endpoint->identity_url; $this->setup_url = $setup_url; } } diff --git a/Tests/Auth/OpenID/Consumer.php b/Tests/Auth/OpenID/Consumer.php index 156fcdf..55f888f 100644 --- a/Tests/Auth/OpenID/Consumer.php +++ b/Tests/Auth/OpenID/Consumer.php @@ -213,7 +213,7 @@ class Tests_Auth_OpenID_Consumer extends PHPUnit_TestCase { $query['openid.sig'] = 'fake'; } - $result = $consumer->complete($query, $result->token); + $result = $consumer->complete($query, $result->endpoint); $this->assertEquals($result->status, 'success'); $this->assertEquals($result->identity_url, $user_url); @@ -311,12 +311,15 @@ class _TestIdRes extends PHPUnit_TestCase { $cl = $this->consumer_class; $this->consumer = new $cl($this->store); $this->return_to = "nonny"; + $this->endpoint = new Auth_OpenID_ServiceEndpoint(); + $this->server_id = "sirod"; $this->server_url = "serlie"; $this->consumer_id = "consu"; - $this->token = $this->consumer->_genToken($this->consumer_id, - $this->server_id, - $this->server_url); + + $this->endpoint->identity_url = $this->consumer_id; + $this->endpoint->server_url = $this->server_url; + $this->endpoint->delegate = $this->server_id; } } @@ -327,8 +330,7 @@ class Tests_Auth_OpenID_Consumer_TestSetupNeeded extends _TestIdRes { $query = array( 'openid.mode' => 'id_res', 'openid.user_setup_url' => $setup_url); - $ret = $this->consumer->_doIdRes($query, $this->consumer_id, - $this->server_id, $this->server_url); + $ret = $this->consumer->_doIdRes($query, $this->endpoint); $this->assertEquals($ret->status, Auth_OpenID_SETUP_NEEDED); $this->assertEquals($ret->setup_url, $setup_url); } @@ -357,7 +359,7 @@ class Tests_Auth_OpenID_Consumer_CheckNonceTest extends _TestIdRes { { $this->return_to = sprintf('http://rt.unittest/?nonce=%s', $this->nonce); - $this->response = new Auth_OpenID_SuccessResponse($this->consumer_id, + $this->response = new Auth_OpenID_SuccessResponse($this->endpoint, array('openid.return_to' => $this->return_to)); $ret = $this->consumer->_checkNonce($this->response, $this->nonce); @@ -371,7 +373,7 @@ class Tests_Auth_OpenID_Consumer_CheckNonceTest extends _TestIdRes { $this->store->useNonce($this->nonce); $this->return_to = sprintf('http://rt.unittest/?nonce=%s', $this->nonce); - $this->response = new Auth_OpenID_SuccessResponse($this->consumer_id, + $this->response = new Auth_OpenID_SuccessResponse($this->endpoint, array('openid.return_to' => $this->return_to)); $ret = $this->consumer->_checkNonce($this->response, $this->nonce); $this->assertEquals($ret->status, Auth_OpenID_FAILURE); @@ -383,7 +385,7 @@ class Tests_Auth_OpenID_Consumer_CheckNonceTest extends _TestIdRes { { $this->return_to = sprintf('http://rt.unittest/?nonce=HACKED-%s', $this->nonce); - $this->response = new Auth_OpenID_SuccessResponse($this->consumer_id, + $this->response = new Auth_OpenID_SuccessResponse($this->endpoint, array('openid.return_to' => $this->return_to)); $ret = $this->consumer->_checkNonce($this->response, $this->nonce); $this->assertEquals($ret->status, Auth_OpenID_FAILURE); @@ -394,7 +396,7 @@ class Tests_Auth_OpenID_Consumer_CheckNonceTest extends _TestIdRes { function test_missingNonce() { // no nonce parameter on the return_to - $this->response = new Auth_OpenID_SuccessResponse($this->consumer_id, + $this->response = new Auth_OpenID_SuccessResponse($this->endpoint, array('openid.return_to' => $this->return_to)); $ret = $this->consumer->_checkNonce($this->response, $this->nonce); $this->assertEquals($ret->status, Auth_OpenID_FAILURE); @@ -409,10 +411,7 @@ class Tests_Auth_OpenID_Consumer_TestCheckAuthTriggered extends _TestIdRes { function _doIdRes($query) { - return $this->consumer->_doIdRes($query, - $this->consumer_id, - $this->server_id, - $this->server_url); + return $this->consumer->_doIdRes($query, $this->endpoint); } function test_checkAuthTriggered() @@ -528,37 +527,12 @@ class _MockFetcher { } class Tests_Auth_OpenID_Complete extends _TestIdRes { - function test_badTokenLength() - { - $query = array('openid.mode' => 'id_res'); - $r = $this->consumer->complete($query, 'badtoken'); - $this->assertEquals($r->status, Auth_OpenID_FAILURE); - $this->assertTrue($r->identity_url === null); - } - - function test_badTokenSig() - { - $query = array('openid.mode' => 'id_res'); - $r = $this->consumer->complete($query, 'badtoken' . $this->token); - $this->assertEquals($r->status, Auth_OpenID_FAILURE); - $this->assertTrue($r->identity_url === null); - } - - function test_expiredToken() - { - $this->consumer->token_lifetime = -1; // in the past - $query = array('openid.mode' => 'id_res'); - $r = $this->consumer->complete($query, $this->token); - $this->assertEquals($r->status, Auth_OpenID_FAILURE, "Status comparison"); - $this->assertTrue($r->identity_url === null, "Identity URL comparison"); - } - function test_cancel() { $query = array('openid.mode' => 'cancel'); - $r = $this->consumer->complete($query, 'badtoken'); + $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_CANCEL); - $this->assertTrue($r->identity_url === null); + $this->assertTrue($r->identity_url == $this->endpoint->identity_url); } function test_error() @@ -566,24 +540,24 @@ class Tests_Auth_OpenID_Complete extends _TestIdRes { $msg = 'an error message'; $query = array('openid.mode' =>'error', 'openid.error' => $msg); - $r = $this->consumer->complete($query, 'badtoken'); + $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_FAILURE); - $this->assertTrue($r->identity_url === null); + $this->assertTrue($r->identity_url == $this->endpoint->identity_url); $this->assertEquals($r->message, $msg); } function test_noMode() { $query = array(); - $r = $this->consumer->complete($query, 'badtoken'); + $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_FAILURE); - $this->assertTrue($r->identity_url === null); + $this->assertTrue($r->identity_url == $this->endpoint->identity_url); } function test_idResMissingField() { $query = array('openid.mode' => 'id_res'); - $r = $this->consumer->complete($query, $this->token); + $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_FAILURE); $this->assertEquals($r->identity_url, $this->consumer_id); } @@ -594,7 +568,7 @@ class Tests_Auth_OpenID_Complete extends _TestIdRes { 'openid.return_to' => 'return_to (just anything)', 'openid.identity' => 'something wrong (not this->consumer_id)', 'openid.assoc_handle' => 'does not matter'); - $r = $this->consumer->complete($query, $this->token); + $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_FAILURE); $this->assertEquals($r->identity_url, $this->consumer_id); $this->assertTrue(strpos($r->message, 'delegate') !== false); @@ -681,10 +655,9 @@ class Tests_Auth_OpenID_CheckAuthResponse extends _TestIdRes { class _IdResFetchFailingConsumer extends Auth_OpenID_GenericConsumer { var $message = 'fetch failed'; - function _doIdRes($query, $consumer_id, $server_id, - $server_url) + function _doIdRes($query, $endpoint) { - return new Auth_OpenID_FailureResponse($consumer_id, + return new Auth_OpenID_FailureResponse($endpoint, $this->message); } } @@ -695,7 +668,7 @@ class Tests_Auth_OpenID_FetchErrorInIdRes extends _TestIdRes { function test_idResFailure() { $query = array('openid.mode' => 'id_res'); - $r = $this->consumer->complete($query, $this->token); + $r = $this->consumer->complete($query, $this->endpoint); $this->assertEquals($r->status, Auth_OpenID_FAILURE); $this->assertEquals($r->identity_url, $this->consumer_id); $this->assertEquals($this->consumer->message, $r->message); |