From 781e4b166f63da8d1bd4d63ecd4deaa5dcc99a5c Mon Sep 17 00:00:00 2001 From: Viktor Sevch Date: Wed, 24 Feb 2021 10:49:11 +0200 Subject: [PATCH 1/4] MC-39885: Improve customer api --- .../Magento/Customer/Model/Validator/Name.php | 58 +++++ ...pdateCustomerInformationAddAddressTest.xml | 5 +- app/code/Magento/Customer/etc/validation.xml | 6 + .../Customer/Api/CustomerRepositoryTest.php | 200 ++++++++++++++++++ 4 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 app/code/Magento/Customer/Model/Validator/Name.php diff --git a/app/code/Magento/Customer/Model/Validator/Name.php b/app/code/Magento/Customer/Model/Validator/Name.php new file mode 100644 index 0000000000000..5e0a94604893d --- /dev/null +++ b/app/code/Magento/Customer/Model/Validator/Name.php @@ -0,0 +1,58 @@ +isValidName($customer->getFirstname())) { + parent::_addMessages([['firstname' => 'First Name is not valid!']]); + } + + if (!$this->isValidName($customer->getLastname())) { + parent::_addMessages([['lastname' => 'Last Name is not valid!']]); + } + + if (!$this->isValidName($customer->getMiddlename())) { + parent::_addMessages([['middlename' => 'Middle Name is not valid!']]); + } + + return count($this->_messages) == 0; + } + + /** + * Check if name field is valid. + * + * @param string|null $nameValue + * @return bool + */ + private function isValidName($nameValue) + { + if ($nameValue != null) { + $pattern = '/(?:[\p{L}\p{M}\,\-\_\.\'\"\s\d]){1,255}+/u'; + if (preg_match($pattern, $nameValue, $matches)) { + return $matches[0] == $nameValue; + } + } + + return true; + } +} diff --git a/app/code/Magento/Customer/Test/Mftf/Test/StorefrontVerifyNoXssInjectionOnUpdateCustomerInformationAddAddressTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontVerifyNoXssInjectionOnUpdateCustomerInformationAddAddressTest.xml index 11aed4a3461e1..712ad61a9663e 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/StorefrontVerifyNoXssInjectionOnUpdateCustomerInformationAddAddressTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/StorefrontVerifyNoXssInjectionOnUpdateCustomerInformationAddAddressTest.xml @@ -11,12 +11,15 @@ - + <title value="DEPRECATED [Security] Verify No XSS Injection on Update Customer Information Add Address"/> <description value="Test log in to Storefront and Verify No XSS Injection on Update Customer Information Add Address"/> <testCaseId value="MC-10910"/> <severity value="CRITICAL"/> <group value="customer"/> <group value="mtf_migrated"/> + <skip> + <issueId value="DEPRECATED">Test outdated</issueId> + </skip> </annotations> <before> diff --git a/app/code/Magento/Customer/etc/validation.xml b/app/code/Magento/Customer/etc/validation.xml index 85d657dff266a..bac6e54afa7b5 100644 --- a/app/code/Magento/Customer/etc/validation.xml +++ b/app/code/Magento/Customer/etc/validation.xml @@ -18,11 +18,17 @@ <constraint alias="metadata_data_validator" class="Magento\Customer\Model\Metadata\Validator" /> </entity_constraints> </rule> + <rule name="check_name"> + <entity_constraints> + <constraint alias="name_validator" class="Magento\Customer\Model\Validator\Name" /> + </entity_constraints> + </rule> </rules> <groups> <group name="save"> <uses> <use rule="check_eav"/> + <use rule="check_name"/> </uses> </group> <group name="form"> diff --git a/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerRepositoryTest.php index f7732b5fd68dd..95f7da88b0619 100644 --- a/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Customer/Api/CustomerRepositoryTest.php @@ -1058,4 +1058,204 @@ protected function _createCustomer(?array $additionalData = []) $this->currentCustomerId[] = $customerData['id']; return $customerData; } + + /** + * Test customer create with invalid name's. + * + * @param string $fieldName + * @param string $fieldValue + * @param string $expectedMessage + * @return void + * + * @dataProvider customerDataProvider + */ + public function testCreateCustomerWithInvalidCustomerFirstName(string $fieldName, string $fieldValue, string $expectedMessage): void + { + $customerData = $this->dataObjectProcessor->buildOutputDataArray( + $this->customerHelper->createSampleCustomerDataObject(), + Customer::class + ); + $customerData[$fieldName] = $fieldValue; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $requestData = ['customer' => $customerData]; + + try { + $this->_webApiCall($serviceInfo, $requestData); + $this->fail('Expected exception was not raised'); + } catch (\SoapFault $e) { + $this->assertStringContainsString($expectedMessage, $e->getMessage()); + } catch (\Exception $e) { + $errorObj = $this->processRestExceptionResult($e); + $this->assertEquals(HTTPExceptionCodes::HTTP_BAD_REQUEST, $e->getCode()); + $this->assertEquals($expectedMessage, $errorObj['message']); + } + } + + /** + * Invalid customer data provider + * + * @return array + */ + public function customerDataProvider(): array + { + return [ + ['firstname', 'Jane ☺ ', 'First Name is not valid!'], + ['lastname', '☏ - Doe', 'Last Name is not valid!'], + ['middlename', '⚐ $(date)', 'Middle Name is not valid!'], + [ + 'firstname', + str_repeat('खाना अच्छा है', 20), + 'First Name is not valid!', + ], + [ + 'lastname', + str_repeat('المغلوطة حول استنكار النشوة وتمجيد الألمالمغلوطة حول', 5), + 'Last Name is not valid!', + ], + ]; + } + + /** + * Test customer create with ultibyte chanracters in name's. + * + * @param string $fieldName + * @param string $fieldValue + * @return void + * + * @dataProvider customerWithMultiByteDataProvider + */ + public function testCreateCustomerWithMultibyteCharacters(string $fieldName, string $fieldValue): void + { + $customerData = $this->dataObjectProcessor->buildOutputDataArray( + $this->customerHelper->createSampleCustomerDataObject(), + Customer::class + ); + $customerData[$fieldName] = $fieldValue; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $requestData = ['customer' => $customerData]; + + $response = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertNotNull($response); + $this->assertEquals($fieldValue, $response[$fieldName]); + } + + /** + * Customer with multibyte characters data provider. + * + * @return array + */ + public function customerWithMultiByteDataProvider(): array + { + return [ + [ + 'firstname', + str_repeat('हैखान', 51), + ], + [ + 'lastname', + str_repeat('مغلوطة حول استنكار النشوة وتمجيد الألمالمغلوطة حول', 5), + ], + ]; + } + + /** + * Test customer create with valid name's. + * + * @param string $fieldName + * @param string $fieldValue + * @return void + * + * @dataProvider customerValidNameDataProvider + */ + public function testCreateCustomerWithValidName(string $fieldName, string $fieldValue): void + { + $customerData = $this->dataObjectProcessor->buildOutputDataArray( + $this->customerHelper->createSampleCustomerDataObject(), + Customer::class + ); + $customerData[$fieldName] = $fieldValue; + + $serviceInfo = [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Save', + ], + ]; + + $requestData = ['customer' => $customerData]; + + $response = $this->_webApiCall($serviceInfo, $requestData); + + $this->assertNotNull($response); + $this->assertEquals($fieldValue, $response[$fieldName]); + } + + /** + * Customer valid name data provider. + * + * @return array + */ + public function customerValidNameDataProvider(): array + { + return [ + [ + 'firstname', + 'Anne-Marie', + ], + [ + 'lastname', + 'D\'Artagnan', + ], + [ + 'lastname', + 'Guðmundsdóttir', + ], + [ + 'lastname', + 'María José Carreño Quiñones', + ], + [ + 'lastname', + 'Q. Public', + ], + [ + 'firstname', + 'Elizabeth II', + ], + [ + 'firstname', + 'X Æ A-12 Musk', + ], + ]; + } } From 3bade65291d052b5a2a2454d7297a7ffe97d6d87 Mon Sep 17 00:00:00 2001 From: Viktor Sevch <viktor.sevch@transoftgroup.com> Date: Fri, 26 Feb 2021 08:54:12 +0200 Subject: [PATCH 2/4] MC-39885: Improve customer api --- app/code/Magento/Customer/Model/Validator/Name.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/code/Magento/Customer/Model/Validator/Name.php b/app/code/Magento/Customer/Model/Validator/Name.php index 5e0a94604893d..a9a8a76421875 100644 --- a/app/code/Magento/Customer/Model/Validator/Name.php +++ b/app/code/Magento/Customer/Model/Validator/Name.php @@ -15,6 +15,8 @@ */ class Name extends AbstractValidator { + const PATTERN_NAME = '/(?:[\p{L}\p{M}\,\-\_\.\'\s\d]){1,255}+/u'; + /** * Validate name fields. * @@ -47,8 +49,7 @@ public function isValid($customer) private function isValidName($nameValue) { if ($nameValue != null) { - $pattern = '/(?:[\p{L}\p{M}\,\-\_\.\'\"\s\d]){1,255}+/u'; - if (preg_match($pattern, $nameValue, $matches)) { + if (preg_match(self::PATTERN_NAME, $nameValue, $matches)) { return $matches[0] == $nameValue; } } From 7c4a671d514ea515bf0fdf245bae56fbe6e3869f Mon Sep 17 00:00:00 2001 From: Viktor Sevch <viktor.sevch@transoftgroup.com> Date: Fri, 26 Feb 2021 11:34:12 +0200 Subject: [PATCH 3/4] MC-39885: Improve customer api --- .../Test/Mftf/Test/AdminExactMatchSearchInCustomerGridTest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Test/Mftf/Test/AdminExactMatchSearchInCustomerGridTest.xml b/app/code/Magento/Customer/Test/Mftf/Test/AdminExactMatchSearchInCustomerGridTest.xml index 14d569ed9101d..ef9c90847adec 100644 --- a/app/code/Magento/Customer/Test/Mftf/Test/AdminExactMatchSearchInCustomerGridTest.xml +++ b/app/code/Magento/Customer/Test/Mftf/Test/AdminExactMatchSearchInCustomerGridTest.xml @@ -21,7 +21,7 @@ <before> <createData entity="Simple_US_Customer" stepKey="createFirstCustomer"/> <createData entity="Simple_US_Customer" stepKey="createSecondCustomer"> - <field key="firstname">"Jane Doe"</field> + <field key="firstname">Jane Doe</field> </createData> <actionGroup ref="AdminLoginActionGroup" stepKey="login"/> </before> From f77a37aa1ec0034eb96d365fd9974ba68da0ea98 Mon Sep 17 00:00:00 2001 From: Viktor Sevch <viktor.sevch@transoftgroup.com> Date: Fri, 26 Feb 2021 19:12:14 +0200 Subject: [PATCH 4/4] MC-39885: Improve customer api --- app/code/Magento/Customer/Model/Validator/Name.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/code/Magento/Customer/Model/Validator/Name.php b/app/code/Magento/Customer/Model/Validator/Name.php index a9a8a76421875..9bab241465d6c 100644 --- a/app/code/Magento/Customer/Model/Validator/Name.php +++ b/app/code/Magento/Customer/Model/Validator/Name.php @@ -15,7 +15,7 @@ */ class Name extends AbstractValidator { - const PATTERN_NAME = '/(?:[\p{L}\p{M}\,\-\_\.\'\s\d]){1,255}+/u'; + private const PATTERN_NAME = '/(?:[\p{L}\p{M}\,\-\_\.\'\s\d]){1,255}+/u'; /** * Validate name fields.