diff --git a/Checkout/Customer/Subscriber/CustomerTokenSubscriber.php b/Checkout/Customer/Subscriber/CustomerTokenSubscriber.php index b6fa5559bd..d9c1c7a441 100644 --- a/Checkout/Customer/Subscriber/CustomerTokenSubscriber.php +++ b/Checkout/Customer/Subscriber/CustomerTokenSubscriber.php @@ -3,6 +3,7 @@ namespace Shopware\Core\Checkout\Customer\Subscriber; use Shopware\Core\Checkout\Customer\CustomerEvents; +use Shopware\Core\Framework\DataAbstractionLayer\EntityWriteResult; use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityDeletedEvent; use Shopware\Core\Framework\DataAbstractionLayer\Event\EntityWrittenEvent; use Shopware\Core\PlatformRequest; @@ -37,64 +38,85 @@ public static function getSubscribedEvents() } public function onCustomerWritten(EntityWrittenEvent $event): void + { + foreach ($event->getWriteResults() as $writeResult) { + if ($writeResult->getOperation() !== EntityWriteResult::OPERATION_UPDATE) { + continue; + } + + $payload = $writeResult->getPayload(); + if (!$this->customerCredentialsChanged($payload)) { + continue; + } + + $customerId = $payload['id']; + $newToken = $this->invalidateUsingSession($customerId); + + if ($newToken) { + $this->contextPersister->revokeAllCustomerTokens($customerId, $newToken); + } else { + $this->contextPersister->revokeAllCustomerTokens($customerId); + } + } + } + + public function onCustomerDeleted(EntityDeletedEvent $event): void + { + foreach ($event->getIds() as $customerId) { + $this->contextPersister->revokeAllCustomerTokens($customerId); + } + } + + private function customerCredentialsChanged(array $payload): bool + { + return isset($payload['password']); + } + + private function invalidateUsingSession(string $customerId): ?string { $master = $this->requestStack->getMainRequest(); if (!$master) { - return; + return null; } + // Is not a storefront request if (!$master->attributes->has(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT)) { - return; + return null; } /** @var SalesChannelContext $context */ $context = $master->attributes->get(PlatformRequest::ATTRIBUTE_SALES_CHANNEL_CONTEXT_OBJECT); - $token = $context->getToken(); - - $payloads = $event->getPayloads(); - - foreach ($payloads as $payload) { - if ($this->customerCredentialsChanged($payload)) { - $newToken = $this->contextPersister->replace($token, $context); - $context->assign([ - 'token' => $newToken, - ]); - - if (!$master->hasSession()) { - return; - } + // Not loggedin skip + if ($context->getCustomer() === null) { + return null; + } - $session = $master->getSession(); - $session->migrate(); - $session->set('sessionId', $session->getId()); + // The written customer is not the same as logged-in. We don't modify the user session + if ($context->getCustomer()->getId() !== $customerId) { + return null; + } - $session->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $newToken); - $master->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $newToken); + $token = $context->getToken(); - return; - } - } - } + $newToken = $this->contextPersister->replace($token, $context); - public function onCustomerDeleted(EntityDeletedEvent $event): void - { - $master = $this->requestStack->getMainRequest(); + $context->assign([ + 'token' => $newToken, + ]); - if (!$master) { - return; + if (!$master->hasSession()) { + return null; } - $customerIds = $event->getIds(); + $session = $master->getSession(); + $session->migrate(); + $session->set('sessionId', $session->getId()); - foreach ($customerIds as $customerId) { - $this->contextPersister->revokeAllCustomerTokens($customerId); - } - } + $session->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $newToken); + $master->headers->set(PlatformRequest::HEADER_CONTEXT_TOKEN, $newToken); - private function customerCredentialsChanged(array $payload): bool - { - return isset($payload['password']); + return $newToken; } } diff --git a/Checkout/Test/Customer/Subscriber/CustomerTokenSubscriberTest.php b/Checkout/Test/Customer/Subscriber/CustomerTokenSubscriberTest.php index fc55e3319f..c81e51c94e 100644 --- a/Checkout/Test/Customer/Subscriber/CustomerTokenSubscriberTest.php +++ b/Checkout/Test/Customer/Subscriber/CustomerTokenSubscriberTest.php @@ -39,6 +39,35 @@ public function setUp(): void $this->customerRepository = $this->getContainer()->get('customer.repository'); } + public function testCustomerTokenSubscriber(): void + { + $customerId = $this->createCustomer(); + + $this->connection->insert('sales_channel_api_context', [ + 'customer_id' => Uuid::fromHexToBytes($customerId), + 'token' => 'test', + 'sales_channel_id' => Uuid::fromHexToBytes(TestDefaults::SALES_CHANNEL), + 'updated_at' => (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT), + 'payload' => '{"customerId": "1234"}', + ]); + + $this->customerRepository->update([ + [ + 'id' => $customerId, + 'password' => 'fooo', + ], + ], Context::createDefaultContext()); + + static::assertSame( + [ + 'customerId' => null, + 'billingAddressId' => null, + 'shippingAddressId' => null, + ], + json_decode($this->connection->fetchOne('SELECT payload FROM sales_channel_api_context WHERE token = "test"'), true) + ); + } + public function testCustomerTokenSubscriberStorefrontShouldStillBeLoggedIn(): void { $customerId = $this->createCustomer(); diff --git a/Checkout/Test/Order/SalesChannel/OrderRouteTest.php b/Checkout/Test/Order/SalesChannel/OrderRouteTest.php index b3f0696845..71bb1fcb53 100644 --- a/Checkout/Test/Order/SalesChannel/OrderRouteTest.php +++ b/Checkout/Test/Order/SalesChannel/OrderRouteTest.php @@ -712,11 +712,15 @@ public function testOrderSalesChannelRestriction(): void ], ], ]); - $testOrder = $this->createOrder($this->customerId, $this->email, $this->password); + + $orderId = Uuid::randomHex(); + $orderData = $this->getOrderData($orderId, $this->customerId, $this->email, $this->password, $this->context); + unset($orderData[0]['orderCustomer']['customer']['password']); + $this->orderRepository->create($orderData, $this->context); $this->orderRepository->update([ [ - 'id' => $testOrder, + 'id' => $orderId, 'salesChannelId' => $testChannel['id'], ], ], $this->context); diff --git a/System/SalesChannel/Context/SalesChannelContextPersister.php b/System/SalesChannel/Context/SalesChannelContextPersister.php index c6fc545a64..1205f87aff 100644 --- a/System/SalesChannel/Context/SalesChannelContextPersister.php +++ b/System/SalesChannel/Context/SalesChannelContextPersister.php @@ -172,7 +172,9 @@ public function revokeAllCustomerTokens(string $customerId, string ...$preserveT ->update('sales_channel_api_context') ->set('payload', ':payload') ->set('customer_id', 'NULL') + ->set('updated_at', ':updatedAt') ->where('customer_id = :customerId') + ->setParameter('updatedAt', (new \DateTime())->format(Defaults::STORAGE_DATE_TIME_FORMAT)) ->setParameter(':payload', json_encode($revokeParams)) ->setParameter(':customerId', Uuid::fromHexToBytes($customerId));