You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

403 lines
11 KiB

9 years ago
9 years ago
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2016, ownCloud, Inc.
  4. *
  5. * @author Bjoern Schiessle <bjoern@schiessle.org>
  6. * @author Björn Schießle <bjoern@schiessle.org>
  7. * @author Clark Tomlinson <fallen013@gmail.com>
  8. * @author Joas Schilling <coding@schilljs.com>
  9. * @author Morris Jobke <hey@morrisjobke.de>
  10. * @author Roeland Jago Douma <roeland@famdouma.nl>
  11. *
  12. * @license AGPL-3.0
  13. *
  14. * This code is free software: you can redistribute it and/or modify
  15. * it under the terms of the GNU Affero General Public License, version 3,
  16. * as published by the Free Software Foundation.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU Affero General Public License for more details.
  22. *
  23. * You should have received a copy of the GNU Affero General Public License, version 3,
  24. * along with this program. If not, see <http://www.gnu.org/licenses/>
  25. *
  26. */
  27. namespace OCA\Encryption\Tests\Hooks;
  28. use OCA\Encryption\Crypto\Crypt;
  29. use OCA\Encryption\Hooks\UserHooks;
  30. use OCA\Encryption\KeyManager;
  31. use OCA\Encryption\Recovery;
  32. use OCA\Encryption\Session;
  33. use OCA\Encryption\Users\Setup;
  34. use OCA\Encryption\Util;
  35. use OCP\ILogger;
  36. use OCP\IUser;
  37. use OCP\IUserManager;
  38. use OCP\IUserSession;
  39. use Test\TestCase;
  40. /**
  41. * Class UserHooksTest
  42. *
  43. * @group DB
  44. * @package OCA\Encryption\Tests\Hooks
  45. */
  46. class UserHooksTest extends TestCase {
  47. /**
  48. * @var \PHPUnit_Framework_MockObject_MockObject
  49. */
  50. private $utilMock;
  51. /**
  52. * @var \PHPUnit_Framework_MockObject_MockObject
  53. */
  54. private $recoveryMock;
  55. /**
  56. * @var \PHPUnit_Framework_MockObject_MockObject
  57. */
  58. private $sessionMock;
  59. /**
  60. * @var \PHPUnit_Framework_MockObject_MockObject
  61. */
  62. private $keyManagerMock;
  63. /**
  64. * @var \PHPUnit_Framework_MockObject_MockObject
  65. */
  66. private $userManagerMock;
  67. /**
  68. * @var \PHPUnit_Framework_MockObject_MockObject
  69. */
  70. private $userSetupMock;
  71. /**
  72. * @var \PHPUnit_Framework_MockObject_MockObject
  73. */
  74. private $userSessionMock;
  75. /**
  76. * @var \PHPUnit_Framework_MockObject_MockObject
  77. */
  78. private $cryptMock;
  79. /**
  80. * @var \PHPUnit_Framework_MockObject_MockObject
  81. */
  82. private $loggerMock;
  83. /**
  84. * @var UserHooks
  85. */
  86. private $instance;
  87. private $params = ['uid' => 'testUser', 'password' => 'password'];
  88. public function testLogin() {
  89. $this->userSetupMock->expects($this->once())
  90. ->method('setupUser')
  91. ->willReturnOnConsecutiveCalls(true, false);
  92. $this->keyManagerMock->expects($this->once())
  93. ->method('init')
  94. ->with('testUser', 'password');
  95. $this->assertNull($this->instance->login($this->params));
  96. }
  97. public function testLogout() {
  98. $this->sessionMock->expects($this->once())
  99. ->method('clear');
  100. $this->instance->logout();
  101. $this->addToAssertionCount(1);
  102. }
  103. public function testPostCreateUser() {
  104. $this->userSetupMock->expects($this->once())
  105. ->method('setupUser');
  106. $this->instance->postCreateUser($this->params);
  107. $this->addToAssertionCount(1);
  108. }
  109. public function testPostDeleteUser() {
  110. $this->keyManagerMock->expects($this->once())
  111. ->method('deletePublicKey')
  112. ->with('testUser');
  113. $this->instance->postDeleteUser($this->params);
  114. $this->addToAssertionCount(1);
  115. }
  116. public function testPrePasswordReset() {
  117. $params = ['uid' => 'user1'];
  118. $expected = ['user1' => true];
  119. $this->instance->prePasswordReset($params);
  120. $passwordResetUsers = $this->invokePrivate($this->instance, 'passwordResetUsers');
  121. $this->assertSame($expected, $passwordResetUsers);
  122. }
  123. public function testPostPasswordReset() {
  124. $params = ['uid' => 'user1', 'password' => 'password'];
  125. $this->invokePrivate($this->instance, 'passwordResetUsers', [['user1' => true]]);
  126. $this->keyManagerMock->expects($this->once())->method('backupUserKeys')
  127. ->with('passwordReset', 'user1');
  128. $this->keyManagerMock->expects($this->once())->method('deleteUserKeys')
  129. ->with('user1');
  130. $this->userSetupMock->expects($this->once())->method('setupUser')
  131. ->with('user1', 'password');
  132. $this->instance->postPasswordReset($params);
  133. $passwordResetUsers = $this->invokePrivate($this->instance, 'passwordResetUsers');
  134. $this->assertEmpty($passwordResetUsers);
  135. }
  136. /**
  137. * @dataProvider dataTestPreSetPassphrase
  138. */
  139. public function testPreSetPassphrase($canChange) {
  140. /** @var UserHooks | \PHPUnit_Framework_MockObject_MockObject $instance */
  141. $instance = $this->getMockBuilder(UserHooks::class)
  142. ->setConstructorArgs(
  143. [
  144. $this->keyManagerMock,
  145. $this->userManagerMock,
  146. $this->loggerMock,
  147. $this->userSetupMock,
  148. $this->userSessionMock,
  149. $this->utilMock,
  150. $this->sessionMock,
  151. $this->cryptMock,
  152. $this->recoveryMock
  153. ]
  154. )
  155. ->setMethods(['setPassphrase'])
  156. ->getMock();
  157. $userMock = $this->createMock(IUser::class);
  158. $this->userManagerMock->expects($this->once())
  159. ->method('get')
  160. ->with($this->params['uid'])
  161. ->willReturn($userMock);
  162. $userMock->expects($this->once())
  163. ->method('canChangePassword')
  164. ->willReturn($canChange);
  165. if ($canChange) {
  166. // in this case the password will be changed in the post hook
  167. $instance->expects($this->never())->method('setPassphrase');
  168. } else {
  169. // if user can't change the password we update the encryption
  170. // key password already in the pre hook
  171. $instance->expects($this->once())
  172. ->method('setPassphrase')
  173. ->with($this->params);
  174. }
  175. $instance->preSetPassphrase($this->params);
  176. }
  177. public function dataTestPreSetPassphrase() {
  178. return [
  179. [true],
  180. [false]
  181. ];
  182. }
  183. public function testSetPassphrase() {
  184. $this->sessionMock->expects($this->exactly(4))
  185. ->method('getPrivateKey')
  186. ->willReturnOnConsecutiveCalls(true, false);
  187. $this->cryptMock->expects($this->exactly(4))
  188. ->method('encryptPrivateKey')
  189. ->willReturn(true);
  190. $this->cryptMock->expects($this->any())
  191. ->method('generateHeader')
  192. ->willReturn(Crypt::HEADER_START . ':Cipher:test:' . Crypt::HEADER_END);
  193. $this->keyManagerMock->expects($this->exactly(4))
  194. ->method('setPrivateKey')
  195. ->willReturnCallback(function ($user, $key) {
  196. $header = substr($key, 0, strlen(Crypt::HEADER_START));
  197. $this->assertSame(
  198. Crypt::HEADER_START,
  199. $header, 'every encrypted file should start with a header');
  200. });
  201. $this->assertNull($this->instance->setPassphrase($this->params));
  202. $this->params['recoveryPassword'] = 'password';
  203. $this->recoveryMock->expects($this->exactly(3))
  204. ->method('isRecoveryEnabledForUser')
  205. ->with('testUser')
  206. ->willReturnOnConsecutiveCalls(true, false);
  207. $this->instance = $this->getMockBuilder(UserHooks::class)
  208. ->setConstructorArgs(
  209. [
  210. $this->keyManagerMock,
  211. $this->userManagerMock,
  212. $this->loggerMock,
  213. $this->userSetupMock,
  214. $this->userSessionMock,
  215. $this->utilMock,
  216. $this->sessionMock,
  217. $this->cryptMock,
  218. $this->recoveryMock
  219. ]
  220. )->setMethods(['initMountPoints'])->getMock();
  221. $this->instance->expects($this->exactly(3))->method('initMountPoints');
  222. // Test first if statement
  223. $this->assertNull($this->instance->setPassphrase($this->params));
  224. // Test Second if conditional
  225. $this->keyManagerMock->expects($this->exactly(2))
  226. ->method('userHasKeys')
  227. ->with('testUser')
  228. ->willReturn(true);
  229. $this->assertNull($this->instance->setPassphrase($this->params));
  230. // Test third and final if condition
  231. $this->utilMock->expects($this->once())
  232. ->method('userHasFiles')
  233. ->with('testUser')
  234. ->willReturn(false);
  235. $this->cryptMock->expects($this->once())
  236. ->method('createKeyPair');
  237. $this->keyManagerMock->expects($this->once())
  238. ->method('setPrivateKey');
  239. $this->recoveryMock->expects($this->once())
  240. ->method('recoverUsersFiles')
  241. ->with('password', 'testUser');
  242. $this->assertNull($this->instance->setPassphrase($this->params));
  243. }
  244. public function testSetPassphraseResetUserMode() {
  245. $params = ['uid' => 'user1', 'password' => 'password'];
  246. $this->invokePrivate($this->instance, 'passwordResetUsers', [[$params['uid'] => true]]);
  247. $this->sessionMock->expects($this->never())->method('getPrivateKey');
  248. $this->keyManagerMock->expects($this->never())->method('setPrivateKey');
  249. $this->assertTrue($this->instance->setPassphrase($params));
  250. $this->invokePrivate($this->instance, 'passwordResetUsers', [[]]);
  251. }
  252. public function testSetPasswordNoUser() {
  253. $this->sessionMock->expects($this->once())
  254. ->method('getPrivateKey')
  255. ->willReturn(true);
  256. $userSessionMock = $this->getMockBuilder(IUserSession::class)
  257. ->disableOriginalConstructor()
  258. ->getMock();
  259. $userSessionMock->expects($this->any())->method('getUser')->will($this->returnValue(null));
  260. $this->recoveryMock->expects($this->once())
  261. ->method('isRecoveryEnabledForUser')
  262. ->with('testUser')
  263. ->willReturn(false);
  264. $userHooks = $this->getMockBuilder(UserHooks::class)
  265. ->setConstructorArgs(
  266. [
  267. $this->keyManagerMock,
  268. $this->userManagerMock,
  269. $this->loggerMock,
  270. $this->userSetupMock,
  271. $userSessionMock,
  272. $this->utilMock,
  273. $this->sessionMock,
  274. $this->cryptMock,
  275. $this->recoveryMock
  276. ]
  277. )->setMethods(['initMountPoints'])->getMock();
  278. /** @var \OCA\Encryption\Hooks\UserHooks $userHooks */
  279. $this->assertNull($userHooks->setPassphrase($this->params));
  280. }
  281. protected function setUp() {
  282. parent::setUp();
  283. $this->loggerMock = $this->createMock(ILogger::class);
  284. $this->keyManagerMock = $this->getMockBuilder(KeyManager::class)
  285. ->disableOriginalConstructor()
  286. ->getMock();
  287. $this->userManagerMock = $this->getMockBuilder(IUserManager::class)
  288. ->disableOriginalConstructor()
  289. ->getMock();
  290. $this->userSetupMock = $this->getMockBuilder(Setup::class)
  291. ->disableOriginalConstructor()
  292. ->getMock();
  293. $this->userSessionMock = $this->getMockBuilder(IUserSession::class)
  294. ->disableOriginalConstructor()
  295. ->setMethods([
  296. 'isLoggedIn',
  297. 'getUID',
  298. 'login',
  299. 'logout',
  300. 'setUser',
  301. 'getUser',
  302. 'canChangePassword'
  303. ])
  304. ->getMock();
  305. $this->userSessionMock->expects($this->any())->method('getUID')->will($this->returnValue('testUser'));
  306. $this->userSessionMock->expects($this->any())
  307. ->method($this->anything())
  308. ->will($this->returnSelf());
  309. $utilMock = $this->getMockBuilder(Util::class)
  310. ->disableOriginalConstructor()
  311. ->getMock();
  312. $sessionMock = $this->getMockBuilder(Session::class)
  313. ->disableOriginalConstructor()
  314. ->getMock();
  315. $this->cryptMock = $this->getMockBuilder(Crypt::class)
  316. ->disableOriginalConstructor()
  317. ->getMock();
  318. $recoveryMock = $this->getMockBuilder(Recovery::class)
  319. ->disableOriginalConstructor()
  320. ->getMock();
  321. $this->sessionMock = $sessionMock;
  322. $this->recoveryMock = $recoveryMock;
  323. $this->utilMock = $utilMock;
  324. $this->utilMock->expects($this->any())->method('isMasterKeyEnabled')->willReturn(false);
  325. $this->instance = $this->getMockBuilder(UserHooks::class)
  326. ->setConstructorArgs(
  327. [
  328. $this->keyManagerMock,
  329. $this->userManagerMock,
  330. $this->loggerMock,
  331. $this->userSetupMock,
  332. $this->userSessionMock,
  333. $this->utilMock,
  334. $this->sessionMock,
  335. $this->cryptMock,
  336. $this->recoveryMock
  337. ]
  338. )->setMethods(['setupFS'])->getMock();
  339. }
  340. }