diff --git a/app/code/Magento/CustomerGraphQl/Model/Resolver/Customer/Account/ChangePassword.php b/app/code/Magento/CustomerGraphQl/Model/Resolver/Customer/Account/ChangePassword.php new file mode 100644 index 000000000000..84425df62a62 --- /dev/null +++ b/app/code/Magento/CustomerGraphQl/Model/Resolver/Customer/Account/ChangePassword.php @@ -0,0 +1,88 @@ +userContext = $userContext; + $this->accountManagement = $accountManagement; + $this->customerResolver = $customerResolver; + } + + /** + * @inheritdoc + */ + public function resolve( + Field $field, + $context, + ResolveInfo $info, + array $value = null, + array $args = null + ) { + if (!isset($args['currentPassword'])) { + throw new GraphQlInputException(__('"currentPassword" value should be specified')); + } + + if (!isset($args['newPassword'])) { + throw new GraphQlInputException(__('"newPassword" value should be specified')); + } + + $customerId = (int)$this->userContext->getUserId(); + if ($customerId === 0) { + throw new GraphQlAuthorizationException( + __( + 'Current customer does not have access to the resource "%1"', + [Customer::ENTITY] + ) + ); + } + + $this->accountManagement->changePasswordById($customerId, $args['currentPassword'], $args['newPassword']); + $data = $this->customerResolver->getCustomerById($customerId); + + return $data; + } +} diff --git a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls index 2fbf2b121939..93c741adea87 100644 --- a/app/code/Magento/CustomerGraphQl/etc/schema.graphqls +++ b/app/code/Magento/CustomerGraphQl/etc/schema.graphqls @@ -7,6 +7,7 @@ type Query { type Mutation { generateCustomerToken(email: String!, password: String!): CustomerToken @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\Customer\\Account\\GenerateCustomerToken") @doc(description:"Retrieve Customer token") + changeCustomerPassword(currentPassword: String!, newPassword: String!): Customer @resolver(class: "\\Magento\\CustomerGraphQl\\Model\\Resolver\\Customer\\Account\\ChangePassword") @doc(description:"Changes password for logged in customer") } type CustomerToken { diff --git a/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CustomerChangePasswordTest.php b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CustomerChangePasswordTest.php new file mode 100644 index 000000000000..ede719bb569b --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/GraphQl/Customer/CustomerChangePasswordTest.php @@ -0,0 +1,147 @@ +customerTokenService = Bootstrap::getObjectManager()->get(CustomerTokenServiceInterface::class); + $this->accountManagement = Bootstrap::getObjectManager()->get(AccountManagementInterface::class); + $this->customerRegistry = Bootstrap::getObjectManager()->get(CustomerRegistry::class); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testCustomerChangeValidPassword() + { + $customerEmail = 'customer@example.com'; + $oldCustomerPassword = 'password'; + $newCustomerPassword = 'anotherPassword1'; + + $query = $this->getChangePassQuery($oldCustomerPassword, $newCustomerPassword); + $headerMap = $this->getCustomerAuthHeaders($customerEmail, $oldCustomerPassword); + + $response = $this->graphQlQuery($query, [], '', $headerMap); + $this->assertEquals($customerEmail, $response['changeCustomerPassword']['email']); + + try { + // registry contains the old password hash so needs to be reset + $this->customerRegistry->removeByEmail($customerEmail); + $this->accountManagement->authenticate($customerEmail, $newCustomerPassword); + } catch (LocalizedException $e) { + $this->fail('Password was not changed: ' . $e->getMessage()); + } + } + + public function testGuestUserCannotChangePassword() + { + $query = $this->getChangePassQuery('currentpassword', 'newpassword'); + $this->expectException(\Exception::class); + $this->expectExceptionMessage( + 'GraphQL response contains errors: Current customer' . ' ' . + 'does not have access to the resource "customer"' + ); + $this->graphQlQuery($query); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testChangeWeakPassword() + { + $this->markTestIncomplete('https://github.com/magento/graphql-ce/issues/190'); + $customerEmail = 'customer@example.com'; + $oldCustomerPassword = 'password'; + $newCustomerPassword = 'weakpass'; + + $query = $this->getChangePassQuery($oldCustomerPassword, $newCustomerPassword); + $headerMap = $this->getCustomerAuthHeaders($customerEmail, $oldCustomerPassword); + + $this->expectException(\Exception::class); + $this->expectExceptionMessageRegExp('/Minimum of different classes of characters in password is.*/'); + + $this->graphQlQuery($query, [], '', $headerMap); + } + + /** + * @magentoApiDataFixture Magento/Customer/_files/customer.php + */ + public function testCannotChangeWithIncorrectPassword() + { + $this->markTestIncomplete('https://github.com/magento/graphql-ce/issues/190'); + $customerEmail = 'customer@example.com'; + $oldCustomerPassword = 'password'; + $newCustomerPassword = 'anotherPassword1'; + $incorrectPassword = 'password-incorrect'; + + $query = $this->getChangePassQuery($incorrectPassword, $newCustomerPassword); + + // acquire authentication with correct password + $headerMap = $this->getCustomerAuthHeaders($customerEmail, $oldCustomerPassword); + + $this->expectException(\Exception::class); + $this->expectExceptionMessageRegExp('/The password doesn\'t match this account. Verify the password.*/'); + + // but try to change with incorrect 'old' password + $this->graphQlQuery($query, [], '', $headerMap); + } + + private function getChangePassQuery($currentPassword, $newPassword) + { + $query = <<customerTokenService->createCustomerAccessToken($email, $password); + return ['Authorization' => 'Bearer ' . $customerToken]; + } +}