ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
ilObjUserPasswordTest.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
20 use org\bovigo\vfs;
21 
22 require_once 'libs/composer/vendor/autoload.php';
23 require_once 'Services/User/classes/class.ilUserPasswordManager.php';
24 require_once 'Services/User/classes/class.ilUserPasswordEncoderFactory.php';
25 require_once 'Services/Password/classes/class.ilBasePasswordEncoder.php';
26 require_once 'Services/Utilities/classes/class.ilUtil.php';
27 require_once 'Services/User/classes/class.ilObjUser.php';
28 require_once 'Services/User/exceptions/class.ilUserException.php';
29 require_once 'Services/User/test/ilUserBaseTest.php';
30 
37 {
38  private const PASSWORD = 'password';
39  private const ENCODED_PASSWORD = 'encoded';
40 
41  protected vfs\vfsStreamDirectory $testDirectory;
42  protected string $testDirectoryUrl;
43 
44  public function getTestDirectory(): vfs\vfsStreamDirectory
45  {
46  return $this->testDirectory;
47  }
48 
49  public function setTestDirectory(vfs\vfsStreamDirectory $testDirectory): void
50  {
51  $this->testDirectory = $testDirectory;
52  }
53 
54  public function getTestDirectoryUrl(): string
55  {
57  }
58 
59  public function setTestDirectoryUrl(string $testDirectoryUrl): void
60  {
61  $this->testDirectoryUrl = $testDirectoryUrl;
62  }
63 
64  protected function setUp(): void
65  {
66  vfs\vfsStream::setup();
67  $this->setTestDirectory(vfs\vfsStream::newDirectory('tests')->at(vfs\vfsStreamWrapper::getRoot()));
68  $this->setTestDirectoryUrl(vfs\vfsStream::url('root/tests'));
69 
70  parent::setUp();
71  }
72 
77  {
78  $this->assertException(ilUserException::class);
79  new ilUserPasswordManager(['data_directory' => $this->getTestDirectoryUrl()]);
80  }
81 
86  {
87  $this->assertException(ilUserException::class);
89  'password_encoder' => 'md5',
90  'data_directory' => $this->getTestDirectoryUrl()
91  ]);
92  }
93 
98  {
99  $this->expectException(TypeError::class);
100  $this->expectExceptionMessageMatches('/' . ilUserPasswordEncoderFactory::class . '/');
101 
103  'password_encoder' => 'md5',
104  'encoder_factory' => 'test',
105  'data_directory' => $this->getTestDirectoryUrl()
106  ]);
107  }
108 
113  public function testInstanceCanBeCreated(): void
114  {
115  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
116  $factory_mock->expects($this->exactly(2))->method('getSupportedEncoderNames')->will($this->onConsecutiveCalls(
117  [
118  'mockencoder',
119  'second_mockencoder'
120  ],
121  [
122  'mockencoder'
123  ]
124  ));
125 
126  $password_manager = new ilUserPasswordManager([
127  'password_encoder' => 'md5',
128  'encoder_factory' => $factory_mock,
129  'data_directory' => $this->getTestDirectoryUrl()
130  ]);
131  $this->assertInstanceOf('ilUserPasswordManager', $password_manager);
132  $this->assertEquals('md5', $password_manager->getEncoderName());
133  $this->assertEquals($factory_mock, $password_manager->getEncoderFactory());
134 
135  $this->assertTrue($password_manager->isEncodingTypeSupported('second_mockencoder'));
136  $this->assertFalse($password_manager->isEncodingTypeSupported('second_mockencoder'));
137  }
138 
144  {
145  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
146  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
147  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
148 
149  $user_mock->expects($this->once())->method('setPasswordSalt')->with($this->isType('string'));
150  $user_mock->expects($this->once())->method('getPasswordSalt')->willReturn('asuperrandomsalt');
151  $user_mock->expects($this->once())->method('setPasswordEncodingType')->with($this->equalTo('mockencoder'));
152  $user_mock->expects($this->once())->method('setPasswd')->with(
153  $this->equalTo(self::ENCODED_PASSWORD),
154  $this->equalTo(ilObjUser::PASSWD_CRYPTED)
155  );
156 
157  $encoder->expects($this->once())->method('getName')->willReturn('mockencoder');
158  $encoder->expects($this->once())->method('requiresSalt')->willReturn(true);
159  $encoder->expects($this->once())->method('encodePassword')
160  ->with(
161  $this->equalTo(self::PASSWORD),
162  $this->isType('string')
163  )->willReturn(self::ENCODED_PASSWORD);
164 
165  $factory_mock->expects($this->once())->method('getEncoderByName')->willReturn($encoder);
166 
167  $password_manager = new ilUserPasswordManager([
168  'password_encoder' => 'mockencoder',
169  'encoder_factory' => $factory_mock,
170  'data_directory' => $this->getTestDirectoryUrl()
171  ]);
172 
173  $password_manager->encodePassword($user_mock, self::PASSWORD);
174  }
175 
181  {
182  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
183  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
184  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
185 
186  $user_mock->expects($this->once())->method('setPasswordSalt')->with($this->equalTo(null));
187  $user_mock->expects($this->once())->method('getPasswordSalt')->willReturn(null);
188  $user_mock->expects($this->once())->method('setPasswordEncodingType')->with($this->equalTo('mockencoder'));
189  $user_mock->expects($this->once())->method('setPasswd')->with(
190  $this->equalTo(self::ENCODED_PASSWORD),
191  $this->equalTo(ilObjUser::PASSWD_CRYPTED)
192  );
193 
194  $encoder->expects($this->once())->method('getName')->willReturn('mockencoder');
195  $encoder->expects($this->once())->method('requiresSalt')->willReturn(false);
196  $encoder->expects($this->once())->method('encodePassword')->with(
197  $this->equalTo(self::PASSWORD),
198  $this->equalTo(null)
199  )->willReturn(self::ENCODED_PASSWORD);
200 
201  $factory_mock->expects($this->once())->method('getEncoderByName')->willReturn($encoder);
202 
203  $password_manager = new ilUserPasswordManager([
204  'password_encoder' => 'mockencoder',
205  'encoder_factory' => $factory_mock,
206  'data_directory' => $this->getTestDirectoryUrl()
207  ]);
208 
209  $password_manager->encodePassword($user_mock, self::PASSWORD);
210  }
211 
216  public function testPasswordManagerVerifiesPassword(): void
217  {
218  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
219  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
220  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
221 
222  $user_mock->expects($this->atLeast(1))->method('getPasswordSalt')->willReturn('asuperrandomsalt');
223  $user_mock->expects($this->atLeast(1))->method('getPasswordEncodingType')->willReturn('mockencoder');
224  $user_mock->expects($this->atLeast(1))->method('getPasswd')->willReturn(self::ENCODED_PASSWORD);
225  $user_mock->expects($this->never())->method('resetPassword');
226 
227  $encoder->expects($this->once())->method('getName')->willReturn('mockencoder');
228  $encoder->expects($this->once())->method('isPasswordValid')->with(
229  $this->equalTo(self::ENCODED_PASSWORD),
230  $this->equalTo(self::PASSWORD),
231  $this->isType('string')
232  )->willReturn(true);
233  $encoder->expects($this->once())->method('requiresReencoding')
234  ->with($this->equalTo(self::ENCODED_PASSWORD))
235  ->willReturn(false);
236 
237  $factory_mock->expects($this->once())->method('getEncoderByName')->willReturn($encoder);
238 
239  $password_manager = new ilUserPasswordManager([
240  'password_encoder' => 'mockencoder',
241  'encoder_factory' => $factory_mock,
242  'data_directory' => $this->getTestDirectoryUrl()
243  ]);
244 
245  $this->assertTrue($password_manager->verifyPassword($user_mock, self::PASSWORD));
246  }
247 
253  {
254  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
255  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
256  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
257 
258  $user_mock->expects($this->once())->method('getPasswordSalt')->willReturn('asuperrandomsalt');
259  $user_mock->expects($this->once())->method('getPasswordEncodingType')->willReturn('second_mockencoder');
260  $user_mock->expects($this->once())->method('getPasswd')->willReturn(self::ENCODED_PASSWORD);
261  $user_mock->expects($this->once())->method('resetPassword')->with(
262  $this->equalTo(self::PASSWORD),
263  $this->equalTo(self::PASSWORD)
264  );
265 
266  $encoder->expects($this->once())->method('getName')->willReturn('second_mockencoder');
267  $encoder->expects($this->once())->method('isPasswordValid')->with(
268  $this->equalTo(self::ENCODED_PASSWORD),
269  $this->equalTo(self::PASSWORD),
270  $this->isType('string')
271  )->willReturn(true);
272  $encoder->expects($this->never())->method('requiresReencoding')
273  ->with($this->equalTo(self::ENCODED_PASSWORD))
274  ->willReturn(false);
275 
276  $factory_mock->expects($this->once())->method('getEncoderByName')->willReturn($encoder);
277 
278  $password_manager = new ilUserPasswordManager([
279  'password_encoder' => 'mockencoder',
280  'encoder_factory' => $factory_mock,
281  'data_directory' => $this->getTestDirectoryUrl()
282  ]);
283 
284  $this->assertTrue($password_manager->verifyPassword($user_mock, self::PASSWORD));
285  }
286 
292  {
293  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
294  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
295  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
296 
297  $user_mock->expects($this->once())->method('getPasswordSalt')->willReturn('asuperrandomsalt');
298  $user_mock->expects($this->once())->method('getPasswordEncodingType')->willReturn('mockencoder');
299  $user_mock->expects($this->exactly(2))->method('getPasswd')->willReturn(self::ENCODED_PASSWORD);
300  $user_mock->expects($this->once())->method('resetPassword')->with(
301  $this->equalTo(self::PASSWORD),
302  $this->equalTo(self::PASSWORD)
303  );
304 
305  $encoder->expects($this->once())->method('getName')->willReturn('mockencoder');
306  $encoder->expects($this->once())->method('isPasswordValid')->with(
307  $this->equalTo(self::ENCODED_PASSWORD),
308  $this->equalTo(self::PASSWORD),
309  $this->isType('string')
310  )->willReturn(true);
311  $encoder->expects($this->once())->method('requiresReencoding')
312  ->with($this->equalTo(self::ENCODED_PASSWORD))
313  ->willReturn(true);
314 
315  $factory_mock->expects($this->once())->method('getEncoderByName')->willReturn($encoder);
316 
317  $password_manager = new ilUserPasswordManager([
318  'password_encoder' => 'mockencoder',
319  'encoder_factory' => $factory_mock,
320  'data_directory' => $this->getTestDirectoryUrl()
321  ]);
322 
323  $this->assertTrue($password_manager->verifyPassword($user_mock, self::PASSWORD));
324  }
325 
331  {
332  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
333  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
334  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
335 
336  $user_mock->expects($this->once())->method('getPasswordSalt')->willReturn('asuperrandomsalt');
337  $user_mock->expects($this->once())->method('getPasswordEncodingType')->willReturn('second_mockencoder');
338  $user_mock->expects($this->once())->method('getPasswd')->willReturn(self::ENCODED_PASSWORD);
339  $user_mock->expects($this->never())->method('resetPassword');
340 
341  $encoder->expects($this->once())->method('getName')->willReturn('second_mockencoder');
342  $encoder->expects($this->never())->method('requiresReencoding');
343  $encoder->expects($this->once())->method('isPasswordValid')
344  ->with(
345  $this->equalTo(self::ENCODED_PASSWORD),
346  $this->equalTo(self::PASSWORD),
347  $this->isType('string')
348  )->willReturn(false);
349 
350  $factory_mock->expects($this->once())->method('getEncoderByName')->willReturn($encoder);
351 
352  $password_manager = new ilUserPasswordManager([
353  'password_encoder' => 'mockencoder',
354  'encoder_factory' => $factory_mock,
355  'data_directory' => $this->getTestDirectoryUrl()
356  ]);
357 
358  $this->assertFalse($password_manager->verifyPassword($user_mock, self::PASSWORD));
359  }
360 
364  public function testFactoryCanBeCreated(): void
365  {
367  'data_directory' => $this->getTestDirectoryUrl()
368  ]);
369  $this->assertInstanceOf('ilUserPasswordEncoderFactory', $factory);
370  }
371 
378  {
380  'default_password_encoder' => 'md5',
381  'data_directory' => $this->getTestDirectoryUrl()
382  ]);
383  $this->assertEquals('md5', $factory->getDefaultEncoder());
384 
385  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
386  $encoder->expects($this->atLeastOnce())->method('getName')->willReturn('mockencoder');
387 
388  $second_mockencoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
389  $second_mockencoder->expects($this->atLeastOnce())->method('getName')->willReturn('second_mockencoder');
390 
391  $factory->setEncoders([$encoder, $second_mockencoder]);
392  $this->assertCount(2, $factory->getEncoders());
393  $this->assertCount(2, $factory->getSupportedEncoderNames());
394  $this->assertCount(
395  0,
396  array_diff(['mockencoder', 'second_mockencoder'], $factory->getSupportedEncoderNames())
397  );
398  $this->assertCount(
399  0,
400  array_diff($factory->getSupportedEncoderNames(), ['mockencoder', 'second_mockencoder'])
401  );
402  }
403 
408  /*
409  public function testFactoryRaisesAnExceptionIfAnUnsupportedEncoderWasInjected() : void
410  {
411  $this->assertException(ilUserException::class);
412  $factory = new ilUserPasswordEncoderFactory([
413  'data_directory' => $this->getTestDirectoryUrl()
414  ]);
415  $factory->setEncoders(['phpunit']);
416  }*/
417 
423  {
424  $this->assertException(ilUserException::class);
426  'default_password_encoder' => 'md5',
427  'data_directory' => $this->getTestDirectoryUrl()
428  ]);
429  $factory->getEncoderByName('phpunit');
430  }
431 
437  {
438  $this->assertException(ilUserException::class);
440  'data_directory' => $this->getTestDirectoryUrl()
441  ]);
442  $factory->getEncoderByName('phpunit', true);
443  }
444 
450  {
451  $this->assertException(ilUserException::class);
453  'default_password_encoder' => 'phpunit',
454  'data_directory' => $this->getTestDirectoryUrl()
455  ]);
456  $factory->getEncoderByName('phpunit', true);
457  }
458 
465  {
466  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
467  $encoder->expects($this->atLeastOnce())->method('getName')->willReturn('mockencoder');
468 
470  'default_password_encoder' => $encoder->getName(),
471  'data_directory' => $this->getTestDirectoryUrl()
472  ]);
473  $factory->setEncoders([$encoder]);
474  $this->assertEquals($encoder, $factory->getEncoderByName('phpunit', true));
475  }
476 
483  {
484  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
485  $encoder->expects($this->atLeastOnce())->method('getName')->willReturn('mockencoder');
486 
488  'default_password_encoder' => $encoder->getName(),
489  'data_directory' => $this->getTestDirectoryUrl()
490  ]);
491  $factory->setEncoders([$encoder]);
492  $this->assertEquals($encoder, $factory->getEncoderByName('mockencoder', true));
493  }
494 }
testPasswordManagerNeverMigratesPasswordOnFailedVerificationWithVariantEncoders()
testExceptionIsRaisedIfPasswordManagerIsCreatedWithoutValidFactory()
testFactoryReturnsTheDefaultEncoderIfAnUnsupportedEncoderIsRequestedAndASupportedDefaultEncoderWasSpecifiedInFallbackMode()
testExceptionIsRaisedIfAnUnsupportedEncoderIsRequestedFromFactory()
setTestDirectoryUrl(string $testDirectoryUrl)
testExceptionIsRaisedIfPasswordManagerIsCreatedWithoutEncoderInformation()
assertException(string $exception_class)
vfs vfsStreamDirectory $testDirectory
setTestDirectory(vfs\vfsStreamDirectory $testDirectory)
testFactoryRaisesAnExceptionIfAnUnsupportedEncoderIsRequestedAndNoDefaultEncoderWasSpecifiedInFallbackMode()
const PASSWD_CRYPTED
testFactoryRaisesAnExceptionIfAnUnsupportedEncoderIsRequestedAndTheDefaultEncoderDoesNotMatchOneOfTheSupportedEncodersInFallbackMode()
testPasswordManagerMigratesPasswordOnVerificationWithVariantEncoders()
testExceptionIsRaisedIfPasswordManagerIsCreatedWithoutFactory()
$factory
Definition: metadata.php:75