From 94ad54ec9b96d41a614fbbad4a97b34c41a6901f Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Fri, 20 May 2016 15:38:20 +0200 Subject: Move tests/ to PSR-4 (#24731) * Move a-b to PSR-4 * Move c-d to PSR-4 * Move e+g to PSR-4 * Move h-l to PSR-4 * Move m-r to PSR-4 * Move s-u to PSR-4 * Move files/ to PSR-4 * Move remaining tests to PSR-4 * Remove Test\ from old autoloader --- .../CSP/ContentSecurityPolicyManagerTest.php | 69 +++++++++++ tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php | 56 +++++++++ tests/lib/Security/CSRF/CsrfTokenManagerTest.php | 136 +++++++++++++++++++++ tests/lib/Security/CSRF/CsrfTokenTest.php | 35 ++++++ .../CSRF/TokenStorage/SessionStorageTest.php | 109 +++++++++++++++++ tests/lib/Security/CertificateManagerTest.php | 121 ++++++++++++++++++ tests/lib/Security/CertificateTest.php | 111 +++++++++++++++++ tests/lib/Security/CredentialsManagerTest.php | 104 ++++++++++++++++ tests/lib/Security/CryptoTest.php | 73 +++++++++++ tests/lib/Security/HasherTest.php | 118 ++++++++++++++++++ tests/lib/Security/SecureRandomTest.php | 78 ++++++++++++ tests/lib/Security/TrustedDomainHelperTest.php | 82 +++++++++++++ 12 files changed, 1092 insertions(+) create mode 100644 tests/lib/Security/CSP/ContentSecurityPolicyManagerTest.php create mode 100644 tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php create mode 100644 tests/lib/Security/CSRF/CsrfTokenManagerTest.php create mode 100644 tests/lib/Security/CSRF/CsrfTokenTest.php create mode 100644 tests/lib/Security/CSRF/TokenStorage/SessionStorageTest.php create mode 100644 tests/lib/Security/CertificateManagerTest.php create mode 100644 tests/lib/Security/CertificateTest.php create mode 100644 tests/lib/Security/CredentialsManagerTest.php create mode 100644 tests/lib/Security/CryptoTest.php create mode 100644 tests/lib/Security/HasherTest.php create mode 100644 tests/lib/Security/SecureRandomTest.php create mode 100644 tests/lib/Security/TrustedDomainHelperTest.php (limited to 'tests/lib/Security') diff --git a/tests/lib/Security/CSP/ContentSecurityPolicyManagerTest.php b/tests/lib/Security/CSP/ContentSecurityPolicyManagerTest.php new file mode 100644 index 00000000000..d463e7c648c --- /dev/null +++ b/tests/lib/Security/CSP/ContentSecurityPolicyManagerTest.php @@ -0,0 +1,69 @@ + + * + * @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 + * + */ + +namespace Test\Security\CSP; + + +use OC\Security\CSP\ContentSecurityPolicyManager; + +class ContentSecurityPolicyManagerTest extends \Test\TestCase { + /** @var ContentSecurityPolicyManager */ + private $contentSecurityPolicyManager; + + public function setUp() { + parent::setUp(); + $this->contentSecurityPolicyManager = new ContentSecurityPolicyManager(); + } + + public function testAddDefaultPolicy() { + $this->contentSecurityPolicyManager->addDefaultPolicy(new \OCP\AppFramework\Http\ContentSecurityPolicy()); + } + + public function testGetDefaultPolicyWithPolicies() { + $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + $policy->addAllowedFontDomain('mydomain.com'); + $policy->addAllowedImageDomain('anotherdomain.de'); + $this->contentSecurityPolicyManager->addDefaultPolicy($policy); + $policy = new \OCP\AppFramework\Http\ContentSecurityPolicy(); + $policy->addAllowedFontDomain('example.com'); + $policy->addAllowedImageDomain('example.org'); + $policy->allowInlineScript(true); + $this->contentSecurityPolicyManager->addDefaultPolicy($policy); + $policy = new \OCP\AppFramework\Http\EmptyContentSecurityPolicy(); + $policy->addAllowedChildSrcDomain('childdomain'); + $policy->addAllowedFontDomain('anotherFontDomain'); + $this->contentSecurityPolicyManager->addDefaultPolicy($policy); + + $expected = new \OC\Security\CSP\ContentSecurityPolicy(); + $expected->allowInlineScript(true); + $expected->addAllowedFontDomain('mydomain.com'); + $expected->addAllowedFontDomain('example.com'); + $expected->addAllowedFontDomain('anotherFontDomain'); + $expected->addAllowedImageDomain('anotherdomain.de'); + $expected->addAllowedImageDomain('example.org'); + $expected->addAllowedChildSrcDomain('childdomain'); + $expectedStringPolicy = 'default-src \'none\';script-src \'self\' \'unsafe-inline\' \'unsafe-eval\';style-src \'self\' \'unsafe-inline\';img-src \'self\' data: blob: anotherdomain.de example.org;font-src \'self\' mydomain.com example.com anotherFontDomain;connect-src \'self\';media-src \'self\';child-src childdomain'; + + $this->assertEquals($expected, $this->contentSecurityPolicyManager->getDefaultPolicy()); + $this->assertSame($expectedStringPolicy, $this->contentSecurityPolicyManager->getDefaultPolicy()->buildPolicy()); + } + +} diff --git a/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php b/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php new file mode 100644 index 00000000000..28b85c3951f --- /dev/null +++ b/tests/lib/Security/CSRF/CsrfTokenGeneratorTest.php @@ -0,0 +1,56 @@ + + * + * @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 + * + */ + +namespace Test\Security\CSRF; + +class CsrfTokenGeneratorTest extends \Test\TestCase { + /** @var \OCP\Security\ISecureRandom */ + private $random; + /** @var \OC\Security\CSRF\CsrfTokenGenerator */ + private $csrfTokenGenerator; + + public function setUp() { + parent::setUp(); + $this->random = $this->getMockBuilder('\OCP\Security\ISecureRandom') + ->disableOriginalConstructor()->getMock(); + $this->csrfTokenGenerator = new \OC\Security\CSRF\CsrfTokenGenerator($this->random); + + } + + public function testGenerateTokenWithCustomNumber() { + $this->random + ->expects($this->once()) + ->method('generate') + ->with(3) + ->willReturn('abc'); + $this->assertSame('abc', $this->csrfTokenGenerator->generateToken(3)); + } + + public function testGenerateTokenWithDefault() { + $this->random + ->expects($this->once()) + ->method('generate') + ->with(32) + ->willReturn('12345678901234567890123456789012'); + $this->assertSame('12345678901234567890123456789012', $this->csrfTokenGenerator->generateToken(32)); + } +} + diff --git a/tests/lib/Security/CSRF/CsrfTokenManagerTest.php b/tests/lib/Security/CSRF/CsrfTokenManagerTest.php new file mode 100644 index 00000000000..ab19a43e91e --- /dev/null +++ b/tests/lib/Security/CSRF/CsrfTokenManagerTest.php @@ -0,0 +1,136 @@ + + * + * @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 + * + */ + +namespace Test\Security\CSRF; + +class CsrfTokenManagerTest extends \Test\TestCase { + /** @var \OC\Security\CSRF\CsrfTokenManager */ + private $csrfTokenManager; + /** @var \OC\Security\CSRF\CsrfTokenGenerator */ + private $tokenGenerator; + /** @var \OC\Security\CSRF\TokenStorage\SessionStorage */ + private $storageInterface; + + public function setUp() { + parent::setUp(); + $this->tokenGenerator = $this->getMockBuilder('\OC\Security\CSRF\CsrfTokenGenerator') + ->disableOriginalConstructor()->getMock(); + $this->storageInterface = $this->getMockBuilder('\OC\Security\CSRF\TokenStorage\SessionStorage') + ->disableOriginalConstructor()->getMock(); + + $this->csrfTokenManager = new \OC\Security\CSRF\CsrfTokenManager( + $this->tokenGenerator, + $this->storageInterface + ); + } + + public function testGetTokenWithExistingToken() { + $this->storageInterface + ->expects($this->once()) + ->method('hasToken') + ->willReturn(true); + $this->storageInterface + ->expects($this->once()) + ->method('getToken') + ->willReturn('MyExistingToken'); + + $expected = new \OC\Security\CSRF\CsrfToken('MyExistingToken'); + $this->assertEquals($expected, $this->csrfTokenManager->getToken()); + } + + public function testGetTokenWithoutExistingToken() { + $this->storageInterface + ->expects($this->once()) + ->method('hasToken') + ->willReturn(false); + $this->tokenGenerator + ->expects($this->once()) + ->method('generateToken') + ->willReturn('MyNewToken'); + $this->storageInterface + ->expects($this->once()) + ->method('setToken') + ->with('MyNewToken'); + + $expected = new \OC\Security\CSRF\CsrfToken('MyNewToken'); + $this->assertEquals($expected, $this->csrfTokenManager->getToken()); + } + + public function testRefreshToken() { + $this->tokenGenerator + ->expects($this->once()) + ->method('generateToken') + ->willReturn('MyNewToken'); + $this->storageInterface + ->expects($this->once()) + ->method('setToken') + ->with('MyNewToken'); + + $expected = new \OC\Security\CSRF\CsrfToken('MyNewToken'); + $this->assertEquals($expected, $this->csrfTokenManager->refreshToken()); + } + + public function testRemoveToken() { + $this->storageInterface + ->expects($this->once()) + ->method('removeToken'); + + $this->csrfTokenManager->removeToken(); + } + + public function testIsTokenValidWithoutToken() { + $this->storageInterface + ->expects($this->once()) + ->method('hasToken') + ->willReturn(false); + $token = new \OC\Security\CSRF\CsrfToken('Token'); + + $this->assertSame(false, $this->csrfTokenManager->isTokenValid($token)); + } + + public function testIsTokenValidWithWrongToken() { + $this->storageInterface + ->expects($this->once()) + ->method('hasToken') + ->willReturn(true); + $token = new \OC\Security\CSRF\CsrfToken('Token'); + $this->storageInterface + ->expects($this->once()) + ->method('getToken') + ->willReturn('MyToken'); + + $this->assertSame(false, $this->csrfTokenManager->isTokenValid($token)); + } + + public function testIsTokenValidWithValidToken() { + $this->storageInterface + ->expects($this->once()) + ->method('hasToken') + ->willReturn(true); + $token = new \OC\Security\CSRF\CsrfToken('XlQhHjgWCgBXAEI0Khl+IQEiCXN2LUcDHAQTQAc1HQs=:qgkUlg8l3m8WnkOG4XM9Az33pAt1vSVMx4hcJFsxdqc='); + $this->storageInterface + ->expects($this->once()) + ->method('getToken') + ->willReturn('/3JKTq2ldmzcDr1f5zDJ7Wt0lEgqqfKF'); + + $this->assertSame(true, $this->csrfTokenManager->isTokenValid($token)); + } +} diff --git a/tests/lib/Security/CSRF/CsrfTokenTest.php b/tests/lib/Security/CSRF/CsrfTokenTest.php new file mode 100644 index 00000000000..da640ce5052 --- /dev/null +++ b/tests/lib/Security/CSRF/CsrfTokenTest.php @@ -0,0 +1,35 @@ + + * + * @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 + * + */ + +namespace Test\Security\CSRF; + +class CsrfTokenTest extends \Test\TestCase { + public function testGetEncryptedValue() { + $csrfToken = new \OC\Security\CSRF\CsrfToken('MyCsrfToken'); + $this->assertSame(33, strlen($csrfToken->getEncryptedValue())); + $this->assertSame(':', $csrfToken->getEncryptedValue()[16]); + } + + public function testGetDecryptedValue() { + $csrfToken = new \OC\Security\CSRF\CsrfToken('XlQhHjgWCgBXAEI0Khl+IQEiCXN2LUcDHAQTQAc1HQs=:qgkUlg8l3m8WnkOG4XM9Az33pAt1vSVMx4hcJFsxdqc='); + $this->assertSame('/3JKTq2ldmzcDr1f5zDJ7Wt0lEgqqfKF', $csrfToken->getDecryptedValue()); + } +} diff --git a/tests/lib/Security/CSRF/TokenStorage/SessionStorageTest.php b/tests/lib/Security/CSRF/TokenStorage/SessionStorageTest.php new file mode 100644 index 00000000000..550fa49e1b2 --- /dev/null +++ b/tests/lib/Security/CSRF/TokenStorage/SessionStorageTest.php @@ -0,0 +1,109 @@ + + * + * @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 + * + */ + +namespace Test\Security\CSRF\TokenStorage; + +class SessionStorageTest extends \Test\TestCase { + /** @var \OCP\ISession */ + private $session; + /** @var \OC\Security\CSRF\TokenStorage\SessionStorage */ + private $sessionStorage; + + public function setUp() { + parent::setUp(); + $this->session = $this->getMockBuilder('\OCP\ISession') + ->disableOriginalConstructor()->getMock(); + $this->sessionStorage = new \OC\Security\CSRF\TokenStorage\SessionStorage($this->session); + } + + /** + * @return array + */ + public function getTokenDataProvider() { + return [ + [ + '', + ], + [ + null, + ], + ]; + } + + /** + * @param string $token + * @dataProvider getTokenDataProvider + * + * @expectedException \Exception + * @expectedExceptionMessage Session does not contain a requesttoken + */ + public function testGetTokenWithEmptyToken($token) { + $this->session + ->expects($this->once()) + ->method('get') + ->with('requesttoken') + ->willReturn($token); + $this->sessionStorage->getToken(); + } + + public function testGetTokenWithValidToken() { + $this->session + ->expects($this->once()) + ->method('get') + ->with('requesttoken') + ->willReturn('MyFancyCsrfToken'); + $this->assertSame('MyFancyCsrfToken', $this->sessionStorage->getToken()); + } + + public function testSetToken() { + $this->session + ->expects($this->once()) + ->method('set') + ->with('requesttoken', 'TokenToSet'); + $this->sessionStorage->setToken('TokenToSet'); + } + + public function testRemoveToken() { + $this->session + ->expects($this->once()) + ->method('remove') + ->with('requesttoken'); + $this->sessionStorage->removeToken(); + } + + public function testHasTokenWithExistingToken() { + $this->session + ->expects($this->once()) + ->method('exists') + ->with('requesttoken') + ->willReturn(true); + $this->assertSame(true, $this->sessionStorage->hasToken()); + } + + public function testHasTokenWithoutExistingToken() { + $this->session + ->expects($this->once()) + ->method('exists') + ->with('requesttoken') + ->willReturn(false); + $this->assertSame(false, $this->sessionStorage->hasToken()); + } +} diff --git a/tests/lib/Security/CertificateManagerTest.php b/tests/lib/Security/CertificateManagerTest.php new file mode 100644 index 00000000000..43206569cf4 --- /dev/null +++ b/tests/lib/Security/CertificateManagerTest.php @@ -0,0 +1,121 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Security; + +use \OC\Security\CertificateManager; + +/** + * Class CertificateManagerTest + * + * @group DB + */ +class CertificateManagerTest extends \Test\TestCase { + use \Test\Traits\UserTrait; + use \Test\Traits\MountProviderTrait; + + /** @var CertificateManager */ + private $certificateManager; + /** @var String */ + private $username; + + protected function setUp() { + parent::setUp(); + + $this->username = $this->getUniqueID('', 20); + $this->createUser($this->username, ''); + + $storage = new \OC\Files\Storage\Temporary(); + $this->registerMount($this->username, $storage, '/' . $this->username . '/'); + + \OC_Util::tearDownFS(); + \OC_User::setUserId(''); + \OC\Files\Filesystem::tearDown(); + \OC_Util::setupFS($this->username); + + $config = $this->getMock('OCP\IConfig'); + $config->expects($this->any())->method('getSystemValue') + ->with('installed', false)->willReturn(true); + + $this->certificateManager = new CertificateManager($this->username, new \OC\Files\View(), $config); + } + + protected function tearDown() { + $user = \OC::$server->getUserManager()->get($this->username); + if ($user !== null) { + $user->delete(); + } + parent::tearDown(); + } + + protected function assertEqualsArrays($expected, $actual) { + sort($expected); + sort($actual); + + $this->assertEquals($expected, $actual); + } + + function testListCertificates() { + // Test empty certificate bundle + $this->assertSame(array(), $this->certificateManager->listCertificates()); + + // Add some certificates + $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); + $certificateStore = array(); + $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); + $this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates()); + + // Add another certificates + $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate'); + $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate'); + $this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates()); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Certificate could not get parsed. + */ + function testAddInvalidCertificate() { + $this->certificateManager->addCertificate('InvalidCertificate', 'invalidCertificate'); + } + + /** + * @return array + */ + public function dangerousFileProvider() { + return [ + ['.htaccess'], + ['../../foo.txt'], + ['..\..\foo.txt'], + ]; + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Filename is not valid + * @dataProvider dangerousFileProvider + * @param string $filename + */ + function testAddDangerousFile($filename) { + $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), $filename); + } + + function testRemoveDangerousFile() { + $this->assertFalse($this->certificateManager->removeCertificate('../../foo.txt')); + } + + function testRemoveExistingFile() { + $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); + $this->assertTrue($this->certificateManager->removeCertificate('GoodCertificate')); + } + + function testGetCertificateBundle() { + $this->assertSame('/' . $this->username . '/files_external/rootcerts.crt', $this->certificateManager->getCertificateBundle()); + } + +} diff --git a/tests/lib/Security/CertificateTest.php b/tests/lib/Security/CertificateTest.php new file mode 100644 index 00000000000..6f7d7d4a37f --- /dev/null +++ b/tests/lib/Security/CertificateTest.php @@ -0,0 +1,111 @@ + + * + * @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 + * + */ + +namespace Test\Security; + +use \OC\Security\Certificate; + +class CertificateTest extends \Test\TestCase { + + /** @var Certificate That contains a valid certificate */ + protected $goodCertificate; + /** @var Certificate That contains an invalid certificate */ + protected $invalidCertificate; + /** @var Certificate That contains an expired certificate */ + protected $expiredCertificate; + + protected function setUp() { + parent::setUp(); + + $goodCertificate = file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'); + $this->goodCertificate = new Certificate($goodCertificate, 'GoodCertificate'); + $badCertificate = file_get_contents(__DIR__ . '/../../data/certificates/badCertificate.crt'); + $this->invalidCertificate = new Certificate($badCertificate, 'BadCertificate'); + $expiredCertificate = file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'); + $this->expiredCertificate = new Certificate($expiredCertificate, 'ExpiredCertificate'); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Certificate could not get parsed. + */ + public function testBogusData() { + $certificate = new Certificate('foo', 'bar'); + $certificate->getIssueDate(); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Certificate could not get parsed. + */ + function testCertificateStartingWithFileReference() { + new Certificate('file://'.__DIR__ . '/../../data/certificates/goodCertificate.crt', 'bar'); + } + + public function testGetName() { + $this->assertSame('GoodCertificate', $this->goodCertificate->getName()); + $this->assertSame('BadCertificate', $this->invalidCertificate->getName()); + } + + public function testGetCommonName() { + $this->assertSame('security.owncloud.com', $this->goodCertificate->getCommonName()); + $this->assertSame(null, $this->invalidCertificate->getCommonName()); + } + + public function testGetOrganization() { + $this->assertSame('ownCloud Security', $this->goodCertificate->getOrganization()); + $this->assertSame('Internet Widgits Pty Ltd', $this->invalidCertificate->getOrganization()); + } + + public function testGetIssueDate() { + $expected = new \DateTime('2015-08-27 20:03:42 GMT'); + $this->assertEquals($expected->getTimestamp(), $this->goodCertificate->getIssueDate()->getTimestamp()); + $expected = new \DateTime('2015-08-27 20:19:13 GMT'); + $this->assertEquals($expected->getTimestamp(), $this->invalidCertificate->getIssueDate()->getTimestamp()); + } + + public function testGetExpireDate() { + $expected = new \DateTime('2025-08-24 20:03:42 GMT'); + $this->assertEquals($expected->getTimestamp(), $this->goodCertificate->getExpireDate()->getTimestamp()); + $expected = new \DateTime('2025-08-24 20:19:13 GMT'); + $this->assertEquals($expected->getTimestamp(), $this->invalidCertificate->getExpireDate()->getTimestamp()); + $expected = new \DateTime('2014-08-28 09:12:43 GMT'); + $this->assertEquals($expected->getTimestamp(), $this->expiredCertificate->getExpireDate()->getTimestamp()); + } + + public function testIsExpired() { + $this->assertSame(false, $this->goodCertificate->isExpired()); + $this->assertSame(false, $this->invalidCertificate->isExpired()); + $this->assertSame(true, $this->expiredCertificate->isExpired()); + } + + public function testGetIssuerName() { + $this->assertSame('security.owncloud.com', $this->goodCertificate->getIssuerName()); + $this->assertSame(null, $this->invalidCertificate->getIssuerName()); + $this->assertSame(null, $this->expiredCertificate->getIssuerName()); + } + + public function testGetIssuerOrganization() { + $this->assertSame('ownCloud Security', $this->goodCertificate->getIssuerOrganization()); + $this->assertSame('Internet Widgits Pty Ltd', $this->invalidCertificate->getIssuerOrganization()); + $this->assertSame('Internet Widgits Pty Ltd', $this->expiredCertificate->getIssuerOrganization()); + } +} diff --git a/tests/lib/Security/CredentialsManagerTest.php b/tests/lib/Security/CredentialsManagerTest.php new file mode 100644 index 00000000000..7eb4e4d7b1a --- /dev/null +++ b/tests/lib/Security/CredentialsManagerTest.php @@ -0,0 +1,104 @@ + + * + * @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 + * + */ + +namespace Test\Security; + +use \OCP\Security\ICrypto; +use \OCP\IDBConnection; +use \OC\Security\CredentialsManager; + +class CredentialsManagerTest extends \Test\TestCase { + + /** @var ICrypto */ + protected $crypto; + + /** @var IDBConnection */ + protected $dbConnection; + + /** @var CredentialsManager */ + protected $manager; + + protected function setUp() { + parent::setUp(); + $this->crypto = $this->getMock('\OCP\Security\ICrypto'); + $this->dbConnection = $this->getMockBuilder('\OC\DB\Connection') + ->disableOriginalConstructor() + ->getMock(); + $this->manager = new CredentialsManager($this->crypto, $this->dbConnection); + } + + private function getQeuryResult($row) { + $result = $this->getMockBuilder('\Doctrine\DBAL\Driver\Statement') + ->disableOriginalConstructor() + ->getMock(); + + $result->expects($this->any()) + ->method('fetch') + ->will($this->returnValue($row)); + + return $result; + } + + public function testStore() { + $userId = 'abc'; + $identifier = 'foo'; + $credentials = 'bar'; + + $this->crypto->expects($this->once()) + ->method('encrypt') + ->with(json_encode($credentials)) + ->willReturn('baz'); + + $this->dbConnection->expects($this->once()) + ->method('setValues') + ->with(CredentialsManager::DB_TABLE, + ['user' => $userId, 'identifier' => $identifier], + ['credentials' => 'baz'] + ); + + $this->manager->store($userId, $identifier, $credentials); + } + + public function testRetrieve() { + $userId = 'abc'; + $identifier = 'foo'; + + $this->crypto->expects($this->once()) + ->method('decrypt') + ->with('baz') + ->willReturn(json_encode('bar')); + + $qb = $this->getMockBuilder('\OC\DB\QueryBuilder\QueryBuilder') + ->setConstructorArgs([$this->dbConnection]) + ->setMethods(['execute']) + ->getMock(); + $qb->expects($this->once()) + ->method('execute') + ->willReturn($this->getQeuryResult(['credentials' => 'baz'])); + + $this->dbConnection->expects($this->once()) + ->method('getQueryBuilder') + ->willReturn($qb); + + $this->manager->retrieve($userId, $identifier); + } + +} diff --git a/tests/lib/Security/CryptoTest.php b/tests/lib/Security/CryptoTest.php new file mode 100644 index 00000000000..356d504f4b3 --- /dev/null +++ b/tests/lib/Security/CryptoTest.php @@ -0,0 +1,73 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Security; + +use \OC\Security\Crypto; + +class CryptoTest extends \Test\TestCase { + + public function defaultEncryptionProvider() + { + return array( + array('Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.'), + array(''), + array('我看这本书。 我看這本書') + ); + } + + /** @var Crypto */ + protected $crypto; + + protected function setUp() { + parent::setUp(); + $this->crypto = new Crypto(\OC::$server->getConfig(), \OC::$server->getSecureRandom()); + } + + /** + * @dataProvider defaultEncryptionProvider + */ + function testDefaultEncrypt($stringToEncrypt) { + $ciphertext = $this->crypto->encrypt($stringToEncrypt); + $this->assertEquals($stringToEncrypt, $this->crypto->decrypt($ciphertext)); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage HMAC does not match. + */ + function testWrongPassword() { + $stringToEncrypt = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.'; + $ciphertext = $this->crypto->encrypt($stringToEncrypt); + $this->crypto->decrypt($ciphertext, 'A wrong password!'); + } + + function testLaterDecryption() { + $stringToEncrypt = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.'; + $encryptedString = '44a35023cca2e7a6125e06c29fc4b2ad9d8a33d0873a8b45b0de4ef9284f260c6c46bf25dc62120644c59b8bafe4281ddc47a70c35ae6c29ef7a63d79eefacc297e60b13042ac582733598d0a6b4de37311556bb5c480fd2633de4e6ebafa868c2d1e2d80a5d24f9660360dba4d6e0c8|lhrFgK0zd9U160Wo|a75e57ab701f9124e1113543fd1dc596f21e20d456a0d1e813d5a8aaec9adcb11213788e96598b67fe9486a9f0b99642c18296d0175db44b1ae426e4e91080ee'; + $this->assertEquals($stringToEncrypt, $this->crypto->decrypt($encryptedString, 'ThisIsAVeryS3cur3P4ssw0rd')); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage HMAC does not match. + */ + function testWrongIV() { + $encryptedString = '560f5436ba864b9f12f7f7ca6d41c327554a6f2c0a160a03316b202af07c65163274993f3a46e7547c07ba89304f00594a2f3bd99f83859097c58049c39d0d4ade10e0de914ff0604961e7c849d0271ed6c0b23f984ba16e7d033e3305fb0910e7b6a2a65c988d17dbee71d8f953684d|d2kdFUspVjC0o0sr|1a5feacf87eaa6869a6abdfba9a296e7bbad45b6ad89f7dce67cdc98e2da5dc4379cc672cc655e52bbf19599bf59482fbea13a73937697fa656bf10f3fc4f1aa'; + $this->crypto->decrypt($encryptedString, 'ThisIsAVeryS3cur3P4ssw0rd'); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Authenticated ciphertext could not be decoded. + */ + function testWrongParameters() { + $encryptedString = '1|2'; + $this->crypto->decrypt($encryptedString, 'ThisIsAVeryS3cur3P4ssw0rd'); + } +} diff --git a/tests/lib/Security/HasherTest.php b/tests/lib/Security/HasherTest.php new file mode 100644 index 00000000000..913f4d703e8 --- /dev/null +++ b/tests/lib/Security/HasherTest.php @@ -0,0 +1,118 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Security; + +use OC\Security\Hasher; + +/** + * Class HasherTest + */ +class HasherTest extends \Test\TestCase { + + /** + * @return array + */ + public function versionHashProvider() + { + return array( + array('asf32äà$$a.|3', null), + array('asf32äà$$a.|3|5', null), + array('1|2|3|4', array('version' => 1, 'hash' => '2|3|4')), + array('1|我看|这本书。 我看這本書', array('version' => 1, 'hash' => '我看|这本书。 我看這本書')) + ); + } + + /** + * @return array + */ + public function allHashProviders() + { + return array( + // Bogus values + array(null, 'asf32äà$$a.|3', false), + array(null, false, false), + + // Valid SHA1 strings + array('password', '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', true), + array('owncloud.com', '27a4643e43046c3569e33b68c1a4b15d31306d29', true), + + // Invalid SHA1 strings + array('InvalidString', '5baa61e4c9b93f3f0682250b6cf8331b7ee68fd8', false), + array('AnotherInvalidOne', '27a4643e43046c3569e33b68c1a4b15d31306d29', false), + + // Valid legacy password string with password salt "6Wow67q1wZQZpUUeI6G2LsWUu4XKx" + array('password', '$2a$08$emCpDEl.V.QwPWt5gPrqrOhdpH6ailBmkj2Hd2vD5U8qIy20HBe7.', true), + array('password', '$2a$08$yjaLO4ev70SaOsWZ9gRS3eRSEpHVsmSWTdTms1949mylxJ279hzo2', true), + array('password', '$2a$08$.jNRG/oB4r7gHJhAyb.mDupNUAqTnBIW/tWBqFobaYflKXiFeG0A6', true), + array('owncloud.com', '$2a$08$YbEsyASX/hXVNMv8hXQo7ezreN17T8Jl6PjecGZvpX.Ayz2aUyaZ2', true), + array('owncloud.com', '$2a$11$cHdDA2IkUP28oNGBwlL7jO/U3dpr8/0LIjTZmE8dMPA7OCUQsSTqS', true), + array('owncloud.com', '$2a$08$GH.UoIfJ1e.qeZ85KPqzQe6NR8XWRgJXWIUeE1o/j1xndvyTA1x96', true), + + // Invalid legacy passwords + array('password', '$2a$08$oKAQY5IhnZocP.61MwP7xu7TNeOb7Ostvk3j6UpacvaNMs.xRj7O2', false), + + // Valid passwords "6Wow67q1wZQZpUUeI6G2LsWUu4XKx" + array('password', '1|$2a$05$ezAE0dkwk57jlfo6z5Pql.gcIK3ReXT15W7ITNxVS0ksfhO/4E4Kq', true), + array('password', '1|$2a$05$4OQmloFW4yTVez2MEWGIleDO9Z5G9tWBXxn1vddogmKBQq/Mq93pe', true), + array('password', '1|$2a$11$yj0hlp6qR32G9exGEXktB.yW2rgt2maRBbPgi3EyxcDwKrD14x/WO', true), + array('owncloud.com', '1|$2a$10$Yiss2WVOqGakxuuqySv5UeOKpF8d8KmNjuAPcBMiRJGizJXjA2bKm', true), + array('owncloud.com', '1|$2a$10$v9mh8/.mF/Ut9jZ7pRnpkuac3bdFCnc4W/gSumheQUi02Sr.xMjPi', true), + array('owncloud.com', '1|$2a$05$ST5E.rplNRfDCzRpzq69leRzsTGtY7k88h9Vy2eWj0Ug/iA9w5kGK', true), + + // Invalid passwords + array('password', '0|$2a$08$oKAQY5IhnZocP.61MwP7xu7TNeOb7Ostvk3j6UpacvaNMs.xRj7O2', false), + array('password', '1|$2a$08$oKAQY5IhnZocP.61MwP7xu7TNeOb7Ostvk3j6UpacvaNMs.xRj7O2', false), + array('password', '2|$2a$08$oKAQY5IhnZocP.61MwP7xu7TNeOb7Ostvk3j6UpacvaNMs.xRj7O2', false), + ); + } + + /** @var Hasher */ + protected $hasher; + + /** @var \OCP\IConfig */ + protected $config; + + protected function setUp() { + parent::setUp(); + + $this->config = $this->getMockBuilder('\OCP\IConfig') + ->disableOriginalConstructor()->getMock(); + + $this->hasher = new Hasher($this->config); + } + + function testHash() { + $hash = $this->hasher->hash('String To Hash'); + $this->assertNotNull($hash); + } + + /** + * @dataProvider versionHashProvider + */ + function testSplitHash($hash, $expected) { + $relativePath = self::invokePrivate($this->hasher, 'splitHash', array($hash)); + $this->assertSame($expected, $relativePath); + } + + + /** + * @dataProvider allHashProviders + */ + function testVerify($password, $hash, $expected) { + $this->config + ->expects($this->any()) + ->method('getSystemValue') + ->with('passwordsalt', null) + ->will($this->returnValue('6Wow67q1wZQZpUUeI6G2LsWUu4XKx')); + + $result = $this->hasher->verify($password, $hash); + $this->assertSame($expected, $result); + } + +} diff --git a/tests/lib/Security/SecureRandomTest.php b/tests/lib/Security/SecureRandomTest.php new file mode 100644 index 00000000000..40431c89795 --- /dev/null +++ b/tests/lib/Security/SecureRandomTest.php @@ -0,0 +1,78 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Security; + +use \OC\Security\SecureRandom; + +class SecureRandomTest extends \Test\TestCase { + + public function stringGenerationProvider() { + return array( + array(0, 0), + array(1, 1), + array(128, 128), + array(256, 256), + array(1024, 1024), + array(2048, 2048), + array(64000, 64000), + ); + } + + public static function charCombinations() { + return array( + array('CHAR_LOWER', '[a-z]'), + array('CHAR_UPPER', '[A-Z]'), + array('CHAR_DIGITS', '[0-9]'), + ); + } + + /** @var SecureRandom */ + protected $rng; + + protected function setUp() { + parent::setUp(); + $this->rng = new \OC\Security\SecureRandom(); + } + + /** + * @dataProvider stringGenerationProvider + */ + function testGetLowStrengthGeneratorLength($length, $expectedLength) { + $generator = $this->rng; + + $this->assertEquals($expectedLength, strlen($generator->generate($length))); + } + + /** + * @dataProvider stringGenerationProvider + */ + function testMediumLowStrengthGeneratorLength($length, $expectedLength) { + $generator = $this->rng; + + $this->assertEquals($expectedLength, strlen($generator->generate($length))); + } + + /** + * @dataProvider stringGenerationProvider + */ + function testUninitializedGenerate($length, $expectedLength) { + $this->assertEquals($expectedLength, strlen($this->rng->generate($length))); + } + + /** + * @dataProvider charCombinations + */ + public function testScheme($charName, $chars) { + $generator = $this->rng; + $scheme = constant('OCP\Security\ISecureRandom::' . $charName); + $randomString = $generator->generate(100, $scheme); + $matchesRegex = preg_match('/^'.$chars.'+$/', $randomString); + $this->assertSame(1, $matchesRegex); + } +} diff --git a/tests/lib/Security/TrustedDomainHelperTest.php b/tests/lib/Security/TrustedDomainHelperTest.php new file mode 100644 index 00000000000..dfd51167cca --- /dev/null +++ b/tests/lib/Security/TrustedDomainHelperTest.php @@ -0,0 +1,82 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace Test\Security; + +use \OC\Security\TrustedDomainHelper; +use OCP\IConfig; + +/** + * Class TrustedDomainHelperTest + */ +class TrustedDomainHelperTest extends \Test\TestCase { + /** @var IConfig */ + protected $config; + + protected function setUp() { + parent::setUp(); + + $this->config = $this->getMockBuilder('\OCP\IConfig')->getMock(); + } + + /** + * @dataProvider trustedDomainDataProvider + * @param string $trustedDomains + * @param string $testDomain + * @param bool $result + */ + public function testIsTrustedDomain($trustedDomains, $testDomain, $result) { + $this->config->expects($this->once()) + ->method('getSystemValue') + ->with('trusted_domains') + ->will($this->returnValue($trustedDomains)); + + $trustedDomainHelper = new TrustedDomainHelper($this->config); + $this->assertEquals($result, $trustedDomainHelper->isTrustedDomain($testDomain)); + } + + /** + * @return array + */ + public function trustedDomainDataProvider() { + $trustedHostTestList = [ + 'host.one.test', + 'host.two.test', + '[1fff:0:a88:85a3::ac1f]', + 'host.three.test:443', + ]; + return [ + // empty defaults to false with 8.1 + [null, 'host.one.test:8080', false], + ['', 'host.one.test:8080', false], + [[], 'host.one.test:8080', false], + // trust list when defined + [$trustedHostTestList, 'host.two.test:8080', true], + [$trustedHostTestList, 'host.two.test:9999', true], + [$trustedHostTestList, 'host.three.test:8080', false], + [$trustedHostTestList, 'host.two.test:8080:aa:222', false], + [$trustedHostTestList, '[1fff:0:a88:85a3::ac1f]', true], + [$trustedHostTestList, '[1fff:0:a88:85a3::ac1f]:801', true], + [$trustedHostTestList, '[1fff:0:a88:85a3::ac1f]:801:34', false], + [$trustedHostTestList, 'host.three.test:443', true], + [$trustedHostTestList, 'host.three.test:80', false], + [$trustedHostTestList, 'host.three.test', false], + // trust localhost regardless of trust list + [$trustedHostTestList, 'localhost', true], + [$trustedHostTestList, 'localhost:8080', true], + [$trustedHostTestList, '127.0.0.1', true], + [$trustedHostTestList, '127.0.0.1:8080', true], + // do not trust invalid localhosts + [$trustedHostTestList, 'localhost:1:2', false], + [$trustedHostTestList, 'localhost: evil.host', false], + // do not trust casting + [[1], '1', false], + ]; + } + +} -- cgit v1.2.3