From 5bb5c58b889434d827a9f5c3454ecc1ea9dd6eb0 Mon Sep 17 00:00:00 2001 From: Mohamed El Mrabet Date: Thu, 20 Nov 2025 21:09:31 +0100 Subject: [PATCH 1/7] LoginAsCustomer: Add token generation service with full API test coverage --- .../GenerateLoginCustomerTokenInterface.php | 26 ++++ .../Model/GenerateLoginCustomerToken.php | 52 ++++++++ .../Model/GenerateLoginCustomerTokenTest.php | 125 ++++++++++++++++++ .../Magento/LoginAsCustomerApi/etc/di.xml | 2 + .../Magento/LoginAsCustomerApi/etc/webapi.xml | 17 +++ .../Api/GenerateLoginCustomerTokenTest.php | 76 +++++++++++ .../_files/customer_authentication_data.php | 1 + .../_files/login_as_customer_secret.php | 27 ++++ .../login_as_customer_secret_rollback.php | 8 ++ 9 files changed, 334 insertions(+) create mode 100644 app/code/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenInterface.php create mode 100644 app/code/Magento/LoginAsCustomerApi/Model/GenerateLoginCustomerToken.php create mode 100644 app/code/Magento/LoginAsCustomerApi/Test/Unit/Model/GenerateLoginCustomerTokenTest.php create mode 100644 app/code/Magento/LoginAsCustomerApi/etc/webapi.xml create mode 100644 dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php create mode 100644 dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/customer_authentication_data.php create mode 100644 dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret.php create mode 100644 dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret_rollback.php diff --git a/app/code/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenInterface.php b/app/code/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenInterface.php new file mode 100644 index 0000000000000..98e3b3c719b99 --- /dev/null +++ b/app/code/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenInterface.php @@ -0,0 +1,26 @@ +loginAsCustomerConfig->isEnabled()) { + throw new LocalizedException(__('Login As Customer module is disabled.')); + } + try { + $authenticationData = $this->getAuthenticationDataBySecret->execute($secret); + $customerId = $authenticationData->getCustomerId(); + } catch (\Exception $e) { + throw new AuthenticationException(__('Invalid or expired secret.')); + } + $context = new CustomUserContext( + (int)$customerId, + CustomUserContext::USER_TYPE_CUSTOMER + ); + $params = $this->tokenManager->createUserTokenParameters(); + return $this->tokenManager->create($context, $params); + } +} diff --git a/app/code/Magento/LoginAsCustomerApi/Test/Unit/Model/GenerateLoginCustomerTokenTest.php b/app/code/Magento/LoginAsCustomerApi/Test/Unit/Model/GenerateLoginCustomerTokenTest.php new file mode 100644 index 0000000000000..038b1851fc4b8 --- /dev/null +++ b/app/code/Magento/LoginAsCustomerApi/Test/Unit/Model/GenerateLoginCustomerTokenTest.php @@ -0,0 +1,125 @@ +getAuthenticationDataBySecret = $this->createMock(GetAuthenticationDataBySecretInterface::class); + $this->loginAsCustomerConfig = $this->createMock(LoginAsCustomerConfig::class); + $this->tokenManager = $this->createMock(TokenManager::class); + + $this->service = new GenerateLoginCustomerToken( + $this->getAuthenticationDataBySecret, + $this->loginAsCustomerConfig, + $this->tokenManager + ); + } + + public function testModuleDisabledThrowsException(): void + { + $this->loginAsCustomerConfig + ->expects($this->once()) + ->method('isEnabled') + ->willReturn(false); + + $this->expectException(LocalizedException::class); + $this->expectExceptionMessage('Login As Customer module is disabled.'); + + $this->service->createCustomerAccessToken('secret123'); + } + + public function testInvalidSecretThrowsAuthenticationException(): void + { + $this->loginAsCustomerConfig + ->expects($this->once()) + ->method('isEnabled') + ->willReturn(true); + + $this->getAuthenticationDataBySecret + ->expects($this->once()) + ->method('execute') + ->willThrowException(new \Exception('Secret invalid.')); + + $this->expectException(AuthenticationException::class); + $this->expectExceptionMessage('Invalid or expired secret.'); + + $this->service->createCustomerAccessToken('invalid-secret'); + } + + public function testValidSecretReturnsToken(): void + { + $secret = 'valid-secret'; + $customerId = 42; + $expectedToken = 'generated-token-xyz'; + + $this->loginAsCustomerConfig + ->expects($this->once()) + ->method('isEnabled') + ->willReturn(true); + + $authenticationData = $this->createMock(AuthenticationDataInterface::class); + $authenticationData + ->expects($this->once()) + ->method('getCustomerId') + ->willReturn($customerId); + + $this->getAuthenticationDataBySecret + ->expects($this->once()) + ->method('execute') + ->with($secret) + ->willReturn($authenticationData); + + $tokenParams = $this->createMock(UserTokenParameters::class); + $this->tokenManager + ->expects($this->once()) + ->method('createUserTokenParameters') + ->willReturn($tokenParams); + + $this->tokenManager + ->expects($this->once()) + ->method('create') + ->with( + $this->callback(function ($context) use ($customerId) { + return $context instanceof CustomUserContext + && $context->getUserId() === $customerId + && $context->getUserType() === CustomUserContext::USER_TYPE_CUSTOMER; + }), + $tokenParams + ) + ->willReturn($expectedToken); + + $result = $this->service->createCustomerAccessToken($secret); + + $this->assertSame($expectedToken, $result); + } +} diff --git a/app/code/Magento/LoginAsCustomerApi/etc/di.xml b/app/code/Magento/LoginAsCustomerApi/etc/di.xml index d92f8e06febc2..59f03c92c6dc5 100644 --- a/app/code/Magento/LoginAsCustomerApi/etc/di.xml +++ b/app/code/Magento/LoginAsCustomerApi/etc/di.xml @@ -9,4 +9,6 @@ xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"> + diff --git a/app/code/Magento/LoginAsCustomerApi/etc/webapi.xml b/app/code/Magento/LoginAsCustomerApi/etc/webapi.xml new file mode 100644 index 0000000000000..f982e1ee91558 --- /dev/null +++ b/app/code/Magento/LoginAsCustomerApi/etc/webapi.xml @@ -0,0 +1,17 @@ + + + + + + + + + + diff --git a/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php b/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php new file mode 100644 index 0000000000000..266f0da52fea3 --- /dev/null +++ b/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php @@ -0,0 +1,76 @@ + $secret]; + $token = $this->_webApiCall($this->getServiceInfo(), $requestData); + $this->assertIsString($token); + $this->assertNotEmpty($token); + } + + /** + * @magentoConfigFixture admin_store login_as_customer/general/enabled 1 + */ + public function testInvalidSecretThrowsException(): void + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('{"message":"Invalid or expired secret."}'); + $requestData = ["secret" => 'invalid-secret']; + $this->_webApiCall($this->getServiceInfo(), $requestData); + } + + /** + * @magentoConfigFixture admin_store login_as_customer/general/enabled 0 + */ + public function testModuleDisabledThrowsException(): void + { + $this->expectException(\Exception::class); + $this->expectExceptionMessage('{"message":"Login As Customer module is disabled."}'); + $requestData = ["secret" => 'test']; + $this->_webApiCall($this->getServiceInfo(), $requestData); + } + + /** + * @return array + */ + private function getServiceInfo(): array + { + return [ + 'rest' => [ + 'resourcePath' => self::RESOURCE_PATH, + 'httpMethod' => Request::HTTP_METHOD_POST, + ], + 'soap' => [ + 'service' => self::SERVICE_NAME, + 'serviceVersion' => self::SERVICE_VERSION, + 'operation' => self::SERVICE_NAME . 'Get', + ], + ]; + } +} diff --git a/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/customer_authentication_data.php b/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/customer_authentication_data.php new file mode 100644 index 0000000000000..b3d9bbc7f3711 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/customer_authentication_data.php @@ -0,0 +1 @@ +create(User::class); +$user->load('TestAdmin1', 'username'); +$authData = $objectManager->get(AuthenticationDataInterfaceFactory::class)->create([ + 'customerId' => 1, + 'adminId' => $user->getId(), +]); + +$secret = $objectManager->get(GenerateAuthenticationSecret::class)->execute($authData); + +/** + * Make secret accessible to the test + */ +$GLOBALS['login_as_customer_secret'] = $secret; diff --git a/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret_rollback.php b/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret_rollback.php new file mode 100644 index 0000000000000..cf81d38219da5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret_rollback.php @@ -0,0 +1,8 @@ + Date: Thu, 20 Nov 2025 21:11:45 +0100 Subject: [PATCH 2/7] LoginAsCustomer: Add token generation service with full API test coverage --- .../Api/GenerateLoginCustomerTokenTest.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php b/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php index 266f0da52fea3..95cc13fdb49fb 100644 --- a/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php +++ b/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php @@ -65,12 +65,7 @@ private function getServiceInfo(): array 'rest' => [ 'resourcePath' => self::RESOURCE_PATH, 'httpMethod' => Request::HTTP_METHOD_POST, - ], - 'soap' => [ - 'service' => self::SERVICE_NAME, - 'serviceVersion' => self::SERVICE_VERSION, - 'operation' => self::SERVICE_NAME . 'Get', - ], + ] ]; } } From 98d3ed0e3a2e1786d7599ba4f091120aa168a021 Mon Sep 17 00:00:00 2001 From: Mohamed El Mrabet Date: Thu, 20 Nov 2025 21:16:58 +0100 Subject: [PATCH 3/7] Removing wrong file --- .../LoginAsCustomer/_files/customer_authentication_data.php | 1 - 1 file changed, 1 deletion(-) delete mode 100644 dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/customer_authentication_data.php diff --git a/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/customer_authentication_data.php b/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/customer_authentication_data.php deleted file mode 100644 index b3d9bbc7f3711..0000000000000 --- a/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/customer_authentication_data.php +++ /dev/null @@ -1 +0,0 @@ - Date: Thu, 20 Nov 2025 22:43:03 +0100 Subject: [PATCH 4/7] LoginAsCustomerApi: Add token generation service --- .../Magento/LoginAsCustomerApi/etc/acl.xml | 21 +++ .../Magento/LoginAsCustomerApi/etc/webapi.xml | 2 +- .../Magento/Cms/Api/PageRepositoryTest.php | 2 +- .../Api/GenerateLoginCustomerTokenTest.php | 127 +++++++++++++++--- .../_files/login_as_customer_secret.php | 27 ---- .../login_as_customer_secret_rollback.php | 8 -- .../_files/admin_login_as_customer.php | 56 ++++++++ .../admin_login_as_customer_rollback.php | 43 ++++++ 8 files changed, 229 insertions(+), 57 deletions(-) create mode 100644 app/code/Magento/LoginAsCustomerApi/etc/acl.xml delete mode 100644 dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret.php delete mode 100644 dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret_rollback.php create mode 100644 dev/tests/integration/testsuite/Magento/LoginAsCustomerApi/_files/admin_login_as_customer.php create mode 100644 dev/tests/integration/testsuite/Magento/LoginAsCustomerApi/_files/admin_login_as_customer_rollback.php diff --git a/app/code/Magento/LoginAsCustomerApi/etc/acl.xml b/app/code/Magento/LoginAsCustomerApi/etc/acl.xml new file mode 100644 index 0000000000000..45312d7476d10 --- /dev/null +++ b/app/code/Magento/LoginAsCustomerApi/etc/acl.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + diff --git a/app/code/Magento/LoginAsCustomerApi/etc/webapi.xml b/app/code/Magento/LoginAsCustomerApi/etc/webapi.xml index f982e1ee91558..938d295a4275a 100644 --- a/app/code/Magento/LoginAsCustomerApi/etc/webapi.xml +++ b/app/code/Magento/LoginAsCustomerApi/etc/webapi.xml @@ -11,7 +11,7 @@ - + diff --git a/dev/tests/api-functional/testsuite/Magento/Cms/Api/PageRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Cms/Api/PageRepositoryTest.php index 9fa9d5bb460f7..cdc91d8e8fbce 100644 --- a/dev/tests/api-functional/testsuite/Magento/Cms/Api/PageRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Cms/Api/PageRepositoryTest.php @@ -419,7 +419,7 @@ public function testDelete(): void * @dataProvider byStoresProvider * @magentoApiDataFixture Magento/Cms/_files/pages.php * @magentoApiDataFixture Magento/Store/_files/second_website_with_store_group_and_store.php - * @param string $requestStore + * @param string $requestStore$rules * @return void */ public function testDeleteByStores(string $requestStore): void diff --git a/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php b/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php index 95cc13fdb49fb..8f62969336f1f 100644 --- a/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php +++ b/dev/tests/api-functional/testsuite/Magento/LoginAsCustomerApi/Api/GenerateLoginCustomerTokenTest.php @@ -7,65 +7,152 @@ namespace Magento\LoginAsCustomerApi\Api; +use Magento\Framework\ObjectManagerInterface; use Magento\Framework\Webapi\Rest\Request; +use Magento\Integration\Api\AdminTokenServiceInterface; +use Magento\LoginAsCustomer\Model\GenerateAuthenticationSecret; +use Magento\LoginAsCustomerApi\Api\Data\AuthenticationDataInterfaceFactory; +use Magento\TestFramework\Helper\Bootstrap; use Magento\TestFramework\TestCase\WebapiAbstract; +use Magento\User\Model\User; -/** - * @magentoConfigFixture default/login_as_customer/general/enabled 1 - */ class GenerateLoginCustomerTokenTest extends WebapiAbstract { - private const SERVICE_VERSION = 'V1'; - private const SERVICE_NAME = 'generateLoginCustomerTokenV1'; - private const RESOURCE_PATH = '/V1/integration/customer/login-as-customer'; + private const RESOURCE_PATH = '/V1/integration/customer/login-as-customer'; + private const ADMIN_USERNAME = 'TestAdminLoginAsCustomer'; + + private ObjectManagerInterface $objectManager; + private AdminTokenServiceInterface $adminTokens; + + protected function setUp(): void + { + $this->objectManager = Bootstrap::getObjectManager(); + $this->adminTokens = $this->objectManager->get(AdminTokenServiceInterface::class); + } /** * @magentoApiDataFixture Magento/LoginAsCustomer/_files/customer.php - * @magentoApiDataFixture Magento/LoginAsCustomer/_files/admin.php - * @magentoApiDataFixture Magento/LoginAsCustomer/_files/login_as_customer_secret.php - * @magentoConfigFixture admin_store login_as_customer/general/enabled 1 + * @magentoApiDataFixture Magento/LoginAsCustomerApi/_files/admin_login_as_customer.php + * @magentoConfigFixture default/login_as_customer/general/enabled 1 */ public function testValidSecretGeneratesToken(): void { - $secret = $GLOBALS['login_as_customer_secret']; - $requestData = ["secret" => $secret]; + $user = $this->loadAdminUser(); + $secret = $this->generateSecret((int)$user->getId()); + $requestData = ['secret' => $secret]; + $token = $this->_webApiCall($this->getServiceInfo(), $requestData); + $this->assertIsString($token); $this->assertNotEmpty($token); } /** - * @magentoConfigFixture admin_store login_as_customer/general/enabled 1 + * @magentoApiDataFixture Magento/LoginAsCustomerApi/_files/admin_login_as_customer.php + * @magentoConfigFixture default/login_as_customer/general/enabled 1 */ public function testInvalidSecretThrowsException(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('{"message":"Invalid or expired secret."}'); - $requestData = ["secret" => 'invalid-secret']; - $this->_webApiCall($this->getServiceInfo(), $requestData); + + $this->_webApiCall($this->getServiceInfo(), ['secret' => 'invalid-secret']); } /** - * @magentoConfigFixture admin_store login_as_customer/general/enabled 0 + * @magentoApiDataFixture Magento/LoginAsCustomerApi/_files/admin_login_as_customer.php + * @magentoConfigFixture default/login_as_customer/general/enabled 0 */ public function testModuleDisabledThrowsException(): void { $this->expectException(\Exception::class); $this->expectExceptionMessage('{"message":"Login As Customer module is disabled."}'); - $requestData = ["secret" => 'test']; - $this->_webApiCall($this->getServiceInfo(), $requestData); + + $this->_webApiCall($this->getServiceInfo(), ['secret' => 'test']); + } + + /** + * @magentoApiDataFixture Magento/LoginAsCustomer/_files/customer.php + * @magentoApiDataFixture Magento/LoginAsCustomerApi/_files/admin_login_as_customer.php + * @magentoConfigFixture default/login_as_customer/general/enabled 1 + */ + public function testAdminDeletedAfterSecretGeneration(): void + { + $user = $this->loadAdminUser(); + $secret = $this->generateSecret((int)$user->getId()); + + // Delete admin user + $userResource = $this->objectManager->get(\Magento\User\Model\ResourceModel\User::class); + $userResource->delete($user); + + $this->expectException(\Exception::class); + $this->expectExceptionMessage('The account sign-in was incorrect or your account is disabled temporarily. Please wait and try again later.'); + + $this->_webApiCall($this->getServiceInfo(), ['secret' => $secret]); + } + + /** + * @magentoApiDataFixture Magento/LoginAsCustomer/_files/customer.php + * @magentoApiDataFixture Magento/LoginAsCustomerApi/_files/admin_login_as_customer.php + * @magentoConfigFixture default/login_as_customer/general/enabled 1 + */ + public function testTamperedSecretThrowsException(): void + { + $user = $this->loadAdminUser(); + $secret = $this->generateSecret((int)$user->getId()); + $tampered = $secret . 'AA'; + $this->expectException(\Exception::class); + $this->expectExceptionMessage('{"message":"Invalid or expired secret."}'); + $this->_webApiCall($this->getServiceInfo(), ['secret' => $tampered]); } /** - * @return array + * Generate REST service info with token. */ private function getServiceInfo(): array { - return [ + $token = $this->adminTokens->createAdminAccessToken( + self::ADMIN_USERNAME, + \Magento\TestFramework\Bootstrap::ADMIN_PASSWORD + ); + + return [ 'rest' => [ 'resourcePath' => self::RESOURCE_PATH, 'httpMethod' => Request::HTTP_METHOD_POST, - ] + 'token' => $token, + ], ]; } + + /** + * Loads the admin user created by fixture. + */ + private function loadAdminUser(): User + { + $user = $this->objectManager->create(User::class); + $user->load(self::ADMIN_USERNAME, 'username'); + + if (!$user->getId()) { + $this->fail('Admin user not found. Fixture admin_login_as_customer.php failed.'); + } + + return $user; + } + + /** + * Generates secret for given admin. + */ + private function generateSecret(int $adminId): string + { + $authData = $this->objectManager + ->get(AuthenticationDataInterfaceFactory::class) + ->create([ + 'customerId' => 1, + 'adminId' => $adminId, + ]); + + return $this->objectManager->get(GenerateAuthenticationSecret::class) + ->execute($authData); + } } diff --git a/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret.php b/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret.php deleted file mode 100644 index b456dbe9ca661..0000000000000 --- a/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret.php +++ /dev/null @@ -1,27 +0,0 @@ -create(User::class); -$user->load('TestAdmin1', 'username'); -$authData = $objectManager->get(AuthenticationDataInterfaceFactory::class)->create([ - 'customerId' => 1, - 'adminId' => $user->getId(), -]); - -$secret = $objectManager->get(GenerateAuthenticationSecret::class)->execute($authData); - -/** - * Make secret accessible to the test - */ -$GLOBALS['login_as_customer_secret'] = $secret; diff --git a/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret_rollback.php b/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret_rollback.php deleted file mode 100644 index cf81d38219da5..0000000000000 --- a/dev/tests/integration/testsuite/Magento/LoginAsCustomer/_files/login_as_customer_secret_rollback.php +++ /dev/null @@ -1,8 +0,0 @@ -get(RoleFactory::class)->create(); +$role->setName('login_as_customer_api_role'); +$role->setData('role_name', $role->getName()); +$role->setRoleType(Group::ROLE_TYPE); +$role->setUserType((string)UserContextInterface::USER_TYPE_ADMIN); + +/** @var RoleResource $roleResource */ +$roleResource = Bootstrap::getObjectManager()->get(RoleResource::class); +$roleResource->save($role); + +/** + * ACL rule: allow access to API token generation + */ +$rules = Bootstrap::getObjectManager()->get(RulesFactory::class)->create(); +$rules->setRoleId($role->getId()); +$rules->setResources(['Magento_LoginAsCustomerApi::token']); + +/** @var RulesResource $rulesResource */ +$rulesResource = Bootstrap::getObjectManager()->get(RulesResource::class); +$rulesResource->saveRel($rules); + +/** + * Create admin user + */ +$user = Bootstrap::getObjectManager()->create(User::class); +$user->setUsername('TestAdminLoginAsCustomer') + ->setFirstname('John') + ->setLastname('Doe') + ->setEmail('testAdminLoginAsCustomer@example.com') + ->setPassword(\Magento\TestFramework\Bootstrap::ADMIN_PASSWORD) + ->setIsActive(1) + ->setRoleId($role->getId()); + +/** @var UserResource $userResource */ +$userResource = Bootstrap::getObjectManager()->get(UserResource::class); +$userResource->save($user); diff --git a/dev/tests/integration/testsuite/Magento/LoginAsCustomerApi/_files/admin_login_as_customer_rollback.php b/dev/tests/integration/testsuite/Magento/LoginAsCustomerApi/_files/admin_login_as_customer_rollback.php new file mode 100644 index 0000000000000..8a469b4933ca5 --- /dev/null +++ b/dev/tests/integration/testsuite/Magento/LoginAsCustomerApi/_files/admin_login_as_customer_rollback.php @@ -0,0 +1,43 @@ +create(User::class); +$user->load('TestAdminLoginAsCustomer', 'username'); + +/** @var UserResource $userResource */ +$userResource = Bootstrap::getObjectManager()->get(UserResource::class); +$userResource->delete($user); + +/** @var Role $role */ +$role = Bootstrap::getObjectManager()->get(RoleFactory::class)->create(); +$role->load('login_as_customer_api_role', 'role_name'); + + +/** @var Rules $rules */ +$rules = Bootstrap::getObjectManager()->get(RulesFactory::class)->create(); +$rules->load($role->getId(), 'role_id'); + +/** @var RulesResource $rulesResource */ +$rulesResource = Bootstrap::getObjectManager()->get(RulesResource::class); +$rulesResource->delete($rules); + +/** @var RoleResource $roleResource */ +$roleResource = Bootstrap::getObjectManager()->get(RoleResource::class); +$roleResource->delete($role); + From 08a64a734d78bcdf226d10f75a1255452de6a414 Mon Sep 17 00:00:00 2001 From: Mohamed El Mrabet Date: Thu, 20 Nov 2025 22:58:23 +0100 Subject: [PATCH 5/7] Update Readme --- app/code/Magento/LoginAsCustomerApi/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/code/Magento/LoginAsCustomerApi/README.md b/app/code/Magento/LoginAsCustomerApi/README.md index fddc5d97d4696..cbf1ca9e39b83 100644 --- a/app/code/Magento/LoginAsCustomerApi/README.md +++ b/app/code/Magento/LoginAsCustomerApi/README.md @@ -48,6 +48,9 @@ This module provides API for ability to login into customer account for an admin - `\Magento\LoginAsCustomerApi\Api\SetLoggedAsCustomerCustomerIdInterface`: - set id of customer admin is logged as +- `\Magento\LoginAsCustomerApi\Api\GenerateLoginCustomerTokenInterface`: + - generate an integration access token from a valid Login As Customer secret + For information about a public API, see [Public interfaces & APIs](https://developer.adobe.com/commerce/php/development/components/api-concepts/). ## Additional information From a91fe30baf9bd28df1cc69dc65c646b8c317cbc0 Mon Sep 17 00:00:00 2001 From: Mohamed El Mrabet Date: Thu, 20 Nov 2025 23:00:28 +0100 Subject: [PATCH 6/7] review of code --- .../_files/admin_login_as_customer_rollback.php | 1 - 1 file changed, 1 deletion(-) diff --git a/dev/tests/integration/testsuite/Magento/LoginAsCustomerApi/_files/admin_login_as_customer_rollback.php b/dev/tests/integration/testsuite/Magento/LoginAsCustomerApi/_files/admin_login_as_customer_rollback.php index 8a469b4933ca5..2bda6a7fb9239 100644 --- a/dev/tests/integration/testsuite/Magento/LoginAsCustomerApi/_files/admin_login_as_customer_rollback.php +++ b/dev/tests/integration/testsuite/Magento/LoginAsCustomerApi/_files/admin_login_as_customer_rollback.php @@ -40,4 +40,3 @@ /** @var RoleResource $roleResource */ $roleResource = Bootstrap::getObjectManager()->get(RoleResource::class); $roleResource->delete($role); - From bdcbc3c31bf91ee8a26323eb46652baf9097cc05 Mon Sep 17 00:00:00 2001 From: Mohamed El Mrabet Date: Sun, 23 Nov 2025 22:58:50 +0100 Subject: [PATCH 7/7] fix typo --- .../testsuite/Magento/Cms/Api/PageRepositoryTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/tests/api-functional/testsuite/Magento/Cms/Api/PageRepositoryTest.php b/dev/tests/api-functional/testsuite/Magento/Cms/Api/PageRepositoryTest.php index cdc91d8e8fbce..9fa9d5bb460f7 100644 --- a/dev/tests/api-functional/testsuite/Magento/Cms/Api/PageRepositoryTest.php +++ b/dev/tests/api-functional/testsuite/Magento/Cms/Api/PageRepositoryTest.php @@ -419,7 +419,7 @@ public function testDelete(): void * @dataProvider byStoresProvider * @magentoApiDataFixture Magento/Cms/_files/pages.php * @magentoApiDataFixture Magento/Store/_files/second_website_with_store_group_and_store.php - * @param string $requestStore$rules + * @param string $requestStore * @return void */ public function testDeleteByStores(string $requestStore): void