Skip to content

Commit c74c54a

Browse files
author
Oleksandr Dubovyk
committed
Merge remote-tracking branch 'troll/MAGETWO-62966' into troll-bugfix-pr
2 parents bdc381f + 64504d4 commit c74c54a

File tree

18 files changed

+483
-118
lines changed

18 files changed

+483
-118
lines changed

app/code/Magento/Customer/Controller/Account/ResetPasswordPost.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
use Magento\Customer\Model\Session;
1212
use Magento\Framework\App\Action\Context;
1313
use Magento\Framework\Exception\InputException;
14+
use Magento\Customer\Model\Customer\CredentialsValidator;
15+
use Magento\Framework\App\ObjectManager;
1416

1517
class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount
1618
{
@@ -25,21 +27,30 @@ class ResetPasswordPost extends \Magento\Customer\Controller\AbstractAccount
2527
*/
2628
protected $session;
2729

30+
/**
31+
* @var CredentialsValidator
32+
*/
33+
private $credentialsValidator;
34+
2835
/**
2936
* @param Context $context
3037
* @param Session $customerSession
3138
* @param AccountManagementInterface $accountManagement
3239
* @param CustomerRepositoryInterface $customerRepository
40+
* @param CredentialsValidator|null $credentialsValidator
3341
*/
3442
public function __construct(
3543
Context $context,
3644
Session $customerSession,
3745
AccountManagementInterface $accountManagement,
38-
CustomerRepositoryInterface $customerRepository
46+
CustomerRepositoryInterface $customerRepository,
47+
CredentialsValidator $credentialsValidator = null
3948
) {
4049
$this->session = $customerSession;
4150
$this->accountManagement = $accountManagement;
4251
$this->customerRepository = $customerRepository;
52+
$this->credentialsValidator = $credentialsValidator ?: ObjectManager::getInstance()
53+
->get(CredentialsValidator::class);
4354
parent::__construct($context);
4455
}
4556

@@ -72,6 +83,7 @@ public function execute()
7283

7384
try {
7485
$customerEmail = $this->customerRepository->getById($customerId)->getEmail();
86+
$this->credentialsValidator->checkPasswordDifferentFromEmail($customerEmail, $password);
7587
$this->accountManagement->resetPassword($customerEmail, $resetPasswordToken, $password);
7688
$this->session->unsRpToken();
7789
$this->session->unsRpCustomerId();

app/code/Magento/Customer/Model/AccountManagement.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
use Magento\Framework\Stdlib\DateTime;
4747
use Magento\Framework\Stdlib\StringUtils as StringHelper;
4848
use Magento\Store\Model\StoreManagerInterface;
49+
use Magento\Customer\Model\Customer\CredentialsValidator;
4950

5051
/**
5152
* Handle various customer account actions
@@ -287,6 +288,11 @@ class AccountManagement implements AccountManagementInterface
287288
*/
288289
private $eavValidator;
289290

291+
/**
292+
* @var CredentialsValidator
293+
*/
294+
private $credentialsValidator;
295+
290296
/**
291297
* @param CustomerFactory $customerFactory
292298
* @param ManagerInterface $eventManager
@@ -311,6 +317,7 @@ class AccountManagement implements AccountManagementInterface
311317
* @param CustomerModel $customerModel
312318
* @param ObjectFactory $objectFactory
313319
* @param ExtensibleDataObjectConverter $extensibleDataObjectConverter
320+
* @param CredentialsValidator|null $credentialsValidator
314321
* @SuppressWarnings(PHPMD.ExcessiveParameterList)
315322
*/
316323
public function __construct(
@@ -336,7 +343,8 @@ public function __construct(
336343
DateTime $dateTime,
337344
CustomerModel $customerModel,
338345
ObjectFactory $objectFactory,
339-
ExtensibleDataObjectConverter $extensibleDataObjectConverter
346+
ExtensibleDataObjectConverter $extensibleDataObjectConverter,
347+
CredentialsValidator $credentialsValidator = null
340348
) {
341349
$this->customerFactory = $customerFactory;
342350
$this->eventManager = $eventManager;
@@ -361,6 +369,8 @@ public function __construct(
361369
$this->customerModel = $customerModel;
362370
$this->objectFactory = $objectFactory;
363371
$this->extensibleDataObjectConverter = $extensibleDataObjectConverter;
372+
$this->credentialsValidator = $credentialsValidator ?: ObjectManager::getInstance()
373+
->get(CredentialsValidator::class);
364374
}
365375

366376
/**
@@ -655,6 +665,12 @@ public function createAccount(CustomerInterface $customer, $password = null, $re
655665
{
656666
if ($password !== null) {
657667
$this->checkPasswordStrength($password);
668+
$customerEmail = $customer->getEmail();
669+
try {
670+
$this->credentialsValidator->checkPasswordDifferentFromEmail($customerEmail, $password);
671+
} catch (InputException $e) {
672+
throw new LocalizedException(__('Password cannot be the same as email address.'));
673+
}
658674
$hash = $this->createPasswordHash($password);
659675
} else {
660676
$hash = null;
@@ -826,6 +842,8 @@ private function changePasswordForCustomer($customer, $currentPassword, $newPass
826842
} catch (InvalidEmailOrPasswordException $e) {
827843
throw new InvalidEmailOrPasswordException(__('The password doesn\'t match this account.'));
828844
}
845+
$customerEmail = $customer->getEmail();
846+
$this->credentialsValidator->checkPasswordDifferentFromEmail($customerEmail, $newPassword);
829847
$customerSecure = $this->customerRegistry->retrieveSecureData($customer->getId());
830848
$customerSecure->setRpToken(null);
831849
$customerSecure->setRpTokenCreatedAt(null);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
/**
3+
*
4+
* Copyright © Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
8+
namespace Magento\Customer\Model\Customer;
9+
10+
use Magento\Framework\Exception\InputException;
11+
12+
class CredentialsValidator
13+
{
14+
/**
15+
* Check that password is different from email.
16+
*
17+
* @param string $email
18+
* @param string $password
19+
* @return void
20+
* @throws InputException
21+
*/
22+
public function checkPasswordDifferentFromEmail($email, $password)
23+
{
24+
if (strcasecmp($password, $email) == 0) {
25+
throw new InputException(__('Password cannot be the same as email address.'));
26+
}
27+
}
28+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
namespace Magento\Customer\Test\Unit\Model\Customer;
7+
8+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
9+
10+
class CredentialsValidatorTest extends \PHPUnit_Framework_TestCase
11+
{
12+
private $objectManagerHelper;
13+
private $object;
14+
15+
protected function setUp()
16+
{
17+
$this->objectManagerHelper = new ObjectManagerHelper($this);
18+
19+
$this->object = $this->objectManagerHelper
20+
->getObject(\Magento\Customer\Model\Customer\CredentialsValidator::class);
21+
}
22+
23+
/**
24+
* @expectedException \Magento\Framework\Exception\InputException
25+
* @expectedExceptionMessage Password cannot be the same as email address.
26+
*/
27+
public function testCheckPasswordDifferentFromEmail()
28+
{
29+
$email = 'test1@example.com';
30+
$password = strtoupper($email); // for case-insensitive check
31+
32+
$this->object->checkPasswordDifferentFromEmail($email, $password);
33+
}
34+
}

app/code/Magento/Customer/view/frontend/templates/form/edit.phtml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
<input type="password" class="input-text" name="current_password" id="current-password" data-input="current-password" autocomplete="off" />
5151
</div>
5252
</div>
53-
<div class="field new password required" data-container="new-password" data-mage-init='{"passwordStrengthIndicator": {}}'>
53+
<div class="field new password required" data-container="new-password">
5454
<label class="label" for="password"><span><?php echo $block->escapeHtml(__('New Password')) ?></span></label>
5555
<div class="control">
5656
<input type="password" class="input-text" name="password" id="password"
@@ -126,6 +126,11 @@
126126
"titleChangePassword": "<?php echo $block->escapeJs($block->escapeHtml(__('Change Password'))) ?>",
127127
"titleChangeEmailAndPassword": "<?php echo $block->escapeJs($block->escapeHtml(__('Change Email and Password'))) ?>"
128128
}
129+
},
130+
"[data-container=new-password]": {
131+
"passwordStrengthIndicator": {
132+
"formSelector": "form.form-edit-account"
133+
}
129134
}
130135
}
131136
</script>

app/code/Magento/Customer/view/frontend/templates/form/register.phtml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
133133
<input type="email" name="email" autocomplete="email" id="email_address" value="<?php echo $block->escapeHtmlAttr($block->getFormData()->getEmail()) ?>" title="<?php echo $block->escapeHtmlAttr(__('Email')) ?>" class="input-text" data-validate="{required:true, 'validate-email':true}">
134134
</div>
135135
</div>
136-
<div class="field password required" data-mage-init='{"passwordStrengthIndicator": {}}'>
136+
<div class="field password required">
137137
<label for="password" class="label"><span><?php echo $block->escapeHtml(__('Password')) ?></span></label>
138138
<div class="control">
139139
<input type="password" name="password" id="password"
@@ -220,3 +220,13 @@ require([
220220
}
221221
</script>
222222
<?php endif; ?>
223+
224+
<script type="text/x-magento-init">
225+
{
226+
".field.password": {
227+
"passwordStrengthIndicator": {
228+
"formSelector": "form.form-create-account"
229+
}
230+
}
231+
}
232+
</script>

app/code/Magento/Customer/view/frontend/web/change-email-password.js

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@ define([
3434
}, this));
3535

3636
this._checkChoice();
37+
this._bind();
38+
},
39+
40+
/**
41+
* Event binding, will monitor change, keyup and paste events.
42+
* @private
43+
*/
44+
_bind: function () {
45+
this._on($(this.options.emailSelector), {
46+
'change': this._updatePasswordFieldWithEmailValue,
47+
'keyup': this._updatePasswordFieldWithEmailValue,
48+
'paste': this._updatePasswordFieldWithEmailValue
49+
});
3750
},
3851

