CertificateManagerTest.php 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <?php
  2. /**
  3. * Copyright (c) 2014 Lukas Reschke <lukas@owncloud.com>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. namespace Test\Security;
  9. use OC\Files\Storage\Temporary;
  10. use OC\Files\View;
  11. use \OC\Security\CertificateManager;
  12. use OCP\IConfig;
  13. use OCP\ILogger;
  14. use OCP\Security\ISecureRandom;
  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() {
  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('getSystemValue')
  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. $this->username,
  47. new \OC\Files\View(),
  48. $config,
  49. $this->createMock(ILogger::class),
  50. $this->random
  51. );
  52. }
  53. protected function tearDown() {
  54. $user = \OC::$server->getUserManager()->get($this->username);
  55. if ($user !== null) {
  56. $user->delete();
  57. }
  58. parent::tearDown();
  59. }
  60. protected function assertEqualsArrays($expected, $actual) {
  61. sort($expected);
  62. sort($actual);
  63. $this->assertEquals($expected, $actual);
  64. }
  65. function testListCertificates() {
  66. // Test empty certificate bundle
  67. $this->assertSame(array(), $this->certificateManager->listCertificates());
  68. // Add some certificates
  69. $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
  70. $certificateStore = array();
  71. $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
  72. $this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates());
  73. // Add another certificates
  74. $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate');
  75. $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate');
  76. $this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates());
  77. }
  78. /**
  79. * @expectedException \Exception
  80. * @expectedExceptionMessage Certificate could not get parsed.
  81. */
  82. function testAddInvalidCertificate() {
  83. $this->certificateManager->addCertificate('InvalidCertificate', 'invalidCertificate');
  84. }
  85. /**
  86. * @return array
  87. */
  88. public function dangerousFileProvider() {
  89. return [
  90. ['.htaccess'],
  91. ['../../foo.txt'],
  92. ['..\..\foo.txt'],
  93. ];
  94. }
  95. /**
  96. * @expectedException \Exception
  97. * @expectedExceptionMessage Filename is not valid
  98. * @dataProvider dangerousFileProvider
  99. * @param string $filename
  100. */
  101. function testAddDangerousFile($filename) {
  102. $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), $filename);
  103. }
  104. function testRemoveDangerousFile() {
  105. $this->assertFalse($this->certificateManager->removeCertificate('../../foo.txt'));
  106. }
  107. function testRemoveExistingFile() {
  108. $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
  109. $this->assertTrue($this->certificateManager->removeCertificate('GoodCertificate'));
  110. }
  111. function testGetCertificateBundle() {
  112. $this->assertSame('/' . $this->username . '/files_external/rootcerts.crt', $this->certificateManager->getCertificateBundle());
  113. }
  114. /**
  115. * @dataProvider dataTestNeedRebundling
  116. *
  117. * @param string $uid
  118. * @param int $CaBundleMtime
  119. * @param int $systemWideMtime
  120. * @param int $targetBundleMtime
  121. * @param int $targetBundleExists
  122. * @param bool $expected
  123. */
  124. function testNeedRebundling($uid,
  125. $CaBundleMtime,
  126. $systemWideMtime,
  127. $targetBundleMtime,
  128. $targetBundleExists,
  129. $expected
  130. ) {
  131. $view = $this->getMockBuilder(View::class)
  132. ->disableOriginalConstructor()->getMock();
  133. $config = $this->createMock(IConfig::class);
  134. /** @var CertificateManager | \PHPUnit_Framework_MockObject_MockObject $certificateManager */
  135. $certificateManager = $this->getMockBuilder('OC\Security\CertificateManager')
  136. ->setConstructorArgs([$uid, $view, $config, $this->createMock(ILogger::class), $this->random])
  137. ->setMethods(['getFilemtimeOfCaBundle', 'getCertificateBundle'])
  138. ->getMock();
  139. $certificateManager->expects($this->any())->method('getFilemtimeOfCaBundle')
  140. ->willReturn($CaBundleMtime);
  141. $certificateManager->expects($this->at(1))->method('getCertificateBundle')
  142. ->with($uid)->willReturn('targetBundlePath');
  143. $view->expects($this->any())->method('file_exists')
  144. ->with('targetBundlePath')
  145. ->willReturn($targetBundleExists);
  146. if ($uid !== null && $targetBundleExists) {
  147. $certificateManager->expects($this->at(2))->method('getCertificateBundle')
  148. ->with(null)->willReturn('SystemBundlePath');
  149. }
  150. $view->expects($this->any())->method('filemtime')
  151. ->willReturnCallback(function($path) use ($systemWideMtime, $targetBundleMtime) {
  152. if ($path === 'SystemBundlePath') {
  153. return $systemWideMtime;
  154. } elseif ($path === 'targetBundlePath') {
  155. return $targetBundleMtime;
  156. }
  157. throw new \Exception('unexpected path');
  158. });
  159. $this->assertSame($expected,
  160. $this->invokePrivate($certificateManager, 'needsRebundling', [$uid])
  161. );
  162. }
  163. function dataTestNeedRebundling() {
  164. return [
  165. //values: uid, CaBundleMtime, systemWideMtime, targetBundleMtime, targetBundleExists, expected
  166. // compare minimum of CaBundleMtime and systemWideMtime with targetBundleMtime
  167. ['user1', 10, 20, 30, true, false],
  168. ['user1', 10, 20, 15, true, true],
  169. ['user1', 10, 5, 30, true, false],
  170. ['user1', 10, 5, 8, true, true],
  171. // if no user exists we ignore 'systemWideMtime' because this is the bundle we re-build
  172. [null, 10, 20, 30, true, false],
  173. [null, 10, 20, 15, true, false],
  174. [null, 10, 20, 8, true, true],
  175. [null, 10, 5, 30, true, false],
  176. [null, 10, 5, 8, true, true],
  177. // if no target bundle exists we always build a new one
  178. ['user1', 10, 20, 30, false, true],
  179. ['user1', 10, 20, 15, false, true],
  180. ['user1', 10, 5, 30, false, true],
  181. ['user1', 10, 5, 8, false, true],
  182. [null, 10, 20, 30, false, true],
  183. [null, 10, 20, 15, false, true],
  184. [null, 10, 20, 8, false, true],
  185. [null, 10, 5, 30, false, true],
  186. [null, 10, 5, 8, false, true],
  187. ];
  188. }
  189. }