@@ -33,6 +33,7 @@ use OC\AppFramework\Middleware\Security\SecurityMiddleware; | |||
use OC\AppFramework\Middleware\Security\CORSMiddleware; | |||
use OC\AppFramework\Utility\SimpleContainer; | |||
use OC\AppFramework\Utility\TimeFactory; | |||
use OC\AppFramework\Utility\ControllerMethodReflector; | |||
use OCP\AppFramework\IApi; | |||
use OCP\AppFramework\IAppContainer; | |||
use OCP\AppFramework\Middleware; | |||
@@ -81,7 +82,11 @@ class DIContainer extends SimpleContainer implements IAppContainer{ | |||
}); | |||
$this['Dispatcher'] = $this->share(function($c) { | |||
return new Dispatcher($c['Protocol'], $c['MiddlewareDispatcher']); | |||
return new Dispatcher( | |||
$c['Protocol'], | |||
$c['MiddlewareDispatcher'], | |||
$c['ControllerMethodReflector'] | |||
); | |||
}); | |||
@@ -90,7 +95,11 @@ class DIContainer extends SimpleContainer implements IAppContainer{ | |||
*/ | |||
$app = $this; | |||
$this['SecurityMiddleware'] = $this->share(function($c) use ($app){ | |||
return new SecurityMiddleware($app, $c['Request']); | |||
return new SecurityMiddleware( | |||
$app, | |||
$c['Request'], | |||
$c['ControllerMethodReflector'] | |||
); | |||
}); | |||
$this['CORSMiddleware'] = $this->share(function($c) { | |||
@@ -118,6 +127,9 @@ class DIContainer extends SimpleContainer implements IAppContainer{ | |||
return new TimeFactory(); | |||
}); | |||
$this['ControllerMethodReflector'] = $this->share(function($c) { | |||
return new ControllerMethodReflector(); | |||
}); | |||
} | |||
@@ -26,7 +26,11 @@ namespace OC\AppFramework\Http; | |||
use \OC\AppFramework\Middleware\MiddlewareDispatcher; | |||
use \OC\AppFramework\Http; | |||
use \OC\AppFramework\Utility\ControllerMethodReflector; | |||
use OCP\AppFramework\Controller; | |||
use OCP\AppFramework\Http\Response; | |||
use OCP\IRequest; | |||
/** | |||
@@ -36,17 +40,25 @@ class Dispatcher { | |||
private $middlewareDispatcher; | |||
private $protocol; | |||
private $reflector; | |||
private $request; | |||
/** | |||
* @param Http $protocol the http protocol with contains all status headers | |||
* @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which | |||
* runs the middleware | |||
* @param ControllerMethodReflector the reflector that is used to inject | |||
* the arguments for the controller | |||
* @param IRequest $request the incoming request | |||
*/ | |||
public function __construct(Http $protocol, | |||
MiddlewareDispatcher $middlewareDispatcher) { | |||
MiddlewareDispatcher $middlewareDispatcher, | |||
ControllerMethodReflector $reflector, | |||
IRequest $request) { | |||
$this->protocol = $protocol; | |||
$this->middlewareDispatcher = $middlewareDispatcher; | |||
$this->reflector = $reflector; | |||
$this->request = $request; | |||
} | |||
@@ -63,10 +75,13 @@ class Dispatcher { | |||
$out = array(null, array(), null); | |||
try { | |||
// prefill reflector with everything thats needed for the | |||
// middlewares | |||
$this->reflector->reflect($controller, $methodName); | |||
$this->middlewareDispatcher->beforeController($controller, | |||
$methodName); | |||
$response = $controller->$methodName(); | |||
$response = $this->executeController($controller, $methodName); | |||
// if an exception appears, the middleware checks if it can handle the | |||
// exception and creates a response. If no response is created, it is | |||
@@ -98,4 +113,71 @@ class Dispatcher { | |||
} | |||
/** | |||
* Uses the reflected parameters, types and request parameters to execute | |||
* the controller | |||
* @return Response | |||
*/ | |||
private function executeController($controller, $methodName) { | |||
$arguments = array(); | |||
// valid types that will be casted | |||
$types = array('int', 'integer', 'bool', 'boolean', 'float'); | |||
foreach($this->reflector->getParameters() as $param) { | |||
// try to get the parameter from the request object and cast | |||
// it to the type annotated in the @param annotation | |||
$value = $this->request->getParam($param); | |||
$type = $this->reflector->getType($param); | |||
// if this is submitted using GET or a POST form, 'false' should be | |||
// converted to false | |||
if(($type === 'bool' || $type === 'boolean') && | |||
$value === 'false' && | |||
( | |||
$this->request->method === 'GET' || | |||
( | |||
$this->request->method === 'POST' && | |||
strpos($this->request->getHeader('Content-Type'), | |||
'application/x-www-form-urlencoded') !== false | |||
) | |||
) | |||
) { | |||
$value = false; | |||
} elseif(in_array($type, $types)) { | |||
settype($value, $type); | |||
} | |||
$arguments[] = $value; | |||
} | |||
$response = call_user_func_array(array($controller, $methodName), $arguments); | |||
// format response if not of type response | |||
if(!($response instanceof Response)) { | |||
// get format from the url format or request format parameter | |||
$format = $this->request->getParam('format'); | |||
// if none is given try the first Accept header | |||
if($format === null) { | |||
$header = $this->request->getHeader('Accept'); | |||
$formats = explode(',', $header); | |||
if($header !== null && count($formats) > 0) { | |||
$accept = strtolower(trim($formats[0])); | |||
$format = str_replace('application/', '', $accept); | |||
} else { | |||
$format = 'json'; | |||
} | |||
} | |||
$response = $controller->formatResponse($response, $format); | |||
} | |||
return $response; | |||
} | |||
} |
@@ -25,7 +25,7 @@ | |||
namespace OC\AppFramework\Middleware\Security; | |||
use OC\AppFramework\Http; | |||
use OC\AppFramework\Utility\MethodAnnotationReader; | |||
use OC\AppFramework\Utility\ControllerMethodReflector; | |||
use OCP\AppFramework\Http\RedirectResponse; | |||
use OCP\AppFramework\Middleware; | |||
use OCP\AppFramework\Http\Response; | |||
@@ -55,10 +55,13 @@ class SecurityMiddleware extends Middleware { | |||
/** | |||
* @param IAppContainer $app | |||
* @param IRequest $request | |||
* @param ControllerMethodReflector $reflector | |||
*/ | |||
public function __construct(IAppContainer $app, IRequest $request){ | |||
public function __construct(IAppContainer $app, IRequest $request, | |||
ControllerMethodReflector $reflector){ | |||
$this->app = $app; | |||
$this->request = $request; | |||
$this->reflector = $reflector; | |||
} | |||
@@ -72,28 +75,25 @@ class SecurityMiddleware extends Middleware { | |||
*/ | |||
public function beforeController($controller, $methodName){ | |||
// get annotations from comments | |||
$annotationReader = new MethodAnnotationReader($controller, $methodName); | |||
// this will set the current navigation entry of the app, use this only | |||
// for normal HTML requests and not for AJAX requests | |||
$this->app->getServer()->getNavigationManager()->setActiveEntry($this->app->getAppName()); | |||
// security checks | |||
$isPublicPage = $annotationReader->hasAnnotation('PublicPage'); | |||
$isPublicPage = $this->reflector->hasAnnotation('PublicPage'); | |||
if(!$isPublicPage) { | |||
if(!$this->app->isLoggedIn()) { | |||
throw new SecurityException('Current user is not logged in', Http::STATUS_UNAUTHORIZED); | |||
} | |||
if(!$annotationReader->hasAnnotation('NoAdminRequired')) { | |||
if(!$this->reflector->hasAnnotation('NoAdminRequired')) { | |||
if(!$this->app->isAdminUser()) { | |||
throw new SecurityException('Logged in user must be an admin', Http::STATUS_FORBIDDEN); | |||
} | |||
} | |||
} | |||
if(!$annotationReader->hasAnnotation('NoCSRFRequired')) { | |||
if(!$this->reflector->hasAnnotation('NoCSRFRequired')) { | |||
if(!$this->request->passesCSRFCheck()) { | |||
throw new SecurityException('CSRF check failed', Http::STATUS_PRECONDITION_FAILED); | |||
} |
@@ -28,23 +28,59 @@ namespace OC\AppFramework\Utility; | |||
/** | |||
* Reads and parses annotations from doc comments | |||
*/ | |||
class MethodAnnotationReader { | |||
class ControllerMethodReflector { | |||
private $annotations; | |||
private $types; | |||
private $parameters; | |||
public function __construct() { | |||
$this->types = array(); | |||
$this->parameters = array(); | |||
$this->annotations = array(); | |||
} | |||
/** | |||
* @param object $object an object or classname | |||
* @param string $method the method which we want to inspect for annotations | |||
* @param string $method the method which we want to inspect | |||
*/ | |||
public function __construct($object, $method){ | |||
$this->annotations = array(); | |||
public function reflect($object, $method){ | |||
$reflection = new \ReflectionMethod($object, $method); | |||
$docs = $reflection->getDocComment(); | |||
// extract everything prefixed by @ and first letter uppercase | |||
preg_match_all('/@([A-Z]\w+)/', $docs, $matches); | |||
$this->annotations = $matches[1]; | |||
// extract type parameter information | |||
preg_match_all('/@param (?<type>\w+) \$(?<var>\w+)/', $docs, $matches); | |||
$this->types = array_combine($matches['var'], $matches['type']); | |||
// get method parameters | |||
foreach ($reflection->getParameters() as $param) { | |||
$this->parameters[] = $param->name; | |||
} | |||
} | |||
/** | |||
* Inspects the PHPDoc parameters for types | |||
* @param strint $parameter the parameter whose type comments should be | |||
* parsed | |||
* @return string type in the type parameters (@param int $something) would | |||
* return int | |||
*/ | |||
public function getType($parameter) { | |||
return $this->types[$parameter]; | |||
} | |||
/** | |||
* @return array the arguments of the method | |||
*/ | |||
public function getParameters() { | |||
return $this->parameters; | |||
} | |||
@@ -28,6 +28,8 @@ | |||
namespace OCP\AppFramework; | |||
use OCP\AppFramework\Http\TemplateResponse; | |||
use OCP\AppFramework\Http\JSONResponse; | |||
use OCP\AppFramework\Http\IResponseSerializer; | |||
use OCP\IRequest; | |||
@@ -48,6 +50,8 @@ abstract class Controller { | |||
*/ | |||
protected $request; | |||
private $serializer; | |||
private $formatters; | |||
/** | |||
* constructor of the controller | |||
@@ -66,11 +70,66 @@ abstract class Controller { | |||
IRequest $request){ | |||
$this->appName = $appName; | |||
$this->request = $request; | |||
// default formatters | |||
$this->formatters = array( | |||
'json' => function ($response) { | |||
return new JSONResponse($response); | |||
} | |||
); | |||
} | |||
/** | |||
* Registers a serializer that is executed before a formatter is being | |||
* called, useful for turning any data into PHP arrays that can be used | |||
* by a JSONResponse for instance | |||
* @param IResponseSerializer $serializer | |||
*/ | |||
protected function registerSerializer(IResponseSerializer $serializer) { | |||
$this->serializer = $serializer; | |||
} | |||
/** | |||
* Registers a formatter for a type | |||
* @param string $format | |||
* @param \Closure $closure | |||
*/ | |||
protected function registerFormatter($format, \Closure $formatter) { | |||
$this->formatters[$format] = $formatter; | |||
} | |||
/** | |||
* Serializes and formats a response | |||
* @param mixed response the value that was returned from a controller and | |||
* is not a Response instance | |||
* @param string $format the format for which a formatter has been registered | |||
* @throws \DomainException if format does not match a registered formatter | |||
* @return Response | |||
*/ | |||
public function formatResponse($response, $format='json') { | |||
if(array_key_exists($format, $this->formatters)) { | |||
if ($this->serializer) { | |||
$response = $this->serializer->serialize($response); | |||
} | |||
$formatter = $this->formatters[$format]; | |||
return $formatter($response); | |||
} else { | |||
throw new \DomainException('No formatter registered for format ' . | |||
$format . '!'); | |||
} | |||
} | |||
/** | |||
* Lets you access post and get parameters by the index | |||
* @deprecated write your parameters as method arguments instead | |||
* @param string $key the key which you want to access in the URL Parameter | |||
* placeholder, $_POST or $_GET array. | |||
* The priority how they're returned is the following: | |||
@@ -88,6 +147,7 @@ abstract class Controller { | |||
/** | |||
* Returns all params that were received, be it from the request | |||
* (as GET or POST) or throuh the URL by the route | |||
* @deprecated use $this->request instead | |||
* @return array the array with all parameters | |||
*/ | |||
public function getParams() { | |||
@@ -97,6 +157,7 @@ abstract class Controller { | |||
/** | |||
* Returns the method of the request | |||
* @deprecated use $this->request instead | |||
* @return string the method of the request (POST, GET, etc) | |||
*/ | |||
public function method() { | |||
@@ -106,6 +167,7 @@ abstract class Controller { | |||
/** | |||
* Shortcut for accessing an uploaded file through the $_FILES array | |||
* @deprecated use $this->request instead | |||
* @param string $key the key that will be taken from the $_FILES array | |||
* @return array the file in the $_FILES element | |||
*/ | |||
@@ -116,6 +178,7 @@ abstract class Controller { | |||
/** | |||
* Shortcut for getting env variables | |||
* @deprecated use $this->request instead | |||
* @param string $key the key that will be taken from the $_ENV array | |||
* @return array the value in the $_ENV element | |||
*/ | |||
@@ -126,6 +189,7 @@ abstract class Controller { | |||
/** | |||
* Shortcut for getting cookie variables | |||
* @deprecated use $this->request instead | |||
* @param string $key the key that will be taken from the $_COOKIE array | |||
* @return array the value in the $_COOKIE element | |||
*/ | |||
@@ -136,6 +200,7 @@ abstract class Controller { | |||
/** | |||
* Shortcut for rendering a template | |||
* @deprecated return a template response instead | |||
* @param string $templateName the name of the template | |||
* @param array $params the template parameters in key => value structure | |||
* @param string $renderAs user renders a full page, blank only your template |
@@ -1,5 +1,4 @@ | |||
<?php | |||
/** | |||
* ownCloud - App Framework | |||
* | |||
@@ -21,35 +20,8 @@ | |||
* | |||
*/ | |||
namespace OCP\AppFramework\Http; | |||
namespace OC\AppFramework\Utility; | |||
class MethodAnnotationReaderTest extends \PHPUnit_Framework_TestCase { | |||
/** | |||
* @Annotation | |||
*/ | |||
public function testReadAnnotation(){ | |||
$reader = new MethodAnnotationReader('\OC\AppFramework\Utility\MethodAnnotationReaderTest', | |||
'testReadAnnotation'); | |||
$this->assertTrue($reader->hasAnnotation('Annotation')); | |||
} | |||
/** | |||
* @Annotation | |||
* @param test | |||
*/ | |||
public function testReadAnnotationNoLowercase(){ | |||
$reader = new MethodAnnotationReader('\OC\AppFramework\Utility\MethodAnnotationReaderTest', | |||
'testReadAnnotationNoLowercase'); | |||
$this->assertTrue($reader->hasAnnotation('Annotation')); | |||
$this->assertFalse($reader->hasAnnotation('param')); | |||
} | |||
} | |||
interface IResponseSerializer { | |||
function serialize($response); | |||
} |
@@ -61,12 +61,16 @@ class TemplateResponse extends Response { | |||
* constructor of TemplateResponse | |||
* @param string $appName the name of the app to load the template from | |||
* @param string $templateName the name of the template | |||
* @param array $params an array of parameters which should be passed to the | |||
* template | |||
* @param string $renderAs how the page should be rendered, defaults to user | |||
*/ | |||
public function __construct($appName, $templateName) { | |||
public function __construct($appName, $templateName, array $params=array(), | |||
$renderAs='user') { | |||
$this->templateName = $templateName; | |||
$this->appName = $appName; | |||
$this->params = array(); | |||
$this->renderAs = 'user'; | |||
$this->params = $params; | |||
$this->renderAs = $renderAs; | |||
} | |||
@@ -26,9 +26,31 @@ namespace OCP\AppFramework; | |||
use OC\AppFramework\Http\Request; | |||
use OCP\AppFramework\Http\TemplateResponse; | |||
use OCP\AppFramework\Http\JSONResponse; | |||
use OCP\AppFramework\Http\IResponseSerializer; | |||
class ChildController extends Controller {}; | |||
class ToUpperCaseSerializer implements IResponseSerializer { | |||
public function serialize($response) { | |||
return array(strtoupper($response)); | |||
} | |||
} | |||
class ChildController extends Controller { | |||
public function custom($in) { | |||
$this->registerFormatter('json', function ($response) { | |||
return new JSONResponse(array(strlen($response))); | |||
}); | |||
return $in; | |||
} | |||
public function serializer($in) { | |||
$this->registerSerializer(new ToUpperCaseSerializer()); | |||
return $in; | |||
} | |||
}; | |||
class ControllerTest extends \PHPUnit_Framework_TestCase { | |||
@@ -129,4 +151,35 @@ class ControllerTest extends \PHPUnit_Framework_TestCase { | |||
} | |||
/** | |||
* @expectedException \DomainException | |||
*/ | |||
public function testFormatResonseInvalidFormat() { | |||
$this->controller->formatResponse(null, 'test'); | |||
} | |||
public function testFormat() { | |||
$response = $this->controller->formatResponse(array('hi'), 'json'); | |||
$this->assertEquals(array('hi'), $response->getData()); | |||
} | |||
public function testCustomFormatter() { | |||
$response = $this->controller->custom('hi'); | |||
$response = $this->controller->formatResponse($response, 'json'); | |||
$this->assertEquals(array(2), $response->getData()); | |||
} | |||
public function testCustomSerializer() { | |||
$response = $this->controller->serializer('hi'); | |||
$response = $this->controller->formatResponse($response, 'json'); | |||
$this->assertEquals(array('HI'), $response->getData()); | |||
} | |||
} |
@@ -25,8 +25,28 @@ | |||
namespace OC\AppFramework\Http; | |||
use OC\AppFramework\Middleware\MiddlewareDispatcher; | |||
use OC\AppFramework\Utility\ControllerMethodReflector; | |||
use OCP\AppFramework\Http; | |||
//require_once(__DIR__ . "/../classloader.php"); | |||
use OCP\AppFramework\Http\JSONResponse; | |||
use OCP\AppFramework\Controller; | |||
class TestController extends Controller { | |||
public function __construct($appName, $request) { | |||
parent::__construct($appName, $request); | |||
} | |||
/** | |||
* @param int $int | |||
* @param bool $bool | |||
*/ | |||
public function exec($int, $bool) { | |||
$this->registerFormatter('text', function($in) { | |||
return new JSONResponse(array('text' => $in)); | |||
}); | |||
return array($int, $bool); | |||
} | |||
} | |||
class DispatcherTest extends \PHPUnit_Framework_TestCase { | |||
@@ -39,6 +59,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { | |||
private $lastModified; | |||
private $etag; | |||
private $http; | |||
private $reflector; | |||
protected function setUp() { | |||
$this->controllerMethod = 'test'; | |||
@@ -64,8 +85,17 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { | |||
'\OCP\AppFramework\Controller', | |||
array($this->controllerMethod), array($app, $request)); | |||
$this->request = $this->getMockBuilder( | |||
'\OC\AppFramework\Http\Request') | |||
->disableOriginalConstructor() | |||
->getMock(); | |||
$this->reflector = new ControllerMethodReflector(); | |||
$this->dispatcher = new Dispatcher( | |||
$this->http, $this->middlewareDispatcher); | |||
$this->http, $this->middlewareDispatcher, $this->reflector, | |||
$this->request | |||
); | |||
$this->response = $this->getMockBuilder( | |||
'\OCP\AppFramework\Http\Response') | |||
@@ -81,7 +111,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { | |||
* @param string $out | |||
* @param string $httpHeaders | |||
*/ | |||
private function setMiddlewareExpections($out=null, | |||
private function setMiddlewareExpectations($out=null, | |||
$httpHeaders=null, $responseHeaders=array(), | |||
$ex=false, $catchEx=true) { | |||
@@ -159,14 +189,12 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { | |||
->with($this->equalTo($this->controller), | |||
$this->equalTo($this->controllerMethod), | |||
$this->equalTo($out)) | |||
->will($this->returnValue($out)); | |||
->will($this->returnValue($out)); | |||
} | |||
public function testDispatcherReturnsArrayWith2Entries() { | |||
$this->setMiddlewareExpections(); | |||
$this->setMiddlewareExpectations(); | |||
$response = $this->dispatcher->dispatch($this->controller, | |||
$this->controllerMethod); | |||
@@ -180,7 +208,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { | |||
$out = 'yo'; | |||
$httpHeaders = 'Http'; | |||
$responseHeaders = array('hell' => 'yeah'); | |||
$this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders); | |||
$this->setMiddlewareExpectations($out, $httpHeaders, $responseHeaders); | |||
$response = $this->dispatcher->dispatch($this->controller, | |||
$this->controllerMethod); | |||
@@ -195,7 +223,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { | |||
$out = 'yo'; | |||
$httpHeaders = 'Http'; | |||
$responseHeaders = array('hell' => 'yeah'); | |||
$this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true); | |||
$this->setMiddlewareExpectations($out, $httpHeaders, $responseHeaders, true); | |||
$response = $this->dispatcher->dispatch($this->controller, | |||
$this->controllerMethod); | |||
@@ -210,7 +238,7 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { | |||
$out = 'yo'; | |||
$httpHeaders = 'Http'; | |||
$responseHeaders = array('hell' => 'yeah'); | |||
$this->setMiddlewareExpections($out, $httpHeaders, $responseHeaders, true, false); | |||
$this->setMiddlewareExpectations($out, $httpHeaders, $responseHeaders, true, false); | |||
$this->setExpectedException('\Exception'); | |||
$response = $this->dispatcher->dispatch($this->controller, | |||
@@ -218,4 +246,120 @@ class DispatcherTest extends \PHPUnit_Framework_TestCase { | |||
} | |||
private function dispatcherPassthrough() { | |||
$this->middlewareDispatcher->expects($this->once()) | |||
->method('beforeController'); | |||
$this->middlewareDispatcher->expects($this->once()) | |||
->method('afterController') | |||
->will($this->returnCallback(function($a, $b, $in) { | |||
return $in; | |||
})); | |||
$this->middlewareDispatcher->expects($this->once()) | |||
->method('beforeOutput') | |||
->will($this->returnCallback(function($a, $b, $in) { | |||
return $in; | |||
})); | |||
} | |||
public function testControllerParametersInjected() { | |||
$this->request = new Request(array( | |||
'post' => array( | |||
'int' => '3', | |||
'bool' => 'false' | |||
), | |||
'method' => 'POST' | |||
)); | |||
$this->dispatcher = new Dispatcher( | |||
$this->http, $this->middlewareDispatcher, $this->reflector, | |||
$this->request | |||
); | |||
$controller = new TestController('app', $this->request); | |||
// reflector is supposed to be called once | |||
$this->dispatcherPassthrough(); | |||
$response = $this->dispatcher->dispatch($controller, 'exec'); | |||
$this->assertEquals('[3,true]', $response[2]); | |||
} | |||
public function testResponseTransformedByUrlFormat() { | |||
$this->request = new Request(array( | |||
'post' => array( | |||
'int' => '3', | |||
'bool' => 'false' | |||
), | |||
'urlParams' => array( | |||
'format' => 'text' | |||
), | |||
'method' => 'GET' | |||
)); | |||
$this->dispatcher = new Dispatcher( | |||
$this->http, $this->middlewareDispatcher, $this->reflector, | |||
$this->request | |||
); | |||
$controller = new TestController('app', $this->request); | |||
// reflector is supposed to be called once | |||
$this->dispatcherPassthrough(); | |||
$response = $this->dispatcher->dispatch($controller, 'exec'); | |||
$this->assertEquals('{"text":[3,false]}', $response[2]); | |||
} | |||
public function testResponseTransformedByAcceptHeader() { | |||
$this->request = new Request(array( | |||
'post' => array( | |||
'int' => '3', | |||
'bool' => 'false' | |||
), | |||
'server' => array( | |||
'HTTP_ACCEPT' => 'application/text, test', | |||
'HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded' | |||
), | |||
'method' => 'POST' | |||
)); | |||
$this->dispatcher = new Dispatcher( | |||
$this->http, $this->middlewareDispatcher, $this->reflector, | |||
$this->request | |||
); | |||
$controller = new TestController('app', $this->request); | |||
// reflector is supposed to be called once | |||
$this->dispatcherPassthrough(); | |||
$response = $this->dispatcher->dispatch($controller, 'exec'); | |||
$this->assertEquals('{"text":[3,false]}', $response[2]); | |||
} | |||
public function testResponsePrimarilyTransformedByParameterFormat() { | |||
$this->request = new Request(array( | |||
'post' => array( | |||
'int' => '3', | |||
'bool' => 'false' | |||
), | |||
'get' => array( | |||
'format' => 'text' | |||
), | |||
'server' => array( | |||
'HTTP_ACCEPT' => 'application/json, test' | |||
), | |||
'method' => 'POST' | |||
)); | |||
$this->dispatcher = new Dispatcher( | |||
$this->http, $this->middlewareDispatcher, $this->reflector, | |||
$this->request | |||
); | |||
$controller = new TestController('app', $this->request); | |||
// reflector is supposed to be called once | |||
$this->dispatcherPassthrough(); | |||
$response = $this->dispatcher->dispatch($controller, 'exec'); | |||
$this->assertEquals('{"text":[3,true]}', $response[2]); | |||
} | |||
} |
@@ -51,6 +51,22 @@ class TemplateResponseTest extends \PHPUnit_Framework_TestCase { | |||
} | |||
public function testSetParamsConstructor(){ | |||
$params = array('hi' => 'yo'); | |||
$this->tpl = new TemplateResponse($this->api, 'home', $params); | |||
$this->assertEquals(array('hi' => 'yo'), $this->tpl->getParams()); | |||
} | |||
public function testSetRenderAsConstructor(){ | |||
$renderAs = 'myrender'; | |||
$this->tpl = new TemplateResponse($this->api, 'home', array(), $renderAs); | |||
$this->assertEquals($renderAs, $this->tpl->getRenderAs()); | |||
} | |||
public function testSetParams(){ | |||
$params = array('hi' => 'yo'); | |||
$this->tpl->setParams($params); | |||
@@ -63,36 +79,6 @@ class TemplateResponseTest extends \PHPUnit_Framework_TestCase { | |||
$this->assertEquals('home', $this->tpl->getTemplateName()); | |||
} | |||
// public function testRender(){ | |||
// $ocTpl = $this->getMock('Template', array('fetchPage')); | |||
// $ocTpl->expects($this->once()) | |||
// ->method('fetchPage'); | |||
// | |||
// $tpl = new TemplateResponse('core', 'error'); | |||
// | |||
// $tpl->render(); | |||
// } | |||
// | |||
// | |||
// public function testRenderAssignsParams(){ | |||
// $params = array('john' => 'doe'); | |||
// | |||
// $tpl = new TemplateResponse('app', 'home'); | |||
// $tpl->setParams($params); | |||
// | |||
// $tpl->render(); | |||
// } | |||
// | |||
// | |||
// public function testRenderDifferentApp(){ | |||
// | |||
// $tpl = new TemplateResponse('app', 'home', 'app2'); | |||
// | |||
// $tpl->render(); | |||
// } | |||
public function testGetRenderAs(){ | |||
$render = 'myrender'; | |||
$this->tpl->renderAs($render); |
@@ -26,6 +26,7 @@ namespace OC\AppFramework\Middleware\Security; | |||
use OC\AppFramework\Http; | |||
use OC\AppFramework\Http\Request; | |||
use OC\AppFramework\Utility\ControllerMethodReflector; | |||
use OCP\AppFramework\Http\RedirectResponse; | |||
use OCP\AppFramework\Http\JSONResponse; | |||
@@ -37,14 +38,16 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
private $secException; | |||
private $secAjaxException; | |||
private $request; | |||
private $reader; | |||
public function setUp() { | |||
$api = $this->getMock('OC\AppFramework\DependencyInjection\DIContainer', array(), array('test')); | |||
$this->controller = $this->getMock('OCP\AppFramework\Controller', | |||
array(), array($api, new Request())); | |||
$this->reader = new ControllerMethodReflector(); | |||
$this->request = new Request(); | |||
$this->middleware = new SecurityMiddleware($api, $this->request); | |||
$this->middleware = new SecurityMiddleware($api, $this->request, $this->reader); | |||
$this->secException = new SecurityException('hey', false); | |||
$this->secAjaxException = new SecurityException('hey', true); | |||
} | |||
@@ -68,7 +71,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
$api->expects($this->any())->method('getServer') | |||
->will($this->returnValue($serverMock)); | |||
$sec = new SecurityMiddleware($api, $this->request); | |||
$sec = new SecurityMiddleware($api, $this->request, $this->reader); | |||
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); | |||
} | |||
@@ -99,11 +103,12 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
->will($this->returnValue(true)); | |||
} | |||
$sec = new SecurityMiddleware($api, $this->request); | |||
$sec = new SecurityMiddleware($api, $this->request, $this->reader); | |||
try { | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', | |||
$method); | |||
$controller = '\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest'; | |||
$this->reader->reflect($controller, $method); | |||
$sec->beforeController($controller, $method); | |||
} catch (SecurityException $ex){ | |||
$this->assertEquals($status, $ex->getCode()); | |||
} | |||
@@ -184,7 +189,9 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
->method('isLoggedIn') | |||
->will($this->returnValue(true)); | |||
$sec = new SecurityMiddleware($api, $this->request); | |||
$sec = new SecurityMiddleware($api, $this->request, $this->reader); | |||
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', | |||
'testNoChecks'); | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', | |||
'testNoChecks'); | |||
} | |||
@@ -207,7 +214,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
->will($this->returnValue(true)); | |||
} | |||
$sec = new SecurityMiddleware($api, $this->request); | |||
$sec = new SecurityMiddleware($api, $this->request, $this->reader); | |||
if($shouldFail){ | |||
$this->setExpectedException('\OC\AppFramework\Middleware\Security\SecurityException'); | |||
@@ -215,6 +222,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
$this->setExpectedException(null); | |||
} | |||
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', $method); | |||
} | |||
@@ -230,7 +238,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
->method('passesCSRFCheck') | |||
->will($this->returnValue(false)); | |||
$sec = new SecurityMiddleware($api, $request); | |||
$sec = new SecurityMiddleware($api, $request, $this->reader); | |||
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testCsrfCheck'); | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testCsrfCheck'); | |||
} | |||
@@ -246,7 +255,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
->method('passesCSRFCheck') | |||
->will($this->returnValue(false)); | |||
$sec = new SecurityMiddleware($api, $request); | |||
$sec = new SecurityMiddleware($api, $request, $this->reader); | |||
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testNoCsrfCheck'); | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testNoCsrfCheck'); | |||
} | |||
@@ -261,7 +271,8 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
->method('passesCSRFCheck') | |||
->will($this->returnValue(true)); | |||
$sec = new SecurityMiddleware($api, $request); | |||
$sec = new SecurityMiddleware($api, $request, $this->reader); | |||
$this->reader->reflect('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testFailCsrfCheck'); | |||
$sec->beforeController('\OC\AppFramework\Middleware\Security\SecurityMiddlewareTest', 'testFailCsrfCheck'); | |||
} | |||
@@ -318,7 +329,7 @@ class SecurityMiddlewareTest extends \PHPUnit_Framework_TestCase { | |||
$this->request = new Request( | |||
array('server' => array('HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'))); | |||
$this->middleware = new SecurityMiddleware($api, $this->request); | |||
$this->middleware = new SecurityMiddleware($api, $this->request, $this->reader); | |||
$response = $this->middleware->afterException($this->controller, 'test', | |||
$this->secException); | |||
@@ -0,0 +1,115 @@ | |||
<?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\Utility; | |||
class ControllerMethodReflectorTest extends \PHPUnit_Framework_TestCase { | |||
/** | |||
* @Annotation | |||
*/ | |||
public function testReadAnnotation(){ | |||
$reader = new ControllerMethodReflector(); | |||
$reader->reflect( | |||
'\OC\AppFramework\Utility\ControllerMethodReflectorTest', | |||
'testReadAnnotation' | |||
); | |||
$this->assertTrue($reader->hasAnnotation('Annotation')); | |||
} | |||
/** | |||
* @Annotation | |||
* @param test | |||
*/ | |||
public function testReadAnnotationNoLowercase(){ | |||
$reader = new ControllerMethodReflector(); | |||
$reader->reflect( | |||
'\OC\AppFramework\Utility\ControllerMethodReflectorTest', | |||
'testReadAnnotationNoLowercase' | |||
); | |||
$this->assertTrue($reader->hasAnnotation('Annotation')); | |||
$this->assertFalse($reader->hasAnnotation('param')); | |||
} | |||
/** | |||
* @Annotation | |||
* @param int $test | |||
*/ | |||
public function testReadTypeIntAnnotations(){ | |||
$reader = new ControllerMethodReflector(); | |||
$reader->reflect( | |||
'\OC\AppFramework\Utility\ControllerMethodReflectorTest', | |||
'testReadTypeIntAnnotations' | |||
); | |||
$this->assertEquals('int', $reader->getType('test')); | |||
} | |||
/** | |||
* @Annotation | |||
* @param double $test | |||
*/ | |||
public function testReadTypeDoubleAnnotations(){ | |||
$reader = new ControllerMethodReflector(); | |||
$reader->reflect( | |||
'\OC\AppFramework\Utility\ControllerMethodReflectorTest', | |||
'testReadTypeDoubleAnnotations' | |||
); | |||
$this->assertEquals('double', $reader->getType('test')); | |||
} | |||
public function arguments($arg, $arg2) {} | |||
public function testReflectParameters() { | |||
$reader = new ControllerMethodReflector(); | |||
$reader->reflect( | |||
'\OC\AppFramework\Utility\ControllerMethodReflectorTest', | |||
'arguments' | |||
); | |||
$this->assertEquals(array('arg', 'arg2'), $reader->getParameters()); | |||
} | |||
public function arguments2($arg) {} | |||
public function testReflectParameters2() { | |||
$reader = new ControllerMethodReflector(); | |||
$reader->reflect( | |||
'\OC\AppFramework\Utility\ControllerMethodReflectorTest', | |||
'arguments2' | |||
); | |||
$this->assertEquals(array('arg',), $reader->getParameters()); | |||
} | |||
} |