Skip to content

Commit

Permalink
Fixe security annotation @IsGranted and @Security before unserialize …
Browse files Browse the repository at this point in the history
…execution.
  • Loading branch information
Smeagolworms4 committed Feb 27, 2020
1 parent a992fd5 commit 71fa7d0
Show file tree
Hide file tree
Showing 8 changed files with 357 additions and 49 deletions.
10 changes: 5 additions & 5 deletions src/EventSubscriber/SerializerSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
Expand Down Expand Up @@ -41,11 +41,11 @@ class SerializerSubscriber implements EventSubscriberInterface {

public static function getSubscribedEvents() {
return [
KernelEvents::CONTROLLER => [
['onKernelController', 10],
KernelEvents::CONTROLLER_ARGUMENTS => [
['onKernelControllerArguments', -10],
],
KernelEvents::VIEW => [
['onKernelView', -1],
['onKernelView', -10],
],
KernelEvents::EXCEPTION => [
['onKernelValidateException', 257],
Expand All @@ -69,7 +69,7 @@ public function setValidator(ValidatorInterface $validator): self {
return $this;
}

public function onKernelController(ControllerEvent $event) {
public function onKernelControllerArguments(ControllerArgumentsEvent $event) {

$request = $event->getRequest();

Expand Down
31 changes: 29 additions & 2 deletions src/Request/ParamConverter/PostRestParamConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,32 @@
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
use GollumSF\RestBundle\Annotation\Unserialize;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Serializer\Exception\MissingConstructorArgumentsException;
use Symfony\Component\Serializer\SerializerInterface;

class PostRestParamConverter implements ParamConverterInterface {

/** @var DoctrineParamConverter */
private $doctrineParamConverter;

/** @var SerializerInterface */
private $serializer;

public function __construct(SerializerInterface $serializer) {
$this->serializer = $serializer;
}

public function setDoctrineParamConverter(DoctrineParamConverter $doctrineParamConverter): void {
public function setDoctrineParamConverter(DoctrineParamConverter $doctrineParamConverter): void
{
$this->doctrineParamConverter = $doctrineParamConverter;
}

public function apply(Request $request, ParamConverter $configuration) {
/** @var Unserialize $unserializeAnnotation */
$unserializeAnnotation = $request->attributes->get('_'.Unserialize::ALIAS_NAME);
$configurationName = $configuration->getName();
$class = $configuration->getClass();

if (
$unserializeAnnotation &&
Expand All @@ -32,7 +44,22 @@ public function apply(Request $request, ParamConverter $configuration) {
$this->doctrineParamConverter->apply($request, $configuration);
$configuration->setIsOptional($isOptional);
}
$request->attributes->set('_'.Unserialize::ALIAS_NAME.'_class', $configuration->getClass());
if (!$request->attributes->get($configurationName)) {
$content = $request->getContent();
if ($content) {
try {
$entity = $this->serializer->deserialize($content, $class, 'json', $context = [
'groups' => $unserializeAnnotation->getGroups(),
]);
$request->attributes->set($configurationName, $entity);
} catch (MissingConstructorArgumentsException $e) {
throw new BadRequestHttpException($e->getMessage());
} catch (\UnexpectedValueException $e) {
throw new BadRequestHttpException($e->getMessage());
}
}
}
$request->attributes->set('_'.Unserialize::ALIAS_NAME.'_class', $class);
return true;
}
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ protected function getKernel(): KernelInterface {
$this->kernel->addBundle(\Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle::class);
$this->kernel->addBundle(\Doctrine\Bundle\DoctrineBundle\DoctrineBundle::class);
$this->kernel->addBundle(\Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle::class);
$this->kernel->addBundle(\Symfony\Bundle\SecurityBundle\SecurityBundle::class);

$this->kernel->addCompilerPasses([ new PublicServicePass('|GollumSF*|') ]);

Expand Down
19 changes: 19 additions & 0 deletions tests/Integration/Controller/Api/BookControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,25 @@ public function testPut($content) {
$this->assertEquals($book->getTitle(), 'TITLE_NEW_1');
$this->assertEquals($book->getDescription(), 'DESCRIPTION_NEW_1');
}

public function testPostIsGranted() {
$this->loadFixture();

/** @var ExceptionSubscriber $exceptionSubscriber */
$exceptionSubscriber = $this->getContainer()->get(ExceptionSubscriber::class);
$this->reflectionSetValue($exceptionSubscriber, 'debug', false);

$client = $this->getClient();

$client->request('POST', '/api/books/is-granted', [], [], [], \json_encode([
'title' => 'TITLE_NEW_1',
'description' => 'DESCRIPTION_NEW_1',
'author' => 2,
'category' => 2,
]));
$response = $client->getResponse();
$this->assertEquals($response->getStatusCode(), 403);
}

public function providerPatchTitle() {
return [
Expand Down
28 changes: 27 additions & 1 deletion tests/ProjectTest/Controller/Api/BookController.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use GollumSF\RestBundle\Annotation\Validate;
use GollumSF\RestBundle\Model\StaticArrayApiList;
use GollumSF\RestBundle\Search\ApiSearchInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Test\GollumSF\RestBundle\ProjectTest\Entity\Book;
Expand Down Expand Up @@ -36,14 +38,38 @@ public function find(Book $book) {
/**
* @Route("", methods={"POST"})
* @Unserialize("book", groups="book_post")
* @Validate({ "book_post" })
* @Validate("book_post")
* @Serialize(groups="book_get", code=Response::HTTP_CREATED)
*
*/
public function post(Book $book) {
return $book;
}

/**
* @Route("/is-granted", methods={"POST"})
* @IsGranted("IS_AUTHENTICATED_FULLY")
* @Unserialize("book", groups="book_post")
* @Validate("book_post")
* @Serialize(groups="book_get", code=Response::HTTP_CREATED)
*
*/
public function postDenyIsGranted(Book $book) {
return $book;
}

/**
* @Route("/security", methods={"POST"})
* @Security("is_granted('AUTHENTICATED_FULLY')")
* @Unserialize("book", groups="book_post")
* @Validate("book_post")
* @Serialize(groups="book_get", code=Response::HTTP_CREATED)
*
*/
public function postDenySecurity(Book $book) {
return $book;
}

/**
* @Route("/{id}", methods={"PUT"})
* @Unserialize("book", groups="book_put")
Expand Down
15 changes: 14 additions & 1 deletion tests/ProjectTest/Resources/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,17 @@ services:
tags: ['controller.service_arguments']

Test\GollumSF\RestBundle\ProjectTest\DataFixtures\:
resource: '%kernel.project_dir%/tests/ProjectTest/DataFixtures'
resource: '%kernel.project_dir%/tests/ProjectTest/DataFixtures'

security:
providers:
in_memory:
memory:
users:
test_user: { password: test }
firewalls:
main:
anonymous: true
http_basic:
realm: 'Secured Demo Area'
provider: in_memory
41 changes: 20 additions & 21 deletions tests/Unit/EventSubscriber/SerializerSubscriberTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\ViewEvent;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
Expand Down Expand Up @@ -118,19 +117,19 @@ class SerializerSubscriberTest extends TestCase {

public function testGetSubscribedEvents() {
$this->assertEquals(SerializerSubscriber::getSubscribedEvents(), [
KernelEvents::CONTROLLER => [
['onKernelController', -1],
KernelEvents::CONTROLLER_ARGUMENTS => [
['onKernelControllerArguments', -10],
],
KernelEvents::VIEW => [
['onKernelView', -1],
['onKernelView', -10],
],
KernelEvents::EXCEPTION => [
['onKernelValidateException', 257],
],
]);
}

public function provideOnKernelControllerSuccess() {
public function provideonKernelControllerArgumentsSuccess() {
return [
[ 'POST', [], [ 'post' ], \stdClass::class ],
[ 'post', [], [ 'post' ], \stdClass::class ],
Expand All @@ -146,9 +145,9 @@ public function provideOnKernelControllerSuccess() {
}

/**
* @dataProvider provideOnKernelControllerSuccess
* @dataProvider provideonKernelControllerArgumentsSuccess
*/
public function testOnKernelControllerSuccess($method, $groups, $groupResults, $class) {
public function testonKernelControllerArgumentsSuccess($method, $groups, $groupResults, $class) {

$serializer = $this->getMockBuilder(StubSerializer::class)->getMockForAbstractClass();
$kernel = $this->getMockBuilder(KernelInterface::class)->getMockForAbstractClass();
Expand All @@ -165,7 +164,7 @@ public function testOnKernelControllerSuccess($method, $groups, $groupResults, $
'groups' => $groups
]);

$event = new ControllerEvent($kernel, $controller, $request, HttpKernelInterface::MASTER_REQUEST);
$event = new ControllerArgumentsEvent($kernel, $controller, [], $request, HttpKernelInterface::MASTER_REQUEST);

$request
->expects($this->once())
Expand Down Expand Up @@ -206,12 +205,12 @@ public function testOnKernelControllerSuccess($method, $groups, $groupResults, $
$serializer
);

$serializerSubscriber->onKernelController($event);
$serializerSubscriber->onKernelControllerArguments($event);
$this->assertEquals($serializerSubscriber->groups, $groupResults);
}


public function testOnKernelControllerNoClassNoEntity() {
public function testonKernelControllerArgumentsNoClassNoEntity() {

$serializer = $this->getMockBuilder(StubSerializer::class)->getMockForAbstractClass();
$kernel = $this->getMockBuilder(KernelInterface::class)->getMockForAbstractClass();
Expand All @@ -227,7 +226,7 @@ public function testOnKernelControllerNoClassNoEntity() {
'groups' => []
]);

$event = new ControllerEvent($kernel, $controller, $request, HttpKernelInterface::MASTER_REQUEST);
$event = new ControllerArgumentsEvent($kernel, $controller, [], $request, HttpKernelInterface::MASTER_REQUEST);

$request
->expects($this->once())
Expand Down Expand Up @@ -265,11 +264,11 @@ public function testOnKernelControllerNoClassNoEntity() {

$this->expectException(\LogicException::class);

$serializerSubscriber->onKernelController($event);
$serializerSubscriber->onKernelControllerArguments($event);
}


public function testOnKernelControllerNoEntity() {
public function testonKernelControllerArgumentsNoEntity() {

$serializer = $this->getMockBuilder(StubSerializer::class)->getMockForAbstractClass();
$kernel = $this->getMockBuilder(KernelInterface::class)->getMockForAbstractClass();
Expand All @@ -285,7 +284,7 @@ public function testOnKernelControllerNoEntity() {
'groups' => []
]);

$event = new ControllerEvent($kernel, $controller, $request, HttpKernelInterface::MASTER_REQUEST);
$event = new ControllerArgumentsEvent($kernel, $controller, [], $request, HttpKernelInterface::MASTER_REQUEST);

$request
->expects($this->once())
Expand Down Expand Up @@ -323,10 +322,10 @@ public function testOnKernelControllerNoEntity() {

$this->expectException(BadRequestHttpException::class);

$serializerSubscriber->onKernelController($event);
$serializerSubscriber->onKernelControllerArguments($event);
}

public function providerOnKernelControllerSave() {
public function provideronKernelControllerArgumentsSave() {
return [
[true, true, true ],
[true, false, false ],
Expand All @@ -336,9 +335,9 @@ public function providerOnKernelControllerSave() {
}

/**
* @dataProvider providerOnKernelControllerSave
* @dataProvider provideronKernelControllerArgumentsSave
*/
public function testOnKernelControllerSave($isEntity, $save, $called) {
public function testonKernelControllerArgumentsSave($isEntity, $save, $called) {

$serializer = $this->getMockBuilder(StubSerializer::class)->getMockForAbstractClass();
$em = $this->getMockForAbstractClass(ObjectManager::class);
Expand All @@ -354,8 +353,8 @@ public function testOnKernelControllerSave($isEntity, $save, $called) {

$entity = new \stdClass();
$controller = function () {};
$event = new ControllerEvent($kernel, $controller, $request, HttpKernelInterface::MASTER_REQUEST);

$event = new ControllerArgumentsEvent($kernel, $controller, [], $request, HttpKernelInterface::MASTER_REQUEST);

$serializerSubscriber = new SerializerSubscriberOnKernelControllerArgumentsTestSave(
$serializer,
Expand Down Expand Up @@ -419,7 +418,7 @@ public function testOnKernelControllerSave($isEntity, $save, $called) {
;
}

$serializerSubscriber->onKernelController($event);
$serializerSubscriber->onKernelControllerArguments($event);
}

public function providerUnserializeSuccess() {
Expand Down
Loading

0 comments on commit 71fa7d0

Please sign in to comment.