diff --git a/core/lib/Drupal/Core/Session/AccountProxy.php b/core/lib/Drupal/Core/Session/AccountProxy.php index 2c00e62..dbe165e 100644 --- a/core/lib/Drupal/Core/Session/AccountProxy.php +++ b/core/lib/Drupal/Core/Session/AccountProxy.php @@ -108,11 +108,11 @@ public function getAccount() { */ public function impersonateAccount(AccountInterface $account) { // Prevent session information from being saved and push the previous account. - $this->accountStack[] = $this->account; + array_push($this->accountStack, $this->account); $this->originalSessionSaving = $this->sessionManager->isEnabled(); $this->sessionManager->disable(); $this->setAccount($account); - return $this->account; + return $this; } /** @@ -123,30 +123,35 @@ public function revertAccount() { if (!empty($this->accountStack)) { $this->account = array_pop($this->accountStack); } + else { + throw new \RuntimeException(t('No more account impersonations to revert.')); + } // Restore original session saving status if all impersonations are reverted. if (empty($this->accountStack)) { if ($this->originalSessionSaving) { $this->sessionManager->enable(); } } - return $this->account; + return $this; } /** - /** * {@inheritdoc} */ public function revertAll() { // Restore the original account from the stack. if (!empty($this->accountStack)) { - $this->account = $this->accountStack[0]; + $this->account = array_shift($this->accountStack); $this->accountStack = array(); } + else { + throw new \RuntimeException(t('No more account impersonations to revert.')); + } // Restore original session saving status if all impersonations are reverted. if ($this->originalSessionSaving) { $this->sessionManager->enable(); } - return $this->account; + return $this; } /** diff --git a/core/lib/Drupal/Core/Session/AccountProxyInterface.php b/core/lib/Drupal/Core/Session/AccountProxyInterface.php index 9558d65..c4cf390 100644 --- a/core/lib/Drupal/Core/Session/AccountProxyInterface.php +++ b/core/lib/Drupal/Core/Session/AccountProxyInterface.php @@ -38,7 +38,7 @@ public function getAccount(); * call! * * @param \Drupal\Core\Session\AccountInterface - * The account to be impersonated. + * $this. */ public function impersonateAccount(AccountInterface $account); @@ -46,7 +46,7 @@ public function impersonateAccount(AccountInterface $account); * Revert from impersonating another account. * * @return \Drupal\Core\Session\AccountInterface - * The last account that was impersonated. + * $this. */ public function revertAccount(); @@ -57,7 +57,7 @@ public function revertAccount(); * been possibility of multiple impersonations. * * @return \Drupal\Core\Session\AccountInterface - * The original account that was impersonated. + * $this. */ public function revertAll(); } diff --git a/core/modules/simpletest/src/TestBase.php b/core/modules/simpletest/src/TestBase.php index b4d26a5..50f28a2 100644 --- a/core/modules/simpletest/src/TestBase.php +++ b/core/modules/simpletest/src/TestBase.php @@ -1082,9 +1082,18 @@ private function prepareEnvironment() { $request = Request::create('/'); $this->container->set('request', $request); + // Copy the current session and authentication managers into the new environment. + $this->container->set('session_manager', \Drupal::service('session_manager')); + $this->container->set('authentication', \Drupal::service('authentication')); + + // Create new current user service for the test environment. + $this->container->register('current_user', '\Drupal\Core\Session\AccountProxy') + ->addArgument(new Reference('authentication')) + ->addArgument(new Reference('request')) + ->addArgument(new Reference('session_manager')); + // Run all tests as an anonymous user by default, web tests will replace that // during the test set up. - $this->container->set('current_user', \Drupal::currentUser()); $this->container->get('current_user')->impersonateAccount(new AnonymousUserSession()); \Drupal::setContainer($this->container); @@ -1221,9 +1230,6 @@ private function restoreEnvironment() { // Restore original shutdown callbacks. $callbacks = &drupal_register_shutdown_function(); $callbacks = $this->originalShutdownCallbacks; - - // Restore original user session. - \Drupal::currentUser()->revertAll(); } /** diff --git a/core/modules/system/lib/Drupal/system/Tests/Session/UserImpersonatingUserTest.php b/core/modules/system/lib/Drupal/system/Tests/Session/UserImpersonatingUserTest.php index 1aa319e..2e08b23 100644 --- a/core/modules/system/lib/Drupal/system/Tests/Session/UserImpersonatingUserTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Session/UserImpersonatingUserTest.php @@ -5,7 +5,7 @@ * Contains Drupal\user\Tests\UserImpersonatingUserTest. */ -namespace Drupal\user\Tests; +namespace Drupal\system\Tests\Session; use Drupal\Core\Session\AnonymousUserSession; use Drupal\Core\Session\UserSession; @@ -19,8 +19,8 @@ class UserImpersonatingUserTest extends WebTestBase { public static function getInfo() { return array( 'name' => 'Impersonate users', - 'description' => 'Temporarily impersonate another user, and then restore the original user.', - 'group' => 'User', + 'description' => 'Temporarily impersonate another user account, and then restore the original account.', + 'group' => 'Session', ); } @@ -29,10 +29,13 @@ function setUp() { } function testUserImpersonateUser() { - $user = \Drupal::currentUser(); + $session_manager = $this->container->get('session_manager'); + $user = $this->container->get('current_user'); $original_user = clone $user; + $this->verbose('Session saving status: '. var_dump($session_manager->isEnabled())); + $this->assertFalse($session_manager->isEnabled(), 'Session saving is initially disabled.'); - // If not currently logged in, use user_user_impersonate_user() to switch to + // If not currently logged in, use AccountProxy::impersonateAccount() to switch to // user 1. If logged in, switch to the anonymous user instead. if ($user->isAnonymous()) { $user->impersonateAccount(new UserSession(array('uid' => 1))); @@ -42,12 +45,15 @@ function testUserImpersonateUser() { // Verify that the active user has changed, and that session saving is // disabled. - $this->assertEqual($user->id(), ($original_user->id() == 0 ? 1 : 0), t('User switched')); - $this->assertFalse(\Drupal::service('session_manager')->isEnabled(), t('Session saving is disabled.')); + $this->assertEqual($user->id(), ($original_user->id() == 0 ? 1 : 0), 'User switched'); + $this->assertFalse($session_manager->isEnabled(), 'Session saving is disabled.'); + + // Enable session saving for the purpose of this test. + $session_manager->enable(); // Perform a second (nested) impersonation. $user->impersonateAccount(new UserSession(array('uid' => 2))); - $this->assertEqual($user->id(), 2, t('User switched.')); + $this->assertEqual($user->id(), 2, 'User switched.'); // Revert to the user which was active between the first and second // impersonation attempt. @@ -55,8 +61,8 @@ function testUserImpersonateUser() { // Since we are still impersonating the user from the first attempt, // session handling still needs to be disabled. - $this->assertEqual($user->id(), ($original_user->id() == 0 ? 1 : 0), t('User switched.')); - $this->assertFalse(\Drupal::service('session_manager')->isEnabled(), t('Session saving is disabled.')); + $this->assertEqual($user->id(), ($original_user->id() == 0 ? 1 : 0), 'User switched.'); + $this->assertFalse($session_manager->isEnabled(), 'Session saving is disabled.'); // Revert to the original user which was active before the first // impersonation attempt. @@ -64,12 +70,26 @@ function testUserImpersonateUser() { // Assert that the original user is the active user again, and that session // saving has been re-enabled. - $this->assertEqual($user->id(), $original_user->id(), t('Original user successfully restored.')); + $this->assertEqual($user->id(), $original_user->id(), 'Original user successfully restored.'); + $this->assertTrue($session_manager->isEnabled(), 'Session saving is enabled.'); - // Simpletest uses user_impersonate_user() too, revert the impersonation by - // Simpletest to enable session saving again. This is safe because calling - // user_revert_user() too often simply results in returning the active user. - $user->revertAccount(); - $this->assertTrue(\Drupal::service('session_manager')->isEnabled(), t('Session saving is enabled.')); + // Verify that AccountProxy::revertAccount and AccountProxy::revertAll() + // will throw exceptions if there is none left in the stack. + try { + $ex1 = new \RuntimeException(); + $user->revertAccount(); + } + catch (\RuntimeException $e) { + $ex1 = $e; + } + $this->assertEqual($ex1->getMessage(), 'No more account impersonations to revert.', 'Revert account throws exception if called without previous impersonation.'); + try { + $ex2 = new \RuntimeException(); + $user->revertAll(); + } + catch (\RuntimeException $e) { + $ex2 = $e; + } + $this->assertEqual($ex2->getMessage(), 'No more account impersonations to revert.', 'Revert all throws exception if called without previous impersonation.'); } }