securitymiddleware.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <?php
  2. /**
  3. * ownCloud - App Framework
  4. *
  5. * @author Bernhard Posselt
  6. * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com
  7. *
  8. * This library is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  10. * License as published by the Free Software Foundation; either
  11. * version 3 of the License, or any later version.
  12. *
  13. * This library is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public
  19. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. namespace OC\AppFramework\Middleware\Security;
  23. use OC\AppFramework\Http;
  24. use OC\AppFramework\Http\RedirectResponse;
  25. use OC\AppFramework\Utility\MethodAnnotationReader;
  26. use OCP\AppFramework\Middleware;
  27. use OCP\AppFramework\Http\Response;
  28. use OCP\AppFramework\Http\JSONResponse;
  29. use OCP\AppFramework\IAppContainer;
  30. use OCP\IRequest;
  31. /**
  32. * Used to do all the authentication and checking stuff for a controller method
  33. * It reads out the annotations of a controller method and checks which if
  34. * security things should be checked and also handles errors in case a security
  35. * check fails
  36. */
  37. class SecurityMiddleware extends Middleware {
  38. /**
  39. * @var \OCP\AppFramework\IAppContainer
  40. */
  41. private $app;
  42. /**
  43. * @var \OCP\IRequest
  44. */
  45. private $request;
  46. /**
  47. * @param IAppContainer $app
  48. * @param IRequest $request
  49. */
  50. public function __construct(IAppContainer $app, IRequest $request){
  51. $this->app = $app;
  52. $this->request = $request;
  53. }
  54. /**
  55. * This runs all the security checks before a method call. The
  56. * security checks are determined by inspecting the controller method
  57. * annotations
  58. * @param string/Controller $controller the controllername or string
  59. * @param string $methodName the name of the method
  60. * @throws SecurityException when a security check fails
  61. */
  62. public function beforeController($controller, $methodName){
  63. // get annotations from comments
  64. $annotationReader = new MethodAnnotationReader($controller, $methodName);
  65. // this will set the current navigation entry of the app, use this only
  66. // for normal HTML requests and not for AJAX requests
  67. $this->app->getServer()->getNavigationManager()->setActiveEntry($this->app->getAppName());
  68. // security checks
  69. $isPublicPage = $annotationReader->hasAnnotation('PublicPage');
  70. if(!$isPublicPage) {
  71. if(!$this->app->isLoggedIn()) {
  72. throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED);
  73. }
  74. if(!$annotationReader->hasAnnotation('NoAdminRequired')) {
  75. if(!$this->app->isAdminUser()) {
  76. throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN);
  77. }
  78. }
  79. }
  80. if(!$annotationReader->hasAnnotation('NoCSRFRequired')) {
  81. if(!$this->request->passesCSRFCheck()) {
  82. throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED);
  83. }
  84. }
  85. }
  86. /**
  87. * If an SecurityException is being caught, ajax requests return a JSON error
  88. * response and non ajax requests redirect to the index
  89. * @param Controller $controller the controller that is being called
  90. * @param string $methodName the name of the method that will be called on
  91. * the controller
  92. * @param \Exception $exception the thrown exception
  93. * @throws \Exception the passed in exception if it cant handle it
  94. * @return Response a Response object or null in case that the exception could not be handled
  95. */
  96. public function afterException($controller, $methodName, \Exception $exception){
  97. if($exception instanceof SecurityException){
  98. if (stripos($this->request->getHeader('Accept'),'html')===false) {
  99. $response = new JSONResponse(
  100. array('message' => $exception->getMessage()),
  101. $exception->getCode()
  102. );
  103. $this->app->log($exception->getMessage(), 'debug');
  104. } else {
  105. // TODO: replace with link to route
  106. $url = $this->app->getServer()->getURLGenerator()->getAbsoluteURL('index.php');
  107. $response = new RedirectResponse($url);
  108. $this->app->log($exception->getMessage(), 'debug');
  109. }
  110. return $response;
  111. }
  112. throw $exception;
  113. }
  114. }