class-wp-session-tokens.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. <?php
  2. /**
  3. * Session API: WP_Session_Tokens class
  4. *
  5. * @package WordPress
  6. * @subpackage Session
  7. * @since 4.7.0
  8. */
  9. /**
  10. * Abstract class for managing user session tokens.
  11. *
  12. * @since 4.0.0
  13. */
  14. abstract class WP_Session_Tokens {
  15. /**
  16. * User ID.
  17. *
  18. * @since 4.0.0
  19. * @access protected
  20. * @var int User ID.
  21. */
  22. protected $user_id;
  23. /**
  24. * Protected constructor.
  25. *
  26. * @since 4.0.0
  27. *
  28. * @param int $user_id User whose session to manage.
  29. */
  30. protected function __construct( $user_id ) {
  31. $this->user_id = $user_id;
  32. }
  33. /**
  34. * Get a session token manager instance for a user.
  35. *
  36. * This method contains a filter that allows a plugin to swap out
  37. * the session manager for a subclass of WP_Session_Tokens.
  38. *
  39. * @since 4.0.0
  40. * @access public
  41. * @static
  42. *
  43. * @param int $user_id User whose session to manage.
  44. */
  45. final public static function get_instance( $user_id ) {
  46. /**
  47. * Filters the session token manager used.
  48. *
  49. * @since 4.0.0
  50. *
  51. * @param string $session Name of class to use as the manager.
  52. * Default 'WP_User_Meta_Session_Tokens'.
  53. */
  54. $manager = apply_filters( 'session_token_manager', 'WP_User_Meta_Session_Tokens' );
  55. return new $manager( $user_id );
  56. }
  57. /**
  58. * Hashes a session token for storage.
  59. *
  60. * @since 4.0.0
  61. * @access private
  62. *
  63. * @param string $token Session token to hash.
  64. * @return string A hash of the session token (a verifier).
  65. */
  66. final private function hash_token( $token ) {
  67. // If ext/hash is not present, use sha1() instead.
  68. if ( function_exists( 'hash' ) ) {
  69. return hash( 'sha256', $token );
  70. } else {
  71. return sha1( $token );
  72. }
  73. }
  74. /**
  75. * Get a user's session.
  76. *
  77. * @since 4.0.0
  78. * @access public
  79. *
  80. * @param string $token Session token
  81. * @return array User session
  82. */
  83. final public function get( $token ) {
  84. $verifier = $this->hash_token( $token );
  85. return $this->get_session( $verifier );
  86. }
  87. /**
  88. * Validate a user's session token as authentic.
  89. *
  90. * Checks that the given token is present and hasn't expired.
  91. *
  92. * @since 4.0.0
  93. * @access public
  94. *
  95. * @param string $token Token to verify.
  96. * @return bool Whether the token is valid for the user.
  97. */
  98. final public function verify( $token ) {
  99. $verifier = $this->hash_token( $token );
  100. return (bool) $this->get_session( $verifier );
  101. }
  102. /**
  103. * Generate a session token and attach session information to it.
  104. *
  105. * A session token is a long, random string. It is used in a cookie
  106. * link that cookie to an expiration time and to ensure the cookie
  107. * becomes invalidated upon logout.
  108. *
  109. * This function generates a token and stores it with the associated
  110. * expiration time (and potentially other session information via the
  111. * {@see 'attach_session_information'} filter).
  112. *
  113. * @since 4.0.0
  114. * @access public
  115. *
  116. * @param int $expiration Session expiration timestamp.
  117. * @return string Session token.
  118. */
  119. final public function create( $expiration ) {
  120. /**
  121. * Filters the information attached to the newly created session.
  122. *
  123. * Could be used in the future to attach information such as
  124. * IP address or user agent to a session.
  125. *
  126. * @since 4.0.0
  127. *
  128. * @param array $session Array of extra data.
  129. * @param int $user_id User ID.
  130. */
  131. $session = apply_filters( 'attach_session_information', array(), $this->user_id );
  132. $session['expiration'] = $expiration;
  133. // IP address.
  134. if ( !empty( $_SERVER['REMOTE_ADDR'] ) ) {
  135. $session['ip'] = $_SERVER['REMOTE_ADDR'];
  136. }
  137. // User-agent.
  138. if ( ! empty( $_SERVER['HTTP_USER_AGENT'] ) ) {
  139. $session['ua'] = wp_unslash( $_SERVER['HTTP_USER_AGENT'] );
  140. }
  141. // Timestamp
  142. $session['login'] = time();
  143. $token = wp_generate_password( 43, false, false );
  144. $this->update( $token, $session );
  145. return $token;
  146. }
  147. /**
  148. * Update a session token.
  149. *
  150. * @since 4.0.0
  151. * @access public
  152. *
  153. * @param string $token Session token to update.
  154. * @param array $session Session information.
  155. */
  156. final public function update( $token, $session ) {
  157. $verifier = $this->hash_token( $token );
  158. $this->update_session( $verifier, $session );
  159. }
  160. /**
  161. * Destroy a session token.
  162. *
  163. * @since 4.0.0
  164. * @access public
  165. *
  166. * @param string $token Session token to destroy.
  167. */
  168. final public function destroy( $token ) {
  169. $verifier = $this->hash_token( $token );
  170. $this->update_session( $verifier, null );
  171. }
  172. /**
  173. * Destroy all session tokens for this user,
  174. * except a single token, presumably the one in use.
  175. *
  176. * @since 4.0.0
  177. * @access public
  178. *
  179. * @param string $token_to_keep Session token to keep.
  180. */
  181. final public function destroy_others( $token_to_keep ) {
  182. $verifier = $this->hash_token( $token_to_keep );
  183. $session = $this->get_session( $verifier );
  184. if ( $session ) {
  185. $this->destroy_other_sessions( $verifier );
  186. } else {
  187. $this->destroy_all_sessions();
  188. }
  189. }
  190. /**
  191. * Determine whether a session token is still valid,
  192. * based on expiration.
  193. *
  194. * @since 4.0.0
  195. * @access protected
  196. *
  197. * @param array $session Session to check.
  198. * @return bool Whether session is valid.
  199. */
  200. final protected function is_still_valid( $session ) {
  201. return $session['expiration'] >= time();
  202. }
  203. /**
  204. * Destroy all session tokens for a user.
  205. *
  206. * @since 4.0.0
  207. * @access public
  208. */
  209. final public function destroy_all() {
  210. $this->destroy_all_sessions();
  211. }
  212. /**
  213. * Destroy all session tokens for all users.
  214. *
  215. * @since 4.0.0
  216. * @access public
  217. * @static
  218. */
  219. final public static function destroy_all_for_all_users() {
  220. /** This filter is documented in wp-includes/class-wp-session-tokens.php */
  221. $manager = apply_filters( 'session_token_manager', 'WP_User_Meta_Session_Tokens' );
  222. call_user_func( array( $manager, 'drop_sessions' ) );
  223. }
  224. /**
  225. * Retrieve all sessions of a user.
  226. *
  227. * @since 4.0.0
  228. * @access public
  229. *
  230. * @return array Sessions of a user.
  231. */
  232. final public function get_all() {
  233. return array_values( $this->get_sessions() );
  234. }
  235. /**
  236. * This method should retrieve all sessions of a user, keyed by verifier.
  237. *
  238. * @since 4.0.0
  239. * @access protected
  240. *
  241. * @return array Sessions of a user, keyed by verifier.
  242. */
  243. abstract protected function get_sessions();
  244. /**
  245. * This method should look up a session by its verifier (token hash).
  246. *
  247. * @since 4.0.0
  248. * @access protected
  249. *
  250. * @param string $verifier Verifier of the session to retrieve.
  251. * @return array|null The session, or null if it does not exist.
  252. */
  253. abstract protected function get_session( $verifier );
  254. /**
  255. * This method should update a session by its verifier.
  256. *
  257. * Omitting the second argument should destroy the session.
  258. *
  259. * @since 4.0.0
  260. * @access protected
  261. *
  262. * @param string $verifier Verifier of the session to update.
  263. * @param array $session Optional. Session. Omitting this argument destroys the session.
  264. */
  265. abstract protected function update_session( $verifier, $session = null );
  266. /**
  267. * This method should destroy all session tokens for this user,
  268. * except a single session passed.
  269. *
  270. * @since 4.0.0
  271. * @access protected
  272. *
  273. * @param string $verifier Verifier of the session to keep.
  274. */
  275. abstract protected function destroy_other_sessions( $verifier );
  276. /**
  277. * This method should destroy all sessions for a user.
  278. *
  279. * @since 4.0.0
  280. * @access protected
  281. */
  282. abstract protected function destroy_all_sessions();
  283. /**
  284. * This static method should destroy all session tokens for all users.
  285. *
  286. * @since 4.0.0
  287. * @access public
  288. * @static
  289. */
  290. public static function drop_sessions() {}
  291. }