Search code examples
symfonyauthorizationlistenerapi-platform.comaccess-denied

Symfony - Throw an exception returning 403 from a Listener


I'm using Symfony5 with ApiPlatform

I'm using a Listener for multiple tasks including to do some authorization that I can't do in my voters.

So through a simple condition I verify what field of my entity is being modified.

I go through the modified fields, and check if they're different from the only field that can be modified.

here's how :

$modifiedValues = $eventArgs->getEntityManager()->getUnitOfWork()->getEntityChangeSet($eventArgs->getObject());

foreach ($modifiedValues as $key => $value) {
    if ("statut" != $key) {
        throw new AccessDeniedException('Vous ne pouvez pas modifier ce champ.');
    }    
}

Now I'm throwing an AccessDeniedException which I thought would return a 403 but actually return a 500.

The authorization part is actually working but I'm a bit bothered by this "exception" in my logic, cause other authorization rules will return either 200 or 403.

So my questions would be:

  • Does anyone know why this exception behave this way ? If it's normal behavior or something's off
  • Is there another way to return a 403 from this Listener ?

Thanks for your time!


Solution

  • According to documentation you can configure the framework to catch your exception.

    config/packages/api_platform.yaml

    api_platform:
        exception_to_status:
            Symfony\Component\Security\Core\Exception\AccessDeniedException: 403
    

    But you should probably create your own Exception class, extend it from AcessDeniedException and configure it.

    src/Exception/AccessDeniedException.php

    <?php
    
    namespace App\Exception;
    
    use Symfony\Component\Security\Core\Exception\AccessDeniedException;
    
    class MyAccessDeniedException extends AccessDeniedException
    {
    }
    

    config/packages/api_platform.yaml

    api_platform:
        exception_to_status:
            App\Exception\MyAccessDeniedException: 403
    

    Listener.php

    $modifiedValues = $eventArgs->getEntityManager()->getUnitOfWork()->getEntityChangeSet($eventArgs->getObject());
    
    foreach ($modifiedValues as $key => $value) {
        if ("statut" != $key) {
            throw new MyAccessDeniedException('Vous ne pouvez pas modifier ce champ.');
        }    
    }