Skip to content
This repository has been archived by the owner on Apr 29, 2019. It is now read-only.

Commit

Permalink
Merge MAGETWO-70943 into 2.3-bugfixes-031018
Browse files Browse the repository at this point in the history
  • Loading branch information
dvoskoboinikov authored Oct 4, 2018
2 parents a30f2ae + c4c8af6 commit 150b821
Show file tree
Hide file tree
Showing 12 changed files with 199 additions and 2,762 deletions.
11 changes: 9 additions & 2 deletions app/code/Magento/Customer/Api/AccountManagementInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

namespace Magento\Customer\Api;

use Magento\Framework\Exception\InputException;

/**
* Interface for managing customers accounts.
* @api
Expand Down Expand Up @@ -144,19 +146,24 @@ public function initiatePasswordReset($email, $template, $websiteId = null);
/**
* Reset customer password.
*
* @param string $email
* @param string $email If empty value given then the customer
* will be matched by the RP token.
* @param string $resetToken
* @param string $newPassword
*
* @return bool true on success
* @throws \Magento\Framework\Exception\LocalizedException
* @throws InputException
*/
public function resetPassword($email, $resetToken, $newPassword);

/**
* Check if password reset token is valid.
*
* @param int $customerId
* @param int $customerId If null is given then a customer
* will be matched by the RP token.
* @param string $resetPasswordLinkToken
*
* @return bool True if the token is valid
* @throws \Magento\Framework\Exception\State\InputMismatchException If token is mismatched
* @throws \Magento\Framework\Exception\State\ExpiredException If token is expired
Expand Down
21 changes: 13 additions & 8 deletions app/code/Magento/Customer/Controller/Account/CreatePassword.php
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
<?php
/**
*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
namespace Magento\Customer\Controller\Account;

use Magento\Customer\Api\AccountManagementInterface;
use Magento\Customer\Model\Session;
use Magento\Framework\App\Action\HttpGetActionInterface;
use Magento\Framework\View\Result\PageFactory;
use Magento\Framework\App\Action\Context;

class CreatePassword extends \Magento\Customer\Controller\AbstractAccount
/**
* Class CreatePassword
*
* @package Magento\Customer\Controller\Account
*/
class CreatePassword extends \Magento\Customer\Controller\AbstractAccount implements HttpGetActionInterface
{
/**
* @var \Magento\Customer\Api\AccountManagementInterface
Expand Down Expand Up @@ -54,27 +59,27 @@ public function __construct(
public function execute()
{
$resetPasswordToken = (string)$this->getRequest()->getParam('token');
$customerId = (int)$this->getRequest()->getParam('id');
$isDirectLink = $resetPasswordToken != '' && $customerId != 0;
$isDirectLink = $resetPasswordToken != '';
if (!$isDirectLink) {
$resetPasswordToken = (string)$this->session->getRpToken();
$customerId = (int)$this->session->getRpCustomerId();
}

try {
$this->accountManagement->validateResetPasswordLinkToken($customerId, $resetPasswordToken);
$this->accountManagement->validateResetPasswordLinkToken(null, $resetPasswordToken);

if ($isDirectLink) {
$this->session->setRpToken($resetPasswordToken);
$this->session->setRpCustomerId($customerId);
$resultRedirect = $this->resultRedirectFactory->create();
$resultRedirect->setPath('*/*/createpassword');

return $resultRedirect;
} else {
/** @var \Magento\Framework\View\Result\Page $resultPage */
$resultPage = $this->resultPageFactory->create();
$resultPage->getLayout()->getBlock('resetPassword')->setCustomerId($customerId)
$resultPage->getLayout()
->getBlock('resetPassword')
->setResetPasswordLinkToken($resetPasswordToken);

return $resultPage;
}
} catch (\Exception $exception) {
Expand Down
39 changes: 21 additions & 18 deletions app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<?php
/**
*
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
Expand All @@ -10,11 +9,16 @@
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Customer\Model\Session;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\Action\HttpPostActionInterface;
use Magento\Framework\Exception\InputException;
use Magento\Customer\Model\Customer\CredentialsValidator;
use Magento\Framework\App\ObjectManager;

class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount
/**
* Class ResetPasswordPost
*
* @package Magento\Customer\Controller\Account
*/
class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount implements HttpPostActionInterface
{
/**
* @var \Magento\Customer\Api\AccountManagementInterface
Expand All @@ -31,17 +35,14 @@ class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount
*/
protected $session;

/**
* @var CredentialsValidator
*/
private $credentialsValidator;

/**
* @param Context $context
* @param Session $customerSession
* @param AccountManagementInterface $accountManagement
* @param CustomerRepositoryInterface $customerRepository
* @param CredentialsValidator|null $credentialsValidator
*
* @SuppressWarnings(PHPMD.UnusedFormalParameter)
*/
public function __construct(
Context $context,
Expand All @@ -53,8 +54,6 @@ public function __construct(
$this->session = $customerSession;
$this->accountManagement = $accountManagement;
$this->customerRepository = $customerRepository;
$this->credentialsValidator = $credentialsValidator ?: ObjectManager::getInstance()
->get(CredentialsValidator::class);
parent::__construct($context);
}

Expand All @@ -70,29 +69,32 @@ public function execute()
/** @var \Magento\Framework\Controller\Result\Redirect $resultRedirect */
$resultRedirect = $this->resultRedirectFactory->create();
$resetPasswordToken = (string)$this->getRequest()->getQuery('token');
$customerId = (int)$this->getRequest()->getQuery('id');
$password = (string)$this->getRequest()->getPost('password');
$passwordConfirmation = (string)$this->getRequest()->getPost('password_confirmation');

if ($password !== $passwordConfirmation) {
$this->messageManager->addError(__("New Password and Confirm New Password values didn't match."));
$resultRedirect->setPath('*/*/createPassword', ['id' => $customerId, 'token' => $resetPasswordToken]);
$resultRedirect->setPath('*/*/createPassword', ['token' => $resetPasswordToken]);

return $resultRedirect;
}
if (iconv_strlen($password) <= 0) {
$this->messageManager->addError(__('Please enter a new password.'));
$resultRedirect->setPath('*/*/createPassword', ['id' => $customerId, 'token' => $resetPasswordToken]);
$resultRedirect->setPath('*/*/createPassword', ['token' => $resetPasswordToken]);

return $resultRedirect;
}

try {
$customerEmail = $this->customerRepository->getById($customerId)->getEmail();
$this->credentialsValidator->checkPasswordDifferentFromEmail($customerEmail, $password);
$this->accountManagement->resetPassword($customerEmail, $resetPasswordToken, $password);
$this->accountManagement->resetPassword(
null,
$resetPasswordToken,
$password
);
$this->session->unsRpToken();
$this->session->unsRpCustomerId();
$this->messageManager->addSuccess(__('You updated your password.'));
$resultRedirect->setPath('*/*/login');

return $resultRedirect;
} catch (InputException $e) {
$this->messageManager->addError($e->getMessage());
Expand All @@ -102,7 +104,8 @@ public function execute()
} catch (\Exception $exception) {
$this->messageManager->addError(__('Something went wrong while saving the new password.'));
}
$resultRedirect->setPath('*/*/createPassword', ['id' => $customerId, 'token' => $resetPasswordToken]);
$resultRedirect->setPath('*/*/createPassword', ['token' => $resetPasswordToken]);

return $resultRedirect;
}
}
79 changes: 72 additions & 7 deletions app/code/Magento/Customer/Model/AccountManagement.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
use Magento\Customer\Model\Metadata\Validator;
use Magento\Eav\Model\Validator\Attribute\Backend;
use Magento\Framework\Api\ExtensibleDataObjectConverter;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\Area;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\ObjectManager;
Expand All @@ -41,6 +42,7 @@
use Magento\Framework\Intl\DateTimeFactory;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\Math\Random;
use Magento\Framework\Phrase;
use Magento\Framework\Reflection\DataObjectProcessor;
use Magento\Framework\Registry;
use Magento\Framework\Stdlib\DateTime;
Expand Down Expand Up @@ -326,6 +328,11 @@ class AccountManagement implements AccountManagementInterface
*/
private $accountConfirmation;

/**
* @var SearchCriteriaBuilder
*/
private $searchCriteriaBuilder;

/**
* @param CustomerFactory $customerFactory
* @param ManagerInterface $eventManager
Expand Down Expand Up @@ -356,6 +363,7 @@ class AccountManagement implements AccountManagementInterface
* @param SessionManagerInterface|null $sessionManager
* @param SaveHandlerInterface|null $saveHandler
* @param CollectionFactory|null $visitorCollectionFactory
* @param SearchCriteriaBuilder|null $searchCriteriaBuilder
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
*/
public function __construct(
Expand Down Expand Up @@ -387,7 +395,8 @@ public function __construct(
AccountConfirmation $accountConfirmation = null,
SessionManagerInterface $sessionManager = null,
SaveHandlerInterface $saveHandler = null,
CollectionFactory $visitorCollectionFactory = null
CollectionFactory $visitorCollectionFactory = null,
SearchCriteriaBuilder $searchCriteriaBuilder = null
) {
$this->customerFactory = $customerFactory;
$this->eventManager = $eventManager;
Expand Down Expand Up @@ -423,6 +432,8 @@ public function __construct(
?: ObjectManager::getInstance()->get(SaveHandlerInterface::class);
$this->visitorCollectionFactory = $visitorCollectionFactory
?: ObjectManager::getInstance()->get(CollectionFactory::class);
$this->searchCriteriaBuilder = $searchCriteriaBuilder
?: ObjectManager::getInstance()->get(SearchCriteriaBuilder::class);
}

/**
Expand Down Expand Up @@ -591,6 +602,43 @@ public function initiatePasswordReset($email, $template, $websiteId = null)
return false;
}

/**
* Match a customer by their RP token.
*
* @param string $rpToken
* @throws ExpiredException
* @throws NoSuchEntityException
*
* @return CustomerInterface
* @throws LocalizedException
*/
private function matchCustomerByRpToken(string $rpToken): CustomerInterface
{
$this->searchCriteriaBuilder->addFilter(
'rp_token',
$rpToken
);
$this->searchCriteriaBuilder->setPageSize(1);
$found = $this->customerRepository->getList(
$this->searchCriteriaBuilder->create()
);
if ($found->getTotalCount() > 1) {
//Failed to generated unique RP token
throw new ExpiredException(
new Phrase('Reset password token expired.')
);
}
if ($found->getTotalCount() === 0) {
//Customer with such token not found.
throw NoSuchEntityException::singleField(
'rp_token',
$rpToken
);
}
//Unique customer found.
return $found->getItems()[0];
}

/**
* Handle not supported template
*
Expand All @@ -615,16 +663,24 @@ private function handleUnknownTemplate($template)
*/
public function resetPassword($email, $resetToken, $newPassword)
{
$customer = $this->customerRepository->get($email);
if (!$email) {
$customer = $this->matchCustomerByRpToken($resetToken);
$email = $customer->getEmail();
} else {
$customer = $this->customerRepository->get($email);
}
//Validate Token and new password strength
$this->validateResetPasswordToken($customer->getId(), $resetToken);
$this->credentialsValidator->checkPasswordDifferentFromEmail(
$email,
$newPassword
);
$this->checkPasswordStrength($newPassword);
//Update secure data
$customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId());
$customerSecure->setRpToken(null);
$customerSecure->setRpTokenCreatedAt(null);
$customerSecure->setPasswordHash($this->createPasswordHash($newPassword));
$this->getAuthentication()->unlock($customer->getId());
$this->sessionManager->destroy();
$this->destroyCustomerSessions($customer->getId());
$this->customerRepository->save($customer);
Expand Down Expand Up @@ -955,6 +1011,8 @@ protected function createPasswordHash($password)
}

/**
* Returns eval validator
*
* @return Backend
*/
private function getEavValidator()
Expand Down Expand Up @@ -1033,32 +1091,36 @@ public function isCustomerInStore($customerWebsiteId, $storeId)
* @throws \Magento\Framework\Exception\State\ExpiredException If token is expired
* @throws \Magento\Framework\Exception\InputException If token or customer id is invalid
* @throws \Magento\Framework\Exception\NoSuchEntityException If customer doesn't exist
* @throws LocalizedException
*/
private function validateResetPasswordToken($customerId, $resetPasswordLinkToken)
{
if (empty($customerId) || $customerId < 0) {
if ($customerId !== null && $customerId <= 0) {
throw new InputException(
__(
'Invalid value of "%value" provided for the %fieldName field.',
['value' => $customerId, 'fieldName' => 'customerId']
)
);
}

if ($customerId === null) {
//Looking for the customer.
$customerId = $this->matchCustomerByRpToken($resetPasswordLinkToken)
->getId();
}
if (!is_string($resetPasswordLinkToken) || empty($resetPasswordLinkToken)) {
$params = ['fieldName' => 'resetPasswordLinkToken'];
throw new InputException(__('"%fieldName" is required. Enter and try again.', $params));
}

$customerSecureData = $this->customerRegistry->retrieveSecureData($customerId);
$rpToken = $customerSecureData->getRpToken();
$rpTokenCreatedAt = $customerSecureData->getRpTokenCreatedAt();

if (!Security::compareStrings($rpToken, $resetPasswordLinkToken)) {
throw new InputMismatchException(__('The password token is mismatched. Reset and try again.'));
} elseif ($this->isResetPasswordLinkTokenExpired($rpToken, $rpTokenCreatedAt)) {
throw new ExpiredException(__('The password token is expired. Reset and try again.'));
}

return true;
}

Expand Down Expand Up @@ -1141,6 +1203,7 @@ protected function sendPasswordResetNotificationEmail($customer)
* @param int|string|null $defaultStoreId
* @return int
* @deprecated 100.1.0
* @throws LocalizedException
*/
protected function getWebsiteStoreId($customer, $defaultStoreId = null)
{
Expand All @@ -1153,6 +1216,8 @@ protected function getWebsiteStoreId($customer, $defaultStoreId = null)
}

/**
* Return array with template types
*
* @return array
* @deprecated 100.1.0
*/
Expand Down
Loading

0 comments on commit 150b821

Please sign in to comment.