Fix issues with stateless authentication.

Cookies and sessions are no longer required for stateful authentication.
AuthComponent::user() also works correctly in these situations as well.

Fixes #2134
This commit is contained in:
mark_story 2011-10-23 12:54:51 -04:00
parent 75daff8df9
commit e457c14dec
2 changed files with 56 additions and 7 deletions

View file

@ -160,6 +160,14 @@ class AuthComponent extends Component {
*/ */
public static $sessionKey = 'Auth.User'; public static $sessionKey = 'Auth.User';
/**
* The current user, used for stateless authentication when
* sessions are not available.
*
* @var array
*/
protected static $_user = array();
/** /**
* A URL (defined as a string or array) to the controller action that handles * A URL (defined as a string or array) to the controller action that handles
* logins. Defaults to `/users/login` * logins. Defaults to `/users/login`
@ -534,22 +542,28 @@ class AuthComponent extends Component {
} }
/** /**
* Get the current user from the session. * Get the current user.
*
* Will prefer the static user cache over sessions. The static user
* cache is primarily used for stateless authentication. For stateful authentication,
* cookies + sessions will be used.
* *
* @param string $key field to retrieve. Leave null to get entire User record * @param string $key field to retrieve. Leave null to get entire User record
* @return mixed User record. or null if no user is logged in. * @return mixed User record. or null if no user is logged in.
* @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#accessing-the-logged-in-user * @link http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html#accessing-the-logged-in-user
*/ */
public static function user($key = null) { public static function user($key = null) {
if (!CakeSession::check(self::$sessionKey)) { if (empty(self::$_user) && !CakeSession::check(self::$sessionKey)) {
return null; return null;
} }
if (!empty(self::$_user)) {
if ($key == null) { $user = self::$_user;
return CakeSession::read(self::$sessionKey); } else {
$user = CakeSession::read(self::$sessionKey);
}
if ($key === null) {
return $user;
} }
$user = CakeSession::read(self::$sessionKey);
if (isset($user[$key])) { if (isset($user[$key])) {
return $user[$key]; return $user[$key];
} }
@ -573,6 +587,7 @@ class AuthComponent extends Component {
foreach ($this->_authenticateObjects as $auth) { foreach ($this->_authenticateObjects as $auth) {
$result = $auth->getUser($this->request); $result = $auth->getUser($this->request);
if (!empty($result) && is_array($result)) { if (!empty($result) && is_array($result)) {
self::$_user = $result;
return true; return true;
} }
} }

View file

@ -46,6 +46,10 @@ class TestAuthComponent extends AuthComponent {
$this->testStop = true; $this->testStop = true;
} }
public static function clearUser() {
self::$_user = array();
}
} }
/** /**
@ -339,6 +343,7 @@ class AuthComponentTest extends CakeTestCase {
$_SERVER = $this->_server; $_SERVER = $this->_server;
$_ENV = $this->_env; $_ENV = $this->_env;
TestAuthComponent::clearUser();
$this->Auth->Session->delete('Auth'); $this->Auth->Session->delete('Auth');
$this->Auth->Session->delete('Message.auth'); $this->Auth->Session->delete('Message.auth');
unset($this->Controller, $this->Auth); unset($this->Controller, $this->Auth);
@ -975,6 +980,30 @@ class AuthComponentTest extends CakeTestCase {
Configure::write('Routing.prefixes', $admin); Configure::write('Routing.prefixes', $admin);
} }
/**
* Stateless auth methods like Basic should populate data that can be
* accessed by $this->user().
*
* @return void
*/
public function testStatelessAuthWorksWithUser() {
$_SERVER['PHP_AUTH_USER'] = 'mariano';
$_SERVER['PHP_AUTH_PW'] = 'cake';
$url = '/auth_test/add';
$this->Auth->request->addParams(Router::parse($url));
$this->Auth->authenticate = array(
'Basic' => array('userModel' => 'AuthUser')
);
$this->Auth->startup($this->Controller);
$result = $this->Auth->user();
$this->assertEquals('mariano', $result['username']);
$result = $this->Auth->user('username');
$this->assertEquals('mariano', $result);
}
/** /**
* Tests that shutdown destroys the redirect session var * Tests that shutdown destroys the redirect session var
* *
@ -1033,6 +1062,11 @@ class AuthComponentTest extends CakeTestCase {
$this->assertNull($this->Auth->Session->read('Auth.redirect')); $this->assertNull($this->Auth->Session->read('Auth.redirect'));
} }
/**
* Logout should trigger a logout method on authentication objects.
*
* @return void
*/
public function testLogoutTrigger() { public function testLogoutTrigger() {
$this->getMock('BaseAuthenticate', array('authenticate', 'logout'), array(), 'LogoutTriggerMockAuthenticate', false); $this->getMock('BaseAuthenticate', array('authenticate', 'logout'), array(), 'LogoutTriggerMockAuthenticate', false);