Skip to content

Commit 861aade

Browse files
committed
MC-37886: Rate-limit 2FA initial setup E-mails
1 parent bfd92e0 commit 861aade

File tree

3 files changed

+37
-27
lines changed

3 files changed

+37
-27
lines changed

TwoFactorAuth/Model/TfaSession.php

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
*/
1818
class TfaSession extends SessionManager implements TfaSessionInterface
1919
{
20-
const SKIPPED_PROVIDERS_KEY = 'tfa_skipped_config';
20+
private const SKIPPED_PROVIDERS_KEY = 'tfa_skipped_config';
21+
22+
private const TFA_EMAIL_SENT = 'tfa_email_sent';
2123

2224
/**
2325
* @inheritDoc
@@ -42,14 +44,32 @@ public function isGranted(): bool
4244
*/
4345
public function getSkippedProviderConfig(): array
4446
{
45-
return $this->getData(static::SKIPPED_PROVIDERS_KEY) ?? [];
47+
return $this->getData(self::SKIPPED_PROVIDERS_KEY) ?? [];
4648
}
4749

4850
/**
4951
* @inheritDoc
5052
*/
5153
public function setSkippedProviderConfig(array $config): void
5254
{
53-
$this->storage->setData(static::SKIPPED_PROVIDERS_KEY, $config);
55+
$this->storage->setData(self::SKIPPED_PROVIDERS_KEY, $config);
56+
}
57+
58+
/**
59+
* Get flag that tfa configuration email was sent
60+
*
61+
* @return bool
62+
*/
63+
public function isTfaEmailSent(): bool
64+
{
65+
return (bool) $this->storage->getData(self::TFA_EMAIL_SENT);
66+
}
67+
68+
/**
69+
* Set flag that tfa configuration email was sent
70+
*/
71+
public function setTfaEmailSentFlag(): void
72+
{
73+
$this->storage->setData(self::TFA_EMAIL_SENT, true);
5474
}
5575
}

TwoFactorAuth/Model/UserConfig/SignedTokenManager.php

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,14 @@
1313
use Magento\Framework\Serialize\Serializer\Json;
1414
use Magento\Framework\Stdlib\DateTime\DateTime;
1515
use Magento\TwoFactorAuth\Api\UserConfigTokenManagerInterface;
16-
use Magento\Framework\App\CacheInterface;
1716
use Magento\Framework\App\ObjectManager;
17+
use Magento\TwoFactorAuth\Model\TfaSession;
1818

1919
/**
2020
* @inheritDoc
2121
*/
2222
class SignedTokenManager implements UserConfigTokenManagerInterface
2323
{
24-
/**
25-
* @var string
26-
*/
27-
public const CACHE_ID = 'tfa_token';
28-
2924
/**
3025
* @var EncryptorInterface
3126
*/
@@ -42,26 +37,26 @@ class SignedTokenManager implements UserConfigTokenManagerInterface
4237
private $dateTime;
4338

4439
/**
45-
* @var CacheInterface
40+
* @var TfaSession
4641
*/
47-
private $cache;
42+
private $tfaSession;
4843

4944
/**
5045
* @param EncryptorInterface $encryptor
5146
* @param Json $json
5247
* @param DateTime $dateTime
53-
* @param CacheInterface|null $cache
48+
* @param TfaSession|null $tfaSession
5449
*/
5550
public function __construct(
5651
EncryptorInterface $encryptor,
5752
Json $json,
5853
DateTime $dateTime,
59-
CacheInterface $cache = null
54+
TfaSession $tfaSession = null
6055
) {
6156
$this->encryptor = $encryptor;
6257
$this->json = $json;
6358
$this->dateTime = $dateTime;
64-
$this->cache = $cache ?? ObjectManager::getInstance()->get(CacheInterface::class);
59+
$this->tfaSession = $tfaSession ?? ObjectManager::getInstance()->get(TfaSession::class);
6560
}
6661

6762
/**
@@ -72,7 +67,7 @@ public function issueFor(int $userId): string
7267
$data = ['user_id' => $userId, 'tfa_configuration' => true, 'iss' => $this->dateTime->timestamp()];
7368
$encodedData = $this->json->serialize($data);
7469
$signature = base64_encode($this->encryptor->hash($encodedData));
75-
$this->cache->save(base64_encode($encodedData .'.' .$signature), self::CACHE_ID . $userId);
70+
$this->tfaSession->setTfaEmailSentFlag();
7671
return base64_encode($encodedData .'.' .$signature);
7772
}
7873

TwoFactorAuth/Model/UserConfig/UserConfigRequestManager.php

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
use Magento\TwoFactorAuth\Api\UserConfigTokenManagerInterface;
1616
use Magento\TwoFactorAuth\Api\UserNotifierInterface;
1717
use Magento\Framework\Authorization\PolicyInterface as Authorization;
18-
use Magento\Framework\App\CacheInterface;
1918
use Magento\Framework\App\ObjectManager;
19+
use Magento\TwoFactorAuth\Model\TfaSession;
2020

2121
/**
2222
* @inheritDoc
@@ -44,29 +44,29 @@ class UserConfigRequestManager implements UserConfigRequestManagerInterface
4444
private $auth;
4545

4646
/**
47-
* @var CacheInterface
47+
* @var TfaSession
4848
*/
49-
private $cache;
49+
private $tfaSession;
5050

5151
/**
5252
* @param TfaInterface $tfa
5353
* @param UserNotifierInterface $notifier
5454
* @param UserConfigTokenManagerInterface $tokenManager
5555
* @param Authorization $auth
56-
* @param CacheInterface|null $cache
56+
* @param TfaSession|null $tfaSession
5757
*/
5858
public function __construct(
5959
TfaInterface $tfa,
6060
UserNotifierInterface $notifier,
6161
UserConfigTokenManagerInterface $tokenManager,
6262
Authorization $auth,
63-
CacheInterface $cache = null
63+
TfaSession $tfaSession = null
6464
) {
6565
$this->tfa = $tfa;
6666
$this->notifier = $notifier;
6767
$this->tokenManager = $tokenManager;
6868
$this->auth = $auth;
69-
$this->cache = $cache ?? ObjectManager::getInstance()->get(CacheInterface::class);
69+
$this->tfaSession = $tfaSession ?? ObjectManager::getInstance()->get(TfaSession::class);
7070
}
7171

7272
/**
@@ -85,16 +85,11 @@ public function sendConfigRequestTo(User $user): void
8585
{
8686
$userId = (int)$user->getId();
8787
if (empty($this->tfa->getUserProviders($userId))) {
88-
$tfaToken = $this->cache->load(SignedTokenManager::CACHE_ID . $userId);
89-
$isValidOldToken = false;
90-
if ($tfaToken !== false) {
91-
$isValidOldToken = $this->tokenManager->isValidFor($userId, $tfaToken);
92-
}
9388
//Application level configuration is required.
9489
if (!$this->auth->isAllowed($user->getAclRole(), 'Magento_TwoFactorAuth::config')) {
9590
throw new AuthorizationException(__('User is not authorized to edit 2FA configuration'));
9691
}
97-
if (!$isValidOldToken) {
92+
if (!$this->tfaSession->isTfaEmailSent()) {
9893
$this->notifier->sendAppConfigRequestMessage($user, $this->tokenManager->issueFor($userId));
9994
}
10095
} else {

0 commit comments

Comments
 (0)