Skip to content

Commit d217813

Browse files
authored
Merge pull request #1171 from CakeDC/feature/gb-1170
Feature/gb 1170
2 parents 92e6dbc + bdac80e commit d217813

File tree

2 files changed

+244
-34
lines changed

2 files changed

+244
-34
lines changed

config/users.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,9 @@
284284
],
285285
'RbacPolicy' => [],
286286
'PasswordRehash' => [
287-
'identifiers' => ['Password'],
287+
'authenticators' => [
288+
'Form' => 'Authentication.Password',
289+
],
288290
],
289291
],
290292
'OAuth' => [

tests/TestCase/Controller/Traits/LoginTraitTest.php

Lines changed: 241 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace CakeDC\Users\Test\TestCase\Controller\Traits;
1515

16+
use Authentication\Authenticator\AuthenticatorCollection;
1617
use Authentication\Authenticator\Result;
1718
use Authentication\Authenticator\SessionAuthenticator;
1819
use Authentication\Identifier\IdentifierCollection;
@@ -22,6 +23,7 @@
2223
use Cake\Event\Event;
2324
use Cake\Http\Response;
2425
use Cake\Http\ServerRequest;
26+
use CakeDC\Auth\Authentication\AuthenticationService;
2527
use CakeDC\Auth\Authentication\Failure;
2628
use CakeDC\Auth\Authenticator\FormAuthenticator;
2729
use CakeDC\Users\Authenticator\SocialAuthenticator;
@@ -48,9 +50,9 @@ public function setUp(): void
4850
->getMock();
4951

5052
// $this->Trait->Auth = $this->getMockBuilder('Cake\Controller\Component\AuthComponent')
51-
// ->onlyMethods(['setConfig'])
52-
// ->disableOriginalConstructor()
53-
// ->getMock();
53+
// ->onlyMethods(['setConfig'])
54+
// ->disableOriginalConstructor()
55+
// ->getMock();
5456
}
5557

