Skip to content

Commit 0f9d7d9

Browse files
committed
feat: add documentation and test for skipping 2FA verification
1 parent 94f5e8b commit 0f9d7d9

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

Docs/Documentation/Two-Factor-Authenticator.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,32 @@ the QR code shown (image 1).
5252

5353
<img src="OneTimePasswordAuthenticator/App.png?raw=true" width="300"/>
5454

55+
56+
Skipping 2FA Verification
57+
-------------------------
58+
You can conditionally skip the Two-Factor Authentication verify step for specific users
59+
or scenarios by listening to the `UsersPlugin::EVENT_2FA_SKIP_VERIFY` event.
60+
61+
If the event returns `true`, the verification is skipped, and the user is logged in immediately.
62+
The event receives the `user` data as a payload.
63+
64+
**Example: Skipping 2FA based on User Role**
65+
66+
In your `src/Application.php` or a dedicated Event Listener:
67+
68+
```php
69+
use Cake\Event\EventInterface;
70+
use CakeDC\Users\UsersPlugin;
71+
72+
// ...
73+
74+
$this->getEventManager()->on(UsersPlugin::EVENT_2FA_SKIP_VERIFY, function (EventInterface $event) {
75+
$user = $event->getData('user');
76+
77+
// Check if the user has the 'admin' role
78+
if (!empty($user['role']) && $user['role'] === 'admin') {
79+
// Return true to skip the 2FA verification for this user role
80+
$event->setResult(true);
81+
}
82+
});
83+
```

tests/TestCase/Controller/Traits/OneTimePasswordVerifyTraitTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616
use Cake\Core\Configure;
1717
use Cake\Http\ServerRequest;
1818
use Cake\ORM\TableRegistry;
19+
use Cake\Event\Event;
1920
use CakeDC\Auth\Controller\Component\OneTimePasswordAuthenticatorComponent;
21+
use CakeDC\Auth\Authentication\AuthenticationService;
22+
use CakeDC\Auth\Authenticator\TwoFactorAuthenticator;
23+
use CakeDC\Users\UsersPlugin;
2024

2125
class OneTimePasswordVerifyTraitTest extends BaseTrait
2226
{
@@ -277,4 +281,49 @@ public function testVerifyGetDoesNotGenerateNewSecret()
277281
$session->read(),
278282
);
279283
}
284+
285+
/**
286+
* testVerifySkipEventCheck
287+
*/
288+
public function testVerifySkipEventCheck()
289+
{
290+
Configure::write('OneTimePasswordAuthenticator.login', true);
291+
$request = $this->getMockBuilder('Cake\Http\ServerRequest')
292+
->onlyMethods(['is', 'getData', 'getSession'])
293+
->addMethods(['allow'])
294+
->getMock();
295+
$this->Trait->setRequest($request);
296+
297+
$userData = [
298+
'id' => 1,
299+
'secret_verified' => 1,
300+
'email' => 'test@example.com'
301+
];
302+
$session = $this->_mockSession([
303+
'temporarySession' => $userData,
304+
]);
305+
306+
$eventMock = $this->getMockBuilder(Event::class)
307+
->disableOriginalConstructor()
308+
->getMock();
309+
$eventMock->method('getResult')->willReturn(true);
310+
311+
$this->Trait->expects($this->once())
312+
->method('dispatchEvent')
313+
->with(UsersPlugin::EVENT_2FA_SKIP_VERIFY, ['user' => $userData])
314+
->willReturn($eventMock);
315+
316+
$this->Trait->expects($this->once())
317+
->method('redirect');
318+
$this->Trait->verify();
319+
320+
$this->assertNull(
321+
$session->read(AuthenticationService::TWO_FACTOR_VERIFY_SESSION_KEY)
322+
);
323+
324+
$this->assertEquals(
325+
$userData,
326+
$session->read(TwoFactorAuthenticator::USER_SESSION_KEY)
327+
);
328+
}
280329
}

0 commit comments

Comments
 (0)