diff options
-rw-r--r-- | app/Api/AuthApi.php | 82 | ||||
-rw-r--r-- | app/Api/BaseApi.php | 45 | ||||
-rw-r--r-- | app/Api/Middleware/AuthenticationApiMiddleware.php | 130 | ||||
-rw-r--r-- | app/Core/Base.php | 1 | ||||
-rw-r--r-- | app/ServiceProvider/ApiProvider.php | 74 | ||||
-rw-r--r-- | app/common.php | 1 | ||||
-rw-r--r-- | composer.json | 2 | ||||
-rw-r--r-- | composer.lock | 17 | ||||
-rw-r--r-- | jsonrpc.php | 46 |
9 files changed, 218 insertions, 180 deletions
diff --git a/app/Api/AuthApi.php b/app/Api/AuthApi.php deleted file mode 100644 index 1cbce5ae..00000000 --- a/app/Api/AuthApi.php +++ /dev/null @@ -1,82 +0,0 @@ -<?php - -namespace Kanboard\Api; - -use JsonRPC\Exception\AuthenticationFailureException; - -/** - * Base class - * - * @package Kanboard\Api - * @author Frederic Guillot - */ -class AuthApi extends BaseApi -{ - /** - * Check api credentials - * - * @access public - * @param string $username - * @param string $password - * @param string $class - * @param string $method - * @throws AuthenticationFailureException - */ - public function checkCredentials($username, $password, $class, $method) - { - $this->dispatcher->dispatch('app.bootstrap'); - - if ($this->isUserAuthenticated($username, $password)) { - $this->checkProcedurePermission(true, $method); - $this->userSession->initialize($this->userModel->getByUsername($username)); - } elseif ($this->isAppAuthenticated($username, $password)) { - $this->checkProcedurePermission(false, $method); - } else { - $this->logger->error('API authentication failure for '.$username); - throw new AuthenticationFailureException('Wrong credentials'); - } - } - - /** - * Check user credentials - * - * @access public - * @param string $username - * @param string $password - * @return boolean - */ - private function isUserAuthenticated($username, $password) - { - return $username !== 'jsonrpc' && - ! $this->userLockingModel->isLocked($username) && - $this->authenticationManager->passwordAuthentication($username, $password); - } - - /** - * Check administrative credentials - * - * @access public - * @param string $username - * @param string $password - * @return boolean - */ - private function isAppAuthenticated($username, $password) - { - return $username === 'jsonrpc' && $password === $this->getApiToken(); - } - - /** - * Get API Token - * - * @access private - * @return string - */ - private function getApiToken() - { - if (defined('API_AUTHENTICATION_TOKEN')) { - return API_AUTHENTICATION_TOKEN; - } - - return $this->configModel->get('api_token'); - } -} diff --git a/app/Api/BaseApi.php b/app/Api/BaseApi.php index ae41e5b5..9f69aa65 100644 --- a/app/Api/BaseApi.php +++ b/app/Api/BaseApi.php @@ -13,51 +13,6 @@ use Kanboard\Core\Base; */ abstract class BaseApi extends Base { - private $user_allowed_procedures = array( - 'getMe', - 'getMyDashboard', - 'getMyActivityStream', - 'createMyPrivateProject', - 'getMyProjectsList', - 'getMyProjects', - 'getMyOverdueTasks', - ); - - private $both_allowed_procedures = array( - 'getTimezone', - 'getVersion', - 'getDefaultTaskColor', - 'getDefaultTaskColors', - 'getColorList', - 'getProjectById', - 'getTask', - 'getTaskByReference', - 'getAllTasks', - 'openTask', - 'closeTask', - 'moveTaskPosition', - 'createTask', - 'updateTask', - 'getBoard', - 'getProjectActivity', - 'getOverdueTasksByProject', - 'searchTasks', - ); - - public function checkProcedurePermission($is_user, $procedure) - { - $is_both_procedure = in_array($procedure, $this->both_allowed_procedures); - $is_user_procedure = in_array($procedure, $this->user_allowed_procedures); - - if ($is_user && ! $is_both_procedure && ! $is_user_procedure) { - throw new AccessDeniedException('Permission denied'); - } elseif (! $is_user && ! $is_both_procedure && $is_user_procedure) { - throw new AccessDeniedException('Permission denied'); - } - - $this->logger->debug('API call: '.$procedure); - } - public function checkProjectPermission($project_id) { if ($this->userSession->isLogged() && ! $this->projectPermissionModel->isUserAllowed($project_id, $this->userSession->getId())) { diff --git a/app/Api/Middleware/AuthenticationApiMiddleware.php b/app/Api/Middleware/AuthenticationApiMiddleware.php new file mode 100644 index 00000000..5f63e1a1 --- /dev/null +++ b/app/Api/Middleware/AuthenticationApiMiddleware.php @@ -0,0 +1,130 @@ +<?php + +namespace Kanboard\Api\Middleware; + +use JsonRPC\Exception\AccessDeniedException; +use JsonRPC\Exception\AuthenticationFailureException; +use JsonRPC\MiddlewareInterface; +use Kanboard\Core\Base; + +/** + * Class AuthenticationApiMiddleware + * + * @package Kanboard\Api\Middleware + * @author Frederic Guillot + */ +class AuthenticationApiMiddleware extends Base implements MiddlewareInterface +{ + private $user_allowed_procedures = array( + 'getMe', + 'getMyDashboard', + 'getMyActivityStream', + 'createMyPrivateProject', + 'getMyProjectsList', + 'getMyProjects', + 'getMyOverdueTasks', + ); + + private $both_allowed_procedures = array( + 'getTimezone', + 'getVersion', + 'getDefaultTaskColor', + 'getDefaultTaskColors', + 'getColorList', + 'getProjectById', + 'getTask', + 'getTaskByReference', + 'getAllTasks', + 'openTask', + 'closeTask', + 'moveTaskPosition', + 'createTask', + 'updateTask', + 'getBoard', + 'getProjectActivity', + 'getOverdueTasksByProject', + 'searchTasks', + ); + + /** + * Execute Middleware + * + * @access public + * @param string $username + * @param string $password + * @param string $procedureName + * @throws AccessDeniedException + * @throws AuthenticationFailureException + */ + public function execute($username, $password, $procedureName) + { + $this->dispatcher->dispatch('app.bootstrap'); + + if ($this->isUserAuthenticated($username, $password)) { + $this->checkProcedurePermission(true, $procedureName); + $this->userSession->initialize($this->userModel->getByUsername($username)); + } elseif ($this->isAppAuthenticated($username, $password)) { + $this->checkProcedurePermission(false, $procedureName); + } else { + $this->logger->error('API authentication failure for '.$username); + throw new AuthenticationFailureException('Wrong credentials'); + } + } + + /** + * Check user credentials + * + * @access public + * @param string $username + * @param string $password + * @return boolean + */ + private function isUserAuthenticated($username, $password) + { + return $username !== 'jsonrpc' && + ! $this->userLockingModel->isLocked($username) && + $this->authenticationManager->passwordAuthentication($username, $password); + } + + /** + * Check administrative credentials + * + * @access public + * @param string $username + * @param string $password + * @return boolean + */ + private function isAppAuthenticated($username, $password) + { + return $username === 'jsonrpc' && $password === $this->getApiToken(); + } + + /** + * Get API Token + * + * @access private + * @return string + */ + private function getApiToken() + { + if (defined('API_AUTHENTICATION_TOKEN')) { + return API_AUTHENTICATION_TOKEN; + } + + return $this->configModel->get('api_token'); + } + + public function checkProcedurePermission($is_user, $procedure) + { + $is_both_procedure = in_array($procedure, $this->both_allowed_procedures); + $is_user_procedure = in_array($procedure, $this->user_allowed_procedures); + + if ($is_user && ! $is_both_procedure && ! $is_user_procedure) { + throw new AccessDeniedException('Permission denied'); + } elseif (! $is_user && ! $is_both_procedure && $is_user_procedure) { + throw new AccessDeniedException('Permission denied'); + } + + $this->logger->debug('API call: '.$procedure); + } +} diff --git a/app/Core/Base.php b/app/Core/Base.php index 99c093e4..725bd7c0 100644 --- a/app/Core/Base.php +++ b/app/Core/Base.php @@ -140,6 +140,7 @@ use Pimple\Container; * @property \Psr\Log\LoggerInterface $logger * @property \PicoDb\Database $db * @property \Symfony\Component\EventDispatcher\EventDispatcher $dispatcher + * @property \JsonRPC\Server $api */ abstract class Base { diff --git a/app/ServiceProvider/ApiProvider.php b/app/ServiceProvider/ApiProvider.php new file mode 100644 index 00000000..19d945f6 --- /dev/null +++ b/app/ServiceProvider/ApiProvider.php @@ -0,0 +1,74 @@ +<?php + +namespace Kanboard\ServiceProvider; + +use JsonRPC\Server; +use Kanboard\Api\ActionApi; +use Kanboard\Api\AppApi; +use Kanboard\Api\BoardApi; +use Kanboard\Api\CategoryApi; +use Kanboard\Api\ColumnApi; +use Kanboard\Api\CommentApi; +use Kanboard\Api\FileApi; +use Kanboard\Api\GroupApi; +use Kanboard\Api\GroupMemberApi; +use Kanboard\Api\LinkApi; +use Kanboard\Api\MeApi; +use Kanboard\Api\Middleware\AuthenticationApiMiddleware; +use Kanboard\Api\ProjectApi; +use Kanboard\Api\ProjectPermissionApi; +use Kanboard\Api\SubtaskApi; +use Kanboard\Api\SwimlaneApi; +use Kanboard\Api\TaskApi; +use Kanboard\Api\TaskLinkApi; +use Kanboard\Api\UserApi; +use Pimple\Container; +use Pimple\ServiceProviderInterface; + +/** + * Class ApiProvider + * + * @package Kanboard\ServiceProvider + * @author Frederic Guillot + */ +class ApiProvider implements ServiceProviderInterface +{ + /** + * Registers services on the given container. + * + * @param Container $container + * @return Container + */ + public function register(Container $container) + { + $server = new Server(); + $server->setAuthenticationHeader(API_AUTHENTICATION_HEADER); + $server->getMiddlewareHandler() + ->withMiddleware(new AuthenticationApiMiddleware($container)) + ; + + $server->getProcedureHandler() + ->withObject(new MeApi($container)) + ->withObject(new ActionApi($container)) + ->withObject(new AppApi($container)) + ->withObject(new BoardApi($container)) + ->withObject(new ColumnApi($container)) + ->withObject(new CategoryApi($container)) + ->withObject(new CommentApi($container)) + ->withObject(new FileApi($container)) + ->withObject(new LinkApi($container)) + ->withObject(new ProjectApi($container)) + ->withObject(new ProjectPermissionApi($container)) + ->withObject(new SubtaskApi($container)) + ->withObject(new SwimlaneApi($container)) + ->withObject(new TaskApi($container)) + ->withObject(new TaskLinkApi($container)) + ->withObject(new UserApi($container)) + ->withObject(new GroupApi($container)) + ->withObject(new GroupMemberApi($container)) + ; + + $container['api'] = $server; + return $container; + } +} diff --git a/app/common.php b/app/common.php index 4781ddb4..e73d3a64 100644 --- a/app/common.php +++ b/app/common.php @@ -47,4 +47,5 @@ $container->register(new Kanboard\ServiceProvider\ExternalLinkProvider()); $container->register(new Kanboard\ServiceProvider\AvatarProvider()); $container->register(new Kanboard\ServiceProvider\FilterProvider()); $container->register(new Kanboard\ServiceProvider\QueueProvider()); +$container->register(new Kanboard\ServiceProvider\ApiProvider()); $container->register(new Kanboard\ServiceProvider\PluginProvider()); diff --git a/composer.json b/composer.json index 0e80840c..f49bdd8a 100644 --- a/composer.json +++ b/composer.json @@ -26,7 +26,7 @@ "christian-riesen/otp" : "1.4", "eluceo/ical": "0.8.0", "erusev/parsedown" : "1.6.0", - "fguillot/json-rpc" : "1.1.0", + "fguillot/json-rpc" : "1.2.0", "fguillot/picodb" : "1.0.12", "fguillot/simpleLogger" : "1.0.1", "fguillot/simple-validator" : "1.0.0", diff --git a/composer.lock b/composer.lock index 951c835b..1df4e429 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "cb6d74d2ba01afcd7988f4ab99d614a5", - "content-hash": "8c9fce0f4478875b9b4dc1ae53738159", + "hash": "d47d835e84b436f531274f700ec39305", + "content-hash": "643b9cebc73b39d76b6b47eb759d054d", "packages": [ { "name": "christian-riesen/base32", @@ -203,21 +203,24 @@ }, { "name": "fguillot/json-rpc", - "version": "v1.1.0", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/fguillot/JsonRPC.git", - "reference": "e915dab71940e7ac251955c785570048f460d332" + "reference": "b002320b10aa1eeb7aee83f7b703cd6a6e99ff78" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/e915dab71940e7ac251955c785570048f460d332", - "reference": "e915dab71940e7ac251955c785570048f460d332", + "url": "https://api.github.com/repos/fguillot/JsonRPC/zipball/b002320b10aa1eeb7aee83f7b703cd6a6e99ff78", + "reference": "b002320b10aa1eeb7aee83f7b703cd6a6e99ff78", "shasum": "" }, "require": { "php": ">=5.3.4" }, + "require-dev": { + "phpunit/phpunit": "4.8.*" + }, "type": "library", "autoload": { "psr-0": { @@ -235,7 +238,7 @@ ], "description": "Simple Json-RPC client/server library that just works", "homepage": "https://github.com/fguillot/JsonRPC", - "time": "2016-04-27 02:48:10" + "time": "2016-05-29 13:06:36" }, { "name": "fguillot/picodb", diff --git a/jsonrpc.php b/jsonrpc.php index c0dc5c56..50e8f89b 100644 --- a/jsonrpc.php +++ b/jsonrpc.php @@ -2,48 +2,4 @@ require __DIR__.'/app/common.php'; -use JsonRPC\Server; -use Kanboard\Api\AuthApi; -use Kanboard\Api\MeApi; -use Kanboard\Api\ActionApi; -use Kanboard\Api\AppApi; -use Kanboard\Api\BoardApi; -use Kanboard\Api\ColumnApi; -use Kanboard\Api\CategoryApi; -use Kanboard\Api\CommentApi; -use Kanboard\Api\FileApi; -use Kanboard\Api\LinkApi; -use Kanboard\Api\ProjectApi; -use Kanboard\Api\ProjectPermissionApi; -use Kanboard\Api\SubtaskApi; -use Kanboard\Api\SwimlaneApi; -use Kanboard\Api\TaskApi; -use Kanboard\Api\TaskLinkApi; -use Kanboard\Api\UserApi; -use Kanboard\Api\GroupApi; -use Kanboard\Api\GroupMemberApi; - -$server = new Server; -$server->setAuthenticationHeader(API_AUTHENTICATION_HEADER); -$server->before(array(new AuthApi($container), 'checkCredentials')); - -$server->attach(new MeApi($container)); -$server->attach(new ActionApi($container)); -$server->attach(new AppApi($container)); -$server->attach(new BoardApi($container)); -$server->attach(new ColumnApi($container)); -$server->attach(new CategoryApi($container)); -$server->attach(new CommentApi($container)); -$server->attach(new FileApi($container)); -$server->attach(new LinkApi($container)); -$server->attach(new ProjectApi($container)); -$server->attach(new ProjectPermissionApi($container)); -$server->attach(new SubtaskApi($container)); -$server->attach(new SwimlaneApi($container)); -$server->attach(new TaskApi($container)); -$server->attach(new TaskLinkApi($container)); -$server->attach(new UserApi($container)); -$server->attach(new GroupApi($container)); -$server->attach(new GroupMemberApi($container)); - -echo $server->execute(); +echo $container['api']->execute(); |