db ->table(self::TABLE) ->eq('token', $token) ->eq('sequence', $sequence) ->gt('expiration', time()) ->findOne(); } /** * Get all sessions for a given user * * @access public * @param integer $user_id User id * @return array */ public function getAll($user_id) { return $this->db ->table(self::TABLE) ->eq('user_id', $user_id) ->desc('date_creation') ->columns('id', 'ip', 'user_agent', 'date_creation', 'expiration') ->findAll(); } /** * Authenticate the user with the cookie * * @access public * @return bool */ public function authenticate() { $credentials = $this->readCookie(); if ($credentials !== false) { $record = $this->find($credentials['token'], $credentials['sequence']); if ($record) { // Update the sequence $this->writeCookie( $record['token'], $this->update($record['token']), $record['expiration'] ); // Create the session $this->userSession->refresh($this->user->getById($record['user_id'])); // Do not ask 2FA for remember me session $this->session['2fa_validated'] = true; $this->container['dispatcher']->dispatch( 'auth.success', new AuthEvent(self::AUTH_NAME, $this->userSession->getId()) ); return true; } } return false; } /** * Update the database and the cookie with a new sequence * * @access public */ public function refresh() { $credentials = $this->readCookie(); if ($credentials !== false) { $record = $this->find($credentials['token'], $credentials['sequence']); if ($record) { // Update the sequence $this->writeCookie( $record['token'], $this->update($record['token']), $record['expiration'] ); } } } /** * Remove a session record * * @access public * @param integer $session_id Session id * @return mixed */ public function remove($session_id) { return $this->db ->table(self::TABLE) ->eq('id', $session_id) ->remove(); } /** * Remove the current RememberMe session and the cookie * * @access public * @param integer $user_id User id */ public function destroy($user_id) { $credentials = $this->readCookie(); if ($credentials !== false) { $this->deleteCookie(); $this->db ->table(self::TABLE) ->eq('user_id', $user_id) ->eq('token', $credentials['token']) ->remove(); } } /** * Create a new RememberMe session * * @access public * @param integer $user_id User id * @param string $ip IP Address * @param string $user_agent User Agent * @return array */ public function create($user_id, $ip, $user_agent) { $token = hash('sha256', $user_id.$user_agent.$ip.Security::generateToken()); $sequence = Security::generateToken(); $expiration = time() + self::EXPIRATION; $this->cleanup($user_id); $this->db ->table(self::TABLE) ->insert(array( 'user_id' => $user_id, 'ip' => $ip, 'user_agent' => $user_agent, 'token' => $token, 'sequence' => $sequence, 'expiration' => $expiration, 'date_creation' => time(), )); return array( 'token' => $token, 'sequence' => $sequence, 'expiration' => $expiration, ); } /** * Remove old sessions for a given user * * @access public * @param integer $user_id User id * @return bool */ public function cleanup($user_id) { return $this->db ->table(self::TABLE) ->eq('user_id', $user_id) ->lt('expiration', time()) ->remove(); } /** * Return a new sequence token and update the database * * @access public * @param string $token Session token * @return string */ public function update($token) { $new_sequence = Security::generateToken(); $this->db ->table(self::TABLE) ->eq('token', $token) ->update(array('sequence' => $new_sequence)); return $new_sequence; } /** * Encode the cookie * * @access public * @param string $token Session token * @param string $sequence Sequence token * @return string */ public function encodeCookie($token, $sequence) { return implode('|', array($token, $sequence)); } /** * Decode the value of a cookie * * @access public * @param string $value Raw cookie data * @return array */ public function decodeCookie($value) { list($token, $sequence) = explode('|', $value); return array( 'token' => $token, 'sequence' => $sequence, ); } /** * Return true if the current user has a RememberMe cookie * * @access public * @return bool */ public function hasCookie() { return ! empty($_COOKIE[self::COOKIE_NAME]); } /** * Write and encode the cookie * * @access public * @param string $token Session token * @param string $sequence Sequence token * @param string $expiration Cookie expiration */ public function writeCookie($token, $sequence, $expiration) { setcookie( self::COOKIE_NAME, $this->encodeCookie($token, $sequence), $expiration, BASE_URL_DIRECTORY, null, Request::isHTTPS(), true ); } /** * Read and decode the cookie * * @access public * @return mixed */ public function readCookie() { if (empty($_COOKIE[self::COOKIE_NAME])) { return false; } return $this->decodeCookie($_COOKIE[self::COOKIE_NAME]); } /** * Remove the cookie * * @access public */ public function deleteCookie() { setcookie( self::COOKIE_NAME, '', time() - 3600, BASE_URL_DIRECTORY, null, Request::isHTTPS(), true ); } }