Skip to content
This repository was archived by the owner on Dec 19, 2019. It is now read-only.

[Recheck] Allow changing logged in customers password with Graphql mutation #187

Merged
merged 12 commits into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\CustomerGraphQl\Model\Resolver\Customer\Account;

use Magento\Authorization\Model\UserContextInterface;
use Magento\Customer\Api\AccountManagementInterface;
use Magento\Customer\Model\Customer;
use Magento\CustomerGraphQl\Model\Resolver\Customer\CustomerDataProvider;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Exception\GraphQlAuthorizationException;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;

/**
* @inheritdoc
*/
class ChangePassword implements ResolverInterface
{
/**
* @var UserContextInterface
*/
private $userContext;

/**
* @var AccountManagementInterface
*/
private $accountManagement;

/**
* @var CustomerDataProvider
*/
private $customerResolver;

/**
* @param UserContextInterface $userContext
* @param AccountManagementInterface $accountManagement
* @param CustomerDataProvider $customerResolver
*/
public function __construct(
UserContextInterface $userContext,
AccountManagementInterface $accountManagement,
CustomerDataProvider $customerResolver
) {
$this->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;
}
}
1 change: 1 addition & 0 deletions app/code/Magento/CustomerGraphQl/etc/schema.graphqls
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
declare(strict_types=1);

namespace Magento\GraphQl\Customer;

use Magento\Customer\Api\AccountManagementInterface;
use Magento\Customer\Model\CustomerRegistry;
use Magento\Framework\Exception\LocalizedException;
use Magento\Integration\Api\CustomerTokenServiceInterface;
use Magento\TestFramework\Helper\Bootstrap;
use Magento\TestFramework\TestCase\GraphQlAbstract;

class CustomerChangePasswordTest extends GraphQlAbstract
{
/**
* @var AccountManagementInterface
*/
private $accountManagement;

/**
* @var CustomerTokenServiceInterface
*/
private $customerTokenService;

/**
* @var CustomerRegistry
*/
private $customerRegistry;

protected function setUp()
{
$this->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 = '[email protected]';
$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 = '[email protected]';
$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 = '[email protected]';
$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 = <<<QUERY
mutation {
changeCustomerPassword(
currentPassword: "$currentPassword",
newPassword: "$newPassword"
) {
id
email
firstname
lastname
}
}
QUERY;

return $query;
}

/**
* @param string $email
* @param string $password
* @return array
*/
private function getCustomerAuthHeaders(string $email, string $password): array
{
$customerToken = $this->customerTokenService->createCustomerAccessToken($email, $password);
return ['Authorization' => 'Bearer ' . $customerToken];
}
}