TokenStorage.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. /**
  3. * @package Grav\Plugin\Login
  4. *
  5. * @copyright Copyright (C) 2014 - 2017 RocketTheme, LLC. All rights reserved.
  6. * @license MIT License; see LICENSE file for details.
  7. */
  8. namespace Grav\Plugin\Login\RememberMe;
  9. use Grav\Common\Cache;
  10. use Grav\Common\Grav;
  11. use Doctrine\Common\Cache\CacheProvider;
  12. use Doctrine\Common\Cache\FilesystemCache;
  13. use Birke\Rememberme\Storage\StorageInterface;
  14. /**
  15. * Storage wrapper for Doctrine cache
  16. *
  17. * Used for storing the credential/token/persistentToken triplets.
  18. *
  19. * @author Sommerregen <sommerregen@benjamin-regler.de>
  20. */
  21. class TokenStorage implements StorageInterface
  22. {
  23. /**
  24. * @var CacheProvider
  25. */
  26. protected $driver;
  27. /**
  28. * @var string
  29. */
  30. protected $cache_dir;
  31. /**
  32. * Constructor
  33. *
  34. * @param string $path Path to storage directory
  35. * @throws \InvalidArgumentException
  36. */
  37. public function __construct($path = 'cache://rememberme')
  38. {
  39. /** @var Cache $cache */
  40. $cache = Grav::instance()['cache'];
  41. $this->cache_dir = Grav::instance()['locator']->findResource($path, true, true);
  42. // Setup cache
  43. $this->driver = $cache->getCacheDriver();
  44. if ($this->driver instanceof FilesystemCache) {
  45. $this->driver = new FilesystemCache($this->cache_dir);
  46. }
  47. // Set the cache namespace to our unique key
  48. $this->driver->setNamespace($cache->getKey());
  49. }
  50. /**
  51. * Return Tri-state value constant
  52. *
  53. * @param mixed $credential Unique credential (user id,
  54. * email address, user name)
  55. * @param string $token One-Time Token
  56. * @param string $persistentToken Persistent Token
  57. *
  58. * @return int
  59. */
  60. public function findTriplet($credential, $token, $persistentToken)
  61. {
  62. // Hash the tokens, because they can contain a salt and can be
  63. // accessed in the file system
  64. $persistentToken = sha1(trim($persistentToken));
  65. $token = sha1(trim($token));
  66. $id = $this->getId($credential);
  67. if (!$this->driver->contains($id)) {
  68. return self::TRIPLET_NOT_FOUND;
  69. }
  70. list($expire, $tokens) = $this->driver->fetch($id);
  71. if (isset($tokens[$persistentToken]) && $tokens[$persistentToken] === $token) {
  72. return self::TRIPLET_FOUND;
  73. }
  74. return self::TRIPLET_INVALID;
  75. }
  76. /**
  77. * Store the new token for the credential and the persistent token.
  78. * Create a new storage entry, if the combination of credential and
  79. * persistent token does not exist.
  80. *
  81. * @param mixed $credential
  82. * @param string $token
  83. * @param string $persistentToken
  84. * @param int $expire Timestamp when this triplet
  85. * will expire (0 = no expiry)
  86. */
  87. public function storeTriplet($credential, $token, $persistentToken, $expire = null)
  88. {
  89. // Hash the tokens, because they can contain a salt and can be
  90. // accessed in the file system
  91. $persistentToken = sha1(trim($persistentToken));
  92. $token = sha1(trim($token));
  93. $e = null;
  94. $tokens = [];
  95. $id = $this->getId($credential);
  96. if ($this->driver->contains($id)) {
  97. list($e, $tokens) = $this->driver->fetch($id);
  98. }
  99. // Get cache lifetime for tokens
  100. if ($expire === null && $e === null) {
  101. /** @var Cache $cache */
  102. $cache = Grav::instance()['cache'];
  103. $expire = $cache->getLifetime();
  104. } elseif ($expire === null) {
  105. $expire = $e;
  106. }
  107. // Update tokens
  108. $tokens[$persistentToken] = $token;
  109. $this->driver->save($id, [$expire, $tokens], $expire);
  110. return $this;
  111. }
  112. /**
  113. * Replace current token after successful authentication
  114. *
  115. * @param mixed $credential
  116. * @param string $token
  117. * @param string $persistentToken
  118. * @param int $expire
  119. */
  120. public function replaceTriplet($credential, $token, $persistentToken, $expire = null)
  121. {
  122. $this->cleanTriplet($credential, $persistentToken);
  123. $this->storeTriplet($credential, $token, $persistentToken, $expire);
  124. }
  125. /**
  126. * Remove one triplet of the user from the store
  127. *
  128. * @param mixed $credential
  129. * @param string $persistentToken
  130. */
  131. public function cleanTriplet($credential, $persistentToken)
  132. {
  133. // Hash the tokens, because they can contain a salt and can be
  134. // accessed in the file system
  135. $persistentToken = sha1(trim($persistentToken));
  136. // Delete token from storage
  137. $id = $this->getId($credential);
  138. if ($this->driver->contains($id)) {
  139. list($expire, $tokens) = $this->driver->fetch($id);
  140. unset($tokens[$persistentToken]);
  141. $this->driver->save($id, [$expire, $tokens], $expire);
  142. }
  143. }
  144. /**
  145. * Remove all triplets of a user, effectively logging him out on all
  146. * machines
  147. *
  148. * @param mixed $credential
  149. */
  150. public function cleanAllTriplets($credential)
  151. {
  152. $id = $this->getId($credential);
  153. $this->driver->delete($id);
  154. }
  155. /**
  156. * Helper method to clear RememberMe cache
  157. */
  158. public function clearCache()
  159. {
  160. $this->driver->flushAll();
  161. }
  162. /**
  163. * Get the cache id
  164. *
  165. * @param string $key A key to compute the cache id for
  166. * @return string The cache id
  167. */
  168. protected function getId($key)
  169. {
  170. /** @var Cache $cache */
  171. $cache = Grav::instance()['cache'];
  172. return 'login' . md5(trim($key) . $cache->getKey());
  173. }
  174. }