diff --git a/src/Cartalyst/Sentry/Facades/CI/Sentry.php b/src/Cartalyst/Sentry/Facades/CI/Sentry.php index ebd84eef2..c0939cef3 100644 --- a/src/Cartalyst/Sentry/Facades/CI/Sentry.php +++ b/src/Cartalyst/Sentry/Facades/CI/Sentry.php @@ -27,6 +27,7 @@ use Cartalyst\Sentry\Sentry as BaseSentry; use Cartalyst\Sentry\Throttling\Eloquent\Provider as ThrottleProvider; use Cartalyst\Sentry\Users\Eloquent\Provider as UserProvider; +use Cartalyst\Sentry\SessionHandlers\NativeSessionHandler; use Illuminate\Database\Eloquent\Model as Eloquent; use PDO; @@ -89,8 +90,10 @@ public static function createSentry() $userProvider = new UserProvider(new NativeHasher), new GroupProvider, new ThrottleProvider($userProvider), - new CISession($ci->session), - new CICookie($ci->input), + new NativeSessionHandler( + new CISession($ci->session), + new CICookie($ci->input) + ), $ci->input->ip_address() ); } diff --git a/src/Cartalyst/Sentry/Facades/FuelPHP/Sentry.php b/src/Cartalyst/Sentry/Facades/FuelPHP/Sentry.php index 9b5abcf2c..d8080f27f 100644 --- a/src/Cartalyst/Sentry/Facades/FuelPHP/Sentry.php +++ b/src/Cartalyst/Sentry/Facades/FuelPHP/Sentry.php @@ -23,6 +23,7 @@ use Cartalyst\Sentry\Facades\Facade; use Cartalyst\Sentry\Groups\Eloquent\Provider as GroupProvider; use Cartalyst\Sentry\Hashing\NativeHasher; +use Cartalyst\Sentry\SessionHandlers\NativeSessionHandler; use Cartalyst\Sentry\Sessions\FuelPHPSession; use Cartalyst\Sentry\Sentry as BaseSentry; use Cartalyst\Sentry\Throttling\Eloquent\Provider as ThrottleProvider; @@ -65,8 +66,10 @@ public static function createSentry() $userProvider = new UserProvider(new NativeHasher), new GroupProvider, new ThrottleProvider($userProvider), - new FuelPHPSession(Session::instance()), - new FuelPHPCookie, + new NativeSessionHandler( + new FuelPHPSession(Session::instance()), + new FuelPHPCookie + ), Input::real_ip() ); } diff --git a/src/Cartalyst/Sentry/Facades/Kohana/Sentry.php b/src/Cartalyst/Sentry/Facades/Kohana/Sentry.php index 183157ca4..d484416ab 100644 --- a/src/Cartalyst/Sentry/Facades/Kohana/Sentry.php +++ b/src/Cartalyst/Sentry/Facades/Kohana/Sentry.php @@ -23,6 +23,7 @@ use Cartalyst\Sentry\Groups\Kohana\Provider as GroupProvider; use Cartalyst\Sentry\Sessions\KohanaSession; use Cartalyst\Sentry\Sentry as BaseSentry; +use Cartalyst\Sentry\SessionHandlers\NativeSessionHandler; use Cartalyst\Sentry\Throttling\Kohana\Provider as ThrottleProvider; use Cartalyst\Sentry\Users\Kohana\Provider as UserProvider; @@ -67,8 +68,10 @@ public static function createSentry() $userProvider = new UserProvider($hasher), new GroupProvider, new ThrottleProvider($userProvider), - new KohanaSession(\Session::instance($config['session_driver']), $config['session_key']), - new KohanaCookie($config['cookie_key']), + new NativeSessionHandler( + new KohanaSession(\Session::instance($config['session_driver']), $config['session_key']), + new KohanaCookie($config['cookie_key']) + ), \Request::$client_ip ); } diff --git a/src/Cartalyst/Sentry/Facades/Native/Sentry.php b/src/Cartalyst/Sentry/Facades/Native/Sentry.php index d696c08d2..2f5e86366 100644 --- a/src/Cartalyst/Sentry/Facades/Native/Sentry.php +++ b/src/Cartalyst/Sentry/Facades/Native/Sentry.php @@ -27,6 +27,7 @@ use Cartalyst\Sentry\Hashing\NativeHasher; use Cartalyst\Sentry\Sessions\NativeSession; use Cartalyst\Sentry\Sessions\SessionInterface; +use Cartalyst\Sentry\SessionHandlers\NativeSessionHandler; use Cartalyst\Sentry\Sentry as BaseSentry; use Cartalyst\Sentry\Throttling\Eloquent\Provider as ThrottleProvider; use Cartalyst\Sentry\Throttling\ProviderInterface as ThrottleProviderInterface; @@ -63,8 +64,10 @@ public static function createSentry( $userProvider, $groupProvider ?: new GroupProvider, $throttleProvider ?: new ThrottleProvider($userProvider), - $session ?: new NativeSession, - $cookie ?: new NativeCookie, + new NativeSessionHandler( + $session ?: new NativeSession, + $cookie ?: new NativeCookie + ), $ipAddress ?: static::guessIpAddress() ); } diff --git a/src/Cartalyst/Sentry/Sentry.php b/src/Cartalyst/Sentry/Sentry.php index c0c2e8c02..217c04eb1 100644 --- a/src/Cartalyst/Sentry/Sentry.php +++ b/src/Cartalyst/Sentry/Sentry.php @@ -25,6 +25,8 @@ use Cartalyst\Sentry\Hashing\NativeHasher; use Cartalyst\Sentry\Sessions\NativeSession; use Cartalyst\Sentry\Sessions\SessionInterface; +use Cartalyst\Sentry\SessionHandlers\SessionHandlerInterface; +use Cartalyst\Sentry\SessionHandlers\NativeSessionHandler; use Cartalyst\Sentry\Throttling\Eloquent\Provider as ThrottleProvider; use Cartalyst\Sentry\Throttling\ProviderInterface as ThrottleProviderInterface; use Cartalyst\Sentry\Users\LoginRequiredException; @@ -36,6 +38,9 @@ use Cartalyst\Sentry\Users\UserNotActivatedException; class Sentry { + const SESSION_KEY_PERSIST_CODE = 'persistCode'; + const SESSION_KEY_USER_ID = 'userId'; + const SESSION_MASQUERADE_STACK = 'masqueradeStack'; /** * The user that's been retrieved and is used @@ -47,19 +52,6 @@ class Sentry { */ protected $user; - /** - * The session driver used by Sentry. - * - * @var \Cartalyst\Sentry\Sessions\SessionInterface - */ - protected $session; - - /** - * The cookie driver used by Sentry. - * - * @var \Cartalyst\Sentry\Cookies\CookieInterface - */ - protected $cookie; /** * The user provider, used for retrieving @@ -95,6 +87,14 @@ class Sentry { */ protected $ipAddress = '0.0.0.0'; + + /** + * The session handler class + * + * @var \Cartalyst\Sentry\SessionHandler\SessionHandlerInterface + */ + protected $session; + /** * Create a new Sentry object. * @@ -110,8 +110,7 @@ public function __construct( UserProviderInterface $userProvider = null, GroupProviderInterface $groupProvider = null, ThrottleProviderInterface $throttleProvider = null, - SessionInterface $session = null, - CookieInterface $cookie = null, + SessionHandlerInterface $sessionHandler = null, $ipAddress = null ) { @@ -119,8 +118,8 @@ public function __construct( $this->groupProvider = $groupProvider ?: new GroupProvider; $this->throttleProvider = $throttleProvider ?: new ThrottleProvider($this->userProvider); - $this->session = $session ?: new NativeSession; - $this->cookie = $cookie ?: new NativeCookie; + + $this->session = $sessionHandler ?: new NativeSessionHandler(); if (isset($ipAddress)) { @@ -245,21 +244,16 @@ public function check() { if (is_null($this->user)) { - // Check session first, follow by cookie - if ( ! $userArray = $this->session->get() and ! $userArray = $this->cookie->get()) - { - return false; - } + $id = $this->session->get(self::SESSION_KEY_USER_ID); + $persistCode = $this->session->get(self::SESSION_KEY_PERSIST_CODE); - // Now check our user is an array with two elements, - // the username followed by the persist code - if ( ! is_array($userArray) or count($userArray) !== 2) + + // If either user id or persist code is not set we are not logged in + if ($id == null || $persistCode == null) { return false; } - list($id, $persistCode) = $userArray; - // Let's find our user try { @@ -321,18 +315,15 @@ public function login(UserInterface $user, $remember = false) throw new UserNotActivatedException("Cannot login user [$login] as they are not activated."); } - $this->user = $user; - // Create an array of data to persist to the session and / or cookie - $toPersist = array($user->getId(), $user->getPersistCode()); + + $this->user = $user; // Set sessions - $this->session->put($toPersist); + $this->session->set(self::SESSION_KEY_USER_ID, $user->getId()); + $this->session->set(self::SESSION_KEY_PERSIST_CODE, $user->getPersistCode()); - if ($remember) - { - $this->cookie->forever($toPersist); - } + $remember && $this->session->forever(); // The user model can attach any handlers // to the "recordLogin" event. @@ -358,8 +349,7 @@ public function logout() { $this->user = null; - $this->session->forget(); - $this->cookie->forget(); + $this->session->destroy(); } /** @@ -397,7 +387,7 @@ public function getUser() */ public function setSession(SessionInterface $session) { - $this->session = $session; + $this->session->setSession($session); } /** @@ -407,7 +397,7 @@ public function setSession(SessionInterface $session) */ public function getSession() { - return $this->session; + return $this->session->getSession(); } /** @@ -713,6 +703,43 @@ public function findThrottlerByUserLogin($login, $ipAddress = null) return $this->throttleProvider->findByUserLogin($login,$ipAddress); } + /** + * Masquerades as another user + * + * @param \Cartalyst\Sentry\User\UserInterface $user User to masquerade as + * @return void + */ + public function masquerade(UserInterface $user) + { + if (!$this->check()) { + throw new LoginRequiredException(); + } + + $old[static::SESSION_KEY_USER_ID] = $this->session->get(static::SESSION_KEY_USER_ID); + $old[static::SESSION_KEY_PERSIST_CODE] = $this->session->get(static::SESSION_KEY_PERSIST_CODE); + $stack = $this->session->get(static::SESSION_MASQUERADE_STACK) ?: array(); + array_push($stack, $old); + $this->session->set(static::SESSION_MASQUERADE_STACK, $stack); + $this->login($user); + } + + /** + * LogOut of masquerade. Behaves like a normal logout of person is not masqueraded + * + * @return void + */ + public function masqueradedLogout() { + $stack = $this->session->get(static::SESSION_MASQUERADE_STACK); + if ($stack == null || !($oldUser = array_pop($stack))) { + return $this->LogOut(); + } + + $this->session->set(static::SESSION_KEY_USER_ID, $oldUser[static::SESSION_KEY_USER_ID]); + $this->session->set(static::SESSION_KEY_PERSIST_CODE, $oldUser[static::SESSION_KEY_PERSIST_CODE]); + $this->session->set(static::SESSION_MASQUERADE_STACK, $stack); + $this->user = $this->userProvider->findById($oldUser[static::SESSION_KEY_USER_ID]); + } + /** * Handle dynamic method calls into the method. * diff --git a/src/Cartalyst/Sentry/SentryServiceProvider.php b/src/Cartalyst/Sentry/SentryServiceProvider.php index bbf7dc0e8..3c91d291d 100644 --- a/src/Cartalyst/Sentry/SentryServiceProvider.php +++ b/src/Cartalyst/Sentry/SentryServiceProvider.php @@ -25,6 +25,7 @@ use Cartalyst\Sentry\Hashing\Sha256Hasher; use Cartalyst\Sentry\Hashing\WhirlpoolHasher; use Cartalyst\Sentry\Sentry; +use Cartalyst\Sentry\SessionHandlers\NativeSessionHandler; use Cartalyst\Sentry\Sessions\IlluminateSession; use Cartalyst\Sentry\Throttling\Eloquent\Provider as ThrottleProvider; use Cartalyst\Sentry\Users\Eloquent\Provider as UserProvider; @@ -289,8 +290,10 @@ protected function registerSentry() $app['sentry.user'], $app['sentry.group'], $app['sentry.throttle'], - $app['sentry.session'], - $app['sentry.cookie'], + new NativeSessionHandler( + $app['sentry.session'], + $app['sentry.cookie'] + ), $app['request']->getClientIp() ); }); diff --git a/src/Cartalyst/Sentry/SessionHandlers/NativeSessionHandler.php b/src/Cartalyst/Sentry/SessionHandlers/NativeSessionHandler.php new file mode 100644 index 000000000..bf4ecf9bb --- /dev/null +++ b/src/Cartalyst/Sentry/SessionHandlers/NativeSessionHandler.php @@ -0,0 +1,133 @@ +session = $session ?: new NativeSession; + $this->cookie = $cookie ?: new NativeCookie; + } + + /** + * Sets a value in the session + * + * @param string $key The key of the value to be set + * @param mixed $value The value to be set + * @return void + */ + public function set($key, $value) + { + $values = $this->session->get(); + $values[$key] = $value; + $this->session->put($values); + } + + /** + * Get a value in the session + * + * @param string $key The key of the value to get + * @return void + */ + public function get($key) + { + $values = $this->session->get(); + !isset($values[$key]) && $values = (array)$this->cookie->get(); + return isset($values[$key]) ? $values[$key] : null; + } + + /** + * Completely destroy the session + * + * @return true; + */ + public function destroy() + { + $this->session->forget(); + $this->cookie->forget(); + } + + /** + * Set the session interface for this handler + * + * @param Cartalyst\Sentry\Sessions\SessionInterface $session The Sessioninterface to set + * @return void + */ + public function setSession(SessionInterface $session) + { + $this->session = $session; + } + + /** + * Get the sessiondriver + * + * @return Cartalyst\Sentry\Sessions\SessionInterface + */ + public function getSession() + { + return $this->session; + } + + /** + * Make the session be kept forever + * + * @return void + */ + public function forever() + { + // Make sure that the values that are forever are not lost + $cookie = $this->cookie->get(); + $session = $this->session->get(); + if ($cookie == null) { + $cookie = $session; + } else if($session != null) { + $cookie = array_merge($cookie, $this->session->get()); + } + + $this->cookie->forever($cookie); + } +} diff --git a/src/Cartalyst/Sentry/SessionHandlers/SessionHandlerInterface.php b/src/Cartalyst/Sentry/SessionHandlers/SessionHandlerInterface.php new file mode 100644 index 000000000..46d5e7d19 --- /dev/null +++ b/src/Cartalyst/Sentry/SessionHandlers/SessionHandlerInterface.php @@ -0,0 +1,73 @@ +sessionHandler = new NativeSessionHandler( + $this->session = m::mock('Cartalyst\Sentry\Sessions\SessionInterface'), + $this->cookie = m::mock('Cartalyst\Sentry\Cookies\CookieInterface') + ); + } + + /** + * Check if a session is set correctly if the session is empty before + */ + public function testSetWithEmptySession() { + $this->session->shouldReceive('get')->once()->andReturn(null); + $this->session->shouldReceive('put')->once()->with(array('test' => 1)); + $this->sessionHandler->set('test', 1); + } + + /** + * check if a session is set correctly if the session was not empty before + */ + public function testSetWithNonEmptySession() { + $this->session->shouldReceive('get')->once()->andReturn(array('foo' => 'bar')); + $this->session->shouldReceive('put')->once()->with(array('test' => 1, 'foo' => 'bar')); + + $this->sessionHandler->set('test', 1); + } + + /** + * Check if get($key) return null if the key does not exists + */ + public function testGetReturnsNullIfValueDoesNotExist() { + $this->session->shouldReceive('get')->once()->andReturn(array('foo' => 'bar')); + $this->cookie->shouldReceive('get')->once()->andReturn(array('foo' => 'bar')); + $this->assertNull($this->sessionHandler->get('bizz')); + } + + /** + * Check if get($key) return null if no session is set + */ + public function testGetReturnsNullIfNoSessionIsSet() { + $this->session->shouldReceive('get')->once()->andReturn(null); + $this->cookie->shouldReceive('get')->once()->andReturn(null); + $this->assertNull($this->sessionHandler->get('bizz')); + } + + /** + * check if get($key) returns the correct value if it is set in session + */ + public function testGetReturnsIfIsSetInSession() { + $this->session->shouldReceive('get')->once()->andReturn(array('foo' => 'bar')); + $this->assertEquals('bar', $this->sessionHandler->get('foo')); + } + + /** + * check if get($key) returns the correct value if it is set in Cookie, and not in session + */ + public function testGetReturnsIfIsSetInCookieNoSession() { + $this->session->shouldReceive('get')->once()->andReturn(null); + $this->cookie->shouldReceive('get')->once()->andReturn(array('foo' => 'bar')); + $this->assertEquals('bar', $this->sessionHandler->get('foo')); + } + + /** + * check if get($key) returns the correct value if it is set in Cookie, and session is set + * but with different values + */ + public function testGetReturnsIfIsSetInCookieWithSession() { + $this->session->shouldReceive('get')->once()->andReturn(array('fuzz' => 'bizz')); + $this->cookie->shouldReceive('get')->once()->andReturn(array('foo' => 'bar')); + $this->assertEquals('bar', $this->sessionHandler->get('foo')); + } + + /** + * Checks if the destroy method destroys both the session and cookie + */ + public function testDestroyShouldForgetBothSessionAndCookie() { + $this->session->shouldReceive('forget')->once(); + $this->cookie->shouldReceive('forget')->once(); + $this->sessionHandler->destroy(); + } + + /** + * Check if setSession/getSession works + */ + public function testSetGetSession() { + $newSession = m::mock('Cartalyst\Sentry\Sessions\SessionInterface'); + $this->sessionHandler->setSession($newSession); + + $newSession->shouldReceive('put')->with(array('foo' => 'bar'))->once(); + $newSession->shouldReceive('get')->andReturn(null); + $this->sessionHandler->set('foo', 'bar'); + $this->assertEquals($newSession, $this->sessionHandler->getSession()); + } + + /** + * Forever should push the current session to the cookie + */ + public function testForeverPushesSessionToCookie() { + $this->cookie->shouldReceive('get')->andReturn(null); + $this->session->shouldReceive('get')->andReturn(array('foo' => 'bar')); + $this->cookie->shouldReceive('forever')->with(array('foo' => 'bar')); + $this->sessionHandler->forever(); + } + + /** + * Forever should push the current session to the cookie, but keep the existing values + */ + public function testForeverKeepsCookieValues() { + $this->cookie->shouldReceive('get')->andReturn(array('fizz' => 'buzz')); + $this->session->shouldReceive('get')->andReturn(array('foo' => 'bar')); + $this->cookie->shouldReceive('forever')->with(array('foo' => 'bar', 'fizz' => 'buzz')); + $this->sessionHandler->forever(); + } + + /** + * Forever should do nothing if the session is null + */ + public function testForeverKeepsCookieValuesIfSessionIsNull() { + $this->cookie->shouldReceive('get')->andReturn(array('fizz' => 'buzz')); + $this->session->shouldReceive('get')->andReturn(null); + $this->cookie->shouldReceive('forever')->with(array('fizz' => 'buzz')); + $this->sessionHandler->forever(); + } + + + /** + * Forever should do nothing if the session is null and cookie is null + */ + public function testForeverDoesNothingIfSessionAndCookieAreNull() { + $this->cookie->shouldReceive('get')->andReturn(null); + $this->session->shouldReceive('get')->andReturn(null); + $this->cookie->shouldReceive('forever')->with(null); + $this->sessionHandler->forever(); + } + + /** + * If a value exists in both the cookie as well as in the session, the cookie should be overridden + */ + public function testForeverSessionShouldOverrideCookie() { + $this->cookie->shouldReceive('get')->andReturn(array('foo' => 'bar1')); + $this->session->shouldReceive('get')->andReturn(array('foo' => 'bar2')); + $this->cookie->shouldReceive('forever')->with(array('foo' => 'bar2')); + $this->sessionHandler->forever(); + } + +} diff --git a/tests/SentryTest.php b/tests/SentryTest.php index 8e3be3c78..b064b1114 100644 --- a/tests/SentryTest.php +++ b/tests/SentryTest.php @@ -35,9 +35,7 @@ class SentryTest extends PHPUnit_Framework_TestCase { protected $hasher; - protected $session; - - protected $cookie; + protected $sessionHandler; protected $sentry; @@ -52,8 +50,7 @@ public function setUp() $this->userProvider = m::mock('Cartalyst\Sentry\Users\ProviderInterface'), $this->groupProvider = m::mock('Cartalyst\Sentry\Groups\ProviderInterface'), $this->throttleProvider = m::mock('Cartalyst\Sentry\Throttling\ProviderInterface'), - $this->session = m::mock('Cartalyst\Sentry\Sessions\SessionInterface'), - $this->cookie = m::mock('Cartalyst\Sentry\Cookies\CookieInterface') + $this->sessionHandler = m::mock('Cartalyst\Sentry\SessionHandlers\SessionHandlerInterface') ); } @@ -76,6 +73,7 @@ public function testLoggingInUnactivatedUser() $user->shouldReceive('isActivated')->once()->andReturn(false); $user->shouldReceive('getLogin')->once()->andReturn('foo'); + $this->sentry->login($user); } @@ -87,7 +85,10 @@ public function testLoggingInUser() $user->shouldReceive('getPersistCode')->once()->andReturn('persist_code'); $user->shouldReceive('recordLogin')->once(); - $this->session->shouldReceive('put')->with(array('foo', 'persist_code'))->once(); + + $this->sessionHandler->shouldReceive('set')->with(Sentry::SESSION_KEY_USER_ID, 'foo')->once(); + $this->sessionHandler->shouldReceive('set')->with(Sentry::SESSION_KEY_PERSIST_CODE, 'persist_code')->once(); + $this->sentry->login($user); } @@ -223,8 +224,7 @@ public function testAuthenticatingUser() $this->userProvider, $this->groupProvider, $this->throttleProvider, - $this->session, - $this->cookie + $this->sessionHandler ); $credentials = array( @@ -252,8 +252,7 @@ public function testAuthenticatingUserWithThrottling() $this->userProvider, $this->groupProvider, $this->throttleProvider, - $this->session, - $this->cookie + $this->sessionHandler ); $credentials = array( @@ -306,12 +305,11 @@ public function testAuthenticatingUserAndRemembering() public function testCheckLoggingOut() { $this->sentry->setUser(m::mock('Cartalyst\Sentry\Users\UserInterface')); - $this->session->shouldReceive('get')->once(); - $this->session->shouldReceive('forget')->once(); - $this->cookie->shouldReceive('get')->once(); - $this->cookie->shouldReceive('forget')->once(); - + $this->sessionHandler->shouldReceive('destroy')->once(); $this->sentry->logout(); + + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_USER_ID)->once()->andReturn(null); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_PERSIST_CODE)->once()->andReturn(null); $this->assertNull($this->sentry->getUser()); } @@ -341,14 +339,14 @@ public function testCheckingUserWhenUserIsSetAndSuspended() $throttle->shouldReceive('isBanned')->once()->andReturn(false); $throttle->shouldReceive('isSuspended')->once()->andReturn(true); - $session->shouldReceive('forget')->once(); - $cookie->shouldReceive('forget')->once(); - $user->shouldReceive('isActivated')->once()->andReturn(true); $this->throttleProvider->shouldReceive('findByUser')->once()->andReturn($throttle); $this->throttleProvider->shouldReceive('isEnabled')->once()->andReturn(true); + $this->sessionHandler->shouldReceive('setSession')->once(); + $this->sessionHandler->shouldReceive('destroy')->once(); + $this->sentry->setSession($session); $this->sentry->setCookie($cookie); $this->sentry->setUser($user); @@ -364,8 +362,8 @@ public function testCheckingUserWhenUserIsSetAndBanned() $throttle->shouldReceive('isBanned')->once()->andReturn(true); - $session->shouldReceive('forget')->once(); - $cookie->shouldReceive('forget')->once(); + $this->sessionHandler->shouldReceive('setSession')->once(); + $this->sessionHandler->shouldReceive('destroy')->once(); $user->shouldReceive('isActivated')->once()->andReturn(true); @@ -384,68 +382,33 @@ public function testCheckingUserWhenUserIsSetAndNotActivated() $user->shouldReceive('isActivated')->once()->andReturn(false); $this->sentry->setUser($user); + + $this->assertFalse($this->sentry->check()); } - public function testCheckingUserChecksSessionFirst() - { - $this->session->shouldReceive('get')->once()->andReturn(array('foo', 'persist_code')); - $this->cookie->shouldReceive('get')->never(); - - $throttle = m::mock('Cartalyst\Sentry\Throttling\ThrottleInterface'); - $throttle->shouldReceive('isBanned')->once()->andReturn(false); - $throttle->shouldReceive('isSuspended')->once()->andReturn(false); - - $this->throttleProvider->shouldReceive('findByUser')->once()->andReturn($throttle); - $this->throttleProvider->shouldReceive('isEnabled')->once()->andReturn(true); - - $this->userProvider->shouldReceive('findById')->andReturn($user = m::mock('Cartalyst\Sentry\Users\UserInterface')); - - $user->shouldReceive('checkPersistCode')->with('persist_code')->once()->andReturn(true); - $user->shouldReceive('isActivated')->once()->andReturn(true); - - $this->assertTrue($this->sentry->check()); - } - public function testCheckingUserChecksSessionFirstAndThenCookie() + public function testCheckingUserReturnsFalseIfUseridIsNull() { - $this->session->shouldReceive('get')->once(); - $this->cookie->shouldReceive('get')->once()->andReturn(array('foo', 'persist_code')); - - $throttle = m::mock('Cartalyst\Sentry\Throttling\ThrottleInterface'); - $throttle->shouldReceive('isBanned')->once()->andReturn(false); - $throttle->shouldReceive('isSuspended')->once()->andReturn(false); - - $this->userProvider->shouldReceive('findById')->andReturn($user = m::mock('Cartalyst\Sentry\Users\UserInterface')); - $this->throttleProvider->shouldReceive('findByUser')->once()->andReturn($throttle); - $this->throttleProvider->shouldReceive('isEnabled')->once()->andReturn(true); - - $user->shouldReceive('checkPersistCode')->with('persist_code')->once()->andReturn(true); - $user->shouldReceive('isActivated')->once()->andReturn(true); - - $this->assertTrue($this->sentry->check()); - } - - public function testCheckingUserReturnsFalseIfNoArrayIsReturned() - { - $this->session->shouldReceive('get')->once()->andReturn('we_should_never_return_a_string'); - + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_USER_ID)->once()->andReturn(null); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_PERSIST_CODE)->once()->andReturn('persist_code'); + $this->assertFalse($this->sentry->check()); } - public function testCheckingUserReturnsFalseIfIncorrectArrayIsReturned() + public function testCheckingUserReturnsFalseIfPersistCodeIsNull() { - $this->session->shouldReceive('get')->once()->andReturn(array('we', 'should', 'never', 'have', 'more', 'than', 'two')); - + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_USER_ID)->once()->andReturn('user_id'); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_PERSIST_CODE)->once()->andReturn(null); + $this->assertFalse($this->sentry->check()); } - public function testCheckingUserWhenNothingIsFound() + public function testCheckingUserReturnsFalseIfPersistCodeAndUserIdIsNull() { - $this->session->shouldReceive('get')->once()->andReturn(null); - - $this->cookie->shouldReceive('get')->once()->andReturn(null); - + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_USER_ID)->once()->andReturn(null); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_PERSIST_CODE)->once()->andReturn(null); + $this->assertFalse($this->sentry->check()); } @@ -492,106 +455,235 @@ public function testGetUserWithCheck() $sentry->getUser(); } - public function testFindGroupById() - { - $this->groupProvider->shouldReceive('findById')->once()->andReturn(true); - $this->assertTrue($this->sentry->findGroupByID(1)); - } - - public function testFindGroupByName() - { - $this->groupProvider->shouldReceive('findByName')->once()->andReturn(true); - $this->assertTrue($this->sentry->findGroupByName("name")); - } - - public function testFindAllGroups() - { - $this->groupProvider->shouldReceive('findAll')->once()->andReturn(true); - $this->assertTrue($this->sentry->findAllGroups()); - } - - public function testCreateGroup() - { - $this->groupProvider->shouldReceive('create')->once()->andReturn(true); - $this->assertTrue($this->sentry->createGroup(array())); - } - - public function testFindUserByID() - { - $this->userProvider->shouldReceive('findById')->once()->andReturn(true); - $this->assertTrue($this->sentry->findUserById(1)); - } - public function testFindUserByLogin() - { - $this->userProvider->shouldReceive('findByLogin')->once()->andReturn(true); - $this->assertTrue($this->sentry->findUserByLogin("login")); - } - - public function testFindUserByCredentials() - { - $this->userProvider->shouldReceive('findByCredentials')->once()->andReturn(true); - $this->assertTrue($this->sentry->findUserByCredentials(array())); - } - - public function testFindUserByActivationCode() - { - $this->userProvider->shouldReceive('findByActivationCode')->once()->andReturn(true); - $this->assertTrue($this->sentry->findUserByActivationCode("x")); - } - - public function testFindUserByResetPasswordCode() - { - $this->userProvider->shouldReceive('findByResetPasswordCode')->once()->andReturn(true); - $this->assertTrue($this->sentry->findUserByResetPasswordCode("x")); - } - - public function testFindAllUsers() - { - $this->userProvider->shouldReceive('findAll')->once()->andReturn(true); - $this->assertTrue($this->sentry->findAllUsers()); - } - - public function testFindAllUsersInGroup() - { - $group = m::mock('Cartalyst\Sentry\Groups\GroupInterface'); - $this->userProvider->shouldReceive('findAllInGroup')->once()->andReturn(true); - $this->assertTrue($this->sentry->findAllUsersInGroup($group)); - } - - public function testFindAllUsersWithAccess() - { - $this->userProvider->shouldReceive('findAllWithAccess')->once()->andReturn(true); - $this->assertTrue($this->sentry->findAllUsersWithAccess("")); - } - - public function testFindAllUsersWithAnyAccess() - { - $this->userProvider->shouldReceive('findAllWithAnyAccess')->once()->andReturn(true); - $this->assertTrue($this->sentry->findAllUsersWithAnyAccess(array())); - } - - public function testCreateUser() - { - $this->userProvider->shouldReceive('create')->once()->andReturn(true); - $this->assertTrue($this->sentry->createUser(array())); - } - - public function testGetEmptyUser() - { - $this->userProvider->shouldReceive('getEmptyUser')->once()->andReturn(true); - $this->assertTrue($this->sentry->getEmptyUser()); - } - - public function testFindThrottlerByUserID() - { - $this->throttleProvider->shouldReceive('findByUserId')->once()->andReturn(true); - $this->assertTrue($this->sentry->findThrottlerByUserId(1)); - } - - public function testFindThrottlerByUserLogin() - { - $this->throttleProvider->shouldReceive('findByUserLogin')->once()->andReturn(true); - $this->assertTrue($this->sentry->findThrottlerByUserLogin("X")); - } + public function testFindGroupById() + { + $this->groupProvider->shouldReceive('findById')->once()->andReturn(true); + $this->assertTrue($this->sentry->findGroupByID(1)); + } + + public function testFindGroupByName() + { + $this->groupProvider->shouldReceive('findByName')->once()->andReturn(true); + $this->assertTrue($this->sentry->findGroupByName("name")); + } + + public function testFindAllGroups() + { + $this->groupProvider->shouldReceive('findAll')->once()->andReturn(true); + $this->assertTrue($this->sentry->findAllGroups()); + } + + public function testCreateGroup() + { + $this->groupProvider->shouldReceive('create')->once()->andReturn(true); + $this->assertTrue($this->sentry->createGroup(array())); + } + + public function testFindUserByID() + { + $this->userProvider->shouldReceive('findById')->once()->andReturn(true); + $this->assertTrue($this->sentry->findUserById(1)); + } + public function testFindUserByLogin() + { + $this->userProvider->shouldReceive('findByLogin')->once()->andReturn(true); + $this->assertTrue($this->sentry->findUserByLogin("login")); + } + + public function testFindUserByCredentials() + { + $this->userProvider->shouldReceive('findByCredentials')->once()->andReturn(true); + $this->assertTrue($this->sentry->findUserByCredentials(array())); + } + + public function testFindUserByActivationCode() + { + $this->userProvider->shouldReceive('findByActivationCode')->once()->andReturn(true); + $this->assertTrue($this->sentry->findUserByActivationCode("x")); + } + public function testFindUserByResetPasswordCode() + { + $this->userProvider->shouldReceive('findByResetPasswordCode')->once()->andReturn(true); + $this->assertTrue($this->sentry->findUserByResetPasswordCode("x")); + } + + public function testFindAllUsers() + { + $this->userProvider->shouldReceive('findAll')->once()->andReturn(true); + $this->assertTrue($this->sentry->findAllUsers()); + } + + public function testFindAllUsersInGroup() + { + $group = m::mock('Cartalyst\Sentry\Groups\GroupInterface'); + $this->userProvider->shouldReceive('findAllInGroup')->once()->andReturn(true); + $this->assertTrue($this->sentry->findAllUsersInGroup($group)); + } + + public function testFindAllUsersWithAccess() + { + $this->userProvider->shouldReceive('findAllWithAccess')->once()->andReturn(true); + $this->assertTrue($this->sentry->findAllUsersWithAccess("")); + } + + public function testFindAllUsersWithAnyAccess() + { + $this->userProvider->shouldReceive('findAllWithAnyAccess')->once()->andReturn(true); + $this->assertTrue($this->sentry->findAllUsersWithAnyAccess(array())); + } + + public function testCreateUser() + { + $this->userProvider->shouldReceive('create')->once()->andReturn(true); + $this->assertTrue($this->sentry->createUser(array())); + } + + public function testGetEmptyUser() + { + $this->userProvider->shouldReceive('getEmptyUser')->once()->andReturn(true); + $this->assertTrue($this->sentry->getEmptyUser()); + } + + public function testFindThrottlerByUserID() + { + $this->throttleProvider->shouldReceive('findByUserId')->once()->andReturn(true); + $this->assertTrue($this->sentry->findThrottlerByUserId(1)); + } + + public function testFindThrottlerByUserLogin() + { + $this->throttleProvider->shouldReceive('findByUserLogin')->once()->andReturn(true); + $this->assertTrue($this->sentry->findThrottlerByUserLogin("X")); + } + + /** + * Simple masquerade check + */ + public function testSimpleMasquerade() + { + $user = m::mock('Cartalyst\Sentry\Users\UserInterface'); + + $this->userProvider->shouldReceive('findById')->once()->andReturn($userOld = m::mock('Cartalyst\Sentry\Users\UserInterface')); + + + $userOld->shouldReceive('checkPersistCode')->andReturn(true); + $userOld->shouldReceive('isActivated')->andReturn(true); + $userOld->shouldReceive('isEnabled')->andReturn(true); + $userOld->shouldReceive('isBanned')->andReturn(false); + $userOld->shouldReceive('isSuspended')->andReturn(false); + + $this->throttleProvider->shouldReceive('findByUser')->andReturn($user); + $this->throttleProvider->shouldReceive('isEnabled')->andReturn(true); + + $user->shouldReceive('isActivated')->andReturn(true); + $user->shouldReceive('isEnabled')->andReturn(true); + $user->shouldReceive('isBanned')->andReturn(false); + $user->shouldReceive('isSuspended')->andReturn(false); + $user->shouldReceive('getId')->andReturn('test'); + $user->shouldReceive('getPersistCode')->andReturn('persist_code'); + $user->shouldReceive('recordLogin'); + + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_PERSIST_CODE)->andReturn('foo'); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_USER_ID)->andReturn('bar'); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_MASQUERADE_STACK)->andReturn(null); + $this->sessionHandler->shouldReceive('set') + ->with(Sentry::SESSION_MASQUERADE_STACK, array( + array(Sentry::SESSION_KEY_PERSIST_CODE => 'foo', Sentry::SESSION_KEY_USER_ID => 'bar') + ));; + $this->sessionHandler->shouldReceive('set')->with(Sentry::SESSION_KEY_USER_ID, 'test'); + $this->sessionHandler->shouldReceive('set')->with(Sentry::SESSION_KEY_PERSIST_CODE, 'persist_code'); + + $this->sentry->masquerade($user); + } + + /** + * @expectedException Cartalyst\Sentry\Users\LoginRequiredException + */ + public function testMasqueradeNogLoggedInException() { + $user = m::mock('Cartalyst\Sentry\Users\UserInterface'); + + $this->sessionHandler->shouldReceive('get')->andReturn(null); + + $this->sentry->masquerade($user); + } + + /** + * tests If current masquerades are not lost if you masquerade + */ + public function testMasqueradeStackNotLost() + { + $user = m::mock('Cartalyst\Sentry\Users\UserInterface'); + + $this->userProvider->shouldReceive('findById')->once()->andReturn($userOld = m::mock('Cartalyst\Sentry\Users\UserInterface')); + + + $userOld->shouldReceive('checkPersistCode')->andReturn(true); + $userOld->shouldReceive('isActivated')->andReturn(true); + $userOld->shouldReceive('isEnabled')->andReturn(true); + $userOld->shouldReceive('isBanned')->andReturn(false); + $userOld->shouldReceive('isSuspended')->andReturn(false); + + $this->throttleProvider->shouldReceive('findByUser')->andReturn($user); + $this->throttleProvider->shouldReceive('isEnabled')->andReturn(true); + + $user->shouldReceive('isActivated')->andReturn(true); + $user->shouldReceive('isEnabled')->andReturn(true); + $user->shouldReceive('isBanned')->andReturn(false); + $user->shouldReceive('isSuspended')->andReturn(false); + $user->shouldReceive('getId')->andReturn('test'); + $user->shouldReceive('getPersistCode')->andReturn('persist_code'); + $user->shouldReceive('recordLogin'); + + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_PERSIST_CODE)->andReturn('foo'); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_USER_ID)->andReturn('bar'); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_MASQUERADE_STACK)->andReturn(array( + array(Sentry::SESSION_KEY_PERSIST_CODE => 'foo_old', Sentry::SESSION_KEY_USER_ID => 'bar_old') + )); + $this->sessionHandler->shouldReceive('set') + ->with(Sentry::SESSION_MASQUERADE_STACK, array( + array(Sentry::SESSION_KEY_PERSIST_CODE => 'foo_old', Sentry::SESSION_KEY_USER_ID => 'bar_old'), + array(Sentry::SESSION_KEY_PERSIST_CODE => 'foo', Sentry::SESSION_KEY_USER_ID => 'bar') + ));; + $this->sessionHandler->shouldReceive('set')->with(Sentry::SESSION_KEY_USER_ID, 'test'); + $this->sessionHandler->shouldReceive('set')->with(Sentry::SESSION_KEY_PERSIST_CODE, 'persist_code'); + + $this->sentry->masquerade($user); + } + + /** + * Test if a normal masqueradedLogout works if the person is nog masqueraded + */ + public function testCheckMasqueradedLoggingOut() + { + $this->sentry->setUser(m::mock('Cartalyst\Sentry\Users\UserInterface')); + $this->sessionHandler->shouldReceive('destroy')->once(); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_MASQUERADE_STACK)->once()->andReturn(null); + $this->sentry->masqueradedLogout(); + + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_USER_ID)->once()->andReturn(null); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_KEY_PERSIST_CODE)->once()->andReturn(null); + $this->assertNull($this->sentry->getUser()); + } + + /** + * Test if a masqueraded logout goes back to the last user + */ + public function testMasqueradedLogOutGoBack() + { + $this->sentry->setUser(m::mock('Cartalyst\Sentry\Users\UserInterface')); + $this->sessionHandler->shouldReceive('get')->with(Sentry::SESSION_MASQUERADE_STACK)->once()->andReturn(array( + array(Sentry::SESSION_KEY_PERSIST_CODE => 'foo_old', Sentry::SESSION_KEY_USER_ID => 'bar_old'), + array(Sentry::SESSION_KEY_PERSIST_CODE => 'foo', Sentry::SESSION_KEY_USER_ID => 'bar') + )); + + $this->sessionHandler->shouldReceive('set')->with(Sentry::SESSION_KEY_USER_ID, 'bar')->once(); + $this->sessionHandler->shouldReceive('set')->with(Sentry::SESSION_KEY_PERSIST_CODE, 'foo')->once(); + $this->sessionHandler->shouldReceive('set')->with(Sentry::SESSION_MASQUERADE_STACK, array( + array(Sentry::SESSION_KEY_PERSIST_CODE => 'foo_old', Sentry::SESSION_KEY_USER_ID => 'bar_old') + ))->once(); + $this->userProvider->shouldReceive('findById')->with('bar')->andReturn('test'); + $this->sentry->masqueradedLogout(); + $this->assertEquals('test', $this->sentry->getUser()); + } }