ILIAS  release_7 Revision v7.30-3-g800a261c036
All Data Structures Namespaces Files Functions Variables Modules Pages
ilObjUserPasswordTest.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (c) 1998-2014 ILIAS open source, Extended GPL, see docs/LICENSE */
3 
5 
6 require_once 'libs/composer/vendor/autoload.php';
7 require_once 'Services/User/classes/class.ilUserPasswordManager.php';
8 require_once 'Services/User/classes/class.ilUserPasswordEncoderFactory.php';
9 require_once 'Services/Password/classes/class.ilBasePasswordEncoder.php';
10 require_once 'Services/Utilities/classes/class.ilUtil.php';
11 require_once 'Services/User/classes/class.ilObjUser.php';
12 require_once 'Services/User/exceptions/class.ilUserException.php';
13 require_once 'Services/User/test/ilUserBaseTest.php';
14 
21 {
23  const PASSWORD = 'password';
24 
26  const ENCODED_PASSWORD = 'encoded';
27 
29  protected $testDirectory;
30 
32  protected $testDirectoryUrl;
33 
37  public function getTestDirectory() : vfs\vfsStreamDirectory
38  {
39  return $this->testDirectory;
40  }
41 
45  public function setTestDirectory(vfs\vfsStreamDirectory $testDirectory) : void
46  {
47  $this->testDirectory = $testDirectory;
48  }
49 
53  public function getTestDirectoryUrl() : string
54  {
56  }
57 
61  public function setTestDirectoryUrl(string $testDirectoryUrl) : void
62  {
63  $this->testDirectoryUrl = $testDirectoryUrl;
64  }
65 
69  protected function setUp() : void
70  {
71  vfs\vfsStream::setup();
72  $this->setTestDirectory(vfs\vfsStream::newDirectory('tests')->at(vfs\vfsStreamWrapper::getRoot()));
73  $this->setTestDirectoryUrl(vfs\vfsStream::url('root/tests'));
74 
75  parent::setUp();
76  }
77 
82  {
83  $this->assertException(ilUserException::class);
84  new ilUserPasswordManager(['data_directory' => $this->getTestDirectoryUrl()]);
85  }
86 
91  {
92  $this->assertException(ilUserException::class);
94  'password_encoder' => 'md5',
95  'data_directory' => $this->getTestDirectoryUrl()
96  ]);
97  }
98 
103  {
104  if (version_compare(\PHPUnit\Runner\Version::id(), '9.0', '>=')) {
105  $this->expectError(PHPUnit\Framework\Error\Error::class);
106  } else {
107  $this->assertException(PHPUnit\Framework\Error\Error::class);
108  }
109 
110  try {
112  'password_encoder' => 'md5',
113  'encoder_factory' => 'test',
114  'data_directory' => $this->getTestDirectoryUrl()
115  ]);
116  } catch (TypeError $e) {
117  throw new PHPUnit\Framework\Error\Error($e->getMessage(), $e->getCode(), $e->getFile(), $e->getLine());
118  }
119  }
120 
125  public function testInstanceCanBeCreated() : void
126  {
127  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
128  $factory_mock->expects($this->exactly(2))->method('getSupportedEncoderNames')->will($this->onConsecutiveCalls(
129  [
130  'mockencoder',
131  'second_mockencoder'
132  ],
133  [
134  'mockencoder'
135  ]
136  ));
137 
138  $password_manager = new ilUserPasswordManager([
139  'password_encoder' => 'md5',
140  'encoder_factory' => $factory_mock,
141  'data_directory' => $this->getTestDirectoryUrl()
142  ]);
143  $this->assertInstanceOf('ilUserPasswordManager', $password_manager);
144  $this->assertEquals('md5', $password_manager->getEncoderName());
145  $this->assertEquals($factory_mock, $password_manager->getEncoderFactory());
146 
147  $this->assertTrue($password_manager->isEncodingTypeSupported('second_mockencoder'));
148  $this->assertFalse($password_manager->isEncodingTypeSupported('second_mockencoder'));
149  }
150 
156  {
157  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
158  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
159  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
160 
161  $user_mock->expects($this->once())->method('setPasswordSalt')->with($this->isType('string'));
162  $user_mock->expects($this->once())->method('getPasswordSalt')->will($this->returnValue('asuperrandomsalt'));
163  $user_mock->expects($this->once())->method('setPasswordEncodingType')->with($this->equalTo('mockencoder'));
164  $user_mock->expects($this->once())->method('setPasswd')->with(
165  $this->equalTo(self::ENCODED_PASSWORD),
166  $this->equalTo(IL_PASSWD_CRYPTED)
167  );
168 
169  $encoder->expects($this->once())->method('getName')->will($this->returnValue('mockencoder'));
170  $encoder->expects($this->once())->method('requiresSalt')->will($this->returnValue(true));
171  $encoder->expects($this->once())->method('encodePassword')
172  ->with(
173  $this->equalTo(self::PASSWORD),
174  $this->isType('string')
175  )->will($this->returnValue(self::ENCODED_PASSWORD));
176 
177  $factory_mock->expects($this->once())->method('getEncoderByName')->will($this->returnValue($encoder));
178 
179  $password_manager = new ilUserPasswordManager([
180  'password_encoder' => 'mockencoder',
181  'encoder_factory' => $factory_mock,
182  'data_directory' => $this->getTestDirectoryUrl()
183  ]);
184 
185  $password_manager->encodePassword($user_mock, self::PASSWORD);
186  }
187 
193  {
194  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
195  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
196  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
197 
198  $user_mock->expects($this->once())->method('setPasswordSalt')->with($this->equalTo(null));
199  $user_mock->expects($this->once())->method('getPasswordSalt')->will($this->returnValue(null));
200  $user_mock->expects($this->once())->method('setPasswordEncodingType')->with($this->equalTo('mockencoder'));
201  $user_mock->expects($this->once())->method('setPasswd')->with(
202  $this->equalTo(self::ENCODED_PASSWORD),
203  $this->equalTo(IL_PASSWD_CRYPTED)
204  );
205 
206  $encoder->expects($this->once())->method('getName')->will($this->returnValue('mockencoder'));
207  $encoder->expects($this->once())->method('requiresSalt')->will($this->returnValue(false));
208  $encoder->expects($this->once())->method('encodePassword')->with(
209  $this->equalTo(self::PASSWORD),
210  $this->equalTo(null)
211  )->will($this->returnValue(self::ENCODED_PASSWORD));
212 
213  $factory_mock->expects($this->once())->method('getEncoderByName')->will($this->returnValue($encoder));
214 
215  $password_manager = new ilUserPasswordManager([
216  'password_encoder' => 'mockencoder',
217  'encoder_factory' => $factory_mock,
218  'data_directory' => $this->getTestDirectoryUrl()
219  ]);
220 
221  $password_manager->encodePassword($user_mock, self::PASSWORD);
222  }
223 
228  public function testPasswordManagerVerifiesPassword() : void
229  {
230  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
231  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
232  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
233 
234  $user_mock->expects($this->atLeast(1))->method('getPasswordSalt')->will($this->returnValue('asuperrandomsalt'));
235  $user_mock->expects($this->atLeast(1))->method('getPasswordEncodingType')->will($this->returnValue('mockencoder'));
236  $user_mock->expects($this->atLeast(1))->method('getPasswd')->will($this->returnValue(self::ENCODED_PASSWORD));
237  $user_mock->expects($this->never())->method('resetPassword');
238 
239  $encoder->expects($this->once())->method('getName')->will($this->returnValue('mockencoder'));
240  $encoder->expects($this->once())->method('isPasswordValid')->with(
241  $this->equalTo(self::ENCODED_PASSWORD),
242  $this->equalTo(self::PASSWORD),
243  $this->isType('string')
244  )->will($this->returnValue(true));
245  $encoder->expects($this->once())->method('requiresReencoding')
246  ->with($this->equalTo(self::ENCODED_PASSWORD))
247  ->will($this->returnValue(false));
248 
249  $factory_mock->expects($this->once())->method('getEncoderByName')->will($this->returnValue($encoder));
250 
251  $password_manager = new ilUserPasswordManager([
252  'password_encoder' => 'mockencoder',
253  'encoder_factory' => $factory_mock,
254  'data_directory' => $this->getTestDirectoryUrl()
255  ]);
256 
257  $this->assertTrue($password_manager->verifyPassword($user_mock, self::PASSWORD));
258  }
259 
265  {
266  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
267  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
268  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
269 
270  $user_mock->expects($this->once())->method('getPasswordSalt')->will($this->returnValue('asuperrandomsalt'));
271  $user_mock->expects($this->once())->method('getPasswordEncodingType')->will($this->returnValue('second_mockencoder'));
272  $user_mock->expects($this->once())->method('getPasswd')->will($this->returnValue(self::ENCODED_PASSWORD));
273  $user_mock->expects($this->once())->method('resetPassword')->with(
274  $this->equalTo(self::PASSWORD),
275  $this->equalTo(self::PASSWORD)
276  );
277 
278  $encoder->expects($this->once())->method('getName')->will($this->returnValue('second_mockencoder'));
279  $encoder->expects($this->once())->method('isPasswordValid')->with(
280  $this->equalTo(self::ENCODED_PASSWORD),
281  $this->equalTo(self::PASSWORD),
282  $this->isType('string')
283  )->will($this->returnValue(true));
284  $encoder->expects($this->never())->method('requiresReencoding')
285  ->with($this->equalTo(self::ENCODED_PASSWORD))
286  ->will($this->returnValue(false));
287 
288  $factory_mock->expects($this->once())->method('getEncoderByName')->will($this->returnValue($encoder));
289 
290  $password_manager = new ilUserPasswordManager([
291  'password_encoder' => 'mockencoder',
292  'encoder_factory' => $factory_mock,
293  'data_directory' => $this->getTestDirectoryUrl()
294  ]);
295 
296  $this->assertTrue($password_manager->verifyPassword($user_mock, self::PASSWORD));
297  }
298 
304  {
305  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
306  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
307  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
308 
309  $user_mock->expects($this->once())->method('getPasswordSalt')->will($this->returnValue('asuperrandomsalt'));
310  $user_mock->expects($this->once())->method('getPasswordEncodingType')->will($this->returnValue('mockencoder'));
311  $user_mock->expects($this->exactly(2))->method('getPasswd')->will($this->returnValue(self::ENCODED_PASSWORD));
312  $user_mock->expects($this->once())->method('resetPassword')->with(
313  $this->equalTo(self::PASSWORD),
314  $this->equalTo(self::PASSWORD)
315  );
316 
317  $encoder->expects($this->once())->method('getName')->will($this->returnValue('mockencoder'));
318  $encoder->expects($this->once())->method('isPasswordValid')->with(
319  $this->equalTo(self::ENCODED_PASSWORD),
320  $this->equalTo(self::PASSWORD),
321  $this->isType('string')
322  )->will($this->returnValue(true));
323  $encoder->expects($this->once())->method('requiresReencoding')
324  ->with($this->equalTo(self::ENCODED_PASSWORD))
325  ->will($this->returnValue(true));
326 
327  $factory_mock->expects($this->once())->method('getEncoderByName')->will($this->returnValue($encoder));
328 
329  $password_manager = new ilUserPasswordManager([
330  'password_encoder' => 'mockencoder',
331  'encoder_factory' => $factory_mock,
332  'data_directory' => $this->getTestDirectoryUrl()
333  ]);
334 
335  $this->assertTrue($password_manager->verifyPassword($user_mock, self::PASSWORD));
336  }
337 
343  {
344  $user_mock = $this->getMockBuilder(ilObjUser::class)->disableOriginalConstructor()->getMock();
345  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
346  $factory_mock = $this->getMockBuilder(ilUserPasswordEncoderFactory::class)->disableOriginalConstructor()->getMock();
347 
348  $user_mock->expects($this->once())->method('getPasswordSalt')->will($this->returnValue('asuperrandomsalt'));
349  $user_mock->expects($this->once())->method('getPasswordEncodingType')->will($this->returnValue('second_mockencoder'));
350  $user_mock->expects($this->once())->method('getPasswd')->will($this->returnValue(self::ENCODED_PASSWORD));
351  $user_mock->expects($this->never())->method('resetPassword');
352 
353  $encoder->expects($this->once())->method('getName')->will($this->returnValue('second_mockencoder'));
354  $encoder->expects($this->never())->method('requiresReencoding');
355  $encoder->expects($this->once())->method('isPasswordValid')
356  ->with(
357  $this->equalTo(self::ENCODED_PASSWORD),
358  $this->equalTo(self::PASSWORD),
359  $this->isType('string')
360  )->will($this->returnValue(false));
361 
362  $factory_mock->expects($this->once())->method('getEncoderByName')->will($this->returnValue($encoder));
363 
364  $password_manager = new ilUserPasswordManager([
365  'password_encoder' => 'mockencoder',
366  'encoder_factory' => $factory_mock,
367  'data_directory' => $this->getTestDirectoryUrl()
368  ]);
369 
370  $this->assertFalse($password_manager->verifyPassword($user_mock, self::PASSWORD));
371  }
372 
376  public function testFactoryCanBeCreated() : void
377  {
379  'data_directory' => $this->getTestDirectoryUrl()
380  ]);
381  $this->assertInstanceOf('ilUserPasswordEncoderFactory', $factory);
382  }
383 
390  {
392  'default_password_encoder' => 'md5',
393  'data_directory' => $this->getTestDirectoryUrl()
394  ]);
395  $this->assertEquals('md5', $factory->getDefaultEncoder());
396 
397  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
398  $encoder->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('mockencoder'));
399 
400  $second_mockencoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
401  $second_mockencoder->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('second_mockencoder'));
402 
403  $factory->setEncoders([$encoder, $second_mockencoder]);
404  $this->assertCount(2, $factory->getEncoders());
405  $this->assertCount(2, $factory->getSupportedEncoderNames());
406  $this->assertCount(
407  0,
408  array_diff(['mockencoder', 'second_mockencoder'], $factory->getSupportedEncoderNames())
409  );
410  $this->assertCount(
411  0,
412  array_diff($factory->getSupportedEncoderNames(), ['mockencoder', 'second_mockencoder'])
413  );
414  }
415 
421  {
422  $this->assertException(ilUserException::class);
424  'data_directory' => $this->getTestDirectoryUrl()
425  ]);
426  $factory->setEncoders(['phpunit']);
427  }
428 
434  {
435  $this->assertException(ilUserException::class);
437  'default_password_encoder' => 'md5',
438  'data_directory' => $this->getTestDirectoryUrl()
439  ]);
440  $factory->getEncoderByName('phpunit');
441  }
442 
448  {
449  $this->assertException(ilUserException::class);
451  'data_directory' => $this->getTestDirectoryUrl()
452  ]);
453  $factory->getEncoderByName('phpunit', true);
454  }
455 
461  {
462  $this->assertException(ilUserException::class);
464  'default_password_encoder' => 'phpunit',
465  'data_directory' => $this->getTestDirectoryUrl()
466  ]);
467  $factory->getEncoderByName('phpunit', true);
468  }
469 
476  {
477  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
478  $encoder->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('mockencoder'));
479 
481  'default_password_encoder' => $encoder->getName(),
482  'data_directory' => $this->getTestDirectoryUrl()
483  ]);
484  $factory->setEncoders([$encoder]);
485  $this->assertEquals($encoder, $factory->getEncoderByName('phpunit', true));
486  }
487 
494  {
495  $encoder = $this->getMockBuilder(ilBasePasswordEncoder::class)->disableOriginalConstructor()->getMock();
496  $encoder->expects($this->atLeastOnce())->method('getName')->will($this->returnValue('mockencoder'));
497 
499  'default_password_encoder' => $encoder->getName(),
500  'data_directory' => $this->getTestDirectoryUrl()
501  ]);
502  $factory->setEncoders([$encoder]);
503  $this->assertEquals($encoder, $factory->getEncoderByName('mockencoder', true));
504  }
505 }
testPasswordManagerNeverMigratesPasswordOnFailedVerificationWithVariantEncoders()
testExceptionIsRaisedIfPasswordManagerIsCreatedWithoutValidFactory()
testFactoryReturnsTheDefaultEncoderIfAnUnsupportedEncoderIsRequestedAndASupportedDefaultEncoderWasSpecifiedInFallbackMode()
testFactoryRaisesAnExceptionIfAnUnsupportedEncoderWasInjected()
testExceptionIsRaisedIfAnUnsupportedEncoderIsRequestedFromFactory()
assertException($exception_class)
const IL_PASSWD_CRYPTED
setTestDirectoryUrl(string $testDirectoryUrl)
testExceptionIsRaisedIfPasswordManagerIsCreatedWithoutEncoderInformation()
setTestDirectory(vfs\vfsStreamDirectory $testDirectory)
testFactoryRaisesAnExceptionIfAnUnsupportedEncoderIsRequestedAndNoDefaultEncoderWasSpecifiedInFallbackMode()
testFactoryRaisesAnExceptionIfAnUnsupportedEncoderIsRequestedAndTheDefaultEncoderDoesNotMatchOneOfTheSupportedEncodersInFallbackMode()
testPasswordManagerMigratesPasswordOnVerificationWithVariantEncoders()
testExceptionIsRaisedIfPasswordManagerIsCreatedWithoutFactory()
$factory
Definition: metadata.php:58