summaryrefslogtreecommitdiffstats
path: root/tests/lib/AppFramework/Middleware
diff options
context:
space:
mode:
Diffstat (limited to 'tests/lib/AppFramework/Middleware')
-rw-r--r--tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php292
-rw-r--r--tests/lib/AppFramework/Middleware/MiddlewareTest.php99
-rw-r--r--tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php236
-rw-r--r--tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php453
-rw-r--r--tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php95
5 files changed, 1175 insertions, 0 deletions
diff --git a/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php b/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php
new file mode 100644
index 00000000000..f81aca106d6
--- /dev/null
+++ b/tests/lib/AppFramework/Middleware/MiddlewareDispatcherTest.php
@@ -0,0 +1,292 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.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 Test\AppFramework\Middleware;
+
+use OC\AppFramework\Http\Request;
+use OC\AppFramework\Middleware\MiddlewareDispatcher;
+use OCP\AppFramework\Middleware;
+use OCP\AppFramework\Http\Response;
+
+
+// needed to test ordering
+class TestMiddleware extends Middleware {
+ public static $beforeControllerCalled = 0;
+ public static $afterControllerCalled = 0;
+ public static $afterExceptionCalled = 0;
+ public static $beforeOutputCalled = 0;
+
+ public $beforeControllerOrder = 0;
+ public $afterControllerOrder = 0;
+ public $afterExceptionOrder = 0;
+ public $beforeOutputOrder = 0;
+
+ public $controller;
+ public $methodName;
+ public $exception;
+ public $response;
+ public $output;
+
+ private $beforeControllerThrowsEx;
+
+ /**
+ * @param boolean $beforeControllerThrowsEx
+ */
+ public function __construct($beforeControllerThrowsEx) {
+ self::$beforeControllerCalled = 0;
+ self::$afterControllerCalled = 0;
+ self::$afterExceptionCalled = 0;
+ self::$beforeOutputCalled = 0;
+ $this->beforeControllerThrowsEx = $beforeControllerThrowsEx;
+ }
+
+ public function beforeController($controller, $methodName){
+ self::$beforeControllerCalled++;
+ $this->beforeControllerOrder = self::$beforeControllerCalled;
+ $this->controller = $controller;
+ $this->methodName = $methodName;
+ if($this->beforeControllerThrowsEx){
+ throw new \Exception();
+ }
+ }
+
+ public function afterException($controller, $methodName, \Exception $exception){
+ self::$afterExceptionCalled++;
+ $this->afterExceptionOrder = self::$afterExceptionCalled;
+ $this->controller = $controller;
+ $this->methodName = $methodName;
+ $this->exception = $exception;
+ parent::afterException($controller, $methodName, $exception);
+ }
+
+ public function afterController($controller, $methodName, Response $response){
+ self::$afterControllerCalled++;
+ $this->afterControllerOrder = self::$afterControllerCalled;
+ $this->controller = $controller;
+ $this->methodName = $methodName;
+ $this->response = $response;
+ return parent::afterController($controller, $methodName, $response);
+ }
+
+ public function beforeOutput($controller, $methodName, $output){
+ self::$beforeOutputCalled++;
+ $this->beforeOutputOrder = self::$beforeOutputCalled;
+ $this->controller = $controller;
+ $this->methodName = $methodName;
+ $this->output = $output;
+ return parent::beforeOutput($controller, $methodName, $output);
+ }
+}
+
+
+class MiddlewareDispatcherTest extends \Test\TestCase {
+
+ public $exception;
+ public $response;
+ private $out;
+ private $method;
+ private $controller;
+
+ /**
+ * @var MiddlewareDispatcher
+ */
+ private $dispatcher;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->dispatcher = new MiddlewareDispatcher();
+ $this->controller = $this->getControllerMock();
+ $this->method = 'method';
+ $this->response = new Response();
+ $this->out = 'hi';
+ $this->exception = new \Exception();
+ }
+
+
+ private function getControllerMock(){
+ return $this->getMock(
+ 'OCP\AppFramework\Controller',
+ ['method'],
+ ['app',
+ new Request(
+ ['method' => 'GET'],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ )
+ ]
+ );
+ }
+
+
+ private function getMiddleware($beforeControllerThrowsEx=false){
+ $m1 = new TestMiddleware($beforeControllerThrowsEx);
+ $this->dispatcher->registerMiddleware($m1);
+ return $m1;
+ }
+
+
+ public function testAfterExceptionShouldReturnResponseOfMiddleware(){
+ $response = new Response();
+ $m1 = $this->getMock('\OCP\AppFramework\Middleware',
+ array('afterException', 'beforeController'));
+ $m1->expects($this->never())
+ ->method('afterException');
+
+ $m2 = $this->getMock('OCP\AppFramework\Middleware',
+ array('afterException', 'beforeController'));
+ $m2->expects($this->once())
+ ->method('afterException')
+ ->will($this->returnValue($response));
+
+ $this->dispatcher->registerMiddleware($m1);
+ $this->dispatcher->registerMiddleware($m2);
+
+ $this->dispatcher->beforeController($this->controller, $this->method);
+ $this->assertEquals($response, $this->dispatcher->afterException($this->controller, $this->method, $this->exception));
+ }
+
+
+ public function testAfterExceptionShouldThrowAgainWhenNotHandled(){
+ $m1 = new TestMiddleware(false);
+ $m2 = new TestMiddleware(true);
+
+ $this->dispatcher->registerMiddleware($m1);
+ $this->dispatcher->registerMiddleware($m2);
+
+ $this->setExpectedException('\Exception');
+ $this->dispatcher->beforeController($this->controller, $this->method);
+ $this->dispatcher->afterException($this->controller, $this->method, $this->exception);
+ }
+
+
+ public function testBeforeControllerCorrectArguments(){
+ $m1 = $this->getMiddleware();
+ $this->dispatcher->beforeController($this->controller, $this->method);
+
+ $this->assertEquals($this->controller, $m1->controller);
+ $this->assertEquals($this->method, $m1->methodName);
+ }
+
+
+ public function testAfterControllerCorrectArguments(){
+ $m1 = $this->getMiddleware();
+
+ $this->dispatcher->afterController($this->controller, $this->method, $this->response);
+
+ $this->assertEquals($this->controller, $m1->controller);
+ $this->assertEquals($this->method, $m1->methodName);
+ $this->assertEquals($this->response, $m1->response);
+ }
+
+
+ public function testAfterExceptionCorrectArguments(){
+ $m1 = $this->getMiddleware();
+
+ $this->setExpectedException('\Exception');
+
+ $this->dispatcher->beforeController($this->controller, $this->method);
+ $this->dispatcher->afterException($this->controller, $this->method, $this->exception);
+
+ $this->assertEquals($this->controller, $m1->controller);
+ $this->assertEquals($this->method, $m1->methodName);
+ $this->assertEquals($this->exception, $m1->exception);
+ }
+
+
+ public function testBeforeOutputCorrectArguments(){
+ $m1 = $this->getMiddleware();
+
+ $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out);
+
+ $this->assertEquals($this->controller, $m1->controller);
+ $this->assertEquals($this->method, $m1->methodName);
+ $this->assertEquals($this->out, $m1->output);
+ }
+
+
+ public function testBeforeControllerOrder(){
+ $m1 = $this->getMiddleware();
+ $m2 = $this->getMiddleware();
+
+ $this->dispatcher->beforeController($this->controller, $this->method);
+
+ $this->assertEquals(1, $m1->beforeControllerOrder);
+ $this->assertEquals(2, $m2->beforeControllerOrder);
+ }
+
+ public function testAfterControllerOrder(){
+ $m1 = $this->getMiddleware();
+ $m2 = $this->getMiddleware();
+
+ $this->dispatcher->afterController($this->controller, $this->method, $this->response);
+
+ $this->assertEquals(2, $m1->afterControllerOrder);
+ $this->assertEquals(1, $m2->afterControllerOrder);
+ }
+
+
+ public function testAfterExceptionOrder(){
+ $m1 = $this->getMiddleware();
+ $m2 = $this->getMiddleware();
+
+ $this->setExpectedException('\Exception');
+ $this->dispatcher->beforeController($this->controller, $this->method);
+ $this->dispatcher->afterException($this->controller, $this->method, $this->exception);
+
+ $this->assertEquals(1, $m1->afterExceptionOrder);
+ $this->assertEquals(1, $m2->afterExceptionOrder);
+ }
+
+
+ public function testBeforeOutputOrder(){
+ $m1 = $this->getMiddleware();
+ $m2 = $this->getMiddleware();
+
+ $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out);
+
+ $this->assertEquals(2, $m1->beforeOutputOrder);
+ $this->assertEquals(1, $m2->beforeOutputOrder);
+ }
+
+
+ public function testExceptionShouldRunAfterExceptionOfOnlyPreviouslyExecutedMiddlewares(){
+ $m1 = $this->getMiddleware();
+ $m2 = $this->getMiddleware(true);
+ $m3 = $this->getMock('\OCP\AppFramework\Middleware');
+ $m3->expects($this->never())
+ ->method('afterException');
+ $m3->expects($this->never())
+ ->method('beforeController');
+ $m3->expects($this->never())
+ ->method('afterController');
+
+ $this->dispatcher->registerMiddleware($m3);
+
+ $this->dispatcher->beforeOutput($this->controller, $this->method, $this->out);
+
+ $this->assertEquals(2, $m1->beforeOutputOrder);
+ $this->assertEquals(1, $m2->beforeOutputOrder);
+ }
+}
diff --git a/tests/lib/AppFramework/Middleware/MiddlewareTest.php b/tests/lib/AppFramework/Middleware/MiddlewareTest.php
new file mode 100644
index 00000000000..013403a9a4a
--- /dev/null
+++ b/tests/lib/AppFramework/Middleware/MiddlewareTest.php
@@ -0,0 +1,99 @@
+<?php
+
+/**
+ * ownCloud - App Framework
+ *
+ * @author Bernhard Posselt
+ * @copyright 2012 Bernhard Posselt <dev@bernhard-posselt.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 Test\AppFramework\Middleware;
+
+use OC\AppFramework\Http\Request;
+use OCP\AppFramework\Middleware;
+use OCP\AppFramework\Http\Response;
+
+class ChildMiddleware extends Middleware {};
+
+
+class MiddlewareTest extends \Test\TestCase {
+
+ /**
+ * @var Middleware
+ */
+ private $middleware;
+ private $controller;
+ private $exception;
+ private $api;
+ /** @var Response */
+ private $response;
+
+ protected function setUp(){
+ parent::setUp();
+
+ $this->middleware = new ChildMiddleware();
+
+ $this->api = $this->getMockBuilder(
+ 'OC\AppFramework\DependencyInjection\DIContainer')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->controller = $this->getMock(
+ 'OCP\AppFramework\Controller',
+ [],
+ [
+ $this->api,
+ new Request(
+ [],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ )
+ ]
+ );
+ $this->exception = new \Exception();
+ $this->response = $this->getMock('OCP\AppFramework\Http\Response');
+ }
+
+
+ public function testBeforeController() {
+ $this->middleware->beforeController($this->controller, null);
+ $this->assertNull(null);
+ }
+
+
+ public function testAfterExceptionRaiseAgainWhenUnhandled() {
+ $this->setExpectedException('Exception');
+ $afterEx = $this->middleware->afterException($this->controller, null, $this->exception);
+ }
+
+
+ public function testAfterControllerReturnResponseWhenUnhandled() {
+ $response = $this->middleware->afterController($this->controller, null, $this->response);
+
+ $this->assertEquals($this->response, $response);
+ }
+
+
+ public function testBeforeOutputReturnOutputhenUnhandled() {
+ $output = $this->middleware->beforeOutput($this->controller, null, 'test');
+
+ $this->assertEquals('test', $output);
+ }
+
+
+}
diff --git a/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php
new file mode 100644
index 00000000000..8e53c9202cf
--- /dev/null
+++ b/tests/lib/AppFramework/Middleware/Security/CORSMiddlewareTest.php
@@ -0,0 +1,236 @@
+<?php
+/**
+ * ownCloud - App Framework
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @copyright Bernhard Posselt 2014
+ */
+
+
+namespace Test\AppFramework\Middleware\Security;
+
+use OC\AppFramework\Http\Request;
+use OC\AppFramework\Middleware\Security\CORSMiddleware;
+use OC\AppFramework\Utility\ControllerMethodReflector;
+use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\AppFramework\Http\Response;
+
+
+class CORSMiddlewareTest extends \Test\TestCase {
+
+ private $reflector;
+ private $session;
+
+ protected function setUp() {
+ parent::setUp();
+ $this->reflector = new ControllerMethodReflector();
+ $this->session = $this->getMock('\OCP\IUserSession');
+ }
+
+ /**
+ * @CORS
+ */
+ public function testSetCORSAPIHeader() {
+ $request = new Request(
+ [
+ 'server' => [
+ 'HTTP_ORIGIN' => 'test'
+ ]
+ ],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->reflector->reflect($this, __FUNCTION__);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session);
+
+ $response = $middleware->afterController($this, __FUNCTION__, new Response());
+ $headers = $response->getHeaders();
+ $this->assertEquals('test', $headers['Access-Control-Allow-Origin']);
+ }
+
+
+ public function testNoAnnotationNoCORSHEADER() {
+ $request = new Request(
+ [
+ 'server' => [
+ 'HTTP_ORIGIN' => 'test'
+ ]
+ ],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session);
+
+ $response = $middleware->afterController($this, __FUNCTION__, new Response());
+ $headers = $response->getHeaders();
+ $this->assertFalse(array_key_exists('Access-Control-Allow-Origin', $headers));
+ }
+
+
+ /**
+ * @CORS
+ */
+ public function testNoOriginHeaderNoCORSHEADER() {
+ $request = new Request(
+ [],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->reflector->reflect($this, __FUNCTION__);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session);
+
+ $response = $middleware->afterController($this, __FUNCTION__, new Response());
+ $headers = $response->getHeaders();
+ $this->assertFalse(array_key_exists('Access-Control-Allow-Origin', $headers));
+ }
+
+
+ /**
+ * @CORS
+ * @expectedException \OC\AppFramework\Middleware\Security\Exceptions\SecurityException
+ */
+ public function testCorsIgnoredIfWithCredentialsHeaderPresent() {
+ $request = new Request(
+ [
+ 'server' => [
+ 'HTTP_ORIGIN' => 'test'
+ ]
+ ],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->reflector->reflect($this, __FUNCTION__);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session);
+
+ $response = new Response();
+ $response->addHeader('AcCess-control-Allow-Credentials ', 'TRUE');
+ $middleware->afterController($this, __FUNCTION__, $response);
+ }
+
+ /**
+ * @CORS
+ * @PublicPage
+ */
+ public function testNoCORSShouldAllowCookieAuth() {
+ $request = new Request(
+ [],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->reflector->reflect($this, __FUNCTION__);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session);
+ $this->session->expects($this->never())
+ ->method('logout');
+ $this->session->expects($this->never())
+ ->method('login')
+ ->with($this->equalTo('user'), $this->equalTo('pass'))
+ ->will($this->returnValue(true));
+ $this->reflector->reflect($this, __FUNCTION__);
+
+ $middleware->beforeController($this, __FUNCTION__, new Response());
+ }
+
+ /**
+ * @CORS
+ */
+ public function testCORSShouldRelogin() {
+ $request = new Request(
+ ['server' => [
+ 'PHP_AUTH_USER' => 'user',
+ 'PHP_AUTH_PW' => 'pass'
+ ]],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->session->expects($this->once())
+ ->method('logout');
+ $this->session->expects($this->once())
+ ->method('login')
+ ->with($this->equalTo('user'), $this->equalTo('pass'))
+ ->will($this->returnValue(true));
+ $this->reflector->reflect($this, __FUNCTION__);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session);
+
+ $middleware->beforeController($this, __FUNCTION__, new Response());
+ }
+
+ /**
+ * @CORS
+ * @expectedException \OC\AppFramework\Middleware\Security\Exceptions\SecurityException
+ */
+ public function testCORSShouldNotAllowCookieAuth() {
+ $request = new Request(
+ ['server' => [
+ 'PHP_AUTH_USER' => 'user',
+ 'PHP_AUTH_PW' => 'pass'
+ ]],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->session->expects($this->once())
+ ->method('logout');
+ $this->session->expects($this->once())
+ ->method('login')
+ ->with($this->equalTo('user'), $this->equalTo('pass'))
+ ->will($this->returnValue(false));
+ $this->reflector->reflect($this, __FUNCTION__);
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session);
+
+ $middleware->beforeController($this, __FUNCTION__, new Response());
+ }
+
+ public function testAfterExceptionWithSecurityExceptionNoStatus() {
+ $request = new Request(
+ ['server' => [
+ 'PHP_AUTH_USER' => 'user',
+ 'PHP_AUTH_PW' => 'pass'
+ ]],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session);
+ $response = $middleware->afterException($this, __FUNCTION__, new SecurityException('A security exception'));
+
+ $expected = new JSONResponse(['message' => 'A security exception'], 500);
+ $this->assertEquals($expected, $response);
+ }
+
+ public function testAfterExceptionWithSecurityExceptionWithStatus() {
+ $request = new Request(
+ ['server' => [
+ 'PHP_AUTH_USER' => 'user',
+ 'PHP_AUTH_PW' => 'pass'
+ ]],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session);
+ $response = $middleware->afterException($this, __FUNCTION__, new SecurityException('A security exception', 501));
+
+ $expected = new JSONResponse(['message' => 'A security exception'], 501);
+ $this->assertEquals($expected, $response);
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage A regular exception
+ */
+ public function testAfterExceptionWithRegularException() {
+ $request = new Request(
+ ['server' => [
+ 'PHP_AUTH_USER' => 'user',
+ 'PHP_AUTH_PW' => 'pass'
+ ]],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $middleware = new CORSMiddleware($request, $this->reflector, $this->session);
+ $middleware->afterException($this, __FUNCTION__, new \Exception('A regular exception'));
+ }
+
+}
diff --git a/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php b/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php
new file mode 100644
index 00000000000..8cdba76d835
--- /dev/null
+++ b/tests/lib/AppFramework/Middleware/Security/SecurityMiddlewareTest.php
@@ -0,0 +1,453 @@
+<?php
+/**
+ * @author Bernhard Posselt <dev@bernhard-posselt.com>
+ * @author Lukas Reschke <lukas@owncloud.com>
+ *
+ * @copyright Copyright (c) 2015, ownCloud, Inc.
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+
+
+namespace Test\AppFramework\Middleware\Security;
+
+use OC\AppFramework\Http;
+use OC\AppFramework\Http\Request;
+use OC\AppFramework\Middleware\Security\Exceptions\AppNotEnabledException;
+use OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException;
+use OC\AppFramework\Middleware\Security\Exceptions\NotAdminException;
+use OC\AppFramework\Middleware\Security\Exceptions\NotLoggedInException;
+use OC\AppFramework\Middleware\Security\Exceptions\SecurityException;
+use OC\AppFramework\Middleware\Security\SecurityMiddleware;
+use OC\AppFramework\Utility\ControllerMethodReflector;
+use OC\Security\CSP\ContentSecurityPolicy;
+use OCP\AppFramework\Http\RedirectResponse;
+use OCP\AppFramework\Http\JSONResponse;
+use OCP\AppFramework\Http\TemplateResponse;
+
+
+class SecurityMiddlewareTest extends \Test\TestCase {
+
+ private $middleware;
+ private $controller;
+ private $secException;
+ private $secAjaxException;
+ private $request;
+ private $reader;
+ private $logger;
+ private $navigationManager;
+ private $urlGenerator;
+ private $contentSecurityPolicyManager;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->controller = $this->getMockBuilder('OCP\AppFramework\Controller')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->reader = new ControllerMethodReflector();
+ $this->logger = $this->getMockBuilder(
+ 'OCP\ILogger')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->navigationManager = $this->getMockBuilder(
+ 'OCP\INavigationManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->urlGenerator = $this->getMockBuilder(
+ 'OCP\IURLGenerator')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->request = $this->getMockBuilder(
+ 'OCP\IRequest')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->contentSecurityPolicyManager = $this->getMockBuilder(
+ 'OC\Security\CSP\ContentSecurityPolicyManager')
+ ->disableOriginalConstructor()
+ ->getMock();
+ $this->middleware = $this->getMiddleware(true, true);
+ $this->secException = new SecurityException('hey', false);
+ $this->secAjaxException = new SecurityException('hey', true);
+ }
+
+ /**
+ * @param bool $isLoggedIn
+ * @param bool $isAdminUser
+ * @return SecurityMiddleware
+ */
+ private function getMiddleware($isLoggedIn, $isAdminUser) {
+ return new SecurityMiddleware(
+ $this->request,
+ $this->reader,
+ $this->navigationManager,
+ $this->urlGenerator,
+ $this->logger,
+ 'files',
+ $isLoggedIn,
+ $isAdminUser,
+ $this->contentSecurityPolicyManager
+ );
+ }
+
+
+ /**
+ * @PublicPage
+ * @NoCSRFRequired
+ */
+ public function testSetNavigationEntry(){
+ $this->navigationManager->expects($this->once())
+ ->method('setActiveEntry')
+ ->with($this->equalTo('files'));
+
+ $this->reader->reflect(__CLASS__, __FUNCTION__);
+ $this->middleware->beforeController(__CLASS__, __FUNCTION__);
+ }
+
+
+ /**
+ * @param string $method
+ * @param string $test
+ */
+ private function ajaxExceptionStatus($method, $test, $status) {
+ $isLoggedIn = false;
+ $isAdminUser = false;
+
+ // isAdminUser requires isLoggedIn call to return true
+ if ($test === 'isAdminUser') {
+ $isLoggedIn = true;
+ }
+
+ $sec = $this->getMiddleware($isLoggedIn, $isAdminUser);
+
+ try {
+ $this->reader->reflect(__CLASS__, $method);
+ $sec->beforeController(__CLASS__, $method);
+ } catch (SecurityException $ex){
+ $this->assertEquals($status, $ex->getCode());
+ }
+
+ // add assertion if everything should work fine otherwise phpunit will
+ // complain
+ if ($status === 0) {
+ $this->assertTrue(true);
+ }
+ }
+
+ public function testAjaxStatusLoggedInCheck() {
+ $this->ajaxExceptionStatus(
+ __FUNCTION__,
+ 'isLoggedIn',
+ Http::STATUS_UNAUTHORIZED
+ );
+ }
+
+ /**
+ * @NoCSRFRequired
+ */
+ public function testAjaxNotAdminCheck() {
+ $this->ajaxExceptionStatus(
+ __FUNCTION__,
+ 'isAdminUser',
+ Http::STATUS_FORBIDDEN
+ );
+ }
+
+ /**
+ * @PublicPage
+ */
+ public function testAjaxStatusCSRFCheck() {
+ $this->ajaxExceptionStatus(
+ __FUNCTION__,
+ 'passesCSRFCheck',
+ Http::STATUS_PRECONDITION_FAILED
+ );
+ }
+
+ /**
+ * @PublicPage
+ * @NoCSRFRequired
+ */
+ public function testAjaxStatusAllGood() {
+ $this->ajaxExceptionStatus(
+ __FUNCTION__,
+ 'isLoggedIn',
+ 0
+ );
+ $this->ajaxExceptionStatus(
+ __FUNCTION__,
+ 'isAdminUser',
+ 0
+ );
+ $this->ajaxExceptionStatus(
+ __FUNCTION__,
+ 'isSubAdminUser',
+ 0
+ );
+ $this->ajaxExceptionStatus(
+ __FUNCTION__,
+ 'passesCSRFCheck',
+ 0
+ );
+ }
+
+
+ /**
+ * @PublicPage
+ * @NoCSRFRequired
+ */
+ public function testNoChecks(){
+ $this->request->expects($this->never())
+ ->method('passesCSRFCheck')
+ ->will($this->returnValue(false));
+
+ $sec = $this->getMiddleware(false, false);
+
+ $this->reader->reflect(__CLASS__, __FUNCTION__);
+ $sec->beforeController(__CLASS__, __FUNCTION__);
+ }
+
+
+ /**
+ * @param string $method
+ * @param string $expects
+ */
+ private function securityCheck($method, $expects, $shouldFail=false){
+ // admin check requires login
+ if ($expects === 'isAdminUser') {
+ $isLoggedIn = true;
+ $isAdminUser = !$shouldFail;
+ } else {
+ $isLoggedIn = !$shouldFail;
+ $isAdminUser = false;
+ }
+
+ $sec = $this->getMiddleware($isLoggedIn, $isAdminUser);
+
+ if($shouldFail) {
+ $this->setExpectedException('\OC\AppFramework\Middleware\Security\Exceptions\SecurityException');
+ } else {
+ $this->assertTrue(true);
+ }
+
+ $this->reader->reflect(__CLASS__, $method);
+ $sec->beforeController(__CLASS__, $method);
+ }
+
+
+ /**
+ * @PublicPage
+ * @expectedException \OC\AppFramework\Middleware\Security\Exceptions\CrossSiteRequestForgeryException
+ */
+ public function testCsrfCheck(){
+ $this->request->expects($this->once())
+ ->method('passesCSRFCheck')
+ ->will($this->returnValue(false));
+
+ $this->reader->reflect(__CLASS__, __FUNCTION__);
+ $this->middleware->beforeController(__CLASS__, __FUNCTION__);
+ }
+
+
+ /**
+ * @PublicPage
+ * @NoCSRFRequired
+ */
+ public function testNoCsrfCheck(){
+ $this->request->expects($this->never())
+ ->method('passesCSRFCheck')
+ ->will($this->returnValue(false));
+
+ $this->reader->reflect(__CLASS__, __FUNCTION__);
+ $this->middleware->beforeController(__CLASS__, __FUNCTION__);
+ }
+
+
+ /**
+ * @PublicPage
+ */
+ public function testFailCsrfCheck(){
+ $this->request->expects($this->once())
+ ->method('passesCSRFCheck')
+ ->will($this->returnValue(true));
+
+ $this->reader->reflect(__CLASS__, __FUNCTION__);
+ $this->middleware->beforeController(__CLASS__, __FUNCTION__);
+ }
+
+
+ /**
+ * @NoCSRFRequired
+ * @NoAdminRequired
+ */
+ public function testLoggedInCheck(){
+ $this->securityCheck(__FUNCTION__, 'isLoggedIn');
+ }
+
+
+ /**
+ * @NoCSRFRequired
+ * @NoAdminRequired
+ */
+ public function testFailLoggedInCheck(){
+ $this->securityCheck(__FUNCTION__, 'isLoggedIn', true);
+ }
+
+
+ /**
+ * @NoCSRFRequired
+ */
+ public function testIsAdminCheck(){
+ $this->securityCheck(__FUNCTION__, 'isAdminUser');
+ }
+
+
+ /**
+ * @NoCSRFRequired
+ */
+ public function testFailIsAdminCheck(){
+ $this->securityCheck(__FUNCTION__, 'isAdminUser', true);
+ }
+
+
+ public function testAfterExceptionNotCaughtThrowsItAgain(){
+ $ex = new \Exception();
+ $this->setExpectedException('\Exception');
+ $this->middleware->afterException($this->controller, 'test', $ex);
+ }
+
+ public function testAfterExceptionReturnsRedirectForNotLoggedInUser() {
+ $this->request = new Request(
+ [
+ 'server' =>
+ [
+ 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+ 'REQUEST_URI' => 'owncloud/index.php/apps/specialapp'
+ ]
+ ],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->middleware = $this->getMiddleware(false, false);
+ $this->urlGenerator
+ ->expects($this->once())
+ ->method('linkToRoute')
+ ->with(
+ 'core.login.showLoginForm',
+ [
+ 'redirect_url' => 'owncloud%2Findex.php%2Fapps%2Fspecialapp',
+ ]
+ )
+ ->will($this->returnValue('http://localhost/index.php/login?redirect_url=owncloud%2Findex.php%2Fapps%2Fspecialapp'));
+ $this->logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with('Current user is not logged in');
+ $response = $this->middleware->afterException(
+ $this->controller,
+ 'test',
+ new NotLoggedInException()
+ );
+
+ $expected = new RedirectResponse('http://localhost/index.php/login?redirect_url=owncloud%2Findex.php%2Fapps%2Fspecialapp');
+ $this->assertEquals($expected , $response);
+ }
+
+ /**
+ * @return array
+ */
+ public function exceptionProvider() {
+ return [
+ [
+ new AppNotEnabledException(),
+ ],
+ [
+ new CrossSiteRequestForgeryException(),
+ ],
+ [
+ new NotAdminException(),
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider exceptionProvider
+ * @param SecurityException $exception
+ */
+ public function testAfterExceptionReturnsTemplateResponse(SecurityException $exception) {
+ $this->request = new Request(
+ [
+ 'server' =>
+ [
+ 'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
+ 'REQUEST_URI' => 'owncloud/index.php/apps/specialapp'
+ ]
+ ],
+ $this->getMock('\OCP\Security\ISecureRandom'),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->middleware = $this->getMiddleware(false, false);
+ $this->logger
+ ->expects($this->once())
+ ->method('debug')
+ ->with($exception->getMessage());
+ $response = $this->middleware->afterException(
+ $this->controller,
+ 'test',
+ $exception
+ );
+
+ $expected = new TemplateResponse('core', '403', ['file' => $exception->getMessage()], 'guest');
+ $expected->setStatus($exception->getCode());
+ $this->assertEquals($expected , $response);
+ }
+
+
+ public function testAfterAjaxExceptionReturnsJSONError(){
+ $response = $this->middleware->afterException($this->controller, 'test',
+ $this->secAjaxException);
+
+ $this->assertTrue($response instanceof JSONResponse);
+ }
+
+ public function testAfterController() {
+ $response = $this->getMockBuilder('\OCP\AppFramework\Http\Response')->disableOriginalConstructor()->getMock();
+ $defaultPolicy = new ContentSecurityPolicy();
+ $defaultPolicy->addAllowedImageDomain('defaultpolicy');
+ $currentPolicy = new ContentSecurityPolicy();
+ $currentPolicy->addAllowedConnectDomain('currentPolicy');
+ $mergedPolicy = new ContentSecurityPolicy();
+ $mergedPolicy->addAllowedMediaDomain('mergedPolicy');
+ $response
+ ->expects($this->exactly(2))
+ ->method('getContentSecurityPolicy')
+ ->willReturn($currentPolicy);
+ $this->contentSecurityPolicyManager
+ ->expects($this->once())
+ ->method('getDefaultPolicy')
+ ->willReturn($defaultPolicy);
+ $this->contentSecurityPolicyManager
+ ->expects($this->once())
+ ->method('mergePolicies')
+ ->with($defaultPolicy, $currentPolicy)
+ ->willReturn($mergedPolicy);
+ $response->expects($this->once())
+ ->method('setContentSecurityPolicy')
+ ->with($mergedPolicy);
+
+ $this->middleware->afterController($this->controller, 'test', $response);
+ }
+}
diff --git a/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php b/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php
new file mode 100644
index 00000000000..17fcc1904c1
--- /dev/null
+++ b/tests/lib/AppFramework/Middleware/SessionMiddlewareTest.php
@@ -0,0 +1,95 @@
+<?php
+/**
+ * ownCloud - App Framework
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Thomas Müller <deepdiver@owncloud.com>
+ * @copyright Thomas Müller 2014
+ */
+
+
+namespace Test\AppFramework\Middleware;
+
+use OC\AppFramework\Http\Request;
+use OC\AppFramework\Middleware\SessionMiddleware;
+use OC\AppFramework\Utility\ControllerMethodReflector;
+use OCP\AppFramework\Http\Response;
+
+
+class SessionMiddlewareTest extends \Test\TestCase {
+
+ /**
+ * @var ControllerMethodReflector
+ */
+ private $reflector;
+
+ /**
+ * @var Request
+ */
+ private $request;
+
+ protected function setUp() {
+ parent::setUp();
+
+ $this->request = new Request(
+ [],
+ $this->getMockBuilder('\OCP\Security\ISecureRandom')->getMock(),
+ $this->getMock('\OCP\IConfig')
+ );
+ $this->reflector = new ControllerMethodReflector();
+ }
+
+ /**
+ * @UseSession
+ */
+ public function testSessionNotClosedOnBeforeController() {
+ $session = $this->getSessionMock(0);
+
+ $this->reflector->reflect($this, __FUNCTION__);
+ $middleware = new SessionMiddleware($this->request, $this->reflector, $session);
+ $middleware->beforeController($this, __FUNCTION__);
+ }
+
+ /**
+ * @UseSession
+ */
+ public function testSessionClosedOnAfterController() {
+ $session = $this->getSessionMock(1);
+
+ $this->reflector->reflect($this, __FUNCTION__);
+ $middleware = new SessionMiddleware($this->request, $this->reflector, $session);
+ $middleware->afterController($this, __FUNCTION__, new Response());
+ }
+
+ public function testSessionClosedOnBeforeController() {
+ $session = $this->getSessionMock(1);
+
+ $this->reflector->reflect($this, __FUNCTION__);
+ $middleware = new SessionMiddleware($this->request, $this->reflector, $session);
+ $middleware->beforeController($this, __FUNCTION__);
+ }
+
+ public function testSessionNotClosedOnAfterController() {
+ $session = $this->getSessionMock(0);
+
+ $this->reflector->reflect($this, __FUNCTION__);
+ $middleware = new SessionMiddleware($this->request, $this->reflector, $session);
+ $middleware->afterController($this, __FUNCTION__, new Response());
+ }
+
+ /**
+ * @return mixed
+ */
+ private function getSessionMock($expectedCloseCount) {
+ $session = $this->getMockBuilder('\OC\Session\Memory')
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $session->expects($this->exactly($expectedCloseCount))
+ ->method('close');
+ return $session;
+ }
+
+}