user_api-1.0.0-beta1/modules/user_api_email_confirm/tests/src/Kernel/SetEmailResourceTest.php
modules/user_api_email_confirm/tests/src/Kernel/SetEmailResourceTest.php
<?php
declare(strict_types=1);
namespace Drupal\Tests\user_api_email_confirm\Kernel;
use Drupal\Core\Test\AssertMailTrait;
use Drupal\Core\Url;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\rest\Entity\RestResourceConfig;
use Drupal\Tests\user_api\Kernel\UserApiTestTrait;
use Drupal\user\Entity\Role;
use Drupal\user\Entity\User;
use Drupal\user\UserInterface;
use Drupal\user_api_email_confirm\Event\SetEmailEvent;
use Drupal\user_api_email_confirm\UserApiEmailConfirmEvents;
use Drupal\verification_hash\VerificationHashManager;
/**
* SetEmailResource test.
*
* @group user_api_email_confirm
*/
class SetEmailResourceTest extends EntityKernelTestBase {
use UserApiTestTrait;
use AssertMailTrait;
/**
* {@inheritdoc}
*/
protected static $modules = [
'rest',
'serialization',
'user_api',
'user_api_email_confirm',
'verification',
'verification_hash',
];
/**
* The URL to the resource.
*
* @var \Drupal\Core\Url
*/
protected $url;
/**
* The kernel.
*
* @var \Symfony\Component\HttpKernel\HttpKernelInterface
*/
protected $httpKernel;
/**
* User settings config instance.
*
* @var \Drupal\Core\Config\Config
*/
protected $userSettings;
/**
* The user.
*/
protected UserInterface $user;
/**
* The hash manager.
*/
protected VerificationHashManager $hashManager;
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test');
$this->installConfig(['user']);
$this->installConfig(['user_api_email_confirm']);
$this->setUpCurrentUser();
RestResourceConfig::create([
'id' => 'user_api_email_confirm_set_email',
'plugin_id' => 'user_api_email_confirm_set_email',
'granularity' => RestResourceConfig::RESOURCE_GRANULARITY,
'configuration' => [
'methods' => ['POST'],
'formats' => ['json'],
'authentication' => ['cookie'],
],
])->save();
$this->userSettings = $this->config('user.settings');
$this->userSettings
->set('register', UserInterface::REGISTER_VISITORS)
->set('verify_mail', TRUE)
->save();
$this->url = Url::fromRoute('rest.user_api_email_confirm_set_email.POST');
$this->httpKernel = $this->container->get('http_kernel');
$this->user = $this->drupalCreateUser([
'restful post user_api_email_confirm_set_email',
]);
$this->setCurrentUser($this->user);
$anonRole = Role::load(Role::ANONYMOUS_ID);
$this->grantPermissions($anonRole, ['restful post user_api_email_confirm_set_email']);
$this->hashManager = $this->container->get('verification_hash.manager');
}
/**
* Test direct email change on entity.
*/
public function testDirectlyChangingEmail() {
$newMail = 'updated-user@example.com';
// The user cannot change the email directly.
$exception = NULL;
try {
$this->user->setEmail($newMail)->save();
}
catch (\Throwable $e) {
$exception = $e;
}
$this->assertNotNull($exception);
$this->assertEquals($exception->getMessage(), 'Cannot change email directly!');
// Another user (e.g. admin) can directly change email.
$this->setCurrentUser(User::load(1));
$exception = NULL;
try {
$this->user->setEmail($newMail)->save();
}
catch (\Throwable $e) {
$exception = $e;
}
$this->assertNull($exception);
$this->assertEquals($newMail, $this->user->getEmail());
}
/**
* Test direct email change with verification disabled.
*/
public function testDirectlyChangingEmailWithVerificationDisabled() {
$this->config('user_api_email_confirm.settings')->set('notify.mail_change_verification', FALSE)->save();
$newMail = 'updated-user@example.com';
// The user cannot change the email directly.
$exception = NULL;
try {
$this->user->setEmail($newMail)->save();
}
catch (\Throwable $e) {
$exception = $e;
}
$this->assertNull($exception);
$this->assertEquals($newMail, $this->user->getEmail());
}
/**
* Test email change preliminary checks.
*/
public function testEmailChangePreliminaryChecks() {
// FAILURE - Anonymous account.
$this->setCurrentUser(User::getAnonymousUser());
$request = $this->createJsonRequest('POST', $this->url->toString(), []);
$response = $this->httpKernel->handle($request);
$this->assertEquals(403, $response->getStatusCode(), $response->getContent());
// FAILURE - Verification is not enabled.
$this->setCurrentUser($this->user);
$this->config('user_api_email_confirm.settings')->set('notify.mail_change_verification', FALSE)->save();
$request = $this->createJsonRequest('POST', $this->url->toString(), []);
$response = $this->httpKernel->handle($request);
$this->assertEquals(500, $response->getStatusCode(), $response->getContent());
}
/**
* Test email change with hash.
*
* This assumes the user has got the hash and timestamp via email.
*/
public function testEmailChangeWithHash() {
$newMail = 'updated-user@example.com';
$timestamp = \Drupal::time()->getRequestTime();
$hash = $this->hashManager->createHash($this->user, 'set-email', $timestamp, '', $newMail);
$content = [
'email' => $newMail,
];
$request = $this->createJsonRequest('POST', $this->url->toString(), $content);
$request->headers->set('X-Verification-Hash', sprintf('%s$$%s', $hash, $timestamp));
$response = $this->httpKernel->handle($request);
$this->assertEquals(200, $response->getStatusCode(), $response->getContent());
// Reload updated user from storage.
$updated = $this->user->load($this->user->id());
$this->assertEquals($newMail, $updated->getEmail());
}
/**
* Test mail change with expired hash.
*/
public function testMailChangeWithExpiredHash() {
$this->config('user_api_email_confirm.settings')->set('mail_change_timeout', 60)->save();
$newMail = 'updated-user@example.com';
// Expiry is 60 seconds.
// By subtracting 61 secons from now, it is already expired.
$timestamp = \Drupal::time()->getRequestTime() - 61;
$hash = $this->hashManager->createHash($this->user, 'set-email', $timestamp, '', $newMail);
$content = [
'email' => $newMail,
];
$request = $this->createJsonRequest('POST', $this->url->toString(), $content);
$request->headers->set('X-Verification-Hash', sprintf('%s$$%s', $hash, $timestamp));
$response = $this->httpKernel->handle($request);
$this->assertEquals(403, $response->getStatusCode(), $response->getContent());
$this->assertStringContainsString("hash_invalid", $response->getContent());
}
/**
* Test email change with same email.
*/
public function testEmailChangeWithSameEmail() {
$newMail = $this->user->getEmail();
$timestamp = \Drupal::time()->getRequestTime();
$hash = $this->hashManager->createHash($this->user, 'set-email', $timestamp, '', $newMail);
$content = [
'email' => $newMail,
];
$request = $this->createJsonRequest('POST', $this->url->toString(), $content);
$request->headers->set('X-Verification-Hash', sprintf('%s$$%s', $hash, $timestamp));
$response = $this->httpKernel->handle($request);
$this->assertEquals(422, $response->getStatusCode(), $response->getContent());
}
/**
* Test email change with existing email.
*/
public function testEmailChangeWithExistingEmail() {
$otherUser = $this->drupalCreateUser(values: [
'mail' => 'other-user@example.com',
]);
$newMail = $otherUser->getEmail();
$timestamp = \Drupal::time()->getRequestTime();
$hash = $this->hashManager->createHash($this->user, 'set-email', $timestamp, '', $newMail);
$content = [
'email' => $newMail,
];
$request = $this->createJsonRequest('POST', $this->url->toString(), $content);
$request->headers->set('X-Verification-Hash', sprintf('%s$$%s', $hash, $timestamp));
$response = $this->httpKernel->handle($request);
$this->assertEquals(422, $response->getStatusCode(), $response->getContent());
}
/**
* Test mail change with invalid payload.
*/
public function testMailChangeWithInvalidPayload() {
$request = $this->createJsonRequest('POST', $this->url->toString(), []);
$response = $this->httpKernel->handle($request);
$this->assertEquals(422, $response->getStatusCode(), $response->getContent());
}
/**
* Test abort via event.
*/
public function testEventAbort() {
/** @var \Symfony\Component\EventDispatcher\EventDispatcher $eventDispatcher */
$eventDispatcher = $this->container->get('event_dispatcher');
$eventDispatcher->addListener(UserApiEmailConfirmEvents::SET_EMAIL, function (SetEmailEvent $event) {
$event->abort('test', 'test', 500);
});
$newMail = 'updated-user@example.com';
$timestamp = \Drupal::time()->getRequestTime();
$hash = $this->hashManager->createHash($this->user, 'set-email', $timestamp, '', $newMail);
$content = [
'email' => $newMail,
];
$request = $this->createJsonRequest('POST', $this->url->toString(), $content);
$request->headers->set('X-Verification-Hash', sprintf('%s$$%s', $hash, $timestamp));
$response = $this->httpKernel->handle($request);
$this->assertEquals(500, $response->getStatusCode(), $response->getContent());
$this->assertStringContainsString("test", $response->getContent());
}
}
