Skip to content

Commit bfd92e0

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

File tree

2 files changed

+40
-5
lines changed

2 files changed

+40
-5
lines changed

TwoFactorAuth/Model/UserConfig/SignedTokenManager.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,19 @@
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;
17+
use Magento\Framework\App\ObjectManager;
1618

1719
/**
1820
* @inheritDoc
1921
*/
2022
class SignedTokenManager implements UserConfigTokenManagerInterface
2123
{
24+
/**
25+
* @var string
26+
*/
27+
public const CACHE_ID = 'tfa_token';
28+
2229
/**
2330
* @var EncryptorInterface
2431
*/
@@ -34,16 +41,27 @@ class SignedTokenManager implements UserConfigTokenManagerInterface
3441
*/
3542
private $dateTime;
3643

44+
/**
45+
* @var CacheInterface
46+
*/
47+
private $cache;
48+
3749
/**
3850
* @param EncryptorInterface $encryptor
3951
* @param Json $json
4052
* @param DateTime $dateTime
53+
* @param CacheInterface|null $cache
4154
*/
42-
public function __construct(EncryptorInterface $encryptor, Json $json, DateTime $dateTime)
43-
{
55+
public function __construct(
56+
EncryptorInterface $encryptor,
57+
Json $json,
58+
DateTime $dateTime,
59+
CacheInterface $cache = null
60+
) {
4461
$this->encryptor = $encryptor;
4562
$this->json = $json;
4663
$this->dateTime = $dateTime;
64+
$this->cache = $cache ?? ObjectManager::getInstance()->get(CacheInterface::class);
4765
}
4866

4967
/**
@@ -54,7 +72,7 @@ public function issueFor(int $userId): string
5472
$data = ['user_id' => $userId, 'tfa_configuration' => true, 'iss' => $this->dateTime->timestamp()];
5573
$encodedData = $this->json->serialize($data);
5674
$signature = base64_encode($this->encryptor->hash($encodedData));
57-
75+
$this->cache->save(base64_encode($encodedData .'.' .$signature), self::CACHE_ID . $userId);
5876
return base64_encode($encodedData .'.' .$signature);
5977
}
6078

TwoFactorAuth/Model/UserConfig/UserConfigRequestManager.php

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +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;
19+
use Magento\Framework\App\ObjectManager;
1820

1921
/**
2022
* @inheritDoc
@@ -41,22 +43,30 @@ class UserConfigRequestManager implements UserConfigRequestManagerInterface
4143
*/
4244
private $auth;
4345

46+
/**
47+
* @var CacheInterface
48+
*/
49+
private $cache;
50+
4451
/**
4552
* @param TfaInterface $tfa
4653
* @param UserNotifierInterface $notifier
4754
* @param UserConfigTokenManagerInterface $tokenManager
4855
* @param Authorization $auth
56+
* @param CacheInterface|null $cache
4957
*/
5058
public function __construct(
5159
TfaInterface $tfa,
5260
UserNotifierInterface $notifier,
5361
UserConfigTokenManagerInterface $tokenManager,
54-
Authorization $auth
62+
Authorization $auth,
63+
CacheInterface $cache = null
5564
) {
5665
$this->tfa = $tfa;
5766
$this->notifier = $notifier;
5867
$this->tokenManager = $tokenManager;
5968
$this->auth = $auth;
69+
$this->cache = $cache ?? ObjectManager::getInstance()->get(CacheInterface::class);
6070
}
6171

6272
/**
@@ -75,11 +85,18 @@ public function sendConfigRequestTo(User $user): void
7585
{
7686
$userId = (int)$user->getId();
7787
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+
}
7893
//Application level configuration is required.
7994
if (!$this->auth->isAllowed($user->getAclRole(), 'Magento_TwoFactorAuth::config')) {
8095
throw new AuthorizationException(__('User is not authorized to edit 2FA configuration'));
8196
}
82-
$this->notifier->sendAppConfigRequestMessage($user, $this->tokenManager->issueFor($userId));
97+
if (!$isValidOldToken) {
98+
$this->notifier->sendAppConfigRequestMessage($user, $this->tokenManager->issueFor($userId));
99+
}
83100
} else {
84101
//Personal provider config required.
85102
$this->notifier->sendUserConfigRequestMessage($user, $this->tokenManager->issueFor($userId));

0 commit comments

Comments
 (0)