From 83595ecbb2c8388de1c1e09138a8321198413a37 Mon Sep 17 00:00:00 2001 From: Sujith H Date: Wed, 4 Jul 2018 19:32:19 +0530 Subject: [PATCH] [stable10] Backport of Fix login exception in decryptall When the decryptall is called with user-keys enabled, make sure the password provided by user is correct else throw exception. Signed-off-by: Sujith H --- apps/encryption/lib/AppInfo/Application.php | 1 + apps/encryption/lib/Crypto/DecryptAll.php | 29 +++++++++ .../tests/Crypto/DecryptAllTest.php | 64 +++++++++++++++++++ 3 files changed, 94 insertions(+) diff --git a/apps/encryption/lib/AppInfo/Application.php b/apps/encryption/lib/AppInfo/Application.php index dd947123c6d2..e1c3ba2685e3 100644 --- a/apps/encryption/lib/AppInfo/Application.php +++ b/apps/encryption/lib/AppInfo/Application.php @@ -259,6 +259,7 @@ function (IAppContainer $c) { $c->query('KeyManager'), $c->query('Crypt'), $c->query('Session'), + $c->getServer()->getUserManager(), new QuestionHelper() ); } diff --git a/apps/encryption/lib/Crypto/DecryptAll.php b/apps/encryption/lib/Crypto/DecryptAll.php index 49b81f977d81..350ce6c58bba 100644 --- a/apps/encryption/lib/Crypto/DecryptAll.php +++ b/apps/encryption/lib/Crypto/DecryptAll.php @@ -23,9 +23,11 @@ namespace OCA\Encryption\Crypto; +use OC\User\LoginException; use OCA\Encryption\KeyManager; use OCA\Encryption\Session; use OCA\Encryption\Util; +use OCP\IUserManager; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; @@ -49,6 +51,9 @@ class DecryptAll { /** @var Session */ protected $session; + /** @var IUserManager */ + protected $userManager; + /** * @param Util $util * @param KeyManager $keyManager @@ -61,22 +66,28 @@ public function __construct( KeyManager $keyManager, Crypt $crypt, Session $session, + IUserManager $userManager, QuestionHelper $questionHelper ) { $this->util = $util; $this->keyManager = $keyManager; $this->crypt = $crypt; $this->session = $session; + $this->userManager = $userManager; $this->questionHelper = $questionHelper; } /** * prepare encryption module to decrypt all files * + * - Throws LoginException when user login fails either recovery password fails + * or if the user password fails + * * @param InputInterface $input * @param OutputInterface $output * @param $user * @return bool + * @throws LoginException */ public function prepare(InputInterface $input, OutputInterface $output, $user) { @@ -115,6 +126,24 @@ public function prepare(InputInterface $input, OutputInterface $output, $user) { $question->setHidden(true); $question->setHiddenFallback(false); $password = $this->questionHelper->ask($input, $output, $question); + + + $throwLoginException = false; + if ($recoveryKeyId === $user) { + try { + if ($this->keyManager->checkRecoveryPassword($password) === false) { + $throwLoginException = true; + } + } catch (\Exception $e) { + $throwLoginException = true; + } + } elseif ($this->userManager->checkPassword($user, $password) === false) { + $throwLoginException = true; + } + + if ($throwLoginException === true) { + throw new LoginException('Invalid credentials provided'); + } } $privateKey = $this->getPrivateKey($user, $password); diff --git a/apps/encryption/tests/Crypto/DecryptAllTest.php b/apps/encryption/tests/Crypto/DecryptAllTest.php index 288f19b05c7d..e8302f87031c 100644 --- a/apps/encryption/tests/Crypto/DecryptAllTest.php +++ b/apps/encryption/tests/Crypto/DecryptAllTest.php @@ -24,15 +24,27 @@ namespace OCA\Encryption\Tests\Crypto; +use OC\User\LoginException; use OCA\Encryption\Crypto\Crypt; use OCA\Encryption\Crypto\DecryptAll; use OCA\Encryption\KeyManager; use OCA\Encryption\Session; use OCA\Encryption\Util; +use OCP\IUserManager; use Symfony\Component\Console\Helper\QuestionHelper; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; use Test\TestCase; +use Test\Traits\UserTrait; +/** + * Class DecryptAllTest + * + * @group DB + * @package OCA\Encryption\Tests\Crypto + */ class DecryptAllTest extends TestCase { + use UserTrait; /** @var DecryptAll */ protected $instance; @@ -49,6 +61,8 @@ class DecryptAllTest extends TestCase { /** @var Session | \PHPUnit_Framework_MockObject_MockObject */ protected $session; + protected $userManager; + /** @var QuestionHelper | \PHPUnit_Framework_MockObject_MockObject */ protected $questionHelper; @@ -63,6 +77,7 @@ public function setUp() { ->disableOriginalConstructor()->getMock(); $this->session = $this->getMockBuilder('OCA\Encryption\Session') ->disableOriginalConstructor()->getMock(); + $this->userManager = $this->createMock(IUserManager::class); $this->questionHelper = $this->getMockBuilder('Symfony\Component\Console\Helper\QuestionHelper') ->disableOriginalConstructor()->getMock(); @@ -71,6 +86,7 @@ public function setUp() { $this->keyManager, $this->crypt, $this->session, + $this->userManager, $this->questionHelper ); } @@ -131,4 +147,52 @@ public function dataTestGetPrivateKey() { ]; } + public function providerPrepareLoginException() { + return [ + ['user1'], + ['recoverykey'], + ['throwExceptionInCheckRecovery'] + ]; + } + /** + * @dataProvider providerPrepareLoginException + * @expectedException \OC\User\LoginException + * @expectedExceptionMessage Invalid credentials provided + */ + public function testPrepareLoginException($loginType) { + $this->createUser('user1', 'pass'); + $input = $this->createMock(InputInterface::class); + $output = $this->createMock(OutputInterface::class); + + $this->util->expects($this->once()) + ->method('isMasterKeyEnabled') + ->willReturn(false); + + $this->keyManager->expects($this->any()) + ->method('getRecoveryKeyId') + ->willReturn('xyz'); + + $this->questionHelper->expects($this->any()) + ->method('ask') + ->willReturn('foo'); + + if ($loginType === 'user1') { + $this->userManager->expects($this->any()) + ->method('checkPassword') + ->willReturn(false); + $this->instance->prepare($input, $output, 'user1'); + } elseif ($loginType === 'recoverykey') { + $this->keyManager->expects($this->once()) + ->method('checkRecoveryPassword') + ->willReturn(false); + $this->instance->prepare($input, $output, 'xyz'); + } else { + $this->keyManager->expects($this->once()) + ->method('checkRecoveryPassword') + ->willThrowException(new \Exception()); + $this->instance->prepare($input, $output, 'xyz'); + } + + + } }