Skip to content
Permalink
Browse files Browse the repository at this point in the history
NEXT-20305 - Secure proxy route to switch customer with ACL
  • Loading branch information
fschmtt committed Mar 4, 2022
1 parent 2c23a54 commit 329e4d7
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 1 deletion.
2 changes: 2 additions & 0 deletions Framework/Api/Controller/SalesChannelProxyController.php
Expand Up @@ -20,6 +20,7 @@
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Filter\EqualsFilter;
use Shopware\Core\Framework\DataAbstractionLayer\Validation\EntityExists;
use Shopware\Core\Framework\Routing\Annotation\Acl;
use Shopware\Core\Framework\Routing\Annotation\RouteScope;
use Shopware\Core\Framework\Routing\Annotation\Since;
use Shopware\Core\Framework\Routing\Exception\MissingRequestParameterException;
Expand Down Expand Up @@ -167,6 +168,7 @@ public function proxyCreateOrder(string $salesChannelId, Request $request, Conte
/**
* @Since("6.2.0.0")
* @Route("/api/_proxy/switch-customer", name="api.proxy.switch-customer", methods={"PATCH"})
* @Acl({"api_proxy_switch-customer"})
*
* @throws InconsistentCriteriaIdsException
* @throws InvalidSalesChannelIdException
Expand Down
Expand Up @@ -1062,6 +1062,7 @@ public function testProxyCreateOrderPrivileges(): void
static::assertSame('credit', $cart['lineItems'][1]['type']);

$orderPrivileges = [
'api_proxy_switch-customer',
'order:create',
'order_customer:create',
'order_address:create',
Expand All @@ -1075,7 +1076,7 @@ public function testProxyCreateOrderPrivileges(): void
foreach ([true, false] as $testOrderOnly) {
TestUser::createNewTestUser(
$browser->getContainer()->get(Connection::class),
$testOrderOnly ? $orderPrivileges : [CreditOrderLineItemListener::ACL_ORDER_CREATE_DISCOUNT_PRIVILEGE],
$testOrderOnly ? $orderPrivileges : ['api_proxy_switch-customer', CreditOrderLineItemListener::ACL_ORDER_CREATE_DISCOUNT_PRIVILEGE],
)->authorizeBrowser($browser);
$browser->request('POST', $this->getCreateOrderApiUrl($salesChannelContext->getSalesChannel()->getId()));

Expand Down
@@ -0,0 +1,10 @@
<?php declare(strict_types=1);

namespace Shopware\Core\Migration;

/**
* @deprecated tag:v6.5.0 - Will be deleted. Migrations are now namespaced by major version
*/
class Migration1646397836UpdateRolePrivilegesOfOrderCreatorUpdateRolePrivilegesOfOrderCreator extends \Shopware\Core\Migration\V6_4\Migration1646397836UpdateRolePrivilegesOfOrderCreator
{
}
@@ -0,0 +1,64 @@
<?php declare(strict_types=1);

namespace Shopware\Core\Migration\Test;

use Doctrine\DBAL\Connection;
use PHPUnit\Framework\TestCase;
use Shopware\Core\Framework\Api\Acl\Role\AclRoleEntity;
use Shopware\Core\Framework\Context;
use Shopware\Core\Framework\DataAbstractionLayer\Search\Criteria;
use Shopware\Core\Framework\Test\TestCaseBase\IntegrationTestBehaviour;
use Shopware\Core\Framework\Uuid\Uuid;
use Shopware\Core\Migration\V6_4\Migration1646397836UpdateRolePrivilegesOfOrderCreator;

class Migration1646397836UpdateRolePrivilegesOfOrderCreatorTest extends TestCase
{
use IntegrationTestBehaviour;

public function testNewPermissionsAreAdded(): void
{
$repo = $this->getContainer()->get('acl_role.repository');
$connection = $this->getContainer()->get(Connection::class);

$id = Uuid::randomHex();
$context = Context::createDefaultContext();
$repo->create([[
'id' => $id,
'name' => 'test',
'privileges' => ['order.creator'],
]], $context);

$migration = new Migration1646397836UpdateRolePrivilegesOfOrderCreator();
$migration->update($connection);

/** @var AclRoleEntity $role */
$role = $repo->search(new Criteria([$id]), $context)->first();
static::assertNotNull($role);

static::assertContains('api_proxy_switch-customer', $role->getPrivileges());
}

public function testUnrelatedRolesAreNotUpdated(): void
{
$repo = $this->getContainer()->get('acl_role.repository');
$connection = $this->getContainer()->get(Connection::class);

$id = Uuid::randomHex();
$context = Context::createDefaultContext();
$privileges = ['order:create', 'order:read', 'order:update', 'order:delete'];
$repo->create([[
'id' => $id,
'name' => 'test',
'privileges' => $privileges,
]], $context);

$before = $connection->fetchAssociative('SELECT * FROM `acl_role` WHERE id = :id', ['id' => Uuid::fromHexToBytes($id)]);

$migration = new Migration1646397836UpdateRolePrivilegesOfOrderCreator();
$migration->update($connection);

$after = $connection->fetchAssociative('SELECT * FROM `acl_role` WHERE id = :id', ['id' => Uuid::fromHexToBytes($id)]);

static::assertSame($before, $after);
}
}
@@ -0,0 +1,56 @@
<?php declare(strict_types=1);

namespace Shopware\Core\Migration\V6_4;

use Doctrine\DBAL\Connection;
use Shopware\Core\Defaults;
use Shopware\Core\Framework\Migration\MigrationStep;

class Migration1646397836UpdateRolePrivilegesOfOrderCreator extends MigrationStep
{
public const NEW_PRIVILEGES = [
'order.creator' => [
'api_proxy_switch-customer',
],
];

public function getCreationTimestamp(): int
{
return 1646397836;
}

public function update(Connection $connection): void
{
$roles = $connection->fetchAllAssociative('SELECT * from `acl_role`');

foreach ($roles as $role) {
$currentPrivileges = \json_decode($role['privileges'], true, 512, \JSON_THROW_ON_ERROR);
$newPrivileges = array_values($this->fixRolePrivileges($currentPrivileges));

if ($currentPrivileges === $newPrivileges) {
continue;
}

$role['privileges'] = json_encode($newPrivileges);
$role['updated_at'] = (new \DateTimeImmutable())->format(Defaults::STORAGE_DATE_FORMAT);

$connection->update('acl_role', $role, ['id' => $role['id']]);
}
}

public function updateDestructive(Connection $connection): void
{
// implement update destructive
}

private function fixRolePrivileges(array $rolePrivileges): array
{
foreach (self::NEW_PRIVILEGES as $key => $new) {
if (\in_array($key, $rolePrivileges, true)) {
$rolePrivileges = array_merge($rolePrivileges, $new);
}
}

return array_unique($rolePrivileges);
}
}

0 comments on commit 329e4d7

Please sign in to comment.