Improve session handler and add Ajax session check
This commit is contained in:
@@ -95,7 +95,7 @@ class RememberMe extends Base
|
|||||||
// Update the sequence
|
// Update the sequence
|
||||||
$this->writeCookie(
|
$this->writeCookie(
|
||||||
$record['token'],
|
$record['token'],
|
||||||
$this->update($record['token'], $record['sequence']),
|
$this->update($record['token']),
|
||||||
$record['expiration']
|
$record['expiration']
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ class RememberMe extends Base
|
|||||||
// Update the sequence
|
// Update the sequence
|
||||||
$this->writeCookie(
|
$this->writeCookie(
|
||||||
$record['token'],
|
$record['token'],
|
||||||
$this->update($record['token'], $record['sequence']),
|
$this->update($record['token']),
|
||||||
$record['expiration']
|
$record['expiration']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -237,17 +237,15 @@ class RememberMe extends Base
|
|||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param string $token Session token
|
* @param string $token Session token
|
||||||
* @param string $sequence Sequence token
|
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function update($token, $sequence)
|
public function update($token)
|
||||||
{
|
{
|
||||||
$new_sequence = Security::generateToken();
|
$new_sequence = Security::generateToken();
|
||||||
|
|
||||||
$this->db
|
$this->db
|
||||||
->table(self::TABLE)
|
->table(self::TABLE)
|
||||||
->eq('token', $token)
|
->eq('token', $token)
|
||||||
->eq('sequence', $sequence)
|
|
||||||
->update(array('sequence' => $new_sequence));
|
->update(array('sequence' => $new_sequence));
|
||||||
|
|
||||||
return $new_sequence;
|
return $new_sequence;
|
||||||
|
|||||||
@@ -14,6 +14,16 @@ use Helper;
|
|||||||
*/
|
*/
|
||||||
class App extends Base
|
class App extends Base
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Check if the user is connected
|
||||||
|
*
|
||||||
|
* @access public
|
||||||
|
*/
|
||||||
|
public function status()
|
||||||
|
{
|
||||||
|
$this->response->text('OK');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dashboard for the current user
|
* Dashboard for the current user
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ abstract class Base
|
|||||||
public function beforeAction($controller, $action)
|
public function beforeAction($controller, $action)
|
||||||
{
|
{
|
||||||
// Start the session
|
// Start the session
|
||||||
$this->session->open(BASE_URL_DIRECTORY, SESSION_SAVE_PATH);
|
$this->session->open(BASE_URL_DIRECTORY);
|
||||||
|
|
||||||
// HTTP secure headers
|
// HTTP secure headers
|
||||||
$this->response->csp(array('style-src' => "'self' 'unsafe-inline'"));
|
$this->response->csp(array('style-src' => "'self' 'unsafe-inline'"));
|
||||||
@@ -161,6 +161,11 @@ abstract class Base
|
|||||||
|
|
||||||
// Authentication
|
// Authentication
|
||||||
if (! $this->authentication->isAuthenticated($controller, $action)) {
|
if (! $this->authentication->isAuthenticated($controller, $action)) {
|
||||||
|
|
||||||
|
if ($this->request->isAjax()) {
|
||||||
|
$this->response->text('Not Authorized', 401);
|
||||||
|
}
|
||||||
|
|
||||||
$this->response->redirect('?controller=user&action=login&redirect_query='.urlencode($this->request->getQueryString()));
|
$this->response->redirect('?controller=user&action=login&redirect_query='.urlencode($this->request->getQueryString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -342,7 +342,7 @@ class Board extends Base
|
|||||||
if ($project_id > 0 && $this->request->isAjax()) {
|
if ($project_id > 0 && $this->request->isAjax()) {
|
||||||
|
|
||||||
if (! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) {
|
if (! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) {
|
||||||
$this->response->status(401);
|
$this->response->text('Forbidden', 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
$values = $this->request->getJson();
|
$values = $this->request->getJson();
|
||||||
@@ -366,7 +366,7 @@ class Board extends Base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$this->response->status(401);
|
$this->response->status(403);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,7 +383,7 @@ class Board extends Base
|
|||||||
$timestamp = $this->request->getIntegerParam('timestamp');
|
$timestamp = $this->request->getIntegerParam('timestamp');
|
||||||
|
|
||||||
if ($project_id > 0 && ! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) {
|
if ($project_id > 0 && ! $this->projectPermission->isUserAllowed($project_id, $this->acl->getUserId())) {
|
||||||
$this->response->text('Not Authorized', 401);
|
$this->response->text('Forbidden', 403);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->project->isModifiedSince($project_id, $timestamp)) {
|
if ($this->project->isModifiedSince($project_id, $timestamp)) {
|
||||||
@@ -402,7 +402,7 @@ class Board extends Base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$this->response->status(401);
|
$this->response->status(403);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,14 +36,9 @@ class Session
|
|||||||
*
|
*
|
||||||
* @access public
|
* @access public
|
||||||
* @param string $base_path Cookie path
|
* @param string $base_path Cookie path
|
||||||
* @param string $save_path Custom session save path
|
|
||||||
*/
|
*/
|
||||||
public function open($base_path = '/', $save_path = '')
|
public function open($base_path = '/')
|
||||||
{
|
{
|
||||||
if ($save_path !== '') {
|
|
||||||
session_save_path($save_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
// HttpOnly and secure flags for session cookie
|
// HttpOnly and secure flags for session cookie
|
||||||
session_set_cookie_params(
|
session_set_cookie_params(
|
||||||
self::SESSION_LIFETIME,
|
self::SESSION_LIFETIME,
|
||||||
@@ -56,12 +51,15 @@ class Session
|
|||||||
// Avoid session id in the URL
|
// Avoid session id in the URL
|
||||||
ini_set('session.use_only_cookies', '1');
|
ini_set('session.use_only_cookies', '1');
|
||||||
|
|
||||||
|
// Enable strict mode
|
||||||
|
ini_set('session.use_strict_mode', '1');
|
||||||
|
|
||||||
// Ensure session ID integrity
|
// Ensure session ID integrity
|
||||||
ini_set('session.entropy_file', '/dev/urandom');
|
ini_set('session.entropy_file', '/dev/urandom');
|
||||||
ini_set('session.entropy_length', '32');
|
ini_set('session.entropy_length', '32');
|
||||||
ini_set('session.hash_bits_per_character', 6);
|
ini_set('session.hash_bits_per_character', 6);
|
||||||
|
|
||||||
// If session was autostarted with session.auto_start = 1 in php.ini destroy it, otherwise we cannot login
|
// If session was autostarted with session.auto_start = 1 in php.ini destroy it
|
||||||
if (isset($_SESSION)) {
|
if (isset($_SESSION)) {
|
||||||
session_destroy();
|
session_destroy();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ class Acl extends Base
|
|||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $user_actions = array(
|
private $user_actions = array(
|
||||||
'app' => array('index', 'preview'),
|
'app' => array('index', 'preview', 'status'),
|
||||||
'project' => array('index', 'show', 'exporttasks', 'exportdaily', 'share', 'edit', 'update', 'users', 'remove', 'duplicate', 'disable', 'enable', 'activity', 'search', 'tasks', 'create', 'save'),
|
'project' => array('index', 'show', 'exporttasks', 'exportdaily', 'share', 'edit', 'update', 'users', 'remove', 'duplicate', 'disable', 'enable', 'activity', 'search', 'tasks', 'create', 'save'),
|
||||||
'board' => array('index', 'show', 'save', 'check', 'changeassignee', 'updateassignee', 'changecategory', 'updatecategory', 'movecolumn', 'edit', 'update', 'add', 'confirm', 'remove', 'subtasks', 'togglesubtask', 'attachments', 'comments', 'description'),
|
'board' => array('index', 'show', 'save', 'check', 'changeassignee', 'updateassignee', 'changecategory', 'updatecategory', 'movecolumn', 'edit', 'update', 'add', 'confirm', 'remove', 'subtasks', 'togglesubtask', 'attachments', 'comments', 'description'),
|
||||||
'user' => array('edit', 'forbidden', 'logout', 'show', 'external', 'unlinkgoogle', 'unlinkgithub', 'sessions', 'removesession', 'last', 'notifications', 'password'),
|
'user' => array('edit', 'forbidden', 'logout', 'show', 'external', 'unlinkgoogle', 'unlinkgithub', 'sessions', 'removesession', 'last', 'notifications', 'password'),
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
<title><?= isset($title) ? Helper\escape($title) : 'Kanboard' ?></title>
|
<title><?= isset($title) ? Helper\escape($title) : 'Kanboard' ?></title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body data-status-url="<?= Helper\u('app', 'status') ?>" data-login-url="<?= Helper\u('user', 'login') ?>">
|
||||||
<?php if (isset($no_layout) && $no_layout): ?>
|
<?php if (isset($no_layout) && $no_layout): ?>
|
||||||
<?= $content_for_layout ?>
|
<?= $content_for_layout ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Custom session save path
|
|
||||||
defined('SESSION_SAVE_PATH') or define('SESSION_SAVE_PATH', '');
|
|
||||||
|
|
||||||
// Application version
|
// Application version
|
||||||
defined('APP_VERSION') or define('APP_VERSION', 'master');
|
defined('APP_VERSION') or define('APP_VERSION', 'master');
|
||||||
|
|
||||||
|
|||||||
@@ -128,6 +128,22 @@ var Kanboard = (function() {
|
|||||||
$(".preview-area").hide();
|
$(".preview-area").hide();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Check session and redirect to the login page if not logged
|
||||||
|
CheckSession: function() {
|
||||||
|
|
||||||
|
if (Kanboard.IsVisible() && ! $(".form-login").length) {
|
||||||
|
$.ajax({
|
||||||
|
cache: false,
|
||||||
|
url: $("body").data("status-url"),
|
||||||
|
statusCode: {
|
||||||
|
401: function(data) {
|
||||||
|
window.location = $("body").data("login-url");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Common init
|
// Common init
|
||||||
Init: function() {
|
Init: function() {
|
||||||
|
|
||||||
@@ -151,6 +167,9 @@ var Kanboard = (function() {
|
|||||||
// Markdown Preview for textareas
|
// Markdown Preview for textareas
|
||||||
$("#markdown-preview").click(Kanboard.MarkdownPreview);
|
$("#markdown-preview").click(Kanboard.MarkdownPreview);
|
||||||
$("#markdown-write").click(Kanboard.MarkdownWriter);
|
$("#markdown-write").click(Kanboard.MarkdownWriter);
|
||||||
|
|
||||||
|
// Check the session every 10s
|
||||||
|
window.setInterval(Kanboard.CheckSession, 10000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,22 @@ var Kanboard = (function() {
|
|||||||
$(".preview-area").hide();
|
$(".preview-area").hide();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Check session and redirect to the login page if not logged
|
||||||
|
CheckSession: function() {
|
||||||
|
|
||||||
|
if (Kanboard.IsVisible() && ! $(".form-login").length) {
|
||||||
|
$.ajax({
|
||||||
|
cache: false,
|
||||||
|
url: $("body").data("status-url"),
|
||||||
|
statusCode: {
|
||||||
|
401: function(data) {
|
||||||
|
window.location = $("body").data("login-url");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// Common init
|
// Common init
|
||||||
Init: function() {
|
Init: function() {
|
||||||
|
|
||||||
@@ -136,6 +152,9 @@ var Kanboard = (function() {
|
|||||||
// Markdown Preview for textareas
|
// Markdown Preview for textareas
|
||||||
$("#markdown-preview").click(Kanboard.MarkdownPreview);
|
$("#markdown-preview").click(Kanboard.MarkdownPreview);
|
||||||
$("#markdown-write").click(Kanboard.MarkdownWriter);
|
$("#markdown-write").click(Kanboard.MarkdownWriter);
|
||||||
|
|
||||||
|
// Check the session every 10s
|
||||||
|
window.setInterval(Kanboard.CheckSession, 10000);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user