Move token generation to Security namespace

This commit is contained in:
Frederic Guillot 2015-10-25 15:05:19 -04:00
parent 06e9486c59
commit 6756ef2301
15 changed files with 80 additions and 86 deletions

View File

@ -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)

View File

@ -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;
/**
@ -16,22 +13,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
*
@ -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();
}
}

View File

@ -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;
}

View File

@ -8,7 +8,7 @@ namespace Kanboard\Core;
* @package core
* @author Frederic Guillot
*/
class Response
class Response extends Base
{
/**
* Send no cache headers

View File

@ -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;
}
}

View File

@ -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().'"/>';
}
/**

View File

@ -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)) {

View File

@ -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()));
}
/**

View File

@ -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()));
}
/**

View File

@ -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()));
}
/**

View File

@ -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()."')
");
}

View File

@ -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()."')
");
}

View File

@ -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()."')
");
}

View File

@ -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',

View File

@ -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));
}
}