Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error 500 rose on 'AccessDeniedException' #20233

Closed
Cypaubr opened this issue Oct 18, 2016 · 18 comments
Closed

Error 500 rose on 'AccessDeniedException' #20233

Cypaubr opened this issue Oct 18, 2016 · 18 comments

Comments

@Cypaubr
Copy link

Cypaubr commented Oct 18, 2016

When the user tries to access a route needing an user authentication using the Anonymous account, a HTTP 500 error is rose. Why not a 403? Is there any way to rise a 403?

@xabbuh
Copy link
Member

xabbuh commented Oct 18, 2016

You should not see a 500 response. Are you sure that this is triggered by Symfony core and not by one of your own exceptions? Can you show an example that reproduces your issue (best by forking the Symfony Standard Edition and making the necessary changes)?

@Cypaubr
Copy link
Author

Cypaubr commented Oct 18, 2016

The controller for this route only returns a 'Hello World' message so the exception is triggered by Symfony. In my security.yml I just set up a simple firewall on this route disabling anonymous auth and enabling security like this :

app:
            pattern: ^/(fr|en)/app$
            anonymous: false
            security: true
            provider: db
            form_login:
                login_path: one_day_connect
                check_path: user_connect
            logout:
                path: one_day_logout
                target: one_day_homepage

@xabbuh
Copy link
Member

xabbuh commented Oct 18, 2016

Please give us more information. Which errors are logged in your log file? What is the full stack trace you see when you try to access the controller in the dev environment?

@Cypaubr
Copy link
Author

Cypaubr commented Oct 18, 2016

Here is the log :

INFO - Matched route "one_day_app_home". 
INFO - Populated the TokenStorage with an anonymous Token. 
DEBUG - Access denied, the user is not fully authenticated; redirecting to authentication entry point. 
CRITICAL - Uncaught PHP Exception Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException: "Full authentication is required to access this resource." at C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\Security\Http\Firewall\ExceptionListener.php line 128 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
DEBUG - Notified event "kernel.request" to listener "Symfony\Component\EventDispatcher\Debug\WrappedListener::__invoke". 
INFO - Referencing the "Twig_Extension_Core" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead. 
INFO - Referencing the "Twig_Extension_Core" extension by its name (defined by getName()) is deprecated since 1.26 and will be removed in Twig 2.0. Use the Fully Qualified Extension Class Name instead. 
DEBUG - Notified event "kernel.controller" to listener "Symfony\Bundle\FrameworkBundle\DataCollector\RouterDataCollector::onKernelController". 
DEBUG - Notified event "kernel.controller" to listener "Symfony\Component\HttpKernel\DataCollector\RequestDataCollector::onKernelController". 
DEBUG - Notified event "kernel.controller" to listener "Sensio\Bundle\FrameworkExtraBundle\EventListener\ControllerListener::onKernelController". 
DEBUG - Notified event "kernel.controller" to listener "Sensio\Bundle\FrameworkExtraBundle\EventListener\ParamConverterListener::onKernelController". 
DEBUG - Notified event "kernel.controller" to listener "Sensio\Bundle\FrameworkExtraBundle\EventListener\HttpCacheListener::onKernelController". 
DEBUG - Notified event "kernel.controller" to listener "Sensio\Bundle\FrameworkExtraBundle\EventListener\SecurityListener::onKernelController". 
DEBUG - Notified event "kernel.controller" to listener "Sensio\Bundle\FrameworkExtraBundle\EventListener\TemplateListener::onKernelController". 

And here is the stacktrace :

