Permalink
Browse files

Merge pull request #308 from FriendsOfSymfony/access_denied_listener

added a way to enforce a 403 response on an access denied exception
  • Loading branch information...
2 parents 28a9cc0 + 0edd822 commit 7dc85eb2ac086f98ff56a6af7a9f02d1bf7d951d @lsmith77 lsmith77 committed Oct 3, 2012
@@ -41,6 +41,10 @@ public function getConfigTreeBuilder()
$rootNode
->children()
+ ->arrayNode('access_denied_listener')
+ ->useAttributeAsKey('name')
+ ->prototype('boolean')->end()
+ ->end()
->scalarNode('param_fetcher_listener')->defaultFalse()->end()
->scalarNode('cache_dir')->cannotBeEmpty()->defaultValue('%kernel.cache_dir%/fos_rest')
->validate()
@@ -73,7 +77,6 @@ public function getConfigTreeBuilder()
->children()
->scalarNode('version')->defaultNull()->end()
->arrayNode('groups')
- ->defaultValue(array())
->prototype('scalar')->end()
->end()
->end()
@@ -108,7 +111,6 @@ private function addViewSection(ArrayNodeDefinition $rootNode)
->end()
->arrayNode('mime_types')
->useAttributeAsKey('name')
- ->defaultValue(array())
->prototype('variable')->end()
->end()
->arrayNode('formats')
@@ -134,9 +134,14 @@ public function load(array $configs, ContainerBuilder $container)
}
}
- if ($config['allowed_methods_listener']) {
+ if (!empty($config['allowed_methods_listener'])) {
$loader->load('allowed_methods_listener.xml');
}
+
+ if (!empty($config['access_denied_listener'])) {
+ $loader->load('access_denied_listener.xml');
+ $container->setParameter($this->getAlias().'.access_denied_listener.formats', $config['access_denied_listener']);
+ }
}
/**
@@ -0,0 +1,55 @@
+<?php
+
+/*
+ * This file is part of the FOSRestBundle package.
+ *
+ * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace FOS\RestBundle\EventListener;
+
+use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\Security\Core\Exception\AccessDeniedException;
+
+/**
+ * This listener handles ensures that for specific formats AccessDeniedExceptions
+ * will return a 403 regardless of how the firewall is configured
+ *
+ * @author Lukas Kahwe Smith <smith@pooteeweet.org>
+ */
+class AccessDeniedListener
+{
+ private $formats;
+
+ /**
+ * Constructor.
+ *
+ * @param ContainerInterface $container container
+ * @param boolean $setParamsAsAttributes params as attributes
+ */
+ public function __construct($formats = array())
+ {
+ $this->formats = $formats;
+ }
+
+ /**
+ * @param GetResponseForExceptionEvent $event The event
+ */
+ public function onKernelException(GetResponseForExceptionEvent $event)
+ {
+ $exception = $event->getException();
+ if (!$exception instanceof AccessDeniedException) {
+ return;
+ }
+
+ $request = $event->getRequest();
+ if (!empty($this->formats[$request->getRequestFormat()])) {
+ $response = new Response('You dont have the necessary permissions', 403);
+ $event->setResponse($response);
+ }
+ }
+}
@@ -0,0 +1,22 @@
+<?xml version="1.0" ?>
+
+<container xmlns="http://symfony.com/schema/dic/services"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
+
+ <parameters>
+
+ <parameter key="fos_rest.access_denied_listener.class">FOS\RestBundle\EventListener\AccessDeniedListener</parameter>
+ <parameter key="fos_rest.access_denied_listener.formats" type="collection"/>
+
+ </parameters>
+
+ <services>
+
+ <service id="fos_rest.access_denied_listener" class="%fos_rest.access_denied_listener.class%">
+ <tag name="kernel.event_listener" event="kernel.exception" method="onKernelException" priority="5"/>
+ <argument>%fos_rest.access_denied_listener.formats%</argument>
+ </service>
+
+ </services>
+</container>
@@ -346,5 +346,22 @@ fos_rest:
allowed_methods_listener: true
```
+### Security Exception Listener
+
+By default it is the responsibility of firewall access points to deal with AccessDeniedExceptions.
+For example the ``form`` entry point will redirect to the login page. However for a RESTful application
+the proper thing to happen is to return a 403 HTTP status code. This listener is triggered before
+the normal exception listener and firewall entry points and forces returning a 403 for any of the
+formats configured.
+
+You need to enable this listener like this as it is disabled by default:
+
+```
+fos_rest:
+ access_denied_listener:
+ # all requests using the 'json' format will return a 403 on an access denied violation
+ json: true
+```
+
## That was it!
[Return to the index](index.md) or continue reading about [ExceptionController support](4-exception-controller-support.md).
@@ -3,6 +3,10 @@ Full default configuration
```yaml
fos_rest:
+ access_denied_listener:
+
+ # Prototype
+ name: []
param_fetcher_listener: false
cache_dir: %kernel.cache_dir%/fos_rest
allowed_methods_listener: false

0 comments on commit 7dc85eb

Please sign in to comment.