PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Friday, January 21, 2022

[FIXED] API Platform GraphQL Security in Relationships

 January 21, 2022     api-platform.com, entity-relationship, graphql, security, symfony     No comments   

Issue

My problem is the security implementation of the entities when consumed through GraphQL, the queries are perfect, they return the necessary data, but the problem occurs when a query is generated and the many-to-one relationship is limited to having a role "ROLE_ADMIN", the query returns the data even when the user has the role "IS_AUTHENTICATED_ANONYMOUSLY"

How to add the security layer so that data from protected relationships cannot be obtained?

The product query must be seen without any role.

Additional Information

GraphQL Query User Admin

query {
    userAdmin(id: "api/user_admins/1") {
        id
        name
    }
}

GraphQL Query User Admin Result OK

{
  "errors": [
    {
      "message": "Sorry, but you don't have access",
      "extensions": {
        "category": "graphql"
      }
  ]
}

GraphQL Query Product

query {
    products {
        edges {
            node {
                name
                price
                user {
                    name
                }
            }
        }
    }
}

GraphQL Query Product Result FAILED

{
  "data": {
    "products": {
      "edges": [
        {
          "node": {
            "name": "GERLACH-HAAG",
            "price": "175",
            "user": {
              "name": "Sidney Deane" /** this information should not be seen **/
            }
          }
        }
      ]
    }
  }
}

Entity Product Configuration

<?php

/**
 * @ApiResource(
 *     graphql={
 *          "item_query",
 *          "collection_query",
 *          "delete"={ "security" = "is_granted('ROLE_ADMIN')" },
 *          "create"={ "security" = "is_granted('ROLE_ADMIN')" },
 *          "update"={ "security" = "is_granted('ROLE_ADMIN')" }
 *     }
 * )
 * @ORM\Table(name="TBL_PRODUCTS")
 * @ORM\Entity(repositoryClass=ProductRepository::class)
 * @ORM\HasLifecycleCallbacks()
 */
class Product
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="bigint", name="ID")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, name="NAME")
     */
    private $name;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\UserAdmin")
     * @ORM\JoinColumn(name="USER", referencedColumnName="ID")
     */
    private $user;

Entity User Admin Configuration

<?php

/**
 * @ApiResource(
 *     graphql={
 *          "item_query"={ "security" = "is_granted('ROLE_ADMIN')" },
 *          "collection_query"={ "security" = "is_granted('ROLE_ADMIN')" },
 *          "delete"={ "security" = "is_granted('ROLE_ADMIN')" },
 *          "create"={ "security" = "is_granted('ROLE_ADMIN')" },
 *          "update"={ "security" = "is_granted('ROLE_ADMIN')" }
 *     }
 * )
 * @ORM\Table(name="TBL_USERS_ADMIN")
 * @ORM\Entity(repositoryClass=UserAdminRepository::class)
 * @ORM\HasLifecycleCallbacks()
 */
class UserAdmin implements UserInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="bigint", name="ID")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, name="USERNAME")
     */
    private $username;

    /**
     * @ORM\Column(type="string", length=180, name="PASSWORD")
     */
    private $password;

    /**
     * @ORM\Column(type="string", length=180, name="NAME")
     */
    private $name;

Please help !!!!


Solution

The security attribute allows to define roles or permissions necessary to execute a given query. However, it doesn't define which relation available trough this query the user can access. To do so, you can use dynamic serialization groups.

Basically, mark the properties requiring a special role to be returned in the response with a specific serialization group, such as @Groups("admin"), then create a dynamic serialization context builder to add the special group if the connected user has this special role:

<?php

namespace App\Serializer;

use ApiPlatform\Core\GraphQl\Serializer\SerializerContextBuilderInterface;
use App\Entity\Book;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;

final class BookContextBuilder implements SerializerContextBuilderInterface
{
    private $decorated;
    private $authorizationChecker;

    public function __construct(SerializerContextBuilderInterface $decorated, AuthorizationCheckerInterface $authorizationChecker)
    {
        $this->decorated = $decorated;
        $this->authorizationChecker = $authorizationChecker;
    }

    public function create(?string $resourceClass, string $operationName, array $resolverContext, bool $normalization): array
    {
        $context = $this->decorated->create($resourceClass, $operationName, $resolverContext, $normalization);
        $resourceClass = $context['resource_class'] ?? null;

        if ($resourceClass === Book::class && isset($context['groups']) && $this->authorizationChecker->isGranted('ROLE_ADMIN') && false === $normalization) {
            $context['groups'][] = 'admin';
        }

        return $context;
    }
}

In the master version (API Platform 2.6), the security attribute is now also available for properties. Unfortunately, this feature is currently available only in the REST subsystem, but we will be very pleased to merge a Pull Request adding support for this attribute to the GraphQL subsystem.



Answered By - Kévin Dunglas
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing