mirror of
https://github.com/bdnugget/magento2.git
synced 2026-11-08 01:37:36 +00:00
344 lines
11 KiB
PHP
344 lines
11 KiB
PHP
<?php
|
|
/**
|
|
* Copyright © Magento, Inc. All rights reserved.
|
|
* See COPYING.txt for license details.
|
|
*/
|
|
declare(strict_types=1);
|
|
|
|
namespace Magento\Customer\Test\Unit\Model;
|
|
|
|
use Magento\Backend\App\ConfigInterface;
|
|
use Magento\Customer\Api\CustomerRepositoryInterface;
|
|
use Magento\Customer\Api\Data\CustomerInterface;
|
|
use Magento\Customer\Model\Authentication;
|
|
use Magento\Customer\Model\Customer;
|
|
use Magento\Customer\Model\CustomerAuthUpdate;
|
|
use Magento\Customer\Model\CustomerRegistry;
|
|
use Magento\Customer\Model\Data\CustomerSecure;
|
|
use Magento\Framework\Encryption\EncryptorInterface;
|
|
use Magento\Framework\Exception\InvalidEmailOrPasswordException;
|
|
use Magento\Framework\Stdlib\DateTime;
|
|
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
|
|
use PHPUnit\Framework\MockObject\MockObject;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
|
|
*/
|
|
class AuthenticationTest extends TestCase
|
|
{
|
|
/**
|
|
* @var ConfigInterface|MockObject
|
|
*/
|
|
private $backendConfigMock;
|
|
|
|
/**
|
|
* @var CustomerRegistry|MockObject
|
|
*/
|
|
private $customerRegistryMock;
|
|
|
|
/**
|
|
* @var EncryptorInterface|MockObject
|
|
*/
|
|
protected $encryptorMock;
|
|
|
|
/**
|
|
* @var CustomerRepositoryInterface|MockObject
|
|
*/
|
|
private $customerRepositoryMock;
|
|
|
|
/**
|
|
* @var CustomerSecure|MockObject
|
|
*/
|
|
private $customerSecureMock;
|
|
|
|
/**
|
|
* @var Authentication
|
|
*/
|
|
private $authentication;
|
|
|
|
/**
|
|
* @var DateTime
|
|
*/
|
|
private $dateTimeMock;
|
|
|
|
/**
|
|
* @var CustomerAuthUpdate|MockObject
|
|
*/
|
|
protected $customerAuthUpdate;
|
|
|
|
/**
|
|
* @var ObjectManagerHelper
|
|
*/
|
|
protected $objectManager;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$this->objectManager = new ObjectManagerHelper($this);
|
|
|
|
$this->backendConfigMock = $this->getMockBuilder(ConfigInterface::class)
|
|
->disableOriginalConstructor()
|
|
->setMethods(['getValue'])
|
|
->getMockForAbstractClass();
|
|
$this->customerRegistryMock = $this->createPartialMock(
|
|
CustomerRegistry::class,
|
|
['retrieveSecureData', 'retrieve']
|
|
);
|
|
$this->customerRepositoryMock = $this->getMockBuilder(CustomerRepositoryInterface::class)
|
|
->disableOriginalConstructor()
|
|
->getMockForAbstractClass();
|
|
$this->encryptorMock = $this->getMockBuilder(EncryptorInterface::class)
|
|
->disableOriginalConstructor()
|
|
->getMockForAbstractClass();
|
|
$this->dateTimeMock = $this->getMockBuilder(DateTime::class)
|
|
->disableOriginalConstructor()
|
|
->getMock();
|
|
$this->dateTimeMock->expects($this->any())
|
|
->method('formatDate')
|
|
->willReturn('formattedDate');
|
|
$this->customerSecureMock = $this->getMockBuilder(CustomerSecure::class)
|
|
->addMethods(
|
|
[
|
|
'getId',
|
|
'getPasswordHash',
|
|
'isCustomerLocked',
|
|
'getFailuresNum',
|
|
'getFirstFailure',
|
|
'getLockExpires',
|
|
'setFirstFailure',
|
|
'setFailuresNum',
|
|
'setLockExpires'
|
|
]
|
|
)
|
|
->disableOriginalConstructor()
|
|
->getMock();
|
|
|
|
$this->customerAuthUpdate = $this->getMockBuilder(CustomerAuthUpdate::class)
|
|
->disableOriginalConstructor()
|
|
->getMock();
|
|
|
|
$this->authentication = $this->objectManager->getObject(
|
|
Authentication::class,
|
|
[
|
|
'customerRegistry' => $this->customerRegistryMock,
|
|
'backendConfig' => $this->backendConfigMock,
|
|
'customerRepository' => $this->customerRepositoryMock,
|
|
'encryptor' => $this->encryptorMock,
|
|
'dateTime' => $this->dateTimeMock,
|
|
]
|
|
);
|
|
|
|
$this->objectManager->setBackwardCompatibleProperty(
|
|
$this->authentication,
|
|
'customerAuthUpdate',
|
|
$this->customerAuthUpdate
|
|
);
|
|
}
|
|
|
|
public function testProcessAuthenticationFailureLockingIsDisabled()
|
|
{
|
|
$customerId = 1;
|
|
$this->backendConfigMock->expects($this->exactly(2))
|
|
->method('getValue')
|
|
->withConsecutive(
|
|
[Authentication::LOCKOUT_THRESHOLD_PATH],
|
|
[Authentication::MAX_FAILURES_PATH]
|
|
)
|
|
->willReturnOnConsecutiveCalls(0, 0);
|
|
$this->customerRegistryMock->expects($this->once())
|
|
->method('retrieveSecureData')
|
|
->with($customerId)
|
|
->willReturn($this->customerSecureMock);
|
|
$this->authentication->processAuthenticationFailure($customerId);
|
|
}
|
|
|
|
/**
|
|
* @param int $failureNum
|
|
* @param string $firstFailure
|
|
* @param string $lockExpires
|
|
* @param int $setFailureNumCallCtr
|
|
* @param int $setFailureNumValue
|
|
* @param int $setFirstFailureCallCtr
|
|
* @param int $setFirstFailureValue
|
|
* @param int $setLockExpiresCallCtr
|
|
* @param int $setLockExpiresValue
|
|
* @dataProvider processAuthenticationFailureDataProvider
|
|
*/
|
|
public function testProcessAuthenticationFailureFirstAttempt(
|
|
$failureNum,
|
|
$firstFailure,
|
|
$lockExpires,
|
|
$setFailureNumCallCtr,
|
|
$setFailureNumValue,
|
|
$setFirstFailureCallCtr,
|
|
$setLockExpiresCallCtr,
|
|
$setLockExpiresValue
|
|
) {
|
|
$customerId = 1;
|
|
$this->backendConfigMock->expects($this->exactly(2))
|
|
->method('getValue')
|
|
->withConsecutive(
|
|
[Authentication::LOCKOUT_THRESHOLD_PATH],
|
|
[Authentication::MAX_FAILURES_PATH]
|
|
)
|
|
->willReturnOnConsecutiveCalls(10, 5);
|
|
|
|
$this->customerRegistryMock->expects($this->once())
|
|
->method('retrieveSecureData')
|
|
->with($customerId)
|
|
->willReturn($this->customerSecureMock);
|
|
$this->customerAuthUpdate->expects($this->once())
|
|
->method('saveAuth')
|
|
->with($customerId)
|
|
->willReturnSelf();
|
|
|
|
$this->customerSecureMock->expects($this->once())->method('getFailuresNum')->willReturn($failureNum);
|
|
$this->customerSecureMock->expects($this->once())
|
|
->method('getFirstFailure')
|
|
->willReturn($firstFailure ? (new \DateTime())->modify($firstFailure)->format('Y-m-d H:i:s') : null);
|
|
$this->customerSecureMock->expects($this->once())
|
|
->method('getLockExpires')
|
|
->willReturn($lockExpires ? (new \DateTime())->modify($lockExpires)->format('Y-m-d H:i:s') : null);
|
|
$this->customerSecureMock->expects($this->exactly($setFirstFailureCallCtr))->method('setFirstFailure');
|
|
$this->customerSecureMock->expects($this->exactly($setFailureNumCallCtr))
|
|
->method('setFailuresNum')
|
|
->with($setFailureNumValue);
|
|
$this->customerSecureMock->expects($this->exactly($setLockExpiresCallCtr))
|
|
->method('setLockExpires')
|
|
->with($setLockExpiresValue);
|
|
|
|
$this->authentication->processAuthenticationFailure($customerId);
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function processAuthenticationFailureDataProvider()
|
|
{
|
|
return [
|
|
'first attempt' => [0, null, null, 1, 1, 1, 1, null],
|
|
'not locked' => [3, '-400 second', null, 1, 4, 0, 0, null],
|
|
'lock expired' => [5, '-400 second', '-100 second', 1, 1, 1, 1, null],
|
|
'max attempt' => [4, '-400 second', null, 1, 5, 0, 1, 'formattedDate'],
|
|
];
|
|
}
|
|
|
|
public function testUnlock()
|
|
{
|
|
$customerId = 1;
|
|
$this->customerRegistryMock->expects($this->once())
|
|
->method('retrieveSecureData')
|
|
->with($customerId)
|
|
->willReturn($this->customerSecureMock);
|
|
$this->customerAuthUpdate->expects($this->once())
|
|
->method('saveAuth')
|
|
->with($customerId)
|
|
->willReturnSelf();
|
|
$this->customerSecureMock->expects($this->once())->method('setFailuresNum')->with(0);
|
|
$this->customerSecureMock->expects($this->once())->method('setFirstFailure')->with(null);
|
|
$this->customerSecureMock->expects($this->once())->method('setLockExpires')->with(null);
|
|
$this->authentication->unlock($customerId);
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function validatePasswordAndLockStatusDataProvider()
|
|
{
|
|
return [[true], [false]];
|
|
}
|
|
|
|
/**
|
|
* @return void
|
|
*/
|
|
public function testIsLocked()
|
|
{
|
|
$customerId = 7;
|
|
|
|
$customerModelMock = $this->getMockBuilder(Customer::class)
|
|
->disableOriginalConstructor()
|
|
->getMock();
|
|
$customerModelMock->expects($this->once())
|
|
->method('isCustomerLocked');
|
|
$this->customerRegistryMock->expects($this->once())
|
|
->method('retrieve')
|
|
->with($customerId)
|
|
->willReturn($customerModelMock);
|
|
|
|
$this->authentication->isLocked($customerId);
|
|
}
|
|
|
|
/**
|
|
* @param bool $result
|
|
* @dataProvider validateCustomerPassword
|
|
*/
|
|
public function testAuthenticate($result)
|
|
{
|
|
$customerId = 7;
|
|
$password = '1234567';
|
|
$hash = '1b2af329dd0';
|
|
|
|
$customerMock = $this->getMockForAbstractClass(CustomerInterface::class);
|
|
$this->customerRepositoryMock->expects($this->any())
|
|
->method('getById')
|
|
->willReturn($customerMock);
|
|
|
|
$this->customerSecureMock->expects($this->any())
|
|
->method('getId')
|
|
->willReturn($customerId);
|
|
|
|
$this->customerSecureMock->expects($this->once())
|
|
->method('getPasswordHash')
|
|
->willReturn($hash);
|
|
|
|
$this->customerRegistryMock->expects($this->any())
|
|
->method('retrieveSecureData')
|
|
->with($customerId)
|
|
->willReturn($this->customerSecureMock);
|
|
|
|
$this->encryptorMock->expects($this->once())
|
|
->method('validateHash')
|
|
->with($password, $hash)
|
|
->willReturn($result);
|
|
|
|
if ($result) {
|
|
$this->assertTrue($this->authentication->authenticate($customerId, $password));
|
|
} else {
|
|
$this->backendConfigMock->expects($this->exactly(2))
|
|
->method('getValue')
|
|
->withConsecutive(
|
|
[Authentication::LOCKOUT_THRESHOLD_PATH],
|
|
[Authentication::MAX_FAILURES_PATH]
|
|
)
|
|
->willReturnOnConsecutiveCalls(1, 1);
|
|
$this->customerSecureMock->expects($this->once())
|
|
->method('isCustomerLocked')
|
|
->willReturn(false);
|
|
|
|
$this->customerRegistryMock->expects($this->once())
|
|
->method('retrieve')
|
|
->with($customerId)
|
|
->willReturn($this->customerSecureMock);
|
|
|
|
$this->customerAuthUpdate->expects($this->once())
|
|
->method('saveAuth')
|
|
->with($customerId)
|
|
->willReturnSelf();
|
|
|
|
$this->expectException(InvalidEmailOrPasswordException::class);
|
|
$this->authentication->authenticate($customerId, $password);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function validateCustomerPassword()
|
|
{
|
|
return [
|
|
[true],
|
|
[false],
|
|
];
|
|
}
|
|
}
|