[1] Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException: Full authentication is required to access this resource.
    at n/a
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\Security\Http\Firewall\ExceptionListener.php line 128

    at Symfony\Component\Security\Http\Firewall\ExceptionListener->handleAccessDeniedException(object(GetResponseForExceptionEvent), object(AccessDeniedException))
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\Security\Http\Firewall\ExceptionListener.php line 97

    at Symfony\Component\Security\Http\Firewall\ExceptionListener->onKernelException(object(GetResponseForExceptionEvent), 'kernel.exception', object(TraceableEventDispatcher))
        in  line 

    at call_user_func(array(object(ExceptionListener), 'onKernelException'), object(GetResponseForExceptionEvent), 'kernel.exception', object(TraceableEventDispatcher))
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\EventDispatcher\Debug\WrappedListener.php line 61

    at Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(object(GetResponseForExceptionEvent), 'kernel.exception', object(ContainerAwareEventDispatcher))
        in  line 

    at call_user_func(object(WrappedListener), object(GetResponseForExceptionEvent), 'kernel.exception', object(ContainerAwareEventDispatcher))
        in C:\wamp64\www\1day-symfony\var\cache\dev\classes.php line 1756

    at Symfony\Component\EventDispatcher\EventDispatcher->doDispatch(array(object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'kernel.exception', object(GetResponseForExceptionEvent))
        in C:\wamp64\www\1day-symfony\var\cache\dev\classes.php line 1671

    at Symfony\Component\EventDispatcher\EventDispatcher->dispatch('kernel.exception', object(GetResponseForExceptionEvent))
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher.php line 136

    at Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch('kernel.exception', object(GetResponseForExceptionEvent))
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\HttpKernel.php line 221

    at Symfony\Component\HttpKernel\HttpKernel->handleException(object(AccessDeniedException), object(Request), '1')
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\HttpKernel.php line 75

    at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), '1', true)
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\Kernel.php line 169

    at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
        in C:\wamp64\www\1day-symfony\web\app_dev.php line 32

[2] Symfony\Component\Security\Core\Exception\AccessDeniedException: Access Denied.
    at n/a
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\Security\Http\Firewall\AccessListener.php line 70

    at Symfony\Component\Security\Http\Firewall\AccessListener->handle(object(GetResponseEvent))
        in C:\wamp64\www\1day-symfony\var\cache\dev\classes.php line 2504

    at Symfony\Component\Security\Http\Firewall->onKernelRequest(object(GetResponseEvent), 'kernel.request', object(TraceableEventDispatcher))
        in  line 

    at call_user_func(array(object(Firewall), 'onKernelRequest'), object(GetResponseEvent), 'kernel.request', object(TraceableEventDispatcher))
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\EventDispatcher\Debug\WrappedListener.php line 61

    at Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(object(GetResponseEvent), 'kernel.request', object(ContainerAwareEventDispatcher))
        in  line 

    at call_user_func(object(WrappedListener), object(GetResponseEvent), 'kernel.request', object(ContainerAwareEventDispatcher))
        in C:\wamp64\www\1day-symfony\var\cache\dev\classes.php line 1756

    at Symfony\Component\EventDispatcher\EventDispatcher->doDispatch(array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'kernel.request', object(GetResponseEvent))
        in C:\wamp64\www\1day-symfony\var\cache\dev\classes.php line 1671

    at Symfony\Component\EventDispatcher\EventDispatcher->dispatch('kernel.request', object(GetResponseEvent))
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher.php line 136

    at Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch('kernel.request', object(GetResponseEvent))
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\HttpKernel.php line 125

    at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), '1')
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\HttpKernel.php line 64

    at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), '1', true)
        in C:\wamp64\www\1day-symfony\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\Kernel.php line 169

    at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
        in C:\wamp64\www\1day-symfony\web\app_dev.php line 32

@jakzal
Copy link
Contributor

jakzal commented Oct 18, 2016

related (not sure if duplicate yet) : #15236 #11663 #19906 #8467

@xabbuh
Copy link
Member

xabbuh commented Oct 18, 2016

@Cypaubr I just tried to reproduce your issue, but was not able to do so. Can you please fork the Symfony Standard Edition and make the changes that are necessary to reproduce it? Which Symfony version do you use?

@Cypaubr
Copy link
Author

Cypaubr commented Oct 18, 2016

I do that quickly! I run Symfony 3.0.9.

@Koc
Copy link
Contributor

Koc commented Oct 23, 2016

Similar to (or duplicate of) #8467

@jakzal
Copy link
Contributor

jakzal commented Oct 23, 2016

@Cypaubr any news?

@xabbuh
Copy link
Member

xabbuh commented Nov 12, 2016

Closing due to the lack of feedback. @Cypaubr please feel free to leave a comment when you came up with a reproducable scenario. But please also be aware that we will have to be able to reproduce your issue with Symfony 3.1 as 3.0 is not maintained anymore (and I suggest to update your application to 3.1).

@xabbuh xabbuh closed this as completed Nov 12, 2016
@jclg
Copy link

jclg commented Nov 21, 2016

Hi

First create a new symfony project (currently 3.1.7)
symfony new my_project

Launch the webserver
php bin/console server:start

Add the following at the end of app/config/security.yml

    access_control:
            - { path: ^/, roles: IS_AUTHENTICATED_ANONYMOUSLY, ips: [127.0.0.2] }
            - { path: ^/, roles: ROLE_NO_ACCESS }

