20
20
use Magento \Customer \Model \Metadata \Validator ;
21
21
use Magento \Eav \Model \Validator \Attribute \Backend ;
22
22
use Magento \Framework \Api \ExtensibleDataObjectConverter ;
23
+ use Magento \Framework \Api \SearchCriteriaBuilder ;
23
24
use Magento \Framework \App \Area ;
24
25
use Magento \Framework \App \Config \ScopeConfigInterface ;
25
26
use Magento \Framework \App \ObjectManager ;
41
42
use Magento \Framework \Intl \DateTimeFactory ;
42
43
use Magento \Framework \Mail \Template \TransportBuilder ;
43
44
use Magento \Framework \Math \Random ;
45
+ use Magento \Framework \Phrase ;
44
46
use Magento \Framework \Reflection \DataObjectProcessor ;
45
47
use Magento \Framework \Registry ;
46
48
use Magento \Framework \Stdlib \DateTime ;
@@ -326,6 +328,11 @@ class AccountManagement implements AccountManagementInterface
326
328
*/
327
329
private $ accountConfirmation ;
328
330
331
+ /**
332
+ * @var SearchCriteriaBuilder
333
+ */
334
+ private $ searchCriteriaBuilder ;
335
+
329
336
/**
330
337
* @param CustomerFactory $customerFactory
331
338
* @param ManagerInterface $eventManager
@@ -356,6 +363,7 @@ class AccountManagement implements AccountManagementInterface
356
363
* @param SessionManagerInterface|null $sessionManager
357
364
* @param SaveHandlerInterface|null $saveHandler
358
365
* @param CollectionFactory|null $visitorCollectionFactory
366
+ * @param SearchCriteriaBuilder|null $searchCriteriaBuilder
359
367
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
360
368
*/
361
369
public function __construct (
@@ -387,7 +395,8 @@ public function __construct(
387
395
AccountConfirmation $ accountConfirmation = null ,
388
396
SessionManagerInterface $ sessionManager = null ,
389
397
SaveHandlerInterface $ saveHandler = null ,
390
- CollectionFactory $ visitorCollectionFactory = null
398
+ CollectionFactory $ visitorCollectionFactory = null ,
399
+ SearchCriteriaBuilder $ searchCriteriaBuilder = null
391
400
) {
392
401
$ this ->customerFactory = $ customerFactory ;
393
402
$ this ->eventManager = $ eventManager ;
@@ -423,6 +432,8 @@ public function __construct(
423
432
?: ObjectManager::getInstance ()->get (SaveHandlerInterface::class);
424
433
$ this ->visitorCollectionFactory = $ visitorCollectionFactory
425
434
?: ObjectManager::getInstance ()->get (CollectionFactory::class);
435
+ $ this ->searchCriteriaBuilder = $ searchCriteriaBuilder
436
+ ?: ObjectManager::getInstance ()->get (SearchCriteriaBuilder::class);
426
437
}
427
438
428
439
/**
@@ -591,6 +602,43 @@ public function initiatePasswordReset($email, $template, $websiteId = null)
591
602
return false ;
592
603
}
593
604
605
+ /**
606
+ * Match a customer by their RP token.
607
+ *
608
+ * @param string $rpToken
609
+ * @throws ExpiredException
610
+ * @throws NoSuchEntityException
611
+ *
612
+ * @return CustomerInterface
613
+ * @throws LocalizedException
614
+ */
615
+ private function matchCustomerByRpToken (string $ rpToken ): CustomerInterface
616
+ {
617
+ $ this ->searchCriteriaBuilder ->addFilter (
618
+ 'rp_token ' ,
619
+ $ rpToken
620
+ );
621
+ $ this ->searchCriteriaBuilder ->setPageSize (1 );
622
+ $ found = $ this ->customerRepository ->getList (
623
+ $ this ->searchCriteriaBuilder ->create ()
624
+ );
625
+ if ($ found ->getTotalCount () > 1 ) {
626
+ //Failed to generated unique RP token
627
+ throw new ExpiredException (
628
+ new Phrase ('Reset password token expired. ' )
629
+ );
630
+ }
631
+ if ($ found ->getTotalCount () === 0 ) {
632
+ //Customer with such token not found.
633
+ throw NoSuchEntityException::singleField (
634
+ 'rp_token ' ,
635
+ $ rpToken
636
+ );
637
+ }
638
+ //Unique customer found.
639
+ return $ found ->getItems ()[0 ];
640
+ }
641
+
594
642
/**
595
643
* Handle not supported template
596
644
*
@@ -615,16 +663,24 @@ private function handleUnknownTemplate($template)
615
663
*/
616
664
public function resetPassword ($ email , $ resetToken , $ newPassword )
617
665
{
618
- $ customer = $ this ->customerRepository ->get ($ email );
666
+ if (!$ email ) {
667
+ $ customer = $ this ->matchCustomerByRpToken ($ resetToken );
668
+ $ email = $ customer ->getEmail ();
669
+ } else {
670
+ $ customer = $ this ->customerRepository ->get ($ email );
671
+ }
619
672
//Validate Token and new password strength
620
673
$ this ->validateResetPasswordToken ($ customer ->getId (), $ resetToken );
674
+ $ this ->credentialsValidator ->checkPasswordDifferentFromEmail (
675
+ $ email ,
676
+ $ newPassword
677
+ );
621
678
$ this ->checkPasswordStrength ($ newPassword );
622
679
//Update secure data
623
680
$ customerSecure = $ this ->customerRegistry ->retrieveSecureData ($ customer ->getId ());
624
681
$ customerSecure ->setRpToken (null );
625
682
$ customerSecure ->setRpTokenCreatedAt (null );
626
683
$ customerSecure ->setPasswordHash ($ this ->createPasswordHash ($ newPassword ));
627
- $ this ->getAuthentication ()->unlock ($ customer ->getId ());
628
684
$ this ->sessionManager ->destroy ();
629
685
$ this ->destroyCustomerSessions ($ customer ->getId ());
630
686
$ this ->customerRepository ->save ($ customer );
@@ -955,6 +1011,8 @@ protected function createPasswordHash($password)
955
1011
}
956
1012
957
1013
/**
1014
+ * Returns eval validator
1015
+ *
958
1016
* @return Backend
959
1017
*/
960
1018
private function getEavValidator ()
@@ -1033,32 +1091,36 @@ public function isCustomerInStore($customerWebsiteId, $storeId)
1033
1091
* @throws \Magento\Framework\Exception\State\ExpiredException If token is expired
1034
1092
* @throws \Magento\Framework\Exception\InputException If token or customer id is invalid
1035
1093
* @throws \Magento\Framework\Exception\NoSuchEntityException If customer doesn't exist
1094
+ * @throws LocalizedException
1036
1095
*/
1037
1096
private function validateResetPasswordToken ($ customerId , $ resetPasswordLinkToken )
1038
1097
{
1039
- if (empty ( $ customerId) || $ customerId < 0 ) {
1098
+ if ($ customerId !== null && $ customerId <= 0 ) {
1040
1099
throw new InputException (
1041
1100
__ (
1042
1101
'Invalid value of "%value" provided for the %fieldName field. ' ,
1043
1102
['value ' => $ customerId , 'fieldName ' => 'customerId ' ]
1044
1103
)
1045
1104
);
1046
1105
}
1106
+
1107
+ if ($ customerId === null ) {
1108
+ //Looking for the customer.
1109
+ $ customerId = $ this ->matchCustomerByRpToken ($ resetPasswordLinkToken )
1110
+ ->getId ();
1111
+ }
1047
1112
if (!is_string ($ resetPasswordLinkToken ) || empty ($ resetPasswordLinkToken )) {
1048
1113
$ params = ['fieldName ' => 'resetPasswordLinkToken ' ];
1049
1114
throw new InputException (__ ('"%fieldName" is required. Enter and try again. ' , $ params ));
1050
1115
}
1051
-
1052
1116
$ customerSecureData = $ this ->customerRegistry ->retrieveSecureData ($ customerId );
1053
1117
$ rpToken = $ customerSecureData ->getRpToken ();
1054
1118
$ rpTokenCreatedAt = $ customerSecureData ->getRpTokenCreatedAt ();
1055
-
1056
1119
if (!Security::compareStrings ($ rpToken , $ resetPasswordLinkToken )) {
1057
1120
throw new InputMismatchException (__ ('The password token is mismatched. Reset and try again. ' ));
1058
1121
} elseif ($ this ->isResetPasswordLinkTokenExpired ($ rpToken , $ rpTokenCreatedAt )) {
1059
1122
throw new ExpiredException (__ ('The password token is expired. Reset and try again. ' ));
1060
1123
}
1061
-
1062
1124
return true ;
1063
1125
}
1064
1126
@@ -1141,6 +1203,7 @@ protected function sendPasswordResetNotificationEmail($customer)
1141
1203
* @param int|string|null $defaultStoreId
1142
1204
* @return int
1143
1205
* @deprecated 100.1.0
1206
+ * @throws LocalizedException
1144
1207
*/
1145
1208
protected function getWebsiteStoreId ($ customer , $ defaultStoreId = null )
1146
1209
{
@@ -1153,6 +1216,8 @@ protected function getWebsiteStoreId($customer, $defaultStoreId = null)
1153
1216
}
1154
1217
1155
1218
/**
1219
+ * Return array with template types
1220
+ *
1156
1221
* @return array
1157
1222
* @deprecated 100.1.0
1158
1223
*/
0 commit comments