TokenBasedRememberMeServicesTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. <?php
  2. namespace Symfony\Tests\Component\Security\Http\RememberMe;
  3. use Symfony\Component\Security\Core\Authentication\Token\RememberMeToken;
  4. use Symfony\Component\Security\Core\Authentication\Token\Token;
  5. use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
  6. use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
  7. use Symfony\Component\HttpFoundation\Request;
  8. use Symfony\Component\HttpFoundation\Response;
  9. use Symfony\Component\Security\Http\RememberMe\TokenBasedRememberMeServices;
  10. use Symfony\Component\Security\Core\Exception\TokenNotFoundException;
  11. use Symfony\Component\Security\Core\Exception\CookieTheftException;
  12. class TokenBasedRememberMeServicesTest extends \PHPUnit_Framework_TestCase
  13. {
  14. public function testAutoLoginReturnsNullWhenNoCookie()
  15. {
  16. $service = $this->getService(null, array('name' => 'foo'));
  17. $this->assertNull($service->autoLogin(new Request()));
  18. }
  19. /**
  20. * @expectedException Symfony\Component\Security\Core\Exception\AuthenticationException
  21. * @expectedMessage The cookie is invalid.
  22. */
  23. public function testAutoLoginThrowsExceptionOnInvalidCookie()
  24. {
  25. $service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => false, 'remember_me_parameter' => 'foo'));
  26. $request = new Request;
  27. $request->request->set('foo', 'true');
  28. $request->cookies->set('foo', 'foo');
  29. $service->autoLogin($request);
  30. }
  31. /**
  32. * @expectedException Symfony\Component\Security\Core\Exception\UsernameNotFoundException
  33. */
  34. public function testAutoLoginThrowsExceptionOnNonExistentUser()
  35. {
  36. $userProvider = $this->getProvider();
  37. $service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
  38. $request = new Request;
  39. $request->cookies->set('foo', $this->getCookie('fooclass', 'foouser', time()+3600, 'foopass'));
  40. $userProvider
  41. ->expects($this->once())
  42. ->method('loadUserByUsername')
  43. ->will($this->throwException(new UsernameNotFoundException('user not found')))
  44. ;
  45. $service->autoLogin($request);
  46. }
  47. /**
  48. * @expectedException Symfony\Component\Security\Core\Exception\AuthenticationException
  49. * @expectedMessage The cookie's hash is invalid.
  50. */
  51. public function testAutoLoginDoesNotAcceptCookieWithInvalidHash()
  52. {
  53. $userProvider = $this->getProvider();
  54. $service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
  55. $request = new Request;
  56. $request->cookies->set('foo', base64_encode('class:'.base64_encode('foouser').':123456789:fooHash'));
  57. $user = $this->getMock('Symfony\Component\Security\Core\User\AccountInterface');
  58. $user
  59. ->expects($this->once())
  60. ->method('getPassword')
  61. ->will($this->returnValue('foopass'))
  62. ;
  63. $userProvider
  64. ->expects($this->once())
  65. ->method('loadUserByUsername')
  66. ->with($this->equalTo('foouser'))
  67. ->will($this->returnValue($user))
  68. ;
  69. $service->autoLogin($request);
  70. }
  71. /**
  72. * @expectedException Symfony\Component\Security\Core\Exception\AuthenticationException
  73. * @expectedMessage The cookie has expired.
  74. */
  75. public function testAutoLoginDoesNotAcceptAnExpiredCookie()
  76. {
  77. $userProvider = $this->getProvider();
  78. $service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
  79. $request = new Request;
  80. $request->cookies->set('foo', $this->getCookie('fooclass', 'foouser', time() - 1, 'foopass'));
  81. $user = $this->getMock('Symfony\Component\Security\Core\User\AccountInterface');
  82. $user
  83. ->expects($this->once())
  84. ->method('getPassword')
  85. ->will($this->returnValue('foopass'))
  86. ;
  87. $userProvider
  88. ->expects($this->once())
  89. ->method('loadUserByUsername')
  90. ->with($this->equalTo('foouser'))
  91. ->will($this->returnValue($user))
  92. ;
  93. $service->autoLogin($request);
  94. }
  95. public function testAutoLogin()
  96. {
  97. $user = $this->getMock('Symfony\Component\Security\Core\User\AccountInterface');
  98. $user
  99. ->expects($this->once())
  100. ->method('getRoles')
  101. ->will($this->returnValue(array('ROLE_FOO')))
  102. ;
  103. $user
  104. ->expects($this->once())
  105. ->method('getPassword')
  106. ->will($this->returnValue('foopass'))
  107. ;
  108. $userProvider = $this->getProvider();
  109. $userProvider
  110. ->expects($this->once())
  111. ->method('loadUserByUsername')
  112. ->with($this->equalTo('foouser'))
  113. ->will($this->returnValue($user))
  114. ;
  115. $service = $this->getService($userProvider, array('name' => 'foo', 'always_remember_me' => true, 'lifetime' => 3600));
  116. $request = new Request;
  117. $request->cookies->set('foo', $this->getCookie('fooclass', 'foouser', time()+3600, 'foopass'));
  118. $returnedToken = $service->autoLogin($request);
  119. $this->assertInstanceOf('Symfony\Component\Security\Core\Authentication\Token\RememberMeToken', $returnedToken);
  120. $this->assertSame($user, $returnedToken->getUser());
  121. $this->assertEquals('fookey', $returnedToken->getKey());
  122. }
  123. public function testLogout()
  124. {
  125. $service = $this->getService(null, array('name' => 'foo', 'path' => null, 'domain' => null));
  126. $request = new Request();
  127. $response = new Response();
  128. $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
  129. $this->assertFalse($response->headers->hasCookie('foo'));
  130. $service->logout($request, $response, $token);
  131. $cookie = $response->headers->getCookie('foo');
  132. $this->assertTrue($cookie->isCleared());
  133. $this->assertNull($cookie->getPath());
  134. $this->assertNull($cookie->getDomain());
  135. }
  136. public function testLoginFail()
  137. {
  138. $service = $this->getService(null, array('name' => 'foo', 'path' => '/foo', 'domain' => 'foodomain.foo'));
  139. $request = new Request();
  140. $response = new Response();
  141. $this->assertFalse($response->headers->hasCookie('foo'));
  142. $service->loginFail($request, $response);
  143. $cookie = $response->headers->getCookie('foo');
  144. $this->assertTrue($cookie->isCleared());
  145. $this->assertEquals('/foo', $cookie->getPath());
  146. $this->assertEquals('foodomain.foo', $cookie->getDomain());
  147. }
  148. public function testLoginSuccessDoesNotRenewRememberMeToken()
  149. {
  150. $service = $this->getService(null, array('name' => 'foo', 'domain' => 'myfoodomain.foo', 'path' => '/foo/path', 'secure' => true, 'httponly' => true, 'lifetime' => 3600));
  151. $request = new Request;
  152. $response = new Response;
  153. $user = $this->getMock('Symfony\Component\Security\Core\User\AccountInterface');
  154. $user
  155. ->expects($this->once())
  156. ->method('getRoles')
  157. ->will($this->returnValue(array('ROLE_FOO')))
  158. ;
  159. $token = new RememberMeToken($user, 'fookey', 'foo');
  160. $this->assertFalse($response->headers->hasCookie('foo'));
  161. $service->loginSuccess($request, $response, $token);
  162. $this->assertFalse($response->headers->hasCookie('foo'));
  163. }
  164. public function testLoginSuccessIgnoresTokensWhichDoNotContainAnAccountInterfaceImplementation()
  165. {
  166. $service = $this->getService(null, array('name' => 'foo', 'always_remember_me' => true));
  167. $request = new Request;
  168. $response = new Response;
  169. $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
  170. $token
  171. ->expects($this->once())
  172. ->method('getUser')
  173. ->will($this->returnValue('foo'))
  174. ;
  175. $this->assertFalse($response->headers->hasCookie('foo'));
  176. $service->loginSuccess($request, $response, $token);
  177. $this->assertFalse($response->headers->hasCookie('foo'));
  178. }
  179. public function testLoginSuccess()
  180. {
  181. $service = $this->getService(null, array('name' => 'foo', 'domain' => 'myfoodomain.foo', 'path' => '/foo/path', 'secure' => true, 'httponly' => true, 'lifetime' => 3600, 'always_remember_me' => true));
  182. $request = new Request;
  183. $response = new Response;
  184. $token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
  185. $user = $this->getMock('Symfony\Component\Security\Core\User\AccountInterface');
  186. $user
  187. ->expects($this->once())
  188. ->method('getPassword')
  189. ->will($this->returnValue('foopass'))
  190. ;
  191. $user
  192. ->expects($this->once())
  193. ->method('getUsername')
  194. ->will($this->returnValue('foouser'))
  195. ;
  196. $token
  197. ->expects($this->atLeastOnce())
  198. ->method('getUser')
  199. ->will($this->returnValue($user))
  200. ;
  201. $this->assertFalse($response->headers->hasCookie('foo'));
  202. $service->loginSuccess($request, $response, $token);
  203. $cookie = $response->headers->getCookie('foo');
  204. $this->assertFalse($cookie->isCleared());
  205. $this->assertTrue($cookie->isSecure());
  206. $this->assertTrue($cookie->isHttpOnly());
  207. $this->assertTrue($cookie->getExpire() > time() + 3590 && $cookie->getExpire() < time() + 3610);
  208. $this->assertEquals('myfoodomain.foo', $cookie->getDomain());
  209. $this->assertEquals('/foo/path', $cookie->getPath());
  210. }
  211. protected function getCookie($class, $username, $expires, $password)
  212. {
  213. $service = $this->getService();
  214. $r = new \ReflectionMethod($service, 'generateCookieValue');
  215. $r->setAccessible(true);
  216. return $r->invoke($service, $class, $username, $expires, $password);
  217. }
  218. protected function encodeCookie(array $parts)
  219. {
  220. $service = $this->getService();
  221. $r = new \ReflectionMethod($service, 'encodeCookie');
  222. $r->setAccessible(true);
  223. return $r->invoke($service, $parts);
  224. }
  225. protected function getService($userProvider = null, $options = array(), $logger = null)
  226. {
  227. if (null === $userProvider) {
  228. $userProvider = $this->getProvider();
  229. }
  230. $service = new TokenBasedRememberMeServices(array($userProvider), 'fookey', 'fookey', $options, $logger);
  231. return $service;
  232. }
  233. protected function getProvider()
  234. {
  235. $provider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface');
  236. $provider
  237. ->expects($this->any())
  238. ->method('supportsClass')
  239. ->will($this->returnValue(true))
  240. ;
  241. return $provider;
  242. }
  243. }