CertificateManagerTest.php 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com>
  5. * This file is licensed under the Affero General Public License version 3 or
  6. * later.
  7. * See the COPYING-README file.
  8. */
  9. namespace Test\Security;
  10. use OC\Files\View;
  11. use OC\Security\CertificateManager;
  12. use OCP\IConfig;
  13. use OCP\Security\ISecureRandom;
  14. use Psr\Log\LoggerInterface;
  15. /**
  16. * Class CertificateManagerTest
  17. *
  18. * @group DB
  19. */
  20. class CertificateManagerTest extends \Test\TestCase {
  21. use \Test\Traits\UserTrait;
  22. use \Test\Traits\MountProviderTrait;
  23. /** @var CertificateManager */
  24. private $certificateManager;
  25. /** @var String */
  26. private $username;
  27. /** @var ISecureRandom */
  28. private $random;
  29. protected function setUp(): void {
  30. parent::setUp();
  31. $this->username = $this->getUniqueID('', 20);
  32. $this->createUser($this->username, '');
  33. $storage = new \OC\Files\Storage\Temporary();
  34. $this->registerMount($this->username, $storage, '/' . $this->username . '/');
  35. \OC_Util::tearDownFS();
  36. \OC_User::setUserId('');
  37. \OC\Files\Filesystem::tearDown();
  38. \OC_Util::setupFS($this->username);
  39. $config = $this->createMock(IConfig::class);
  40. $config->expects($this->any())->method('getSystemValueBool')
  41. ->with('installed', false)->willReturn(true);
  42. $this->random = $this->createMock(ISecureRandom::class);
  43. $this->random->method('generate')
  44. ->willReturn('random');
  45. $this->certificateManager = new CertificateManager(
  46. new \OC\Files\View(),
  47. $config,
  48. $this->createMock(LoggerInterface::class),
  49. $this->random
  50. );
  51. }
  52. protected function tearDown(): void {
  53. $user = \OC::$server->getUserManager()->get($this->username);
  54. if ($user !== null) {
  55. $user->delete();
  56. }
  57. parent::tearDown();
  58. }
  59. protected function assertEqualsArrays($expected, $actual) {
  60. sort($expected);
  61. sort($actual);
  62. $this->assertEquals($expected, $actual);
  63. }
  64. public function testListCertificates() {
  65. // Test empty certificate bundle
  66. $this->assertSame([], $this->certificateManager->listCertificates());
  67. // Add some certificates
  68. $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
  69. $certificateStore = [];
  70. $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
  71. $this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates());
  72. // Add another certificates
  73. $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate');
  74. $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate');
  75. $this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates());
  76. }
  77. public function testAddInvalidCertificate() {
  78. $this->expectException(\Exception::class);
  79. $this->expectExceptionMessage('Certificate could not get parsed.');
  80. $this->certificateManager->addCertificate('InvalidCertificate', 'invalidCertificate');
  81. }
  82. /**
  83. * @return array
  84. */
  85. public function dangerousFileProvider() {
  86. return [
  87. ['.htaccess'],
  88. ['../../foo.txt'],
  89. ['..\..\foo.txt'],
  90. ];
  91. }
  92. /**
  93. * @dataProvider dangerousFileProvider
  94. * @param string $filename
  95. */
  96. public function testAddDangerousFile($filename) {
  97. $this->expectException(\Exception::class);
  98. $this->expectExceptionMessage('Filename is not valid');
  99. $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), $filename);
  100. }
  101. public function testRemoveDangerousFile() {
  102. $this->assertFalse($this->certificateManager->removeCertificate('../../foo.txt'));
  103. }
  104. public function testRemoveExistingFile() {
  105. $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
  106. $this->assertTrue($this->certificateManager->removeCertificate('GoodCertificate'));
  107. }
  108. public function testGetCertificateBundle() {
  109. $this->assertSame('/files_external/rootcerts.crt', $this->certificateManager->getCertificateBundle());
  110. }
  111. /**
  112. * @dataProvider dataTestNeedRebundling
  113. *
  114. * @param int $CaBundleMtime
  115. * @param int $targetBundleMtime
  116. * @param int $targetBundleExists
  117. * @param bool $expected
  118. */
  119. public function testNeedRebundling($CaBundleMtime,
  120. $targetBundleMtime,
  121. $targetBundleExists,
  122. $expected
  123. ) {
  124. $view = $this->getMockBuilder(View::class)
  125. ->disableOriginalConstructor()->getMock();
  126. $config = $this->createMock(IConfig::class);
  127. /** @var CertificateManager | \PHPUnit\Framework\MockObject\MockObject $certificateManager */
  128. $certificateManager = $this->getMockBuilder('OC\Security\CertificateManager')
  129. ->setConstructorArgs([$view, $config, $this->createMock(LoggerInterface::class), $this->random])
  130. ->setMethods(['getFilemtimeOfCaBundle', 'getCertificateBundle'])
  131. ->getMock();
  132. $certificateManager->expects($this->any())->method('getFilemtimeOfCaBundle')
  133. ->willReturn($CaBundleMtime);
  134. $certificateManager->expects($this->once())->method('getCertificateBundle')
  135. ->willReturn('targetBundlePath');
  136. $view->expects($this->any())->method('file_exists')
  137. ->with('targetBundlePath')
  138. ->willReturn($targetBundleExists);
  139. $view->expects($this->any())->method('filemtime')
  140. ->willReturnCallback(function ($path) use ($targetBundleMtime) {
  141. if ($path === 'targetBundlePath') {
  142. return $targetBundleMtime;
  143. }
  144. throw new \Exception('unexpected path');
  145. });
  146. $this->assertSame($expected,
  147. $this->invokePrivate($certificateManager, 'needsRebundling')
  148. );
  149. }
  150. public function dataTestNeedRebundling() {
  151. return [
  152. //values: CaBundleMtime, targetBundleMtime, targetBundleExists, expected
  153. [10, 30, true, false],
  154. [10, 15, true, false],
  155. [10, 8, true, true],
  156. [10, 30, true, false],
  157. [10, 8, true, true],
  158. // if no target bundle exists we always build a new one
  159. [10, 30, false, true],
  160. [10, 15, false, true],
  161. [10, 8, false, true],
  162. [10, 30, false, true],
  163. [10, 8, false, true],
  164. ];
  165. }
  166. }