5658
/**
@@ -147,76 +149,282 @@ public function testLoginHappy()
147149
*/
148150
public function testLoginRehash()
149151
{
152+
\Cake\Core\Configure::write('Auth.PasswordRehash', [
153+
'authenticators' => [
154+
'Form' => 'Password',
155+
],
156+
]);
157+
150158
$passwordIdentifier = $this->getMockBuilder(PasswordIdentifier::class)
151159
->onlyMethods(['needsPasswordRehash'])
152160
->getMock();
153161
$passwordIdentifier->expects($this->any())
154162
->method('needsPasswordRehash')
155163
->willReturn(true);
156-
$identifiers = new IdentifierCollection([]);
157-
$identifiers->set('Password', $passwordIdentifier);
158164

159-
$SessionAuth = new SessionAuthenticator($identifiers);
165+
$identifierCollection = new IdentifierCollection([]);
166+
$identifierCollection->set('Password', $passwordIdentifier);
160167

161-
$sessionFailure = new Failure(
162-
$SessionAuth,
163-
new Result(null, Result::FAILURE_IDENTITY_NOT_FOUND),
164-
);
165-
$failures = [$sessionFailure];
168+
$formAuthenticator = $this->getMockBuilder(FormAuthenticator::class)
169+
->disableOriginalConstructor()
170+
->addMethods(['getIdentifier'])
171+
->getMock();
172+
$formAuthenticator->expects($this->any())
173+
->method('getIdentifier')
174+
->willReturn($identifierCollection);
175+
176+
$authenticatorCollection = $this->getMockBuilder(AuthenticatorCollection::class)
177+
->disableOriginalConstructor()
178+
->getMock();
179+
$authenticatorCollection->expects($this->any())
180+
->method('has')->with('Form')->willReturn(true);
181+
$authenticatorCollection->expects($this->any())
182+
->method('get')->with('Form')->willReturn($formAuthenticator);
166183

184+
$user = $this->Trait->getUsersTable()->get('00000000-0000-0000-0000-000000000002');
185+
$passwordBefore = $user['password'];
167186
$userPassword = 'testLoginRehash' . time();
187+
188+
$service = $this->getMockBuilder(AuthenticationService::class)
189+
->disableOriginalConstructor()
190+
->getMock();
191+
$service->expects($this->any())
192+
->method('authenticators')
193+
->willReturn($authenticatorCollection);
194+
$service->expects($this->any())
195+
->method('identifiers')
196+
->willReturn(new IdentifierCollection([]));
197+
$service->expects($this->any())
198+
->method('getAuthenticationProvider')
199+
->willReturn($formAuthenticator);
200+
201+
$result = new Result($user, Result::SUCCESS);
202+
$service->expects($this->any())->method('getResult')->willReturn($result);
203+
168204
$this->_mockDispatchEvent(new Event('event'));
169-
$this->_mockRequestPost();
170-
$this->Trait->getRequest()->expects($this->any())
205+
206+
$request = $this->getMockBuilder('Cake\Http\ServerRequest')
207+
->onlyMethods(['is', 'getData'])
208+
->getMock();
209+
210+
$request->expects($this->any())
211+
->method('is')
212+
->with('post')
213+
->willReturn(true);
214+
215+
$request->expects($this->any())
171216
->method('getData')
172-
->with($this->equalTo('password'))
173-
->willReturn($userPassword);
217+
->willReturnCallback(function ($key = null) use ($userPassword, $user) {
218+
if ($key === 'password') {
219+
return $userPassword;
220+
}
221+
if ($key === 'username' || $key === 'email') {
222+
return $user->email;
223+
}
224+
225+
return [];
226+
});
227+
228+
$identityWrapper = new \Authentication\Identity($user);
229+
$request = $request->withAttribute('authentication', $service);
230+
$request = $request->withAttribute('identity', $identityWrapper);
231+
232+
$this->Trait->setRequest($request);
233+
234+
$authComponent = $this->getMockBuilder(\Cake\Controller\Component::class)
235+
->disableOriginalConstructor()
236+
->onlyMethods(['getConfig'])
237+
->getMock();
238+
$authComponent->expects($this->any())
239+
->method('getConfig')
240+
->with('loginRedirect')
241+
->willReturn('/home');
242+
243+
$this->Trait->components()->set('Authentication', $authComponent);
174244

175245
$this->_mockFlash();
176-
$user = $this->Trait->getUsersTable()->get('00000000-0000-0000-0000-000000000002');
177-
$passwordBefore = $user['password'];
178-
$this->assertNotEmpty($passwordBefore);
179-
$this->_mockAuthentication($user->toArray(), $failures, $identifiers);
180246
$this->Trait->Flash->expects($this->never())
181247
->method('error');
248+
182249
$this->Trait->expects($this->once())
183250
->method('redirect')
184251
->with($this->successLoginRedirect)
185-
->will($this->returnValue(new Response()));
252+
->willReturn(new Response());
186253

187254
$registry = new ComponentRegistry(new \Cake\Controller\Controller(new \Cake\Http\ServerRequest()));
188255
$config = [
189256
'component' => 'CakeDC/Users.Login',
190-
'defaultMessage' => __d('cake_d_c/users', 'Username or password is incorrect'),
191-
'messages' => [
192-
FormAuthenticator::FAILURE_INVALID_RECAPTCHA => __d('cake_d_c/users', 'Invalid reCaptcha'),
193-
],
194257
'targetAuthenticator' => FormAuthenticator::class,
258+
'PasswordRehash' => [
259+
'authenticators' => ['Form' => 'Password'],
260+
],
195261
];
262+
196263
$Login = $this->getMockBuilder(LoginComponent::class)
197264
->onlyMethods(['getController'])
198265
->setConstructorArgs([$registry, $config])
199266
->getMock();
200267

201268
$Login->expects($this->any())
202269
->method('getController')
203-
->will($this->returnValue($this->Trait));
270+
->willReturn($this->Trait);
204271
$this->Trait->expects($this->any())
205272
->method('loadComponent')
206273
->with(
207274
$this->equalTo('CakeDC/Users.Login'),
208-
$this->equalTo($config),
275+
$this->anything(),
209276
)
210-
->will($this->returnValue($Login));
277+
->willReturn($Login);
211278

212279
$result = $this->Trait->login();
213280
$this->assertInstanceOf(Response::class, $result);
281+
214282
$userAfter = $this->Trait->getUsersTable()->get('00000000-0000-0000-0000-000000000002');
215-
$passwordAfter = $userAfter['password'];
216-
$this->assertNotEquals($passwordBefore, $passwordAfter);
283+
$this->assertNotEquals($passwordBefore, $userAfter['password']);
284+
217285
$passwordHasher = new DefaultPasswordHasher();
218-
$check = $passwordHasher->check($userPassword, $passwordAfter);
219-
$this->assertTrue($check);
286+
$this->assertTrue($passwordHasher->check($userPassword, $userAfter['password']));
287+
}
288+
289+
public function testLoginRehashWithAuthenticatorStructure()
290+
{
291+
\Cake\Core\Configure::write('Auth.PasswordRehash', [
292+
'authenticators' => [
293+
'Form' => 'Authentication.Password',
294+
],
295+
]);
296+
297+
$userId = '00000000-0000-0000-0000-000000000002';
298+
$user = $this->Trait->getUsersTable()->get($userId);
299+
$oldHash = '$2y$10$OldHashNeedsUpgrade00000000000000000000000000000000';
300+
$this->Trait->getUsersTable()->updateAll(
301+
['password' => $oldHash],
302+
['id' => $userId],
303+
);
304+
305+
$passwordIdentifier = $this->getMockBuilder(PasswordIdentifier::class)
306+
->onlyMethods(['needsPasswordRehash'])
307+
->getMock();
308+
$passwordIdentifier->expects($this->any())
309+
->method('needsPasswordRehash')
310+
->willReturn(true);
311+
312+
$identifierCollection = new IdentifierCollection([]);
313+
$identifierCollection->set('Authentication.Password', $passwordIdentifier);
314+
315+
$formAuthenticator = $this->getMockBuilder(FormAuthenticator::class)
316+
->disableOriginalConstructor()
317+
->addMethods(['getIdentifier'])
318+
->getMock();
319+
$formAuthenticator->expects($this->any())
320+
->method('getIdentifier')
321+
->willReturn($identifierCollection);
322+
323+
$authenticatorCollection = $this->getMockBuilder(AuthenticatorCollection::class)
324+
->disableOriginalConstructor()
325+
->getMock();
326+
$authenticatorCollection->expects($this->any())
327+
->method('has')->with('Form')->willReturn(true);
328+
$authenticatorCollection->expects($this->any())
329+
->method('get')->with('Form')->willReturn($formAuthenticator);
330+
331+
$service = $this->getMockBuilder(AuthenticationService::class)
332+
->disableOriginalConstructor()
333+
->getMock();
334+
$service->expects($this->any())
335+
->method('authenticators')
336+
->willReturn($authenticatorCollection);
337+
$service->expects($this->any())
338+
->method('identifiers')
339+
->willReturn(new IdentifierCollection([]));
340+
$service->expects($this->any())
341+
->method('getAuthenticationProvider')
342+
->willReturn($formAuthenticator);
343+
344+
$result = new Result($user, Result::SUCCESS);
345+
$service->expects($this->any())->method('getResult')->willReturn($result);
346+
347+
$this->_mockDispatchEvent(new Event('event'));
348+
349+
$request = $this->getMockBuilder('Cake\Http\ServerRequest')
350+
->onlyMethods(['is', 'getData'])
351+
->getMock();
352+
353+
$request->expects($this->any())
354+
->method('is')
355+
->with('post')
356+
->willReturn(true);
357+
358+
$request->expects($this->any())
359+
->method('getData')
360+
->willReturnCallback(function ($key = null) use ($user) {
361+
if ($key === 'password') {
362+
return 'password123';
363+
}
364+
if ($key === 'username' || $key === 'email') {
365+
return $user->email;
366+
}
367+
368+
return [];
369+
});
370+
371+
$identityWrapper = new \Authentication\Identity($user);
372+
373+
$request = $request->withAttribute('authentication', $service);
374+
$request = $request->withAttribute('identity', $identityWrapper);
375+
376+
$this->Trait->setRequest($request);
377+
378+
$authComponent = $this->getMockBuilder(\Cake\Controller\Component::class)
379+
->disableOriginalConstructor()
380+
->onlyMethods(['getConfig'])
381+
->getMock();
382+
383+
$authComponent->expects($this->any())
384+
->method('getConfig')
385+
->with('loginRedirect')
386+
->willReturn('/');
387+
388+
$this->Trait->components()->set('Authentication', $authComponent);
389+
390+
$registry = new ComponentRegistry(new \Cake\Controller\Controller(new \Cake\Http\ServerRequest()));
391+
$config = [
392+
'component' => 'CakeDC/Users.Login',
393+
'targetAuthenticator' => FormAuthenticator::class,
394+
'PasswordRehash' => [
395+
'authenticators' => ['Form' => 'Authentication.Password'],
396+
],
397+
];
398+
399+
$Login = $this->getMockBuilder(LoginComponent::class)
400+
->onlyMethods(['getController'])
401+
->setConstructorArgs([$registry, $config])
402+
->getMock();
403+
404+
$Login->expects($this->any())
405+
->method('getController')
406+
->willReturn($this->Trait);
407+
408+
$this->Trait->expects($this->any())
409+
->method('loadComponent')
410+
->with(
411+
$this->equalTo('CakeDC/Users.Login'),
412+
$this->anything(),
413+
)
414+
->willReturn($Login);
415+
416+
$this->Trait->expects($this->once())
417+
->method('redirect')
418+
->willReturn(new Response());
419+
420+
$this->Trait->login();
421+
422+
$userAfter = $this->Trait->getUsersTable()->get($userId);
423+
424+
$this->assertNotEquals(
425+
$oldHash,
426+
$userAfter->password,
427+
);
220428
}
221429

222430
/**
@@ -267,8 +475,8 @@ public function testLoginGet()
267475
->method('getController')
268476
->will($this->returnValue($this->Trait));
269477
// $this->Trait->expects($this->any())
270-
// ->method('getRequest')
271-
// ->will($this->returnValue($request));
478+
// ->method('getRequest')
479+
// ->will($this->returnValue($request));
272480
$this->Trait->expects($this->any())
273481
->method('loadComponent')
274482
->with(

0 commit comments

Comments
 (0)