3952
/**
@@ -67,10 +80,7 @@ define([
6780

6881
$(this.options.currentPasswordSelector).attr('data-validate', '{required:true}').prop('disabled', false);
6982
$(this.options.emailSelector).attr('data-validate', '{required:true}').prop('disabled', false);
70-
$(this.options.newPasswordSelector).attr(
71-
'data-validate',
72-
'{required:true, \'validate-customer-password\':true}'
73-
).prop('disabled', false);
83+
this._updatePasswordFieldWithEmailValue();
7484
$(this.options.confirmPasswordSelector).attr(
7585
'data-validate',
7686
'{required:true, equalTo:"' + this.options.newPasswordSelector + '"}'
@@ -119,6 +129,19 @@ define([
119129
$(this.options.emailContainerSelector).hide();
120130

121131
$(this.options.emailSelector).removeAttr('data-validate').prop('disabled', true);
132+
},
133+
134+
/**
135+
* Update password validation rules with email input field value
136+
* @private
137+
*/
138+
_updatePasswordFieldWithEmailValue: function () {
139+
$(this.options.newPasswordSelector).attr(
140+
'data-validate',
141+
'{required:true, ' +
142+
'\'validate-customer-password\':true, ' +
143+
'\'password-not-equal-to-user-name\':\'' + $(this.options.emailSelector).val() + '\'}'
144+
).prop('disabled', false);
122145
}
123146
});
124147

