summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/Auth/RememberMe.php8
-rw-r--r--app/Controller/Base.php37
-rw-r--r--app/Core/Request.php5
-rw-r--r--app/Core/Response.php2
-rw-r--r--app/Core/Security/Token.php (renamed from app/Core/Security.php)41
-rw-r--r--app/Helper/Form.php6
-rw-r--r--app/Helper/Url.php6
-rw-r--r--app/Model/Config.php4
-rw-r--r--app/Model/Project.php4
-rw-r--r--app/Model/User.php4
-rw-r--r--app/Schema/Mysql.php6
-rw-r--r--app/Schema/Postgres.php4
-rw-r--r--app/Schema/Sqlite.php6
-rw-r--r--app/ServiceProvider/ClassProvider.php4
-rw-r--r--tests/units/Core/Security/TokenTest.php29
15 files changed, 80 insertions, 86 deletions
diff --git a/app/Auth/RememberMe.php b/app/Auth/RememberMe.php
index 0290e36c..24f30a2c 100644
--- a/app/Auth/RememberMe.php
+++ b/app/Auth/RememberMe.php
@@ -5,7 +5,7 @@ namespace Kanboard\Auth;
use Kanboard\Core\Base;
use Kanboard\Core\Request;
use Kanboard\Event\AuthEvent;
-use Kanboard\Core\Security;
+use Kanboard\Core\Security\Token;
/**
* RememberMe model
@@ -165,8 +165,8 @@ class RememberMe extends Base
*/
public function create($user_id, $ip, $user_agent)
{
- $token = hash('sha256', $user_id.$user_agent.$ip.Security::generateToken());
- $sequence = Security::generateToken();
+ $token = hash('sha256', $user_id.$user_agent.$ip.Token::getToken());
+ $sequence = Token::getToken();
$expiration = time() + self::EXPIRATION;
$this->cleanup($user_id);
@@ -216,7 +216,7 @@ class RememberMe extends Base
*/
public function update($token)
{
- $new_sequence = Security::generateToken();
+ $new_sequence = Token::getToken();
$this->db
->table(self::TABLE)
diff --git a/app/Controller/Base.php b/app/Controller/Base.php
index a955b12c..829e0ad2 100644
--- a/app/Controller/Base.php
+++ b/app/Controller/Base.php
@@ -3,9 +3,6 @@
namespace Kanboard\Controller;
use Pimple\Container;
-use Kanboard\Core\Security;
-use Kanboard\Core\Request;
-use Kanboard\Core\Response;
use Symfony\Component\EventDispatcher\Event;
/**
@@ -17,22 +14,6 @@ use Symfony\Component\EventDispatcher\Event;
abstract class Base extends \Kanboard\Core\Base
{
/**
- * Request instance
- *
- * @accesss protected
- * @var \Kanboard\Core\Request
- */
- protected $request;
-
- /**
- * Response instance
- *
- * @accesss protected
- * @var \Kanboard\Core\Response
- */
- protected $response;
-
- /**
* Constructor
*
* @access public
@@ -41,11 +22,9 @@ abstract class Base extends \Kanboard\Core\Base
public function __construct(Container $container)
{
$this->container = $container;
- $this->request = new Request;
- $this->response = new Response;
if (DEBUG) {
- $this->container['logger']->debug('START_REQUEST='.$_SERVER['REQUEST_URI']);
+ $this->logger->debug('START_REQUEST='.$_SERVER['REQUEST_URI']);
}
}
@@ -57,14 +36,14 @@ abstract class Base extends \Kanboard\Core\Base
public function __destruct()
{
if (DEBUG) {
- foreach ($this->container['db']->getLogMessages() as $message) {
- $this->container['logger']->debug($message);
+ foreach ($this->db->getLogMessages() as $message) {
+ $this->logger->debug($message);
}
- $this->container['logger']->debug('SQL_QUERIES={nb}', array('nb' => $this->container['db']->nbQueries));
- $this->container['logger']->debug('RENDERING={time}', array('time' => microtime(true) - @$_SERVER['REQUEST_TIME_FLOAT']));
- $this->container['logger']->debug('MEMORY='.$this->helper->text->bytes(memory_get_usage()));
- $this->container['logger']->debug('END_REQUEST='.$_SERVER['REQUEST_URI']);
+ $this->logger->debug('SQL_QUERIES={nb}', array('nb' => $this->container['db']->nbQueries));
+ $this->logger->debug('RENDERING={time}', array('time' => microtime(true) - @$_SERVER['REQUEST_TIME_FLOAT']));
+ $this->logger->debug('MEMORY='.$this->helper->text->bytes(memory_get_usage()));
+ $this->logger->debug('END_REQUEST='.$_SERVER['REQUEST_URI']);
}
}
@@ -201,7 +180,7 @@ abstract class Base extends \Kanboard\Core\Base
*/
protected function checkCSRFParam()
{
- if (! Security::validateCSRFToken($this->request->getStringParam('csrf_token'))) {
+ if (! $this->token->validateCSRFToken($this->request->getStringParam('csrf_token'))) {
$this->forbidden();
}
}
diff --git a/app/Core/Request.php b/app/Core/Request.php
index 5eda2d02..0398760e 100644
--- a/app/Core/Request.php
+++ b/app/Core/Request.php
@@ -8,7 +8,7 @@ namespace Kanboard\Core;
* @package core
* @author Frederic Guillot
*/
-class Request
+class Request extends Base
{
/**
* Get URL string parameter
@@ -57,7 +57,8 @@ class Request
*/
public function getValues()
{
- if (! empty($_POST) && Security::validateCSRFFormToken($_POST)) {
+ if (! empty($_POST) && ! empty($_POST['csrf_token']) && $this->token->validateCSRFToken($_POST['csrf_token'])) {
+ unset($_POST['csrf_token']);
return $_POST;
}
diff --git a/app/Core/Response.php b/app/Core/Response.php
index 528a6302..6788473a 100644
--- a/app/Core/Response.php
+++ b/app/Core/Response.php
@@ -8,7 +8,7 @@ namespace Kanboard\Core;
* @package core
* @author Frederic Guillot
*/
-class Response
+class Response extends Base
{
/**
* Send no cache headers
diff --git a/app/Core/Security.php b/app/Core/Security/Token.php
index 54207ee1..7aca08af 100644
--- a/app/Core/Security.php
+++ b/app/Core/Security/Token.php
@@ -1,14 +1,16 @@
<?php
-namespace Kanboard\Core;
+namespace Kanboard\Core\Security;
+
+use Kanboard\Core\Base;
/**
- * Security class
+ * Token Handler
*
- * @package core
+ * @package security
* @author Frederic Guillot
*/
-class Security
+class Token extends Base
{
/**
* Generate a random token with different methods: openssl or /dev/urandom or fallback to uniqid()
@@ -17,7 +19,7 @@ class Security
* @access public
* @return string Random token
*/
- public static function generateToken()
+ public static function getToken()
{
if (function_exists('openssl_random_pseudo_bytes')) {
return bin2hex(\openssl_random_pseudo_bytes(30));
@@ -31,18 +33,16 @@ class Security
/**
* Generate and store a CSRF token in the current session
*
- * @static
* @access public
* @return string Random token
*/
- public static function getCSRFToken()
+ public function getCSRFToken()
{
- $nonce = self::generateToken();
-
- if (empty($_SESSION['csrf_tokens'])) {
+ if (! isset($_SESSION['csrf_tokens'])) {
$_SESSION['csrf_tokens'] = array();
}
+ $nonce = self::getToken();
$_SESSION['csrf_tokens'][$nonce] = true;
return $nonce;
@@ -51,12 +51,11 @@ class Security
/**
* Check if the token exists for the current session (a token can be used only one time)
*
- * @static
* @access public
* @param string $token CSRF token
* @return bool
*/
- public static function validateCSRFToken($token)
+ public function validateCSRFToken($token)
{
if (isset($_SESSION['csrf_tokens'][$token])) {
unset($_SESSION['csrf_tokens'][$token]);
@@ -65,22 +64,4 @@ class Security
return false;
}
-
- /**
- * Check if the token used in a form is correct and then remove the value
- *
- * @static
- * @access public
- * @param array $values Form values
- * @return bool
- */
- public static function validateCSRFFormToken(array &$values)
- {
- if (! empty($values['csrf_token']) && self::validateCSRFToken($values['csrf_token'])) {
- unset($values['csrf_token']);
- return true;
- }
-
- return false;
- }
}
diff --git a/app/Helper/Form.php b/app/Helper/Form.php
index 5f19f2a8..bfd75ee3 100644
--- a/app/Helper/Form.php
+++ b/app/Helper/Form.php
@@ -2,7 +2,7 @@
namespace Kanboard\Helper;
-use Kanboard\Core\Security;
+use Kanboard\Core\Base;
/**
* Form helpers
@@ -10,7 +10,7 @@ use Kanboard\Core\Security;
* @package helper
* @author Frederic Guillot
*/
-class Form extends \Kanboard\Core\Base
+class Form extends Base
{
/**
* Hidden CSRF token field
@@ -20,7 +20,7 @@ class Form extends \Kanboard\Core\Base
*/
public function csrf()
{
- return '<input type="hidden" name="csrf_token" value="'.Security::getCSRFToken().'"/>';
+ return '<input type="hidden" name="csrf_token" value="'.$this->token->getCSRFToken().'"/>';
}
/**
diff --git a/app/Helper/Url.php b/app/Helper/Url.php
index f120252d..e47256ba 100644
--- a/app/Helper/Url.php
+++ b/app/Helper/Url.php
@@ -3,7 +3,7 @@
namespace Kanboard\Helper;
use Kanboard\Core\Request;
-use Kanboard\Core\Security;
+use Kanboard\Core\Base;
/**
* Url helpers
@@ -11,7 +11,7 @@ use Kanboard\Core\Security;
* @package helper
* @author Frederic Guillot
*/
-class Url extends \Kanboard\Core\Base
+class Url extends Base
{
private $base = '';
private $directory = '';
@@ -158,7 +158,7 @@ class Url extends \Kanboard\Core\Base
}
if ($csrf) {
- $qs['csrf_token'] = Security::getCSRFToken();
+ $qs['csrf_token'] = $this->token->getCSRFToken();
}
if (! empty($qs)) {
diff --git a/app/Model/Config.php b/app/Model/Config.php
index cf634f80..3b90f58d 100644
--- a/app/Model/Config.php
+++ b/app/Model/Config.php
@@ -3,7 +3,7 @@
namespace Kanboard\Model;
use Kanboard\Core\Translator;
-use Kanboard\Core\Security;
+use Kanboard\Core\Security\Token;
use Kanboard\Core\Session;
/**
@@ -265,7 +265,7 @@ class Config extends Setting
*/
public function regenerateToken($option)
{
- $this->save(array($option => Security::generateToken()));
+ $this->save(array($option => Token::getToken()));
}
/**
diff --git a/app/Model/Project.php b/app/Model/Project.php
index b767af26..9e30a9b8 100644
--- a/app/Model/Project.php
+++ b/app/Model/Project.php
@@ -4,7 +4,7 @@ namespace Kanboard\Model;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
-use Kanboard\Core\Security;
+use Kanboard\Core\Security\Token;
/**
* Project model
@@ -491,7 +491,7 @@ class Project extends Base
$this->db
->table(self::TABLE)
->eq('id', $project_id)
- ->save(array('is_public' => 1, 'token' => Security::generateToken()));
+ ->save(array('is_public' => 1, 'token' => Token::getToken()));
}
/**
diff --git a/app/Model/User.php b/app/Model/User.php
index 6e7e94e0..dc00c0c5 100644
--- a/app/Model/User.php
+++ b/app/Model/User.php
@@ -6,7 +6,7 @@ use PicoDb\Database;
use SimpleValidator\Validator;
use SimpleValidator\Validators;
use Kanboard\Core\Session;
-use Kanboard\Core\Security;
+use Kanboard\Core\Security\Token;
/**
* User model
@@ -383,7 +383,7 @@ class User extends Base
return $this->db
->table(self::TABLE)
->eq('id', $user_id)
- ->save(array('token' => Security::generateToken()));
+ ->save(array('token' => Token::getToken()));
}
/**
diff --git a/app/Schema/Mysql.php b/app/Schema/Mysql.php
index a021c1cc..54d58592 100644
--- a/app/Schema/Mysql.php
+++ b/app/Schema/Mysql.php
@@ -3,7 +3,7 @@
namespace Schema;
use PDO;
-use Kanboard\Core\Security;
+use Kanboard\Core\Security\Token;
const VERSION = 93;
@@ -869,7 +869,7 @@ function version_20(PDO $pdo)
function version_19(PDO $pdo)
{
$pdo->exec("ALTER TABLE config ADD COLUMN api_token VARCHAR(255) DEFAULT ''");
- $pdo->exec("UPDATE config SET api_token='".Security::generateToken()."'");
+ $pdo->exec("UPDATE config SET api_token='".Token::getToken()."'");
}
function version_18(PDO $pdo)
@@ -1091,6 +1091,6 @@ function version_1(PDO $pdo)
$pdo->exec("
INSERT INTO config
(webhooks_token)
- VALUES ('".Security::generateToken()."')
+ VALUES ('".Token::getToken()."')
");
}
diff --git a/app/Schema/Postgres.php b/app/Schema/Postgres.php
index a3fb6d49..6f7efed0 100644
--- a/app/Schema/Postgres.php
+++ b/app/Schema/Postgres.php
@@ -3,7 +3,7 @@
namespace Schema;
use PDO;
-use Kanboard\Core\Security;
+use Kanboard\Core\Security\Token;
const VERSION = 73;
@@ -994,6 +994,6 @@ function version_1(PDO $pdo)
$pdo->exec("
INSERT INTO config
(webhooks_token, api_token)
- VALUES ('".Security::generateToken()."', '".Security::generateToken()."')
+ VALUES ('".Token::getToken()."', '".Token::getToken()."')
");
}
diff --git a/app/Schema/Sqlite.php b/app/Schema/Sqlite.php
index b9ab86f8..d27f11ec 100644
--- a/app/Schema/Sqlite.php
+++ b/app/Schema/Sqlite.php
@@ -2,7 +2,7 @@
namespace Schema;
-use Kanboard\Core\Security;
+use Kanboard\Core\Security\Token;
use PDO;
const VERSION = 88;
@@ -799,7 +799,7 @@ function version_20(PDO $pdo)
function version_19(PDO $pdo)
{
$pdo->exec("ALTER TABLE config ADD COLUMN api_token TEXT DEFAULT ''");
- $pdo->exec("UPDATE config SET api_token='".Security::generateToken()."'");
+ $pdo->exec("UPDATE config SET api_token='".Token::getToken()."'");
}
function version_18(PDO $pdo)
@@ -1068,6 +1068,6 @@ function version_1(PDO $pdo)
$pdo->exec("
INSERT INTO config
(webhooks_token)
- VALUES ('".Security::generateToken()."')
+ VALUES ('".Token::getToken()."')
");
}
diff --git a/app/ServiceProvider/ClassProvider.php b/app/ServiceProvider/ClassProvider.php
index c103d639..c1a59f85 100644
--- a/app/ServiceProvider/ClassProvider.php
+++ b/app/ServiceProvider/ClassProvider.php
@@ -84,6 +84,7 @@ class ClassProvider implements ServiceProviderInterface
'HttpClient',
'Lexer',
'Request',
+ 'Response',
'Router',
'Session',
'Template',
@@ -94,6 +95,9 @@ class ClassProvider implements ServiceProviderInterface
'Core\Plugin' => array(
'Hook',
),
+ 'Core\Security' => array(
+ 'Token',
+ ),
'Integration' => array(
'BitbucketWebhook',
'GithubWebhook',
diff --git a/tests/units/Core/Security/TokenTest.php b/tests/units/Core/Security/TokenTest.php
new file mode 100644
index 00000000..dbb7bd1a
--- /dev/null
+++ b/tests/units/Core/Security/TokenTest.php
@@ -0,0 +1,29 @@
+<?php
+
+require_once __DIR__.'/../../Base.php';
+
+use Kanboard\Core\Security\Token;
+
+class TokenTest extends Base
+{
+ public function testGenerateToken()
+ {
+ $t1 = Token::getToken();
+ $t2 = Token::getToken();
+
+ $this->assertNotEmpty($t1);
+ $this->assertNotEmpty($t2);
+
+ $this->assertNotEquals($t1, $t2);
+ }
+
+ public function testCSRFTokens()
+ {
+ $token = new Token($this->container);
+ $t1 = $token->getCSRFToken();
+
+ $this->assertNotEmpty($t1);
+ $this->assertTrue($token->validateCSRFToken($t1));
+ $this->assertFalse($token->validateCSRFToken($t1));
+ }
+}