mirror of
https://github.com/bdnugget/magento2.git
synced 2026-11-07 17:27:36 +00:00
221 lines
6.8 KiB
PHP
221 lines
6.8 KiB
PHP
<?php
|
|
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
|
|
namespace Magento\User\Observer\Backend;
|
|
|
|
use Magento\Backend\Model\Auth\Session;
|
|
use Magento\Backend\Model\UrlInterface;
|
|
use Magento\Framework\Encryption\EncryptorInterface;
|
|
use Magento\Framework\Event\Observer as EventObserver;
|
|
use Magento\Framework\Exception\State\UserLockedException;
|
|
use Magento\Framework\Message\ManagerInterface;
|
|
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;
|
|
use Magento\User\Model\UserFactory;
|
|
|
|
/**
|
|
* User backend observer model for authentication
|
|
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
|
* @SuppressWarnings(PHPMD.CookieAndSessionMisuse)
|
|
*/
|
|
class AuthObserver implements ObserverInterface
|
|
{
|
|
/**
|
|
* Backend configuration interface
|
|
*
|
|
* @var ObserverConfig
|
|
*/
|
|
protected $observerConfig;
|
|
|
|
/**
|
|
* Admin user resource model
|
|
*
|
|
* @var ResourceUser
|
|
*/
|
|
protected $userResource;
|
|
|
|
/**
|
|
* Backend url interface
|
|
*
|
|
* @var UrlInterface
|
|
*/
|
|
protected $url;
|
|
|
|
/**
|
|
* Backend authorization session
|
|
*
|
|
* @var Session
|
|
*/
|
|
protected $authSession;
|
|
|
|
/**
|
|
* Factory class for user model
|
|
*
|
|
* @var UserFactory
|
|
*/
|
|
protected $userFactory;
|
|
|
|
/**
|
|
* Encryption model
|
|
*
|
|
* @var EncryptorInterface
|
|
*/
|
|
protected $encryptor;
|
|
|
|
/**
|
|
* Message manager interface
|
|
*
|
|
* @var ManagerInterface
|
|
*/
|
|
protected $messageManager;
|
|
|
|
/**
|
|
* @param ObserverConfig $observerConfig
|
|
* @param ResourceUser $userResource
|
|
* @param UrlInterface $url
|
|
* @param Session $authSession
|
|
* @param UserFactory $userFactory
|
|
* @param EncryptorInterface $encryptor
|
|
* @param ManagerInterface $messageManager
|
|
*/
|
|
public function __construct(
|
|
ObserverConfig $observerConfig,
|
|
ResourceUser $userResource,
|
|
UrlInterface $url,
|
|
Session $authSession,
|
|
UserFactory $userFactory,
|
|
EncryptorInterface $encryptor,
|
|
ManagerInterface $messageManager
|
|
) {
|
|
$this->observerConfig = $observerConfig;
|
|
$this->userResource = $userResource;
|
|
$this->url = $url;
|
|
$this->authSession = $authSession;
|
|
$this->userFactory = $userFactory;
|
|
$this->encryptor = $encryptor;
|
|
$this->messageManager = $messageManager;
|
|
}
|
|
|
|
/**
|
|
* Admin locking and password hashing upgrade logic implementation
|
|
*
|
|
* @param EventObserver $observer
|
|
* @return void
|
|
* @throws \Magento\Framework\Exception\LocalizedException
|
|
*/
|
|
public function execute(EventObserver $observer)
|
|
{
|
|
$password = $observer->getEvent()->getPassword();
|
|
/** @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());
|
|
|
|
$latestPassword = $this->userResource->getLatestPassword($user->getId());
|
|
$this->_checkExpiredPassword($latestPassword);
|
|
|
|
if (!$this->encryptor->validateHashVersion($user->getPassword(), true)) {
|
|
$user->setPassword($password)
|
|
->setData('force_new_password', true)
|
|
->save();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update locking information for the user
|
|
*
|
|
* @param User $user
|
|
* @return void
|
|
*/
|
|
private function _updateLockingInformation($user)
|
|
{
|
|
$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);
|
|
}
|
|
|
|
/**
|
|
* Check whether the latest password is expired
|
|
*
|
|
* Side-effect can be when passwords were changed with different lifetime configuration settings
|
|
*
|
|
* @param array $latestPassword
|
|
* @return void
|
|
*/
|
|
private function _checkExpiredPassword($latestPassword)
|
|
{
|
|
if ($latestPassword && $this->observerConfig->_isLatestPasswordExpired($latestPassword)) {
|
|
if ($this->observerConfig->isPasswordChangeForced()) {
|
|
$message = __('It\'s time to change your password.');
|
|
} else {
|
|
$myAccountUrl = $this->url->getUrl('adminhtml/system_account/');
|
|
$message = __('It\'s time to <a href="%1">change your password</a>.', $myAccountUrl);
|
|
}
|
|
|
|
$messages = $this->messageManager->getMessages();
|
|
|
|
// Remove existing messages with same ID to avoid duplication
|
|
$messages->deleteMessageByIdentifier(User::MESSAGE_ID_PASSWORD_EXPIRED);
|
|
|
|
$this->messageManager->addNoticeMessage($message);
|
|
$message = $messages->getLastAddedMessage();
|
|
if ($message) {
|
|
$message->setIdentifier(User::MESSAGE_ID_PASSWORD_EXPIRED)->setIsSticky(true);
|
|
$this->authSession->setPciAdminUserIsPasswordExpired(true);
|
|
}
|
|
}
|
|
}
|
|
}
|