/app/Controller/Base.php

https://github.com/wheatbin/wheatbin · PHP · 311 lines · 167 code · 40 blank · 104 comment · 31 complexity · 75f8964630237ce9a909e997c459d119 MD5 · raw file

  1. <?php
  2. namespace Kanboard\Controller;
  3. use Kanboard\Core\Security\Role;
  4. /**
  5. * Base controller
  6. *
  7. * @package controller
  8. * @author Frederic Guillot
  9. */
  10. abstract class Base extends \Kanboard\Core\Base
  11. {
  12. /**
  13. * Method executed before each action
  14. *
  15. * @access public
  16. */
  17. public function beforeAction($controller, $action)
  18. {
  19. $this->sessionManager->open();
  20. $this->dispatcher->dispatch('app.bootstrap');
  21. $this->sendHeaders($action);
  22. $this->authenticationManager->checkCurrentSession();
  23. if (! $this->applicationAuthorization->isAllowed($controller, $action, Role::APP_PUBLIC)) {
  24. $this->handleAuthentication();
  25. $this->handlePostAuthentication($controller, $action);
  26. $this->checkApplicationAuthorization($controller, $action);
  27. $this->checkProjectAuthorization($controller, $action);
  28. }
  29. }
  30. /**
  31. * Send HTTP headers
  32. *
  33. * @access private
  34. */
  35. private function sendHeaders($action)
  36. {
  37. // HTTP secure headers
  38. $this->response->csp($this->container['cspRules']);
  39. $this->response->nosniff();
  40. $this->response->xss();
  41. // Allow the public board iframe inclusion
  42. if (ENABLE_XFRAME && $action !== 'readonly') {
  43. $this->response->xframe();
  44. }
  45. if (ENABLE_HSTS) {
  46. $this->response->hsts();
  47. }
  48. }
  49. /**
  50. * Check authentication
  51. *
  52. * @access private
  53. */
  54. private function handleAuthentication()
  55. {
  56. if (! $this->userSession->isLogged() && ! $this->authenticationManager->preAuthentication()) {
  57. if ($this->request->isAjax()) {
  58. $this->response->text('Not Authorized', 401);
  59. }
  60. $this->sessionStorage->redirectAfterLogin = $this->request->getUri();
  61. $this->response->redirect($this->helper->url->to('auth', 'login'));
  62. }
  63. }
  64. /**
  65. * Handle Post-Authentication (2FA)
  66. *
  67. * @access private
  68. */
  69. private function handlePostAuthentication($controller, $action)
  70. {
  71. $ignore = ($controller === 'twofactor' && in_array($action, array('code', 'check'))) || ($controller === 'auth' && $action === 'logout');
  72. if ($ignore === false && $this->userSession->hasPostAuthentication() && ! $this->userSession->isPostAuthenticationValidated()) {
  73. if ($this->request->isAjax()) {
  74. $this->response->text('Not Authorized', 401);
  75. }
  76. $this->response->redirect($this->helper->url->to('twofactor', 'code'));
  77. }
  78. }
  79. /**
  80. * Check application authorization
  81. *
  82. * @access private
  83. */
  84. private function checkApplicationAuthorization($controller, $action)
  85. {
  86. if (! $this->helper->user->hasAccess($controller, $action)) {
  87. $this->forbidden();
  88. }
  89. }
  90. /**
  91. * Check project authorization
  92. *
  93. * @access private
  94. */
  95. private function checkProjectAuthorization($controller, $action)
  96. {
  97. $project_id = $this->request->getIntegerParam('project_id');
  98. $task_id = $this->request->getIntegerParam('task_id');
  99. // Allow urls without "project_id"
  100. if ($task_id > 0 && $project_id === 0) {
  101. $project_id = $this->taskFinder->getProjectId($task_id);
  102. }
  103. if ($project_id > 0 && ! $this->helper->user->hasProjectAccess($controller, $action, $project_id)) {
  104. $this->forbidden();
  105. }
  106. }
  107. /**
  108. * Application not found page (404 error)
  109. *
  110. * @access protected
  111. * @param boolean $no_layout Display the layout or not
  112. */
  113. protected function notfound($no_layout = false)
  114. {
  115. $this->response->html($this->template->layout('app/notfound', array(
  116. 'title' => t('Page not found'),
  117. 'no_layout' => $no_layout,
  118. )));
  119. }
  120. /**
  121. * Application forbidden page
  122. *
  123. * @access protected
  124. * @param boolean $no_layout Display the layout or not
  125. */
  126. protected function forbidden($no_layout = false)
  127. {
  128. if ($this->request->isAjax()) {
  129. $this->response->text('Not Authorized', 401);
  130. }
  131. $this->response->html($this->template->layout('app/forbidden', array(
  132. 'title' => t('Access Forbidden'),
  133. 'no_layout' => $no_layout,
  134. )));
  135. }
  136. /**
  137. * Check if the CSRF token from the URL is correct
  138. *
  139. * @access protected
  140. */
  141. protected function checkCSRFParam()
  142. {
  143. if (! $this->token->validateCSRFToken($this->request->getStringParam('csrf_token'))) {
  144. $this->forbidden();
  145. }
  146. }
  147. /**
  148. * Check webhook token
  149. *
  150. * @access protected
  151. */
  152. protected function checkWebhookToken()
  153. {
  154. if ($this->config->get('webhook_token') !== $this->request->getStringParam('token')) {
  155. $this->response->text('Not Authorized', 401);
  156. }
  157. }
  158. /**
  159. * Common layout for task views
  160. *
  161. * @access protected
  162. * @param string $template Template name
  163. * @param array $params Template parameters
  164. * @return string
  165. */
  166. protected function taskLayout($template, array $params)
  167. {
  168. $content = $this->template->render($template, $params);
  169. $params['task_content_for_layout'] = $content;
  170. $params['title'] = $params['task']['project_name'].' &gt; '.$params['task']['title'];
  171. $params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId());
  172. return $this->template->layout('task/layout', $params);
  173. }
  174. /**
  175. * Common layout for project views
  176. *
  177. * @access protected
  178. * @param string $template Template name
  179. * @param array $params Template parameters
  180. * @return string
  181. */
  182. protected function projectLayout($template, array $params, $sidebar_template = 'project/sidebar')
  183. {
  184. $content = $this->template->render($template, $params);
  185. $params['project_content_for_layout'] = $content;
  186. $params['title'] = $params['project']['name'] === $params['title'] ? $params['title'] : $params['project']['name'].' &gt; '.$params['title'];
  187. $params['board_selector'] = $this->projectUserRole->getProjectsByUser($this->userSession->getId());
  188. $params['sidebar_template'] = $sidebar_template;
  189. return $this->template->layout('project/layout', $params);
  190. }
  191. /**
  192. * Common method to get a task for task views
  193. *
  194. * @access protected
  195. * @return array
  196. */
  197. protected function getTask()
  198. {
  199. $project_id = $this->request->getIntegerParam('project_id');
  200. $task = $this->taskFinder->getDetails($this->request->getIntegerParam('task_id'));
  201. if (empty($task)) {
  202. $this->notfound();
  203. }
  204. if ($project_id !== 0 && $project_id != $task['project_id']) {
  205. $this->forbidden();
  206. }
  207. return $task;
  208. }
  209. /**
  210. * Common method to get a project
  211. *
  212. * @access protected
  213. * @param integer $project_id Default project id
  214. * @return array
  215. */
  216. protected function getProject($project_id = 0)
  217. {
  218. $project_id = $this->request->getIntegerParam('project_id', $project_id);
  219. $project = $this->project->getById($project_id);
  220. if (empty($project)) {
  221. $this->flash->failure(t('Project not found.'));
  222. $this->response->redirect($this->helper->url->to('project', 'index'));
  223. }
  224. return $project;
  225. }
  226. /**
  227. * Common method to get the user
  228. *
  229. * @access protected
  230. * @return array
  231. */
  232. protected function getUser()
  233. {
  234. $user = $this->user->getById($this->request->getIntegerParam('user_id', $this->userSession->getId()));
  235. if (empty($user)) {
  236. $this->notfound();
  237. }
  238. if (! $this->userSession->isAdmin() && $this->userSession->getId() != $user['id']) {
  239. $this->forbidden();
  240. }
  241. return $user;
  242. }
  243. /**
  244. * Common method to get project filters
  245. *
  246. * @access protected
  247. * @param string $controller
  248. * @param string $action
  249. * @return array
  250. */
  251. protected function getProjectFilters($controller, $action)
  252. {
  253. $project = $this->getProject();
  254. $search = $this->request->getStringParam('search', $this->userSession->getFilters($project['id']));
  255. $board_selector = $this->projectUserRole->getProjectsByUser($this->userSession->getId());
  256. unset($board_selector[$project['id']]);
  257. $filters = array(
  258. 'controller' => $controller,
  259. 'action' => $action,
  260. 'project_id' => $project['id'],
  261. 'search' => urldecode($search),
  262. );
  263. $this->userSession->setFilters($project['id'], $filters['search']);
  264. return array(
  265. 'project' => $project,
  266. 'board_selector' => $board_selector,
  267. 'filters' => $filters,
  268. 'title' => $project['name'],
  269. );
  270. }
  271. }