FriendsOfSymfony / FOSRestBundle

This Bundle provides various tools to rapidly develop RESTful API's with Symfony
http://symfony.com/doc/master/bundles/FOSRestBundle/index.html
MIT License
2.79k stars 702 forks source link

Naive implementation of RequestBodyParamConverterwith POST... or it's just my bad? #2375

Open gremo opened 2 years ago

gremo commented 2 years ago

The implementation of RequestBodyParamConverter seems so "naive", hope that is my bad configuration or something. It works fine when you don't provide entity identifiers in the body payload, but is potentially dangerous when you do.

Consider this scenario: a POST request to /api/products in order to create a new entity:

POST /api/products HTTP/1.1
HOST: localhost:8000
content-type: application/json
content-length: 36

{
  "id": 1,
  "name": "Foo Bar"
}

In this scenario, the converter deserialized the provided payload. In turn, the JMS serializer would retrive the existing record with the given id, and merge the name property. Without any futher control, you end up updating the resource instead of creating a new one!

Even worst example: a PUT to/products/1 request with { "id": 2, "name": "Foo Bar" } as payload, which is supposed to replace the resource at the id 1. In this case it would end up updating the wrong resource!

This is an example controller action:

/**
 * Creates a new product.
 *
 * @Rest\Post("/products", name="_api_products_create")
 * @ParamConverter("product", class=Product::class, converter="fos_rest.request_body")
 * @Rest\View(statusCode=Response::HTTP_OK)
 */
public function createAction(Product $product, ConstraintViolationListInterface $violations)
{
    if (count($violations)) {
        return $this->view($violations, Response::HTTP_BAD_REQUEST);
    }

    $em = $this->getDoctrine()->getManagerForClass($product);
    $em->persist($product);
    $em->flush();

    return $product;
}