Then browse to http://localhost:8000/
"InsufficientAuthenticationException: Full authentication is required to access this resource." Got 500 but 403 expected.

@javiereguiluz
Copy link
Member

@jclg this is what's happening when you use the code that you shared:

  1. The URL is protected, so the firewall correctly throws a AccessDeniedException (code 403) thanks to this code:
if (!$this->accessDecisionManager->decide($token, $attributes, $request)) {
    throw new AccessDeniedException();
}
  1. The Security component has an exception listener to handle in some special way the exceptions related to security.

  2. In this case, the listener executes the handleAccessDeniedException() method. In particular, this is the code that is being executed in your case:

if (null !== $this->logger) {
                $this->logger->debug('Access denied, the user is not fully authenticated; redirecting to authentication entry point.', array('exception' => $exception));
            }

            try {
                $insufficientAuthenticationException = new InsufficientAuthenticationException('Full authentication is required to access this resource.', 0, $exception);
                $insufficientAuthenticationException->setToken($token);

                $event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException));
            } catch (\Exception $e) {
                $event->setException($e);
            }

If you open the log file, you'll see the Access denied ... redirecting to ... message

  1. The problem is that the $this->startAuthentication() throws an exception itself. Why? Because this code:
    private function startAuthentication(Request $request, AuthenticationException $authException)
    {
        if (null === $this->authenticationEntryPoint) {
            throw $authException;
        }

        // ...
    }
  1. In the application there is no "authentication entry point" defined, so it's null and the exception is thrown. This is a InsufficientAuthenticationException (code 500) and that's why you see a HTTP 500 error in the application.

  2. If you define an authentication mechanism (form login, HTTP basic, etc.) the "entry point" is not null and then you don't see this 500 error.

So, I'd say that this is the expected behavior in this case and this is not a bug.

@Cypaubr
Copy link
Author

Cypaubr commented Nov 21, 2016

@javiereguiluz In my case I am using an authentication mechanism (form login) and I still see a 500 error...

@jakzal jakzal reopened this Nov 21, 2016
@jakzal
Copy link
Contributor

jakzal commented Nov 21, 2016

@Cypaubr in that case please provide steps to reproduce your issue. Steps provided by @jclg (thank you!) are not sufficient as @javiereguiluz explained.

@MacSim75
Copy link

@javiereguiluz I am sorry but you're wrong.
I am on the same use case than @jclg and I expect to have a 403 not a 500.
A form login has never been required on a website. Why the hell would I have to build an authentication mechanism if I don't need it ?
That AccessDeniedException should throw a 403 even if you don't have an authentication mechanism on your website.
Getting a 500 on an AccessDeniedException is really not what I expect.
For me that's a bug

@javiereguiluz
Copy link
Member

@MacSim75 don't be sorry 😄 I'm wrong lots of times every day 😅

In order to reproduce this bug and reopen it, we'd nee the detailed steps to reproduce it. Even better if you could share a simple Symfony project in GitHub reproducing this issue. Thanks!

@MacSim75
Copy link

Well what you say is not entirely wrong. You made a really good explaination on "what happen".
It's just on the last sentence that I disagree when you say "I'd say that this is the expected behavior in this case and this is not a bug."
As I said I would never expect to have a 500 when I expect a 403 and an authentication mechanism has never been required to build a website. So there's no way to say that getting a 500 instead of a 403 should be the expected behavior. Either the call $event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException)); shouldn't be triggered or it should ONLY be triggered if an authentication mechanism has been found ; all other use cases should return a real 403, no more.
But it's my own opinion, maybe I am wrong.
I have no more informations to give compared to #20233 (comment)
I am in the same case as @jclg and I really don't understand that weird 500 return.

@MacSim75
Copy link

I guess you were finally right, it's the expected behavior as said in https://symfony.com/doc/current/security/access_control.html :

If access is denied, the system will try to authenticate the user if not already (e.g. redirect the user to the login page). If the user is already logged in, the 403 "access denied" error page will be shown. See How to Customize Error Pages for more information.

I still don't understand that behavior.
We should at least have a parameter "redirect_403_to_login" or something like that.
When this parameter is TRUE we should call $event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException));
If the parameter is FALSE or unset, that call shouldn't be triggered and Symfony should display the 403 Exception.
We would then have the ability to use access_denied_handler to make a custom return.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants