Skip to content

Commit

Permalink
Introduce trait, add tests, fix comments
Browse files Browse the repository at this point in the history
  • Loading branch information
dunglas committed Dec 24, 2017
1 parent 2d70d9b commit 236f224
Show file tree
Hide file tree
Showing 24 changed files with 273 additions and 68 deletions.
2 changes: 1 addition & 1 deletion features/authorization/deny.feature
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ Feature: Authorization checking
"""
Then the response status code should be 201

Scenario: An user retrieves cannot retrieve an item he doesn't own
Scenario: An user cannot retrieve an item he doesn't own
When I add "Accept" header equal to "application/ld+json"
And I add "Authorization" header equal to "Basic ZHVuZ2xhczprZXZpbg=="
And I send a "GET" request to "/secured_dummies/1"
Expand Down
16 changes: 8 additions & 8 deletions src/Bridge/Symfony/Bundle/Resources/config/graphql.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>
<service id="api_platform.graphql.executor" class="ApiPlatform\Core\Graphql\Executor" public="false" />
<service id="api_platform.graphql.executor" class="ApiPlatform\Core\GraphQl\Executor" public="false" />

<!-- Resolvers -->

<service id="api_platform.graphql.resolver.factory.collection" class="ApiPlatform\Core\Graphql\Resolver\Factory\CollectionResolverFactory" public="false">
<service id="api_platform.graphql.resolver.factory.collection" class="ApiPlatform\Core\GraphQl\Resolver\Factory\CollectionResolverFactory" public="false">
<argument type="service" id="api_platform.collection_data_provider" />
<argument type="service" id="api_platform.subresource_data_provider" />
<argument type="service" id="serializer" />
Expand All @@ -20,26 +20,26 @@
<argument>%api_platform.collection.pagination.enabled%</argument>
</service>

<service id="api_platform.graphql.resolver.factory.item_mutation" class="ApiPlatform\Core\Graphql\Resolver\Factory\ItemMutationResolverFactory" public="false">
<service id="api_platform.graphql.resolver.factory.item_mutation" class="ApiPlatform\Core\GraphQl\Resolver\Factory\ItemMutationResolverFactory" public="false">
<argument type="service" id="api_platform.iri_converter" />
<argument type="service" id="api_platform.data_persister" />
<argument type="service" id="serializer" />
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
<argument type="service" id="api_platform.security.resource_access_checker" on-invalid="ignore" />
</service>

<service id="api_platform.graphql.resolver.item" class="ApiPlatform\Core\Graphql\Resolver\ItemResolver" public="false">
<service id="api_platform.graphql.resolver.item" class="ApiPlatform\Core\GraphQl\Resolver\ItemResolver" public="false">
<argument type="service" id="api_platform.iri_converter" />
<argument type="service" id="serializer" />
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
<argument type="service" id="api_platform.security.resource_access_checker" on-invalid="ignore" />
</service>

<service id="api_platform.graphql.resolver.resource_field" class="ApiPlatform\Core\Graphql\Resolver\ResourceFieldResolver" public="false">
<service id="api_platform.graphql.resolver.resource_field" class="ApiPlatform\Core\GraphQl\Resolver\ResourceFieldResolver" public="false">
<argument type="service" id="api_platform.iri_converter" />
</service>

<service id="api_platform.graphql.schema_builder" class="ApiPlatform\Core\Graphql\Type\SchemaBuilder" public="false">
<service id="api_platform.graphql.schema_builder" class="ApiPlatform\Core\GraphQl\Type\SchemaBuilder" public="false">
<argument type="service" id="api_platform.metadata.property.name_collection_factory" />
<argument type="service" id="api_platform.metadata.property.metadata_factory" />
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
Expand All @@ -53,7 +53,7 @@

<!-- Action -->

<service id="api_platform.graphql.action.entrypoint" class="ApiPlatform\Core\Graphql\Action\EntrypointAction" public="true">
<service id="api_platform.graphql.action.entrypoint" class="ApiPlatform\Core\GraphQl\Action\EntrypointAction" public="true">
<argument type="service" id="api_platform.graphql.schema_builder" />
<argument type="service" id="api_platform.graphql.executor" />
<argument type="service" id="twig" />
Expand All @@ -64,7 +64,7 @@

<!-- Serializer -->

<service id="api_platform.graphql.normalizer.item" class="ApiPlatform\Core\Graphql\Serializer\ItemNormalizer" public="false">
<service id="api_platform.graphql.normalizer.item" class="ApiPlatform\Core\GraphQl\Serializer\ItemNormalizer" public="false">
<argument type="service" id="api_platform.metadata.property.name_collection_factory" />
<argument type="service" id="api_platform.metadata.property.metadata_factory" />
<argument type="service" id="api_platform.iri_converter" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Graphql\Action;
namespace ApiPlatform\Core\GraphQl\Action;

use ApiPlatform\Core\Graphql\ExecutorInterface;
use ApiPlatform\Core\Graphql\Type\SchemaBuilderInterface;
use ApiPlatform\Core\GraphQl\ExecutorInterface;
use ApiPlatform\Core\GraphQl\Type\SchemaBuilderInterface;
use GraphQL\Error\Error;
use GraphQL\Executor\ExecutionResult;
use Symfony\Component\HttpFoundation\JsonResponse;
Expand Down
2 changes: 1 addition & 1 deletion src/Graphql/Executor.php → src/GraphQl/Executor.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Graphql;
namespace ApiPlatform\Core\GraphQl;

use GraphQL\Executor\ExecutionResult;
use GraphQL\GraphQL;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Graphql;
namespace ApiPlatform\Core\GraphQl;

use GraphQL\Executor\ExecutionResult;
use GraphQL\Type\Schema;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Graphql\Resolver\Factory;
namespace ApiPlatform\Core\GraphQl\Resolver\Factory;

use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\PaginatorInterface;
use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface;
use ApiPlatform\Core\Exception\ResourceClassNotSupportedException;
use ApiPlatform\Core\Graphql\Serializer\ItemNormalizer;
use ApiPlatform\Core\GraphQl\Resolver\ResourceAccessCheckerTrait;
use ApiPlatform\Core\GraphQl\Serializer\ItemNormalizer;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Security\ResourceAccessCheckerInterface;
use GraphQL\Error\Error;
Expand All @@ -36,6 +37,8 @@
*/
final class CollectionResolverFactory implements ResolverFactoryInterface
{
use ResourceAccessCheckerTrait;

private $collectionDataProvider;
private $subresourceDataProvider;
private $normalizer;
Expand Down Expand Up @@ -76,6 +79,7 @@ public function __invoke(string $resourceClass = null, string $rootClass = null,
}

$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
$this->canAccess($this->resourceAccessChecker, $resourceMetadata, $resourceClass, $info, $collection);

if (null !== $this->resourceAccessChecker) {
$isGranted = $resourceMetadata->getGraphqlAttribute('query', 'access_control', null, true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,14 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Graphql\Resolver\Factory;
namespace ApiPlatform\Core\GraphQl\Resolver\Factory;

use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
use ApiPlatform\Core\Exception\InvalidArgumentException;
use ApiPlatform\Core\Exception\ItemNotFoundException;
use ApiPlatform\Core\Graphql\Serializer\ItemNormalizer;
use ApiPlatform\Core\GraphQl\Resolver\ResourceAccessCheckerTrait;
use ApiPlatform\Core\GraphQl\Serializer\ItemNormalizer;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Security\ResourceAccessCheckerInterface;
use GraphQL\Error\Error;
Expand All @@ -34,6 +35,8 @@
*/
final class ItemMutationResolverFactory implements ResolverFactoryInterface
{
use ResourceAccessCheckerTrait;

private $iriConverter;
private $dataPersister;
private $normalizer;
Expand Down Expand Up @@ -68,12 +71,7 @@ public function __invoke(string $resourceClass = null, string $rootClass = null,
}

$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
if (null !== $this->resourceAccessChecker) {
$isGranted = $resourceMetadata->getGraphqlAttribute('query', 'access_control', null, true);
if (null !== $isGranted && !$this->resourceAccessChecker->isGranted($resourceClass, $isGranted, ['object' => $item])) {
throw Error::createLocatedError('Access Denied.', $info->fieldNodes, $info->path);
}
}
$this->canAccess($this->resourceAccessChecker, $resourceMetadata, $resourceClass, $info, $item);

switch ($operationName) {
case 'create':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Graphql\Resolver\Factory;
namespace ApiPlatform\Core\GraphQl\Resolver\Factory;

/**
* Builds a GraphQL resolver.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Graphql\Resolver;
namespace ApiPlatform\Core\GraphQl\Resolver;

use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Exception\ItemNotFoundException;
use ApiPlatform\Core\Graphql\Serializer\ItemNormalizer;
use ApiPlatform\Core\GraphQl\Serializer\ItemNormalizer;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Security\ResourceAccessCheckerInterface;
use ApiPlatform\Core\Util\ClassInfoTrait;
Expand All @@ -34,6 +34,7 @@
final class ItemResolver
{
use ClassInfoTrait;
use ResourceAccessCheckerTrait;

private $iriConverter;
private $resourceAccessChecker;
Expand Down Expand Up @@ -68,6 +69,7 @@ public function __invoke($source, $args, $context, ResolveInfo $info)

$resourceClass = $this->getObjectClass($item);
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
$this->canAccess($this->resourceAccessChecker, $resourceMetadata, $resourceClass, $info, $item);

if (null !== $this->resourceAccessChecker) {
$isGranted = $resourceMetadata->getGraphqlAttribute('query', 'access_control', null, true);
Expand Down
57 changes: 57 additions & 0 deletions src/GraphQl/Resolver/ResourceAccessCheckerTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace ApiPlatform\Core\GraphQl\Resolver;

use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
use ApiPlatform\Core\Security\ResourceAccessCheckerInterface;
use GraphQL\Error\Error;
use GraphQL\Type\Definition\ResolveInfo;

/**
* Checks if the current logged in user can access to this resource.
*
* @experimental
*
* @author Kévin Dunglas <dunglas@gmail.com>
*/
trait ResourceAccessCheckerTrait
{
/**
* @param object $object
*
* @throws Error
*/
public function canAccess(ResourceAccessCheckerInterface $resourceAccessChecker = null, ResourceMetadata $resourceMetadata, string $resourceClass, ResolveInfo $info, $object = null)
{
if (null === $resourceAccessChecker) {
return;
}

$isGranted = $resourceMetadata->getGraphqlAttribute('query', 'access_control', null, true);
if (null === $isGranted || $resourceAccessChecker->isGranted($resourceClass, $isGranted, ['object' => $object])) {
return;
}

throw Error::createLocatedError('Access Denied.', $info->fieldNodes, $info->path);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Graphql\Resolver;
namespace ApiPlatform\Core\GraphQl\Resolver;

use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Graphql\Serializer\ItemNormalizer;
use ApiPlatform\Core\GraphQl\Serializer\ItemNormalizer;
use GraphQL\Type\Definition\ResolveInfo;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
* file that was distributed with this source code.
*/

namespace ApiPlatform\Core\Graphql\Serializer;
namespace ApiPlatform\Core\GraphQl\Serializer;

use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
use ApiPlatform\Core\Serializer\AbstractItemNormalizer;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Graphql\Type;
namespace ApiPlatform\Core\GraphQl\Type;

use ApiPlatform\Core\Exception\ResourceClassNotFoundException;
use ApiPlatform\Core\Graphql\Resolver\Factory\ResolverFactoryInterface;
use ApiPlatform\Core\Graphql\Serializer\ItemNormalizer;
use ApiPlatform\Core\GraphQl\Resolver\Factory\ResolverFactoryInterface;
use ApiPlatform\Core\GraphQl\Serializer\ItemNormalizer;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Graphql\Type;
namespace ApiPlatform\Core\GraphQl\Type;

use GraphQL\Type\Schema;

Expand Down
2 changes: 1 addition & 1 deletion src/Security/EventListener/DenyAccessListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFa
}

$this->resourceAccessChecker = new ResourceAccessChecker($resourceAccessCheckerOrExpressionLanguage, $authenticationTrustResolver, $roleHierarchy, $tokenStorage, $authorizationChecker);
@trigger_error(sprintf('Passing an instance of "%s" as second argument of "%s" is deprecated since API Platform 2.2 and will not be possible anymore in API Platform 3. Pass an instance of "%s" and no extra argument instead.', ExpressionLanguage::class, self::class, ResourceAccessCheckerInterface::class), E_USER_DEPRECATED);
@trigger_error(sprintf('Passing an instance of "%s" or null as second argument of "%s" is deprecated since API Platform 2.2 and will not be possible anymore in API Platform 3. Pass an instance of "%s" and no extra argument instead.', ExpressionLanguage::class, self::class, ResourceAccessCheckerInterface::class), E_USER_DEPRECATED);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Tests\Graphql\Action;
namespace ApiPlatform\Core\Tests\GraphQl\Action;

use ApiPlatform\Core\Graphql\Action\EntrypointAction;
use ApiPlatform\Core\Graphql\ExecutorInterface;
use ApiPlatform\Core\Graphql\Type\SchemaBuilderInterface;
use ApiPlatform\Core\GraphQl\Action\EntrypointAction;
use ApiPlatform\Core\GraphQl\ExecutorInterface;
use ApiPlatform\Core\GraphQl\Type\SchemaBuilderInterface;
use GraphQL\Executor\ExecutionResult;
use GraphQL\Type\Schema;
use PHPUnit\Framework\TestCase;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Tests\Graphql\Resolver\Factory;
namespace ApiPlatform\Core\Tests\GraphQl\Resolver\Factory;

use ApiPlatform\Core\Api\IdentifiersExtractorInterface;
use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
use ApiPlatform\Core\DataProvider\PaginatorInterface;
use ApiPlatform\Core\DataProvider\SubresourceDataProviderInterface;
use ApiPlatform\Core\Graphql\Resolver\Factory\CollectionResolverFactory;
use ApiPlatform\Core\Graphql\Serializer\ItemNormalizer;
use ApiPlatform\Core\GraphQl\Resolver\Factory\CollectionResolverFactory;
use ApiPlatform\Core\GraphQl\Serializer\ItemNormalizer;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Tests\Graphql\Resolver\Factory;
namespace ApiPlatform\Core\Tests\GraphQl\Resolver\Factory;

use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\DataPersister\DataPersisterInterface;
use ApiPlatform\Core\Exception\ItemNotFoundException;
use ApiPlatform\Core\Graphql\Resolver\Factory\ItemMutationResolverFactory;
use ApiPlatform\Core\Graphql\Resolver\Factory\ResolverFactoryInterface;
use ApiPlatform\Core\GraphQl\Resolver\Factory\ItemMutationResolverFactory;
use ApiPlatform\Core\GraphQl\Resolver\Factory\ResolverFactoryInterface;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@

declare(strict_types=1);

namespace ApiPlatform\Core\Tests\Graphql\Resolver;
namespace ApiPlatform\Core\Tests\GraphQl\Resolver;

use ApiPlatform\Core\Api\IriConverterInterface;
use ApiPlatform\Core\Exception\ItemNotFoundException;
use ApiPlatform\Core\Graphql\Resolver\ItemResolver;
use ApiPlatform\Core\GraphQl\Resolver\ItemResolver;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy;
Expand Down

0 comments on commit 236f224

Please sign in to comment.