From 8ebc157793f23bae5e40ac509e81db45f6af5202 Mon Sep 17 00:00:00 2001 From: Pavel Bystritsky Date: Mon, 3 Aug 2020 16:53:25 +0300 Subject: [PATCH] magento/security-package#260: Cover reCAPTCHA for customer account edit with integration tests. --- .../Test/Integration/EditFromTest.php | 316 ++++++++++++++++++ 1 file changed, 316 insertions(+) create mode 100644 ReCaptchaCustomer/Test/Integration/EditFromTest.php diff --git a/ReCaptchaCustomer/Test/Integration/EditFromTest.php b/ReCaptchaCustomer/Test/Integration/EditFromTest.php new file mode 100644 index 00000000..b62e0983 --- /dev/null +++ b/ReCaptchaCustomer/Test/Integration/EditFromTest.php @@ -0,0 +1,316 @@ +mutableScopeConfig = $this->_objectManager->get(MutableScopeConfig::class); + $this->formKey = $this->_objectManager->get(FormKey::class); + $this->customerRepository = $this->_objectManager->get(CustomerRepositoryInterface::class); + $this->session = $this->_objectManager->get(Session::class); + $this->url = $this->_objectManager->get(UrlInterface::class); + + $this->captchaValidationResultMock = $this->createMock(ValidationResult::class); + $captchaValidationResultMock = $this->createMock(Validator::class); + $captchaValidationResultMock->expects($this->any()) + ->method('isValid') + ->willReturn($this->captchaValidationResultMock); + $this->_objectManager->addSharedInstance($captchaValidationResultMock, Validator::class); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + */ + public function testGetRequestIfReCaptchaIsDisabled(): void + { + $this->setConfig(false, 'test_public_key', 'test_private_key'); + + $this->checkSuccessfulGetResponse(); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + * + * It's needed for proper work of "ifconfig" in layout during tests running + * @magentoConfigFixture default_store recaptcha_frontend/type_for/customer_edit invisible + */ + public function testGetRequestIfReCaptchaKeysAreNotConfigured(): void + { + $this->setConfig(true, null, null); + + $this->checkSuccessfulGetResponse(); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + * + * It's needed for proper work of "ifconfig" in layout during tests running + * @magentoConfigFixture default_store recaptcha_frontend/type_for/customer_edit invisible + */ + public function testGetRequestIfReCaptchaIsEnabled(): void + { + $this->setConfig(true, 'test_public_key', 'test_private_key'); + + $this->checkSuccessfulGetResponse(true); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + */ + public function testPostRequestIfReCaptchaIsDisabled(): void + { + $this->setConfig(false, 'test_public_key', 'test_private_key'); + + $this->checkSuccessfulPostResponse(); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + */ + public function testPostRequestIfReCaptchaKeysAreNotConfigured(): void + { + $this->setConfig(true, null, null); + + $this->checkSuccessfulPostResponse(); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + */ + public function testPostRequestWithSuccessfulReCaptchaValidation(): void + { + $this->setConfig(true, 'test_public_key', 'test_private_key'); + $this->captchaValidationResultMock->expects($this->once())->method('isValid')->willReturn(true); + + $this->checkSuccessfulPostResponse( + [CaptchaResponseResolverInterface::PARAM_RECAPTCHA => 'test'] + ); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + */ + public function testPostRequestIfReCaptchaParameterIsMissed(): void + { + $this->setConfig(true, 'test_public_key', 'test_private_key'); + + $this->checkFailedPostResponse(); + } + + /** + * @magentoConfigFixture default_store customer/captcha/enable 0 + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/public_key test_public_key + * @magentoConfigFixture base_website recaptcha_frontend/type_invisible/private_key test_private_key + * @magentoConfigFixture base_website recaptcha_frontend/type_for/customer_edit invisible + */ + public function testPostRequestWithFailedReCaptchaValidation(): void + { + $this->setConfig(true, 'test_public_key', 'test_private_key'); + $this->captchaValidationResultMock->expects($this->once())->method('isValid')->willReturn(false); + + $this->checkFailedPostResponse( + [CaptchaResponseResolverInterface::PARAM_RECAPTCHA => 'test'] + ); + } + + /** + * @param bool $shouldContainReCaptcha + * @return void + */ + private function checkSuccessfulGetResponse($shouldContainReCaptcha = false): void + { + $this->session->loginById(1); + $this->dispatch('customer/account/edit'); + $content = $this->getResponse()->getBody(); + + self::assertNotEmpty($content); + + $shouldContainReCaptcha + ? $this->assertStringContainsString('field-recaptcha', $content) + : $this->assertStringNotContainsString('field-recaptcha', $content); + + self::assertEmpty($this->getSessionMessages(MessageInterface::TYPE_ERROR)); + } + + /** + * @param array $postValues + * @return void + */ + private function checkSuccessfulPostResponse(array $postValues = []): void + { + $this->session->loginById(1); + $this->makePostRequest($postValues); + + $this->assertRedirect(self::equalTo($this->url->getRouteUrl('customer/account'))); + self::assertEmpty($this->getSessionMessages(MessageInterface::TYPE_ERROR)); + + $customer = $this->customerRepository->getById(1); + $this->assertEquals('Test First Name', $customer->getFirstname()); + $this->assertEquals('Test Last Name', $customer->getLastname()); + $this->assertEquals('customer@example.com', $customer->getEmail()); + } + + /** + * @param array $postValues + * @return void + */ + private function checkFailedPostResponse(array $postValues = []): void + { + $this->session->loginById(1); + $this->makePostRequest($postValues); + + $this->assertRedirect(self::stringStartsWith($this->url->getRouteUrl('customer/account/edit'))); + $this->assertSessionMessages( + self::equalTo(['reCAPTCHA verification failed']), + MessageInterface::TYPE_ERROR + ); + + $customer = $this->customerRepository->getById(1); + $this->assertEquals('John', $customer->getFirstname()); + $this->assertEquals('Smith', $customer->getLastname()); + $this->assertEquals('customer@example.com', $customer->getEmail()); + } + + /** + * @param array $postValues + * @return void + */ + private function makePostRequest(array $postValues = []): void + { + $this->getRequest() + ->setMethod(Http::METHOD_POST) + ->setPostValue( + array_replace_recursive( + [ + 'form_key' => $this->formKey->getFormKey(), + 'firstname' => 'Test First Name', + 'lastname' => 'Test Last Name', + ], + $postValues + ) + ); + + $this->dispatch('customer/account/editpost'); + } + + /** + * @param bool $isEnabled + * @param string|null $public + * @param string|null $private + * @return void + */ + private function setConfig(bool $isEnabled, ?string $public, ?string $private): void + { + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_for/customer_edit', + $isEnabled ? 'invisible' : null, + ScopeInterface::SCOPE_WEBSITE + ); + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_invisible/public_key', + $public, + ScopeInterface::SCOPE_WEBSITE + ); + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_invisible/private_key', + $private, + ScopeInterface::SCOPE_WEBSITE + ); + } + + protected function tearDown(): void + { + parent::tearDown(); + + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_for/customer_edit', + null, + ScopeInterface::SCOPE_WEBSITE + ); + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_invisible/public_key', + null, + ScopeInterface::SCOPE_WEBSITE + ); + $this->mutableScopeConfig->setValue( + 'recaptcha_frontend/type_invisible/private_key', + null, + ScopeInterface::SCOPE_WEBSITE + ); + } +}