summaryrefslogtreecommitdiff
path: root/app/Core
diff options
context:
space:
mode:
authorFrederic Guillot <fred@kanboard.net>2015-11-15 12:50:33 -0500
committerFrederic Guillot <fred@kanboard.net>2015-11-15 12:50:33 -0500
commita675271ad71b7713d1b33bdba3c51b2b04813229 (patch)
treee54d8a95e16ca521193b9fd5a5eb071aa2910823 /app/Core
parent2fc402f6733573627ad25394d109b9f848ef04f6 (diff)
Rewrite of session management
Diffstat (limited to 'app/Core')
-rw-r--r--app/Core/Base.php4
-rw-r--r--app/Core/Mail/Client.php2
-rw-r--r--app/Core/Security/Token.php10
-rw-r--r--app/Core/Session.php144
-rw-r--r--app/Core/Session/FlashMessage.php71
-rw-r--r--app/Core/Session/SessionManager.php102
-rw-r--r--app/Core/Session/SessionStorage.php71
7 files changed, 253 insertions, 151 deletions
diff --git a/app/Core/Base.php b/app/Core/Base.php
index 11f4e31b..d3171024 100644
--- a/app/Core/Base.php
+++ b/app/Core/Base.php
@@ -10,6 +10,9 @@ use Pimple\Container;
* @package core
* @author Frederic Guillot
*
+ * @property \Kanboard\Core\Session\SessionManager $sessionManager
+ * @property \Kanboard\Core\Session\SessionStorage $sessionStorage
+ * @property \Kanboard\Core\Session\FlashMessage $flash
* @property \Kanboard\Core\Helper $helper
* @property \Kanboard\Core\Mail\Client $emailClient
* @property \Kanboard\Core\Paginator $paginator
@@ -17,7 +20,6 @@ use Pimple\Container;
* @property \Kanboard\Core\Http\Request $request
* @property \Kanboard\Core\Http\Router $router
* @property \Kanboard\Core\Http\Response $response
- * @property \Kanboard\Core\Session $session
* @property \Kanboard\Core\Template $template
* @property \Kanboard\Core\OAuth2 $oauth
* @property \Kanboard\Core\Lexer $lexer
diff --git a/app/Core/Mail/Client.php b/app/Core/Mail/Client.php
index 52caef73..7b4268bd 100644
--- a/app/Core/Mail/Client.php
+++ b/app/Core/Mail/Client.php
@@ -51,7 +51,7 @@ class Client extends Base
$author = 'Kanboard';
if ($this->userSession->isLogged()) {
- $author = e('%s via Kanboard', $this->user->getFullname($this->session['user']));
+ $author = e('%s via Kanboard', $this->helper->user->getFullname());
}
$this->getTransport(MAIL_TRANSPORT)->sendEmail($email, $name, $subject, $html, $author);
diff --git a/app/Core/Security/Token.php b/app/Core/Security/Token.php
index 7aca08af..2bb66ef2 100644
--- a/app/Core/Security/Token.php
+++ b/app/Core/Security/Token.php
@@ -38,12 +38,12 @@ class Token extends Base
*/
public function getCSRFToken()
{
- if (! isset($_SESSION['csrf_tokens'])) {
- $_SESSION['csrf_tokens'] = array();
+ if (! isset($this->sessionStorage->csrf)) {
+ $this->sessionStorage->csrf = array();
}
$nonce = self::getToken();
- $_SESSION['csrf_tokens'][$nonce] = true;
+ $this->sessionStorage->csrf[$nonce] = true;
return $nonce;
}
@@ -57,8 +57,8 @@ class Token extends Base
*/
public function validateCSRFToken($token)
{
- if (isset($_SESSION['csrf_tokens'][$token])) {
- unset($_SESSION['csrf_tokens'][$token]);
+ if (isset($this->sessionStorage->csrf[$token])) {
+ unset($this->sessionStorage->csrf[$token]);
return true;
}
diff --git a/app/Core/Session.php b/app/Core/Session.php
deleted file mode 100644
index dd1e760e..00000000
--- a/app/Core/Session.php
+++ /dev/null
@@ -1,144 +0,0 @@
-<?php
-
-namespace Kanboard\Core;
-
-use ArrayAccess;
-use Kanboard\Core\Http\Request;
-
-/**
- * Session class
- *
- * @package core
- * @author Frederic Guillot
- */
-class Session implements ArrayAccess
-{
- /**
- * Return true if the session is open
- *
- * @static
- * @access public
- * @return boolean
- */
- public static function isOpen()
- {
- return session_id() !== '';
- }
-
- /**
- * Open a session
- *
- * @access public
- * @param string $base_path Cookie path
- */
- public function open($base_path = '/')
- {
- // HttpOnly and secure flags for session cookie
- session_set_cookie_params(
- SESSION_DURATION,
- $base_path ?: '/',
- null,
- Request::isHTTPS(),
- true
- );
-
- // Avoid session id in the URL
- ini_set('session.use_only_cookies', '1');
-
- // Enable strict mode
- if (version_compare(PHP_VERSION, '7.0.0') < 0) {
- ini_set('session.use_strict_mode', '1');
- }
-
- // Ensure session ID integrity
- ini_set('session.entropy_file', '/dev/urandom');
- ini_set('session.entropy_length', '32');
- ini_set('session.hash_bits_per_character', 6);
-
- // If the session was autostarted with session.auto_start = 1 in php.ini destroy it
- if (isset($_SESSION)) {
- session_destroy();
- }
-
- // Custom session name
- session_name('__S');
-
- // Start the session
- session_start();
-
- // Regenerate the session id to avoid session fixation issue
- if (empty($_SESSION['__validated'])) {
- session_regenerate_id(true);
- $_SESSION['__validated'] = 1;
- }
- }
-
- /**
- * Destroy the session
- *
- * @access public
- */
- public function close()
- {
- // Flush all sessions variables
- $_SESSION = array();
-
- // Destroy the session cookie
- $params = session_get_cookie_params();
-
- setcookie(
- session_name(),
- '',
- time() - 42000,
- $params['path'],
- $params['domain'],
- $params['secure'],
- $params['httponly']
- );
-
- // Destroy session data
- session_destroy();
- }
-
- /**
- * Register a flash message (success notification)
- *
- * @access public
- * @param string $message Message
- */
- public function flash($message)
- {
- $_SESSION['flash_message'] = $message;
- }
-
- /**
- * Register a flash error message (error notification)
- *
- * @access public
- * @param string $message Message
- */
- public function flashError($message)
- {
- $_SESSION['flash_error_message'] = $message;
- }
-
- public function offsetSet($offset, $value)
- {
- $_SESSION[$offset] = $value;
- }
-
- public function offsetExists($offset)
- {
- return isset($_SESSION[$offset]);
- }
-
- public function offsetUnset($offset)
- {
- unset($_SESSION[$offset]);
- }
-
- public function offsetGet($offset)
- {
- return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null;
- }
-}
diff --git a/app/Core/Session/FlashMessage.php b/app/Core/Session/FlashMessage.php
new file mode 100644
index 00000000..e02d056d
--- /dev/null
+++ b/app/Core/Session/FlashMessage.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace Kanboard\Core\Session;
+
+use Kanboard\Core\Base;
+
+/**
+ * Session Flash Message
+ *
+ * @package session
+ * @author Frederic Guillot
+ */
+class FlashMessage extends Base
+{
+ /**
+ * Add success message
+ *
+ * @access public
+ * @param string $message
+ */
+ public function success($message)
+ {
+ $this->setMessage('success', $message);
+ }
+
+ /**
+ * Add failure message
+ *
+ * @access public
+ * @param string $message
+ */
+ public function failure($message)
+ {
+ $this->setMessage('failure', $message);
+ }
+
+ /**
+ * Add new flash message
+ *
+ * @access public
+ * @param string $key
+ * @param string $message
+ */
+ public function setMessage($key, $message)
+ {
+ if (! isset($this->sessionStorage->flash)) {
+ $this->sessionStorage->flash = array();
+ }
+
+ $this->sessionStorage->flash[$key] = $message;
+ }
+
+ /**
+ * Get flash message
+ *
+ * @access public
+ * @param string $key
+ * @return string
+ */
+ public function getMessage($key)
+ {
+ $message = '';
+
+ if (isset($this->sessionStorage->flash[$key])) {
+ $message = $this->sessionStorage->flash[$key];
+ unset($this->sessionStorage->flash[$key]);
+ }
+
+ return $message;
+ }
+}
diff --git a/app/Core/Session/SessionManager.php b/app/Core/Session/SessionManager.php
new file mode 100644
index 00000000..6153efeb
--- /dev/null
+++ b/app/Core/Session/SessionManager.php
@@ -0,0 +1,102 @@
+<?php
+
+namespace Kanboard\Core\Session;
+
+use Kanboard\Core\Base;
+use Kanboard\Core\Http\Request;
+
+/**
+ * Session Manager
+ *
+ * @package session
+ * @author Frederic Guillot
+ */
+class SessionManager extends Base
+{
+ /**
+ * Return true if the session is open
+ *
+ * @static
+ * @access public
+ * @return boolean
+ */
+ public static function isOpen()
+ {
+ return session_id() !== '';
+ }
+
+ /**
+ * Create a new session
+ *
+ * @access public
+ */
+ public function open()
+ {
+ $this->configure();
+
+ if (ini_get('session.auto_start') == 1) {
+ session_destroy();
+ }
+
+ session_name('KB_SID');
+ session_start();
+
+ $this->container['sessionStorage']->setStorage($_SESSION);
+ }
+
+ /**
+ * Destroy the session
+ *
+ * @access public
+ */
+ public function close()
+ {
+ // Destroy the session cookie
+ $params = session_get_cookie_params();
+
+ setcookie(
+ session_name(),
+ '',
+ time() - 42000,
+ $params['path'],
+ $params['domain'],
+ $params['secure'],
+ $params['httponly']
+ );
+
+ session_unset();
+ session_destroy();
+ }
+
+ /**
+ * Define session settings
+ *
+ * @access private
+ */
+ private function configure()
+ {
+ // Session cookie: HttpOnly and secure flags
+ session_set_cookie_params(
+ SESSION_DURATION,
+ $this->helper->url->dir() ?: '/',
+ null,
+ Request::isHTTPS(),
+ true
+ );
+
+ // Avoid session id in the URL
+ ini_set('session.use_only_cookies', '1');
+ ini_set('session.use_trans_sid', '0');
+
+ // Enable strict mode
+ ini_set('session.use_strict_mode', '1');
+
+ // Better session hash
+ ini_set('session.hash_function', 'sha512');
+ ini_set('session.hash_bits_per_character', 6);
+
+ // Set an additional entropy
+ ini_set('session.entropy_file', '/dev/urandom');
+ ini_set('session.entropy_length', '256');
+ }
+}
diff --git a/app/Core/Session/SessionStorage.php b/app/Core/Session/SessionStorage.php
new file mode 100644
index 00000000..54d803f7
--- /dev/null
+++ b/app/Core/Session/SessionStorage.php
@@ -0,0 +1,71 @@
+<?php
+
+namespace Kanboard\Core\Session;
+
+/**
+ * Session Storage
+ *
+ * @package session
+ * @author Frederic Guillot
+ *
+ * @property array $config
+ * @property array $user
+ * @property array $flash
+ * @property array $csrf
+ * @property array $postAuth
+ * @property string $redirectAfterLogin
+ * @property string $captcha
+ * @property string $commentSorting
+ * @property bool $hasSubtaskInProgress
+ * @property bool $boardCollapsed
+ */
+class SessionStorage
+{
+ /**
+ * Pointer to external storage
+ *
+ * @access private
+ * @var array
+ */
+ private $storage = array();
+
+ /**
+ * Set external storage
+ *
+ * @access public
+ * @param array $storage External session storage (example: $_SESSION)
+ */
+ public function setStorage(array &$storage)
+ {
+ $this->storage =& $storage;
+
+ // Load dynamically existing session variables into object properties
+ foreach ($storage as $key => $value) {
+ $this->$key = $value;
+ }
+ }
+
+ /**
+ * Get all session variables
+ *
+ * @access public
+ * @return array
+ */
+ public function getAll()
+ {
+ $session = get_object_vars($this);
+ unset($session['storage']);
+
+ return $session;
+ }
+
+ /**
+ * Copy class properties to external storage
+ *
+ * @access public
+ */
+ public function __destruct()
+ {
+ $this->storage = $this->getAll();
+ }
+}