看板初始化提交
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
/**
|
||||
* Access Map Definition
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class AccessMap
|
||||
{
|
||||
/**
|
||||
* Default role
|
||||
*
|
||||
* @access private
|
||||
* @var string
|
||||
*/
|
||||
private $defaultRole = '';
|
||||
|
||||
/**
|
||||
* Role hierarchy
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $hierarchy = array();
|
||||
|
||||
/**
|
||||
* Access map
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $map = array();
|
||||
|
||||
/**
|
||||
* Define the default role when nothing match
|
||||
*
|
||||
* @access public
|
||||
* @param string $role
|
||||
* @return AccessMap
|
||||
*/
|
||||
public function setDefaultRole($role)
|
||||
{
|
||||
$this->defaultRole = $role;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define role hierarchy
|
||||
*
|
||||
* @access public
|
||||
* @param string $role
|
||||
* @param array $subroles
|
||||
* @return AccessMap
|
||||
*/
|
||||
public function setRoleHierarchy($role, array $subroles)
|
||||
{
|
||||
foreach ($subroles as $subrole) {
|
||||
if (isset($this->hierarchy[$subrole])) {
|
||||
$this->hierarchy[$subrole][] = $role;
|
||||
} else {
|
||||
$this->hierarchy[$subrole] = array($role);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get computed role hierarchy
|
||||
*
|
||||
* @access public
|
||||
* @param string $role
|
||||
* @return array
|
||||
*/
|
||||
public function getRoleHierarchy($role)
|
||||
{
|
||||
$roles = array($role);
|
||||
|
||||
if (isset($this->hierarchy[$role])) {
|
||||
$roles = array_merge($roles, $this->hierarchy[$role]);
|
||||
}
|
||||
|
||||
return $roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the highest role from a list
|
||||
*
|
||||
* @access public
|
||||
* @param array $roles
|
||||
* @return string
|
||||
*/
|
||||
public function getHighestRole(array $roles)
|
||||
{
|
||||
$rank = array();
|
||||
|
||||
foreach ($roles as $role) {
|
||||
$rank[$role] = count($this->getRoleHierarchy($role));
|
||||
}
|
||||
|
||||
asort($rank);
|
||||
|
||||
return key($rank);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new access rules
|
||||
*
|
||||
* @access public
|
||||
* @param string $controller Controller class name
|
||||
* @param mixed $methods List of method name or just one method
|
||||
* @param string $role Lowest role required
|
||||
* @return AccessMap
|
||||
*/
|
||||
public function add($controller, $methods, $role)
|
||||
{
|
||||
if (is_array($methods)) {
|
||||
foreach ($methods as $method) {
|
||||
$this->addRule($controller, $method, $role);
|
||||
}
|
||||
} else {
|
||||
$this->addRule($controller, $methods, $role);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new access rule
|
||||
*
|
||||
* @access private
|
||||
* @param string $controller
|
||||
* @param string $method
|
||||
* @param string $role
|
||||
* @return AccessMap
|
||||
*/
|
||||
private function addRule($controller, $method, $role)
|
||||
{
|
||||
$controller = strtolower($controller);
|
||||
$method = strtolower($method);
|
||||
|
||||
if (! isset($this->map[$controller])) {
|
||||
$this->map[$controller] = array();
|
||||
}
|
||||
|
||||
$this->map[$controller][$method] = $role;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get roles that match the given controller/method
|
||||
*
|
||||
* @access public
|
||||
* @param string $controller
|
||||
* @param string $method
|
||||
* @return array
|
||||
*/
|
||||
public function getRoles($controller, $method)
|
||||
{
|
||||
$controller = strtolower($controller);
|
||||
$method = strtolower($method);
|
||||
|
||||
foreach (array($method, '*') as $key) {
|
||||
if (isset($this->map[$controller][$key])) {
|
||||
return $this->getRoleHierarchy($this->map[$controller][$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->getRoleHierarchy($this->defaultRole);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
use LogicException;
|
||||
use Kanboard\Core\Base;
|
||||
use Kanboard\Event\AuthFailureEvent;
|
||||
use Kanboard\Event\AuthSuccessEvent;
|
||||
|
||||
/**
|
||||
* Authentication Manager
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class AuthenticationManager extends Base
|
||||
{
|
||||
/**
|
||||
* Event names
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const EVENT_SUCCESS = 'auth.success';
|
||||
const EVENT_FAILURE = 'auth.failure';
|
||||
|
||||
/**
|
||||
* List of authentication providers
|
||||
*
|
||||
* @access private
|
||||
* @var array
|
||||
*/
|
||||
private $providers = array();
|
||||
|
||||
public function reset()
|
||||
{
|
||||
$this->providers = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new authentication provider
|
||||
*
|
||||
* @access public
|
||||
* @param AuthenticationProviderInterface $provider
|
||||
* @return AuthenticationManager
|
||||
*/
|
||||
public function register(AuthenticationProviderInterface $provider)
|
||||
{
|
||||
$this->providers[$provider->getName()] = $provider;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a new authentication provider
|
||||
*
|
||||
* @access public
|
||||
* @param string $name
|
||||
* @return AuthenticationProviderInterface|OAuthAuthenticationProviderInterface|PasswordAuthenticationProviderInterface|PreAuthenticationProviderInterface|OAuthAuthenticationProviderInterface
|
||||
*/
|
||||
public function getProvider($name)
|
||||
{
|
||||
if (! isset($this->providers[$name])) {
|
||||
throw new LogicException('Authentication provider not found: '.$name);
|
||||
}
|
||||
|
||||
return $this->providers[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute providers that are able to validate the current session
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function checkCurrentSession()
|
||||
{
|
||||
if ($this->userSession->isLogged()) {
|
||||
foreach ($this->filterProviders('SessionCheckProviderInterface') as $provider) {
|
||||
if ($provider instanceof OptionalAuthenticationProviderInterface && ! $provider->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! $provider->isValidSession()) {
|
||||
$this->logger->debug('Invalidate session for '.$this->userSession->getUsername());
|
||||
session_flush();
|
||||
$this->preAuthentication();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute pre-authentication providers
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function preAuthentication()
|
||||
{
|
||||
foreach ($this->filterProviders('PreAuthenticationProviderInterface') as $provider) {
|
||||
if ($provider instanceof OptionalAuthenticationProviderInterface && ! $provider->isEnabled()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($provider->authenticate() && $this->userProfile->initialize($provider->getUser())) {
|
||||
$this->dispatcher->dispatch(new AuthSuccessEvent($provider->getName()), self::EVENT_SUCCESS);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute username/password authentication providers
|
||||
*
|
||||
* @access public
|
||||
* @param string $username
|
||||
* @param string $password
|
||||
* @param boolean $fireEvent
|
||||
* @return boolean
|
||||
*/
|
||||
public function passwordAuthentication($username, $password, $fireEvent = true)
|
||||
{
|
||||
foreach ($this->filterProviders('PasswordAuthenticationProviderInterface') as $provider) {
|
||||
$provider->setUsername($username);
|
||||
$provider->setPassword($password);
|
||||
|
||||
if ($provider->authenticate() && $this->userProfile->initialize($provider->getUser())) {
|
||||
if ($fireEvent) {
|
||||
$this->dispatcher->dispatch(new AuthSuccessEvent($provider->getName()), self::EVENT_SUCCESS);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($fireEvent) {
|
||||
$this->dispatcher->dispatch(new AuthFailureEvent($username), self::EVENT_FAILURE);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform OAuth2 authentication
|
||||
*
|
||||
* @access public
|
||||
* @param string $name
|
||||
* @return boolean
|
||||
*/
|
||||
public function oauthAuthentication($name)
|
||||
{
|
||||
$provider = $this->getProvider($name);
|
||||
|
||||
if ($provider->authenticate() && $this->userProfile->initialize($provider->getUser())) {
|
||||
$this->dispatcher->dispatch(new AuthSuccessEvent($provider->getName()), self::EVENT_SUCCESS);
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->dispatcher->dispatch(new AuthFailureEvent, self::EVENT_FAILURE);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last Post-Authentication provider
|
||||
*
|
||||
* @access public
|
||||
* @return PostAuthenticationProviderInterface
|
||||
*/
|
||||
public function getPostAuthenticationProvider()
|
||||
{
|
||||
$providers = $this->filterProviders('PostAuthenticationProviderInterface');
|
||||
|
||||
if (empty($providers)) {
|
||||
throw new LogicException('You must have at least one Post-Authentication Provider configured');
|
||||
}
|
||||
|
||||
return array_pop($providers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter registered providers by interface type
|
||||
*
|
||||
* @access private
|
||||
* @param string $interface
|
||||
* @return array
|
||||
*/
|
||||
private function filterProviders($interface)
|
||||
{
|
||||
$interface = '\Kanboard\Core\Security\\'.$interface;
|
||||
|
||||
return array_filter($this->providers, function (AuthenticationProviderInterface $provider) use ($interface) {
|
||||
return is_a($provider, $interface);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
/**
|
||||
* Authentication Provider Interface
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
interface AuthenticationProviderInterface
|
||||
{
|
||||
/**
|
||||
* Get authentication provider name
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getName();
|
||||
|
||||
/**
|
||||
* Authenticate the user
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function authenticate();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
/**
|
||||
* Authorization Handler
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Authorization
|
||||
{
|
||||
/**
|
||||
* Access Map
|
||||
*
|
||||
* @access private
|
||||
* @var AccessMap
|
||||
*/
|
||||
private $accessMap;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @access public
|
||||
* @param AccessMap $accessMap
|
||||
*/
|
||||
public function __construct(AccessMap $accessMap)
|
||||
{
|
||||
$this->accessMap = $accessMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given role is allowed to access to the specified resource
|
||||
*
|
||||
* @access public
|
||||
* @param string $controller
|
||||
* @param string $method
|
||||
* @param string $role
|
||||
* @return boolean
|
||||
*/
|
||||
public function isAllowed($controller, $method, $role)
|
||||
{
|
||||
$roles = $this->accessMap->getRoles($controller, $method);
|
||||
return in_array($role, $roles);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
/**
|
||||
* OAuth2 Authentication Provider Interface
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
interface OAuthAuthenticationProviderInterface extends AuthenticationProviderInterface
|
||||
{
|
||||
/**
|
||||
* Get user object
|
||||
*
|
||||
* @access public
|
||||
* @return \Kanboard\Core\User\UserProviderInterface
|
||||
*/
|
||||
public function getUser();
|
||||
|
||||
/**
|
||||
* Unlink user
|
||||
*
|
||||
* @access public
|
||||
* @param integer $userId
|
||||
* @return bool
|
||||
*/
|
||||
public function unlink($userId);
|
||||
|
||||
/**
|
||||
* Get configured OAuth2 service
|
||||
*
|
||||
* @access public
|
||||
* @return \Kanboard\Core\Http\OAuth2
|
||||
*/
|
||||
public function getService();
|
||||
|
||||
/**
|
||||
* Set OAuth2 code
|
||||
*
|
||||
* @access public
|
||||
* @param string $code
|
||||
* @return OAuthAuthenticationProviderInterface
|
||||
*/
|
||||
public function setCode($code);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
/**
|
||||
* Optional Authentication Provider Interface
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
interface OptionalAuthenticationProviderInterface
|
||||
{
|
||||
/**
|
||||
* Check if the authentication provider should be used
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function isEnabled();
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
/**
|
||||
* Password Authentication Provider Interface
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
interface PasswordAuthenticationProviderInterface extends AuthenticationProviderInterface
|
||||
{
|
||||
/**
|
||||
* Get user object
|
||||
*
|
||||
* @access public
|
||||
* @return \Kanboard\Core\User\UserProviderInterface
|
||||
*/
|
||||
public function getUser();
|
||||
|
||||
/**
|
||||
* Set username
|
||||
*
|
||||
* @access public
|
||||
* @param string $username
|
||||
*/
|
||||
public function setUsername($username);
|
||||
|
||||
/**
|
||||
* Set password
|
||||
*
|
||||
* @access public
|
||||
* @param string $password
|
||||
*/
|
||||
public function setPassword($password);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
/**
|
||||
* Post Authentication Provider Interface
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
interface PostAuthenticationProviderInterface extends AuthenticationProviderInterface
|
||||
{
|
||||
/**
|
||||
* Called only one time before to prompt the user for pin code
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function beforeCode();
|
||||
|
||||
/**
|
||||
* Set user pin-code
|
||||
*
|
||||
* @access public
|
||||
* @param string $code
|
||||
*/
|
||||
public function setCode($code);
|
||||
|
||||
/**
|
||||
* Generate secret if necessary
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function generateSecret();
|
||||
|
||||
/**
|
||||
* Set secret token (fetched from user profile)
|
||||
*
|
||||
* @access public
|
||||
* @param string $secret
|
||||
*/
|
||||
public function setSecret($secret);
|
||||
|
||||
/**
|
||||
* Get secret token (will be saved in user profile)
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getSecret();
|
||||
|
||||
/**
|
||||
* Get key url (empty if no url can be provided)
|
||||
*
|
||||
* @access public
|
||||
* @param string $label
|
||||
* @return string
|
||||
*/
|
||||
public function getKeyUrl($label);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
/**
|
||||
* Pre-Authentication Provider Interface
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
interface PreAuthenticationProviderInterface extends AuthenticationProviderInterface
|
||||
{
|
||||
/**
|
||||
* Get user object
|
||||
*
|
||||
* @access public
|
||||
* @return \Kanboard\Core\User\UserProviderInterface
|
||||
*/
|
||||
public function getUser();
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
/**
|
||||
* Role Definitions
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Role
|
||||
{
|
||||
const APP_ADMIN = 'app-admin';
|
||||
const APP_MANAGER = 'app-manager';
|
||||
const APP_USER = 'app-user';
|
||||
const APP_PUBLIC = 'app-public';
|
||||
|
||||
const PROJECT_MANAGER = 'project-manager';
|
||||
const PROJECT_MEMBER = 'project-member';
|
||||
const PROJECT_VIEWER = 'project-viewer';
|
||||
|
||||
/**
|
||||
* Get application roles
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getApplicationRoles()
|
||||
{
|
||||
return array(
|
||||
self::APP_ADMIN => t('Administrator'),
|
||||
self::APP_MANAGER => t('Manager'),
|
||||
self::APP_USER => t('User'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get project roles
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getProjectRoles()
|
||||
{
|
||||
return array(
|
||||
self::PROJECT_MANAGER => t('Project Manager'),
|
||||
self::PROJECT_MEMBER => t('Project Member'),
|
||||
self::PROJECT_VIEWER => t('Project Viewer'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given role is custom or not
|
||||
*
|
||||
* @access public
|
||||
* @param string $role
|
||||
* @return bool
|
||||
*/
|
||||
public function isCustomProjectRole($role)
|
||||
{
|
||||
return ! empty($role) && $role !== self::PROJECT_MANAGER && $role !== self::PROJECT_MEMBER && $role !== self::PROJECT_VIEWER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get role name
|
||||
*
|
||||
* @access public
|
||||
* @param string $role
|
||||
* @return string
|
||||
*/
|
||||
public function getRoleName($role)
|
||||
{
|
||||
$roles = $this->getApplicationRoles() + $this->getProjectRoles();
|
||||
return isset($roles[$role]) ? $roles[$role] : t('Unknown');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
/**
|
||||
* Session Check Provider Interface
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
interface SessionCheckProviderInterface
|
||||
{
|
||||
/**
|
||||
* Check if the user session is valid
|
||||
*
|
||||
* @access public
|
||||
* @return boolean
|
||||
*/
|
||||
public function isValidSession();
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
namespace Kanboard\Core\Security;
|
||||
|
||||
use Kanboard\Core\Base;
|
||||
|
||||
/**
|
||||
* Token Handler
|
||||
*
|
||||
* @package security
|
||||
* @author Frederic Guillot
|
||||
*/
|
||||
class Token extends Base
|
||||
{
|
||||
protected static $KEY_LENGTH = 32;
|
||||
protected static $NONCE_LENGTH = 16;
|
||||
protected static $HMAC_ALGO = 'sha256';
|
||||
protected static $HMAC_LENGTH = 16;
|
||||
|
||||
/**
|
||||
* Generate a random token with different methods: openssl or /dev/urandom or fallback to uniqid()
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @return string Random token
|
||||
*/
|
||||
public static function getToken($length = 30)
|
||||
{
|
||||
return bin2hex(random_bytes($length));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and store a one-time CSRF token
|
||||
*
|
||||
* @access public
|
||||
* @return string Random token
|
||||
*/
|
||||
public function getCSRFToken()
|
||||
{
|
||||
return $this->createSessionToken('csrf');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and store a reusable CSRF token
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getReusableCSRFToken()
|
||||
{
|
||||
return $this->createSessionToken('pcsrf');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the token exists for the current session (a token can be used only one time)
|
||||
*
|
||||
* @access public
|
||||
* @param string $token CSRF token
|
||||
* @return bool
|
||||
*/
|
||||
public function validateCSRFToken($token)
|
||||
{
|
||||
return $this->validateSessionToken('csrf', $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the token exists as a reusable CSRF token
|
||||
*
|
||||
* @access public
|
||||
* @param string $token CSRF token
|
||||
* @return bool
|
||||
*/
|
||||
public function validateReusableCSRFToken($token)
|
||||
{
|
||||
return $this->validateSessionToken('pcsrf', $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a session token of the given type
|
||||
*
|
||||
* @access protected
|
||||
* @param string $type Token type
|
||||
* @return string Random token
|
||||
*/
|
||||
protected function createSessionToken($type)
|
||||
{
|
||||
$nonce = self::getToken(self::$NONCE_LENGTH);
|
||||
return $nonce . $this->signSessionToken($type, $nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a session token of the given type
|
||||
*
|
||||
* @access protected
|
||||
* @param string $type Token type
|
||||
* @param string $token Session token
|
||||
* @return bool
|
||||
*/
|
||||
protected function validateSessionToken($type, $token)
|
||||
{
|
||||
if (!is_string($token)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen($token) != (self::$NONCE_LENGTH + self::$HMAC_LENGTH) * 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$nonce = substr($token, 0, self::$NONCE_LENGTH * 2);
|
||||
$hmac = substr($token, self::$NONCE_LENGTH * 2, self::$HMAC_LENGTH * 2);
|
||||
|
||||
return hash_equals($this->signSessionToken($type, $nonce), $hmac);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a nonce with the key belonging to the given type
|
||||
*
|
||||
* @access protected
|
||||
* @param string $type Token type
|
||||
* @param string $nonce Nonce to sign
|
||||
* @return string
|
||||
*/
|
||||
protected function signSessionToken($type, $nonce)
|
||||
{
|
||||
if (!session_exists($type . '_key')) {
|
||||
session_set($type . '_key', self::getToken(self::$KEY_LENGTH));
|
||||
}
|
||||
|
||||
$data = $nonce . '-' . session_id();
|
||||
$key = session_get($type . '_key');
|
||||
$hmac = hash_hmac(self::$HMAC_ALGO, $data, $key, true);
|
||||
|
||||
return bin2hex(substr($hmac, 0, self::$HMAC_LENGTH));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user