Browse Source

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
mark_story 14 years ago
parent
commit
e457c14dec

+ 22 - 7
lib/Cake/Controller/Component/AuthComponent.php

@@ -161,6 +161,14 @@ class AuthComponent extends Component {
 	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
  * 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
  * @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
  */
 	public static function user($key = null) {
-		if (!CakeSession::check(self::$sessionKey)) {
+		if (empty(self::$_user) && !CakeSession::check(self::$sessionKey)) {
 			return null;
 		}
-
-		if ($key == null) {
-			return CakeSession::read(self::$sessionKey);
+		if (!empty(self::$_user)) {
+			$user = self::$_user;
+		} else {
+			$user = CakeSession::read(self::$sessionKey);
+		}
+		if ($key === null) {
+			return $user;
 		}
-
-		$user = CakeSession::read(self::$sessionKey);
 		if (isset($user[$key])) {
 			return $user[$key];
 		}
@@ -573,6 +587,7 @@ class AuthComponent extends Component {
 		foreach ($this->_authenticateObjects as $auth) {
 			$result = $auth->getUser($this->request);
 			if (!empty($result) && is_array($result)) {
+				self::$_user = $result;
 				return true;
 			}
 		}

+ 34 - 0
lib/Cake/Test/Case/Controller/Component/AuthComponentTest.php

@@ -46,6 +46,10 @@ class TestAuthComponent extends AuthComponent {
 		$this->testStop = true;
 	}
 
+	public static function clearUser() {
+		self::$_user = array();
+	}
+
 }
 
 /**
@@ -339,6 +343,7 @@ class AuthComponentTest extends CakeTestCase {
 		$_SERVER = $this->_server;
 		$_ENV = $this->_env;
 
+		TestAuthComponent::clearUser();
 		$this->Auth->Session->delete('Auth');
 		$this->Auth->Session->delete('Message.auth');
 		unset($this->Controller, $this->Auth);
@@ -976,6 +981,30 @@ class AuthComponentTest extends CakeTestCase {
 	}
 
 /**
+ * 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
  *
  * @return void
@@ -1033,6 +1062,11 @@ class AuthComponentTest extends CakeTestCase {
 		$this->assertNull($this->Auth->Session->read('Auth.redirect'));
 	}
 
+/**
+ * Logout should trigger a logout method on authentication objects.
+ *
+ * @return void
+ */
 	public function testLogoutTrigger() {
 		$this->getMock('BaseAuthenticate', array('authenticate', 'logout'), array(), 'LogoutTriggerMockAuthenticate', false);