app/code/Magento/Customer/view/frontend/web/js/password-strength-indicator.js

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ define([
1919
cache: {},
2020
passwordSelector: '[type=password]',
2121
passwordStrengthMeterSelector: '[data-role=password-strength-meter]',
22-
passwordStrengthMeterLabelSelector: '[data-role=password-strength-meter-label]'
22+
passwordStrengthMeterLabelSelector: '[data-role=password-strength-meter-label]',
23+
formSelector: 'form',
24+
emailSelector: 'input[type="email"]'
2325
},
2426

2527
/**
@@ -30,11 +32,14 @@ define([
3032
this.options.cache.input = $(this.options.passwordSelector, this.element);
3133
this.options.cache.meter = $(this.options.passwordStrengthMeterSelector, this.element);
3234
this.options.cache.label = $(this.options.passwordStrengthMeterLabelSelector, this.element);
35+
36+
// We need to look outside the module for backward compatibility, since someone can already use the module.
37+
this.options.cache.email = $(this.options.formSelector).find(this.options.emailSelector);
3338
this._bind();
3439
},
3540

3641
/**
37-
* Event binding, will monitor scroll and resize events (resize events left for backward compat)
42+
* Event binding, will monitor change, keyup and paste events.
3843
* @private
3944
*/
4045
_bind: function () {
@@ -43,6 +48,14 @@ define([
4348
'keyup': this._calculateStrength,
4449
'paste': this._calculateStrength
4550
});
51+
52+
if (this.options.cache.email.length) {
53+
this._on(this.options.cache.email, {
54+
'change': this._calculateStrength,
55+
'keyup': this._calculateStrength,
56+
'paste': this._calculateStrength
57+
});
58+
}
4659
},
4760

4861
/**
@@ -52,16 +65,25 @@ define([
5265
_calculateStrength: function () {
5366
var password = this._getPassword(),
5467
isEmpty = password.length === 0,
55-
zxcvbnScore = zxcvbn(password).score,
68+
zxcvbnScore,
5669
displayScore,
5770
isValid;
5871

5972
// Display score is based on combination of whether password is empty, valid, and zxcvbn strength
6073
if (isEmpty) {
6174
displayScore = 0;
6275
} else {
63-
isValid = $.validator.validateSingleElement(this.options.cache.input);
64-
displayScore = isValid ? zxcvbnScore : 1;
76+
this.options.cache.input.rules('add', {
77+
'password-not-equal-to-user-name': this.options.cache.email.val()
78+
});
79+
80+
if (password.toLowerCase() === this.options.cache.email.val().toLowerCase()) {
81+
displayScore = 1;
82+
} else {
83+
isValid = $.validator.validateSingleElement(this.options.cache.input);
84+
zxcvbnScore = zxcvbn(password).score;
85+
displayScore = isValid ? zxcvbnScore : 1;
86+
}
6587
}
6688

6789
// Update label
@@ -75,32 +97,32 @@ define([
7597
*/
7698
_displayStrength: function (displayScore) {
7799
var strengthLabel = '',
78-
className = 'password-';
100+
className;
79101

80102
switch (displayScore) {
81103
case 0:
82104
strengthLabel = $t('No Password');
83-
className += 'none';
105+
className = 'password-none';
84106
break;
85107

86108
case 1:
87109
strengthLabel = $t('Weak');
88-
className += 'weak';
110+
className = 'password-weak';
89111
break;
90112

91113
case 2:
92114
strengthLabel = $t('Medium');
93-
className += 'medium';
115+
className = 'password-medium';
94116
break;
95117

96118
case 3:
97119
strengthLabel = $t('Strong');
98-
className += 'strong';
120+
className = 'password-strong';
99121
break;
100122

101123
case 4:
102124
strengthLabel = $t('Very Strong');
103-
className += 'very-strong';
125+
className = 'password-very-strong';
104126
break;
105127
}
106128

0 commit comments

Comments
 (0)