Skip to content

Commit

Permalink
Merge pull request #416 from magento-performance/cabpi-316-check-if-u…
Browse files Browse the repository at this point in the history
…ser-is-locked

CABPI-316: Check if user is locked
  • Loading branch information
slopukhov authored Apr 4, 2022
2 parents 6b1bdfa + 7efb445 commit 5006dd7
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 0 deletions.
8 changes: 8 additions & 0 deletions app/code/Magento/AdminAdobeIms/Model/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ public function authenticateByUsername(string $username): bool
$result = $this->verifyIdentityWithoutPassword();
}

/**
* Dispatch admin_user_authenticate_after but with an empty password
*/
$this->_eventManager->dispatch(
'admin_adobe_ims_user_authenticate_after',
['username' => $username, 'user' => $this, 'result' => $result]
);

} catch (LocalizedException $e) {
$this->unsetData();
throw $e;
Expand Down
130 changes: 130 additions & 0 deletions app/code/Magento/AdminAdobeIms/Observer/AuthObserver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

declare(strict_types=1);

namespace Magento\AdminAdobeIms\Observer;

use DateInterval;
use DateTime;
use Exception;
use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\State\UserLockedException;
use Magento\User\Model\Backend\Config\ObserverConfig;
use Magento\User\Model\ResourceModel\User as ResourceUser;
use Magento\User\Model\User;
use Magento\Framework\Event\ObserverInterface;

/**
* User backend observer model for authentication
* Copied from \Magento\User\Observer\Backend\AuthObserver
* and removed not needed methods like checkExpiredPassword
*
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
*/
class AuthObserver implements ObserverInterface
{
/**
* @var ObserverConfig
*/
private ObserverConfig $observerConfig;

/**
* @var ResourceUser
*/
private ResourceUser $userResource;

/**
* @param ObserverConfig $observerConfig
* @param ResourceUser $userResource
*/
public function __construct(
ObserverConfig $observerConfig,
ResourceUser $userResource
) {
$this->observerConfig = $observerConfig;
$this->userResource = $userResource;
}

/**
* Admin locking logic implementation
*
* @param EventObserver $observer
* @return void
* @throws LocalizedException
* @throws Exception
*/
public function execute(EventObserver $observer): void
{
/** @var User $user */
$user = $observer->getEvent()->getUser();
$authResult = $observer->getEvent()->getResult();

if (!$authResult && $user->getId()) {
// update locking information regardless whether user locked or not
$this->updateLockingInformation($user);
}

// check whether user is locked
$lockExpires = $user->getLockExpires();
if ($lockExpires) {
$lockExpires = new DateTime($lockExpires);
if ($lockExpires > new DateTime()) {
throw new UserLockedException(
__(
'The account sign-in was incorrect or your account is disabled temporarily. '
. 'Please wait and try again later.'
)
);
}
}

if (!$authResult) {
return;
}

$this->userResource->unlock($user->getId());
}

/**
* Update locking information for the user
*
* @param User $user
* @return void
* @throws Exception
*/
private function updateLockingInformation(User $user): void
{
$now = new DateTime();
$lockThreshold = $this->observerConfig->getAdminLockThreshold();
$maxFailures = $this->observerConfig->getMaxFailures();
if (!($lockThreshold && $maxFailures)) {
return;
}
$failuresNum = (int)$user->getFailuresNum() + 1;
/** @noinspection PhpAssignmentInConditionInspection */
if ($firstFailureDate = $user->getFirstFailure()) {
$firstFailureDate = new DateTime($firstFailureDate);
}

$newFirstFailureDate = false;
$updateLockExpires = false;
$lockThreshInterval = new DateInterval('PT' . $lockThreshold . 'S');
// set first failure date when this is first failure or last first failure expired
if (1 === $failuresNum
|| !$firstFailureDate
|| ($now->getTimestamp() - $firstFailureDate->getTimestamp()) > $lockThreshold
) {
$newFirstFailureDate = $now;
// otherwise lock user
} elseif ($failuresNum >= $maxFailures) {
$updateLockExpires = $now->add($lockThreshInterval);
}
$this->userResource->updateFailure($user, $updateLockExpires, $newFirstFailureDate);
}
}
4 changes: 4 additions & 0 deletions app/code/Magento/AdminAdobeIms/etc/adminhtml/events.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@
<observer name="new_admin_user_created"
instance="Magento\AdminAdobeIms\Observer\AdminAccountCreatedObserver"/>
</event>
<event name="admin_adobe_ims_user_authenticate_after">
<observer name="admin_adobe_ims_user_authentication"
instance="Magento\AdminAdobeIms\Observer\AuthObserver"/>
</event>
</config>
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,4 @@ app/code/Magento/Elasticsearch/Elasticsearch5/Model/Adapter/FieldMapper/Product/
app/code/Magento/Elasticsearch/Model/Layer/Search/ItemCollectionProvider.php
app/code/Magento/Newsletter/Model/Queue/TransportBuilder.php
app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml
app/code/Magento/AdminAdobeIms/Observer/AuthObserver

0 comments on commit 5006dd7

Please sign in to comment.