1

I need to check that when accessing the BooksController, the header 'X-API-User-Name = admin' is received.

I use this documetations https://symfony.com/doc/current/event_dispatcher/before_after_filters.html

Code It's my middleware

namespace App\Event;

use App\Controller\BooksController;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\ResponseEvent;

class HeaderChecker implements EventSubscriberInterface
{
    const HEADER = 'X-API-User-Name';

    public function onKernelController(ControllerEvent $event): void
    {
        $controller = $event->getController();
        if (is_array($controller)) {
            $controller = $controller[0];
        }

        if ($controller instanceof BooksController) {
            $header = $event->getRequest()->headers->has(self::HEADER);
            if (!$header) return new JsonResponse(['message' => 'Header X-API-User-Name is not found'], Response::HTTP_FORBIDDEN);

            $admin = $event->getRequest()->headers->get(self::HEADER);
            if ($admin !== 'admin') return new JsonResponse(['message' => 'Header X-API-User-Name is not valid'], Response::HTTP_FORBIDDEN);
        }
    }

    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::CONTROLLER => 'onKernelController'
        ];
    }
}

service.yaml code

App\Event\HeaderChecker:
        tags:
            - { name: kernel.event_subscriber, event: kernel.exception, method: 'onKernelController' }

Problem: Through var_dump I checked that the data is coming in, but here's the thing. I need to send a JsonResponse with a 403 status if the X-API-User-Name is not admin. But my EventSubscriber class does not return JsonResponse if X-API-User-Name is not admin. What's my mistake?

Марк
  • 45
  • 7
  • You are tagging controllers as listeners, and you need to tag listener with that tag – Flash Dec 17 '21 at 17:12
  • @Flash, can I have an example of this? – Марк Dec 17 '21 at 17:15
  • if autowiring is on you can just comment these lines in your `service.yaml`, and it should work – Flash Dec 17 '21 at 17:22
  • @Flash, How to do this, I do not understand how I can comment on them? – Марк Dec 17 '21 at 17:24
  • add `#` sign to the start of the line, or you can just delete these lines. Comments just easier to uncomment later if it will not work. (https://www.tutorialspoint.com/yaml/yaml_comments.htm) – Flash Dec 17 '21 at 17:30
  • @Flash, Yes, the error disappeared, but now EventSubscriber does not work, even if I enter incorrect data, then my class does not return JsonResponse but continues to work, why? – Марк Dec 17 '21 at 17:49
  • Try to use ```if ('admin' !== $admin)```, because now you are not checking the contents of the header, only that it is present and not empty. – Flash Dec 17 '21 at 18:22
  • @Flash, Yes, I checked that, but my solution does not work and I do not understand why? – Марк Dec 17 '21 at 18:38
  • Check your profiler events for your subscriber it must be in `Called Listeners` tab if it is called. – Flash Dec 17 '21 at 18:43

1 Answers1

1

Couple of things going on here. If you are using an EventSubscriber then there is no need for any additional lines in services.yaml. From the comments I think you have figured this out.

To verify your listener is wired properly, use bin/console debug:event-dispatcher kernel.controller. Your listener should show up. You could also simply add a dump statement.

With that cleared up, notice that your onKernelController method has a return type of void. You can return anything you want but it won't make a difference. Anything you return is ignored. Which actually brings the question of how is all this implemented anyways? It is very instructive, in my opinion, to look at the HttpKernel::handleRaw method. It's bit overwhelming at first glance but it does show when the kernel events are fired and what happens afterward.

Returning to the issue of how one does indicate a json response is needed, events such as the RequestEvent have a setResponse method. Alas you don't know the controller with a request event.

Sadly, the ControllerEvent does not a setResponse method. Instead it has a setController method which means that you can actually change the controller.

So you need to make a controller action that returns your json response. And then you use $kernel->setController($controller) to use it. I won't show the detailed code as the documentation has examples.

It is a bit involved. Might be easier to just check the headers in the controller action itself and be done with it. On the other hand, once you get it working and understand why it works then you have a very useful tool for the future.

One final thought: if this is about access control then you should probably just throw an access denied exception. No point in given a hacker internal security information. Are there really cases where a legitimate user should be able access this controller without the header?

Cerad
  • 48,157
  • 8
  • 90
  • 92