Skip to content

Commit

Permalink
feat(api-platform): handle scope on endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
tleon committed Aug 29, 2023
1 parent 70bc0e4 commit bf4e8a5
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 6 deletions.
3 changes: 2 additions & 1 deletion app/config/security_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ security:
# Empty provider until a real provider is developed
oauth2:
memory:
users: [ ]
users:
my_client_id: { password: 'prestashop', roles: [ 'ROLE_HOOK:READ' ] }

encoders:
Symfony\Component\Security\Core\User\User: plaintext
Expand Down
2 changes: 1 addition & 1 deletion app/config/security_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ security:
oauth2:
memory:
users:
my_client_id: { password: 'prestashop' }
my_client_id: { password: 'prestashop', roles: [ 'ROLE_HOOK:READ' ] }

encoders:
Symfony\Component\Security\Core\User\User: plaintext
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php

/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/

declare(strict_types=1);

namespace PrestaShopBundle\ApiPlatform\Decorator;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;

class AttributesResourceMetadataCollectionFactoryDecorator implements ResourceMetadataCollectionFactoryInterface
{
private ResourceMetadataCollectionFactoryInterface $innerFactory;

public function __construct(ResourceMetadataCollectionFactoryInterface $innerFactory)
{
$this->innerFactory = $innerFactory;
}

public function create(string $resourceClass): ResourceMetadataCollection
{
// We call the original method since we only want to alter the result of this method.
$resourceMetadataCollection = $this->innerFactory->create($resourceClass);

/** @var ApiResource $resourceMetadata */
foreach ($resourceMetadataCollection as $resourceMetadata) {
$operations = $resourceMetadata->getOperations();
/** @var Operation $operation */
foreach ($operations as $key => $operation) {
$extraProperties = $operation->getExtraProperties();
if (array_key_exists('scopes', $extraProperties)) {
$scopesToAdd = $extraProperties['scopes'];
$modifiedOperationWithSecurity = $operation->withSecurity($this->translateScopeToSecurity($scopesToAdd));
// We unset the extra property scopes so that the element is not treated again.
unset($extraProperties['scopes']);
$modifiedOperation = $modifiedOperationWithSecurity->withExtraProperties($extraProperties);
// We remove the original element and replace it with our clone.
$operations->remove($key);
$operations->add($key, $modifiedOperation);
}
}
}

return $resourceMetadataCollection;
}

private function translateScopeToSecurity(array $scopes): string
{
$security = '';
$arrayLength = count($scopes);
foreach ($scopes as $key => $scope) {
$security .= 'is_granted("ROLE_' . strtoupper($scope) . '")';
if ($key !== $arrayLength - 1) {
$security .= ' OR ';
}
}

return $security;
}
}
10 changes: 8 additions & 2 deletions src/PrestaShopBundle/ApiPlatform/Resources/Hook.php
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@
],
],
provider: QueryProvider::class,
extraProperties: ['query' => GetHookStatus::class]
extraProperties: [
'query' => GetHookStatus::class,
'scopes' => ['hook:read'],
]
),
new Put(
uriTemplate: '/hook-status',
Expand All @@ -84,7 +87,10 @@
requirements: ['id' => '\d+'],
exceptionToStatus: [HookNotFoundException::class => 404],
provider: QueryProvider::class,
extraProperties: ['query' => GetHook::class]
extraProperties: [
'query' => GetHook::class,
'scopes' => ['hook:read'],
]
),
],
)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,9 @@ services:

prestashop.adapter.hook.manager:
alias: PrestaShop\PrestaShop\Adapter\HookManager

prestashop.attributes.ressource.metadata.collection.factory:
class: PrestaShopBundle\ApiPlatform\Decorator\AttributesResourceMetadataCollectionFactoryDecorator
decorates: api_platform.metadata.resource.metadata_collection_factory
arguments:
$innerFactory: '@prestashop.attributes.ressource.metadata.collection.factory.inner'
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ public function getNewToken(
$token = new AccessToken();
$token->setClient($clientEntity);
$token->setUserIdentifier($userIdentifier);
foreach ($scopes as $scope) {
$token->addScope($scope);
}

return $token;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class NullScopeRepository implements ScopeRepositoryInterface
{
public function getScopeEntityByIdentifier($identifier): ?ScopeEntityInterface
{
return null;
return new ScopeEntity('hook:read');
}

public function finalizeScopes(
Expand All @@ -51,6 +51,6 @@ public function finalizeScopes(
ClientEntityInterface $clientEntity,
$userIdentifier = null
): array {
return [];
return [new ScopeEntity('hook:read')];
}
}
50 changes: 50 additions & 0 deletions src/PrestaShopBundle/Security/OAuth2/Repository/ScopeEntity.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/**
* Copyright since 2007 PrestaShop SA and Contributors
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
*
* NOTICE OF LICENSE
*
* This source file is subject to the Open Software License (OSL 3.0)
* that is bundled with this package in the file LICENSE.md.
* It is also available through the world-wide-web at this URL:
* https://opensource.org/licenses/OSL-3.0
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@prestashop.com so we can send you a copy immediately.
*
* DISCLAIMER
*
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
* versions in the future. If you wish to customize PrestaShop for your
* needs please refer to https://devdocs.prestashop.com/ for more information.
*
* @author PrestaShop SA and Contributors <contact@prestashop.com>
* @copyright Since 2007 PrestaShop SA and Contributors
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
*/

declare(strict_types=1);

namespace PrestaShopBundle\Security\OAuth2\Repository;

use League\OAuth2\Server\Entities\ScopeEntityInterface;
use League\OAuth2\Server\Entities\Traits\ScopeTrait;

class ScopeEntity implements ScopeEntityInterface
{
use ScopeTrait;

private string $identifier;

public function __construct(string $identifier)
{
$this->identifier = $identifier;
}

public function getIdentifier(): string
{
return $this->identifier;
}
}

0 comments on commit bf4e8a5

Please sign in to comment.