summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Auth/OpenID/Consumer.php177
-rw-r--r--Tests/Auth/OpenID/Consumer.php75
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);