diff options
Diffstat (limited to 'lib/private/appframework')
5 files changed, 120 insertions, 137 deletions
diff --git a/lib/private/appframework/dependencyinjection/dicontainer.php b/lib/private/appframework/dependencyinjection/dicontainer.php index b06010014f3..523a4153e01 100644 --- a/lib/private/appframework/dependencyinjection/dicontainer.php +++ b/lib/private/appframework/dependencyinjection/dicontainer.php @@ -91,11 +91,12 @@ class DIContainer extends SimpleContainer implements IAppContainer{ return new SecurityMiddleware($c['API'], $c['Request']); }); - $this['MiddlewareDispatcher'] = $this->share(function($c){ + $middleWares = $this->middleWares; + $this['MiddlewareDispatcher'] = $this->share(function($c) use ($middleWares) { $dispatcher = new MiddlewareDispatcher(); $dispatcher->registerMiddleware($c['SecurityMiddleware']); - foreach($this->middleWares as $middleWare) { + foreach($middleWares as $middleWare) { $dispatcher->registerMiddleware($middleWare); } diff --git a/lib/private/appframework/http/request.php b/lib/private/appframework/http/request.php index 34605acdfea..3e1f4ff87ed 100644 --- a/lib/private/appframework/http/request.php +++ b/lib/private/appframework/http/request.php @@ -31,6 +31,8 @@ use OCP\IRequest; class Request implements \ArrayAccess, \Countable, IRequest { + protected $inputStream; + protected $content; protected $items = array(); protected $allowedKeys = array( 'get', @@ -40,35 +42,48 @@ class Request implements \ArrayAccess, \Countable, IRequest { 'env', 'cookies', 'urlParams', - 'params', 'parameters', - 'method' + 'method', + 'requesttoken', ); /** * @param array $vars An associative array with the following optional values: - * @param array 'params' the parsed json array * @param array 'urlParams' the parameters which were matched from the URL * @param array 'get' the $_GET array - * @param array 'post' the $_POST array + * @param array|string 'post' the $_POST array or JSON string * @param array 'files' the $_FILES array * @param array 'server' the $_SERVER array * @param array 'env' the $_ENV array - * @param array 'session' the $_SESSION array * @param array 'cookies' the $_COOKIE array * @param string 'method' the request method (GET, POST etc) + * @param string|false 'requesttoken' the requesttoken or false when not available * @see http://www.php.net/manual/en/reserved.variables.php */ public function __construct(array $vars=array()) { foreach($this->allowedKeys as $name) { - $this->items[$name] = isset($vars[$name]) + $this->items[$name] = isset($vars[$name]) ? $vars[$name] : array(); } + if (defined('PHPUNIT_RUN') && PHPUNIT_RUN + && in_array('fakeinput', stream_get_wrappers())) { + $this->inputStream = 'fakeinput://data'; + } else { + $this->inputStream = 'php://input'; + } + + // Only 'application/x-www-form-urlencoded' requests are automatically + // transformed by PHP, 'application/json' must be decoded manually. + if ($this->method === 'POST' + && strpos($this->getHeader('Content-Type'), 'application/json') !== false + ) { + $this->items['params'] = $this->items['post'] = json_decode(file_get_contents($this->inputStream), true); + } + $this->items['parameters'] = array_merge( - $this->items['params'], $this->items['get'], $this->items['post'], $this->items['urlParams'] @@ -141,17 +156,22 @@ class Request implements \ArrayAccess, \Countable, IRequest { * $request->myvar; or $request->{'myvar'}; or $request->{$myvar} * Looks in the combined GET, POST and urlParams array. * - * if($request->method !== 'POST') { - * throw new Exception('This function can only be invoked using POST'); - * } + * If you access e.g. ->post but the current HTTP request method + * is GET a \LogicException will be thrown. * * @param string $name The key to look for. + * @throws \LogicException * @return mixed|null */ public function __get($name) { switch($name) { + case 'put': + case 'patch': case 'get': case 'post': + if($this->method !== strtoupper($name)) { + throw new \LogicException(sprintf('%s cannot be accessed in a %s request.', $name, $this->method)); + } case 'files': case 'server': case 'env': @@ -159,9 +179,13 @@ class Request implements \ArrayAccess, \Countable, IRequest { case 'parameters': case 'params': case 'urlParams': - return isset($this->items[$name]) - ? $this->items[$name] - : null; + if(in_array($name, array('put', 'patch'))) { + return $this->getContent($name); + } else { + return isset($this->items[$name]) + ? $this->items[$name] + : null; + } break; case 'method': return $this->items['method']; @@ -280,28 +304,86 @@ class Request implements \ArrayAccess, \Countable, IRequest { /** * Returns the request body content. * - * @param Boolean $asResource If true, a resource will be returned + * If the HTTP request method is PUT and the body + * not application/x-www-form-urlencoded or application/json a stream + * resource is returned, otherwise an array. * - * @return string|resource The request body content or a resource to read the body stream. + * @return array|string|resource The request body content or a resource to read the body stream. * * @throws \LogicException */ - function getContent($asResource = false) { - return null; -// if (false === $this->content || (true === $asResource && null !== $this->content)) { -// throw new \LogicException('getContent() can only be called once when using the resource return type.'); -// } -// -// if (true === $asResource) { -// $this->content = false; -// -// return fopen('php://input', 'rb'); -// } -// -// if (null === $this->content) { -// $this->content = file_get_contents('php://input'); -// } -// -// return $this->content; + protected function getContent() { + if ($this->content === false && $this->method === 'PUT') { + throw new \LogicException( + '"put" can only be accessed once if not ' + . 'application/x-www-form-urlencoded or application/json.' + ); + } + + // If the content can't be parsed into an array then return a stream resource. + if ($this->method === 'PUT' + && strpos($this->getHeader('Content-Type'), 'application/x-www-form-urlencoded') === false + && strpos($this->getHeader('Content-Type'), 'application/json') === false + ) { + $this->content = false; + return fopen($this->inputStream, 'rb'); + } + + if (is_null($this->content)) { + $this->content = file_get_contents($this->inputStream); + + /* + * Normal jquery ajax requests are sent as application/x-www-form-urlencoded + * and in $_GET and $_POST PHP transformes the data into an array. + * The first condition mimics this. + * The second condition allows for sending raw application/json data while + * still getting the result as an array. + * + */ + if (strpos($this->getHeader('Content-Type'), 'application/x-www-form-urlencoded') !== false) { + parse_str($this->content, $content); + if(is_array($content)) { + $this->content = $content; + } + } elseif (strpos($this->getHeader('Content-Type'), 'application/json') !== false) { + $content = json_decode($this->content, true); + if(is_array($content)) { + $this->content = $content; + } + } + } + + return $this->content; } -} + + /** + * Checks if the CSRF check was correct + * @return bool true if CSRF check passed + * @see OC_Util::$callLifespan + * @see OC_Util::callRegister() + */ + public function passesCSRFCheck() { + if($this->items['requesttoken'] === false) { + return false; + } + + if (isset($this->items['get']['requesttoken'])) { + $token = $this->items['get']['requesttoken']; + } elseif (isset($this->items['post']['requesttoken'])) { + $token = $this->items['post']['requesttoken']; + } elseif (isset($this->items['server']['HTTP_REQUESTTOKEN'])) { + $token = $this->items['server']['HTTP_REQUESTTOKEN']; + } else { + //no token found. + return false; + } + + // Check if the token is valid + if($token !== $this->items['requesttoken']) { + // Not valid + return false; + } else { + // Valid token + return true; + } + }} diff --git a/lib/private/appframework/middleware/middleware.php b/lib/private/appframework/middleware/middleware.php deleted file mode 100644 index b12c03c3eb8..00000000000 --- a/lib/private/appframework/middleware/middleware.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php - -/** - * ownCloud - App Framework - * - * @author Bernhard Posselt - * @copyright 2012 Bernhard Posselt nukeawhale@gmail.com - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE - * License as published by the Free Software Foundation; either - * version 3 of the License, or any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU AFFERO GENERAL PUBLIC LICENSE for more details. - * - * You should have received a copy of the GNU Affero General Public - * License along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ - - -namespace OC\AppFramework\Middleware; - -use OCP\AppFramework\Http\Response; - - -/** - * Middleware is used to provide hooks before or after controller methods and - * deal with possible exceptions raised in the controller methods. - * They're modeled after Django's middleware system: - * https://docs.djangoproject.com/en/dev/topics/http/middleware/ - */ -abstract class Middleware { - - - /** - * This is being run in normal order before the controller is being - * called which allows several modifications and checks - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - */ - public function beforeController($controller, $methodName){ - - } - - - /** - * This is being run when either the beforeController method or the - * controller method itself is throwing an exception. The middleware is - * asked in reverse order to handle the exception and to return a response. - * If the response is null, it is assumed that the exception could not be - * handled and the error will be thrown again - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - * @param \Exception $exception the thrown exception - * @throws \Exception the passed in exception if it cant handle it - * @return Response a Response object in case that the exception was handled - */ - public function afterException($controller, $methodName, \Exception $exception){ - throw $exception; - } - - - /** - * This is being run after a successful controllermethod call and allows - * the manipulation of a Response object. The middleware is run in reverse order - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - * @param Response $response the generated response from the controller - * @return Response a Response object - */ - public function afterController($controller, $methodName, Response $response){ - return $response; - } - - - /** - * This is being run after the response object has been rendered and - * allows the manipulation of the output. The middleware is run in reverse order - * - * @param Controller $controller the controller that is being called - * @param string $methodName the name of the method that will be called on - * the controller - * @param string $output the generated output from a response - * @return string the output that should be printed - */ - public function beforeOutput($controller, $methodName, $output){ - return $output; - } - -} diff --git a/lib/private/appframework/middleware/middlewaredispatcher.php b/lib/private/appframework/middleware/middlewaredispatcher.php index 70ab108e6b8..c2377b8844b 100644 --- a/lib/private/appframework/middleware/middlewaredispatcher.php +++ b/lib/private/appframework/middleware/middlewaredispatcher.php @@ -26,7 +26,7 @@ namespace OC\AppFramework\Middleware; use OC\AppFramework\Controller\Controller; use OCP\AppFramework\Http\Response; - +use OCP\AppFramework\MiddleWare; /** * This class is used to store and run all the middleware in correct order diff --git a/lib/private/appframework/middleware/security/securitymiddleware.php b/lib/private/appframework/middleware/security/securitymiddleware.php index b65e3510ea5..d6dbcb6b8be 100644 --- a/lib/private/appframework/middleware/security/securitymiddleware.php +++ b/lib/private/appframework/middleware/security/securitymiddleware.php @@ -29,8 +29,8 @@ use OC\AppFramework\Http\Http; use OC\AppFramework\Http\Request; use OC\AppFramework\Http\RedirectResponse; use OC\AppFramework\Utility\MethodAnnotationReader; -use OC\AppFramework\Middleware\Middleware; use OC\AppFramework\Core\API; +use OCP\AppFramework\Middleware; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\JSONResponse; |