diff options
author | Christoph Wurst <christoph@owncloud.com> | 2016-05-11 11:23:25 +0200 |
---|---|---|
committer | Christoph Wurst <christoph@owncloud.com> | 2016-05-23 11:21:10 +0200 |
commit | dfb4d426c24c8cbb7e207a3dd92b5fcd894a1977 (patch) | |
tree | dc640b6bb84d032a6a45ca03ffe91e37d9c99ea9 /tests | |
parent | dec3f9ebcbdeacf5bc483df93900b157a1a5e546 (diff) | |
download | nextcloud-server-dfb4d426c24c8cbb7e207a3dd92b5fcd894a1977.tar.gz nextcloud-server-dfb4d426c24c8cbb7e207a3dd92b5fcd894a1977.zip |
Add two factor auth to core
Diffstat (limited to 'tests')
-rw-r--r-- | tests/Core/Controller/LoginControllerTest.php | 40 | ||||
-rw-r--r-- | tests/core/controller/TwoFactorChallengeControllerTest.php | 219 | ||||
-rw-r--r-- | tests/core/middleware/TwoFactorMiddlewareTest.php | 182 | ||||
-rw-r--r-- | tests/data/app/expected-info.json | 3 | ||||
-rw-r--r-- | tests/lib/authentication/twofactorauth/managertest.php | 187 |
5 files changed, 629 insertions, 2 deletions
diff --git a/tests/Core/Controller/LoginControllerTest.php b/tests/Core/Controller/LoginControllerTest.php index 32902a01530..e82c4cdc076 100644 --- a/tests/Core/Controller/LoginControllerTest.php +++ b/tests/Core/Controller/LoginControllerTest.php @@ -21,6 +21,7 @@ namespace Tests\Core\Controller; +use OC\Authentication\TwoFactorAuth\Manager; use OC\Core\Controller\LoginController; use OCP\AppFramework\Http\RedirectResponse; use OCP\AppFramework\Http\TemplateResponse; @@ -47,6 +48,8 @@ class LoginControllerTest extends TestCase { private $userSession; /** @var IURLGenerator */ private $urlGenerator; + /** @var Manager */ + private $twoFactorManager; public function setUp() { parent::setUp(); @@ -58,6 +61,9 @@ class LoginControllerTest extends TestCase { ->disableOriginalConstructor() ->getMock(); $this->urlGenerator = $this->getMock('\\OCP\\IURLGenerator'); + $this->twoFactorManager = $this->getMockBuilder('\OC\Authentication\TwoFactorAuth\Manager') + ->disableOriginalConstructor() + ->getMock(); $this->loginController = new LoginController( 'core', @@ -66,7 +72,8 @@ class LoginControllerTest extends TestCase { $this->config, $this->session, $this->userSession, - $this->urlGenerator + $this->urlGenerator, + $this->twoFactorManager ); } @@ -299,6 +306,10 @@ class LoginControllerTest extends TestCase { $this->userSession->expects($this->once()) ->method('createSessionToken') ->with($this->request, $user->getUID(), $password); + $this->twoFactorManager->expects($this->once()) + ->method('isTwoFactorAuthenticated') + ->with($user) + ->will($this->returnValue(false)); $this->urlGenerator->expects($this->once()) ->method('linkToRoute') ->with('files.view.index') @@ -336,5 +347,32 @@ class LoginControllerTest extends TestCase { $expected = new \OCP\AppFramework\Http\RedirectResponse(urldecode($redirectUrl)); $this->assertEquals($expected, $this->loginController->tryLogin($user->getUID(), $password, $originalUrl)); } + + public function testLoginWithTwoFactorEnforced() { + $user = $this->getMock('\OCP\IUser'); + $password = 'secret'; + $challengeUrl = 'challenge/url'; + + $this->userManager->expects($this->once()) + ->method('checkPassword') + ->will($this->returnValue($user)); + $this->userSession->expects($this->once()) + ->method('createSessionToken') + ->with($this->request, $user->getUID(), $password); + $this->twoFactorManager->expects($this->once()) + ->method('isTwoFactorAuthenticated') + ->with($user) + ->will($this->returnValue(true)); + $this->twoFactorManager->expects($this->once()) + ->method('prepareTwoFactorLogin') + ->with($user); + $this->urlGenerator->expects($this->once()) + ->method('linkToRoute') + ->with('core.TwoFactorChallenge.selectChallenge') + ->will($this->returnValue($challengeUrl)); + + $expected = new \OCP\AppFramework\Http\RedirectResponse($challengeUrl); + $this->assertEquals($expected, $this->loginController->tryLogin($user, $password, null)); + } } diff --git a/tests/core/controller/TwoFactorChallengeControllerTest.php b/tests/core/controller/TwoFactorChallengeControllerTest.php new file mode 100644 index 00000000000..c65625ec329 --- /dev/null +++ b/tests/core/controller/TwoFactorChallengeControllerTest.php @@ -0,0 +1,219 @@ +<?php + +/** + * @author Christoph Wurst <christoph@owncloud.com> + * + * @copyright Copyright (c) 2016, 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 OC\Core\Controller; + +use Test\TestCase; + +class TwoFactorChallengeControllerTest extends TestCase { + + private $request; + private $twoFactorManager; + private $userSession; + private $session; + private $urlGenerator; + + /** TwoFactorChallengeController */ + private $controller; + + protected function setUp() { + parent::setUp(); + + $this->request = $this->getMock('\OCP\IRequest'); + $this->twoFactorManager = $this->getMockBuilder('\OC\Authentication\TwoFactorAuth\Manager') + ->disableOriginalConstructor() + ->getMock(); + $this->userSession = $this->getMock('\OCP\IUserSession'); + $this->session = $this->getMock('\OCP\ISession'); + $this->urlGenerator = $this->getMock('\OCP\IURLGenerator'); + + $this->controller = new TwoFactorChallengeController( + 'core', $this->request, $this->twoFactorManager, $this->userSession, $this->session, $this->urlGenerator + ); + } + + public function testSelectChallenge() { + $user = $this->getMock('\OCP\IUser'); + $providers = [ + 'prov1', + 'prov2', + ]; + + $this->userSession->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($user)); + $this->twoFactorManager->expects($this->once()) + ->method('getProviders') + ->with($user) + ->will($this->returnValue($providers)); + + $expected = new \OCP\AppFramework\Http\TemplateResponse('core', 'twofactorselectchallenge', [ + 'providers' => $providers, + ], 'guest'); + + $this->assertEquals($expected, $this->controller->selectChallenge()); + } + + public function testShowChallenge() { + $user = $this->getMock('\OCP\IUser'); + $provider = $this->getMockBuilder('\OCP\Authentication\TwoFactorAuth\IProvider') + ->disableOriginalConstructor() + ->getMock(); + $tmpl = $this->getMockBuilder('\OCP\Template') + ->disableOriginalConstructor() + ->getMock(); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($user)); + $this->twoFactorManager->expects($this->once()) + ->method('getProvider') + ->with($user, 'myprovider') + ->will($this->returnValue($provider)); + + $this->session->expects($this->once()) + ->method('exists') + ->with('two_factor_auth_error') + ->will($this->returnValue(true)); + $this->session->expects($this->once()) + ->method('remove') + ->with('two_factor_auth_error'); + $provider->expects($this->once()) + ->method('getTemplate') + ->with($user) + ->will($this->returnValue($tmpl)); + $tmpl->expects($this->once()) + ->method('fetchPage') + ->will($this->returnValue('<html/>')); + + $expected = new \OCP\AppFramework\Http\TemplateResponse('core', 'twofactorshowchallenge', [ + 'error' => true, + 'provider' => $provider, + 'template' => '<html/>', + ], 'guest'); + + $this->assertEquals($expected, $this->controller->showChallenge('myprovider')); + } + + public function testShowInvalidChallenge() { + $user = $this->getMock('\OCP\IUser'); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($user)); + $this->twoFactorManager->expects($this->once()) + ->method('getProvider') + ->with($user, 'myprovider') + ->will($this->returnValue(null)); + $this->urlGenerator->expects($this->once()) + ->method('linkToRoute') + ->with('core.TwoFactorChallenge.selectChallenge') + ->will($this->returnValue('select/challenge/url')); + + $expected = new \OCP\AppFramework\Http\RedirectResponse('select/challenge/url'); + + $this->assertEquals($expected, $this->controller->showChallenge('myprovider')); + } + + public function testSolveChallenge() { + $user = $this->getMock('\OCP\IUser'); + $provider = $this->getMockBuilder('\OCP\Authentication\TwoFactorAuth\IProvider') + ->disableOriginalConstructor() + ->getMock(); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($user)); + $this->twoFactorManager->expects($this->once()) + ->method('getProvider') + ->with($user, 'myprovider') + ->will($this->returnValue($provider)); + + $this->twoFactorManager->expects($this->once()) + ->method('verifyChallenge') + ->with('myprovider', $user, 'token') + ->will($this->returnValue(true)); + $this->urlGenerator->expects($this->once()) + ->method('linkToRoute') + ->with('files.view.index') + ->will($this->returnValue('files/index/url')); + + $expected = new \OCP\AppFramework\Http\RedirectResponse('files/index/url'); + $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token')); + } + + public function testSolveChallengeInvalidProvider() { + $user = $this->getMock('\OCP\IUser'); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($user)); + $this->twoFactorManager->expects($this->once()) + ->method('getProvider') + ->with($user, 'myprovider') + ->will($this->returnValue(null)); + $this->urlGenerator->expects($this->once()) + ->method('linkToRoute') + ->with('core.TwoFactorChallenge.selectChallenge') + ->will($this->returnValue('select/challenge/url')); + + $expected = new \OCP\AppFramework\Http\RedirectResponse('select/challenge/url'); + + $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token')); + } + + public function testSolveInvalidChallenge() { + $user = $this->getMock('\OCP\IUser'); + $provider = $this->getMockBuilder('\OCP\Authentication\TwoFactorAuth\IProvider') + ->disableOriginalConstructor() + ->getMock(); + + $this->userSession->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($user)); + $this->twoFactorManager->expects($this->once()) + ->method('getProvider') + ->with($user, 'myprovider') + ->will($this->returnValue($provider)); + + $this->twoFactorManager->expects($this->once()) + ->method('verifyChallenge') + ->with('myprovider', $user, 'token') + ->will($this->returnValue(false)); + $this->session->expects($this->once()) + ->method('set') + ->with('two_factor_auth_error', true); + $this->urlGenerator->expects($this->once()) + ->method('linkToRoute') + ->with('core.TwoFactorChallenge.showChallenge', [ + 'challengeProviderId' => 'myprovider', + ]) + ->will($this->returnValue('files/index/url')); + $provider->expects($this->once()) + ->method('getId') + ->will($this->returnValue('myprovider')); + + $expected = new \OCP\AppFramework\Http\RedirectResponse('files/index/url'); + $this->assertEquals($expected, $this->controller->solveChallenge('myprovider', 'token')); + } + +} diff --git a/tests/core/middleware/TwoFactorMiddlewareTest.php b/tests/core/middleware/TwoFactorMiddlewareTest.php new file mode 100644 index 00000000000..12136db7fdf --- /dev/null +++ b/tests/core/middleware/TwoFactorMiddlewareTest.php @@ -0,0 +1,182 @@ +<?php + +/** + * @author Christoph Wurst <christoph@owncloud.com> + * + * @copyright Copyright (c) 2016, 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 OC\Core\Middleware; + +use Test\TestCase; + +class TwoFactorMiddlewareTest extends TestCase { + + private $twoFactorManager; + private $userSession; + private $session; + private $urlGenerator; + private $reflector; + + /** @var TwoFactorMiddleware */ + private $middleware; + + protected function setUp() { + parent::setUp(); + + $this->twoFactorManager = $this->getMockBuilder('\OC\Authentication\TwoFactorAuth\Manager') + ->disableOriginalConstructor() + ->getMock(); + $this->userSession = $this->getMockBuilder('\OC\User\Session') + ->disableOriginalConstructor() + ->getMock(); + $this->session = $this->getMock('\OCP\ISession'); + $this->urlGenerator = $this->getMock('\OCP\IURLGenerator'); + $this->reflector = $this->getMock('\OCP\AppFramework\Utility\IControllerMethodReflector'); + + $this->middleware = new TwoFactorMiddleware($this->twoFactorManager, $this->userSession, $this->session, $this->urlGenerator, $this->reflector); + } + + public function testBeforeControllerNotLoggedIn() { + $this->reflector->expects($this->once()) + ->method('hasAnnotation') + ->with('PublicPage') + ->will($this->returnValue(false)); + $this->userSession->expects($this->once()) + ->method('isLoggedIn') + ->will($this->returnValue(false)); + + $this->userSession->expects($this->never()) + ->method('getUser'); + + $this->middleware->beforeController(null, 'index'); + } + + public function testBeforeControllerPublicPage() { + $this->reflector->expects($this->once()) + ->method('hasAnnotation') + ->with('PublicPage') + ->will($this->returnValue(true)); + $this->userSession->expects($this->never()) + ->method('isLoggedIn'); + + $this->middleware->beforeController(null, 'create'); + } + + public function testBeforeControllerNoTwoFactorCheckNeeded() { + $user = $this->getMock('\OCP\IUser'); + + $this->reflector->expects($this->once()) + ->method('hasAnnotation') + ->with('PublicPage') + ->will($this->returnValue(false)); + $this->userSession->expects($this->once()) + ->method('isLoggedIn') + ->will($this->returnValue(true)); + $this->userSession->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($user)); + $this->twoFactorManager->expects($this->once()) + ->method('isTwoFactorAuthenticated') + ->with($user) + ->will($this->returnValue(false)); + + $this->middleware->beforeController(null, 'index'); + } + + /** + * @expectedException \OC\Authentication\Exceptions\TwoFactorAuthRequiredException + */ + public function testBeforeControllerTwoFactorAuthRequired() { + $user = $this->getMock('\OCP\IUser'); + + $this->reflector->expects($this->once()) + ->method('hasAnnotation') + ->with('PublicPage') + ->will($this->returnValue(false)); + $this->userSession->expects($this->once()) + ->method('isLoggedIn') + ->will($this->returnValue(true)); + $this->userSession->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($user)); + $this->twoFactorManager->expects($this->once()) + ->method('isTwoFactorAuthenticated') + ->with($user) + ->will($this->returnValue(true)); + $this->twoFactorManager->expects($this->once()) + ->method('needsSecondFactor') + ->will($this->returnValue(true)); + + $this->middleware->beforeController(null, 'index'); + } + + /** + * @expectedException \OC\Authentication\Exceptions\UserAlreadyLoggedInException + */ + public function testBeforeControllerUserAlreadyLoggedIn() { + $user = $this->getMock('\OCP\IUser'); + + $this->reflector->expects($this->once()) + ->method('hasAnnotation') + ->with('PublicPage') + ->will($this->returnValue(false)); + $this->userSession->expects($this->once()) + ->method('isLoggedIn') + ->will($this->returnValue(true)); + $this->userSession->expects($this->once()) + ->method('getUser') + ->will($this->returnValue($user)); + $this->twoFactorManager->expects($this->once()) + ->method('isTwoFactorAuthenticated') + ->with($user) + ->will($this->returnValue(true)); + $this->twoFactorManager->expects($this->once()) + ->method('needsSecondFactor') + ->will($this->returnValue(false)); + + $twoFactorChallengeController = $this->getMockBuilder('\OC\Core\Controller\TwoFactorChallengeController') + ->disableOriginalConstructor() + ->getMock(); + $this->middleware->beforeController($twoFactorChallengeController, 'index'); + } + + public function testAfterExceptionTwoFactorAuthRequired() { + $ex = new \OC\Authentication\Exceptions\TwoFactorAuthRequiredException(); + + $this->urlGenerator->expects($this->once()) + ->method('linkToRoute') + ->with('core.TwoFactorChallenge.selectChallenge') + ->will($this->returnValue('redirect/url')); + $expected = new \OCP\AppFramework\Http\RedirectResponse('redirect/url'); + + $this->assertEquals($expected, $this->middleware->afterException(null, 'index', $ex)); + } + + public function testAfterException() { + $ex = new \OC\Authentication\Exceptions\UserAlreadyLoggedInException(); + + $this->urlGenerator->expects($this->once()) + ->method('linkToRoute') + ->with('files.view.index') + ->will($this->returnValue('redirect/url')); + $expected = new \OCP\AppFramework\Http\RedirectResponse('redirect/url'); + + $this->assertEquals($expected, $this->middleware->afterException(null, 'index', $ex)); + } + +} diff --git a/tests/data/app/expected-info.json b/tests/data/app/expected-info.json index 81de5341efa..6d8d85ab552 100644 --- a/tests/data/app/expected-info.json +++ b/tests/data/app/expected-info.json @@ -75,5 +75,6 @@ "live-migration": [], "uninstall": [] }, - "background-jobs": [] + "background-jobs": [], + "two-factor-providers": [] } diff --git a/tests/lib/authentication/twofactorauth/managertest.php b/tests/lib/authentication/twofactorauth/managertest.php new file mode 100644 index 00000000000..14e517b363e --- /dev/null +++ b/tests/lib/authentication/twofactorauth/managertest.php @@ -0,0 +1,187 @@ +<?php + +/** + * @author Christoph Wurst <christoph@owncloud.com> + * + * @copyright Copyright (c) 2016, 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\Authentication\TwoFactorAuth; + +use Test\TestCase; +use OC\Authentication\TwoFactorAuth\Manager; + +class ManagerTest extends TestCase { + + /** @var OCP\IUser */ + private $user; + + /** @var OC\App\AppManager */ + private $appManager; + + /** @var OCP\ISession */ + private $session; + + /** @var Manager */ + private $manager; + + /** @var \OCP\IConfig */ + private $config; + + /** @var \OCP\Authentication\TwoFactorAuth\IProvider */ + private $fakeProvider; + + protected function setUp() { + parent::setUp(); + + $this->user = $this->getMock('\OCP\IUser'); + $this->appManager = $this->getMockBuilder('\OC\App\AppManager') + ->disableOriginalConstructor() + ->getMock(); + $this->session = $this->getMock('\OCP\ISession'); + $this->config = $this->getMock('\OCP\IConfig'); + + $this->manager = new Manager($this->appManager, $this->session, $this->config); + + $this->fakeProvider = $this->getMock('\OCP\Authentication\TwoFactorAuth\IProvider'); + $this->fakeProvider->expects($this->any()) + ->method('getId') + ->will($this->returnValue('email')); + $this->fakeProvider->expects($this->any()) + ->method('isTwoFactorAuthEnabledForUser') + ->will($this->returnValue(true)); + \OC::$server->registerService('\OCA\MyCustom2faApp\FakeProvider', function() { + return $this->fakeProvider; + }); + } + + private function prepareProviders() { + $this->appManager->expects($this->any()) + ->method('getEnabledAppsForUser') + ->with($this->user) + ->will($this->returnValue(['mycustom2faapp'])); + + $this->appManager->expects($this->once()) + ->method('getAppInfo') + ->with('mycustom2faapp') + ->will($this->returnValue([ + 'two-factor-providers' => [ + '\OCA\MyCustom2faApp\FakeProvider', + ], + ])); + } + + public function testIsTwoFactorAuthenticated() { + $this->prepareProviders(); + + $user = $this->getMock('\OCP\IUser'); + $user->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('user123')); + $this->config->expects($this->once()) + ->method('getUserValue') + ->with('user123', 'core', 'two_factor_auth_disabled', 0) + ->will($this->returnValue(0)); + + $this->assertTrue($this->manager->isTwoFactorAuthenticated($user)); + } + + public function testGetProvider() { + $this->prepareProviders(); + + $this->assertSame($this->fakeProvider, $this->manager->getProvider($this->user, 'email')); + } + + public function testGetInvalidProvider() { + $this->prepareProviders(); + + $this->assertSame(null, $this->manager->getProvider($this->user, 'nonexistent')); + } + + public function testGetProviders() { + $this->prepareProviders(); + $expectedProviders = [ + 'email' => $this->fakeProvider, + ]; + + $this->assertEquals($expectedProviders, $this->manager->getProviders($this->user)); + } + + public function testVerifyChallenge() { + $this->prepareProviders(); + + $challenge = 'passme'; + $this->fakeProvider->expects($this->once()) + ->method('verifyChallenge') + ->with($this->user, $challenge) + ->will($this->returnValue(true)); + $this->session->expects($this->once()) + ->method('remove') + ->with('two_factor_auth_uid'); + + $this->assertEquals(true, $this->manager->verifyChallenge('email', $this->user, $challenge)); + } + + public function testVerifyChallengeInvalidProviderId() { + $this->prepareProviders(); + + $challenge = 'passme'; + $this->fakeProvider->expects($this->never()) + ->method('verifyChallenge') + ->with($this->user, $challenge); + $this->session->expects($this->never()) + ->method('remove'); + + $this->assertEquals(false, $this->manager->verifyChallenge('dontexist', $this->user, $challenge)); + } + + public function testVerifyInvalidChallenge() { + $this->prepareProviders(); + + $challenge = 'dontpassme'; + $this->fakeProvider->expects($this->once()) + ->method('verifyChallenge') + ->with($this->user, $challenge) + ->will($this->returnValue(false)); + $this->session->expects($this->never()) + ->method('remove'); + + $this->assertEquals(false, $this->manager->verifyChallenge('email', $this->user, $challenge)); + } + + public function testNeedsSecondFactor() { + $this->session->expects($this->once()) + ->method('exists') + ->with('two_factor_auth_uid') + ->will($this->returnValue(false)); + + $this->assertequals(false, $this->manager->needsSecondFactor()); + } + + public function testPrepareTwoFactorLogin() { + $this->user->expects($this->once()) + ->method('getUID') + ->will($this->returnValue('ferdinand')); + + $this->session->expects($this->once()) + ->method('set') + ->with('two_factor_auth_uid', 'ferdinand'); + + $this->manager->prepareTwoFactorLogin($this->user); + } + +} |