symfony: Convert InsufficientAuthenticationException to HttpAccessDeniedException

    firewalls:
        dev:
            pattern:  ^/(_(profiler|wdt|fragment)|css|images|js)/
            security: false

        main:
            pattern:    /
            ololo: ~
            provider: users_entity
            anonymous: ~

    access_control:
        - { path: ^/admin, roles: ROLE_ADMIN }

open as anonymous something like /admin/dashboard and got 500. Expected 403.

[2013-07-10 17:27:49] security.INFO: Populated SecurityContext with an anonymous Token [] []
[2013-07-10 17:27:49] security.INFO: No expression found; abstaining from voting. [] []
[2013-07-10 17:27:49] security.DEBUG: Access is denied (user is not fully authenticated) by "/vhosts/www.ololo.com/new/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/AccessListener.php" at line 73; redirecting to authentication entry point [] []
[2013-07-10 17:27:49] request.CRITICAL: Uncaught PHP Exception Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException: "Full authentication is required to access this resource." at /vhosts/www.ololo.com/new/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php line 109 {"exception":"[object] (Symfony\\Component\\Security\\Core\\Exception\\InsufficientAuthenticationException: Full authentication is required to access this resource. at /vhosts/www.ololo.com/new/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php:109, Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException: Access Denied at /vhosts/www.ololo.com/new/vendor/symfony/symfony/src/Symfony/Component/Security/Http/Firewall/AccessListener.php:73)"} []

About this issue

  • Original URL
  • State: closed
  • Created 11 years ago
  • Comments: 54 (38 by maintainers)

Commits related to this issue

Most upvoted comments

Any update on this?

I am encountering this issue with the FrameworkExtraBundle’s @Security annotation. When the expression fails, the SecurityListener throws an AccessDeniedException as expected, but it is not handled because I do not have form_login or an entry point defined.

Because the exceptions are not occurring in the authentication listeners for me, I am not able to do points 1 or 2 proposed by @jakzal. The suggested EntryPoint implementation added to my firewall fixed the problem.

security:
        api:
            anonymous: true
            entry_point: "system.api_entry"
<?php

use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;

class ApiEntryPoint implements AuthenticationEntryPointInterface
{
    public function start(Request $request, AuthenticationException $authException = null)
    {
        return new JsonResponse([
            'error' => JsonResponse::HTTP_FORBIDDEN,
            'message' => $authException ? $authException->getMessage() : 'Access Denied'
        ], JsonResponse::HTTP_FORBIDDEN);
    }
}

I had the same issue on 3.4.0-BETA3 I resolved it putting the backend before the public firewall:

Pattern always must be restrictive at the start, and be degressive

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false

        backend:
            anonymous: ~
            pattern:    ^/admin
            provider: admin

            form_login:
                login_path: admin_login
                check_path: admin_login
                default_target_path: admin_dashboard

        public:
            anonymous: ~
            pattern:    ^/
            provider: customer

    access_control:
        - { path: ^/admin/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin, roles: ROLE_ADMIN }

I’m still seeing this issue in 3.3 using LexikJWTAuthenticationBundle

@jakzal we’ve since implemented the third option (entry point). However I do still think this is a workaround, rather than a solution. As I mentioned before:

I think this is because the failing firewall does not have an entry point, which is a design choice (there is no login form or anything in this example).

The entry point interface clearly states that it’s:

used to start the authentication scheme

So when returning a 401 other than http basic auth (which provides a login form in the browser), the response does not start any form of authentication, but rather denies access.

If option 2 is not viable, then I’d vote for option 1.

I agree.

Still wondering this has not been fixed for this long? Seems to me there needs to be a check prior the line 131

$event->setResponse($this->startAuthentication($event->getRequest(), $insufficientAuthenticationException));

to check whether there is a login_path parameter, then check whether there is access_denied_url on a given firewall

Because in my case I’m writing API that has no form login whatsoever and uses stateless firewall, thus having no form_login has no where to jump, but to the default error403.json.twig. When Anonymous is disabled on said firewall I get completely different issue with A Token was not found in the TokenStorage. on `vendor\symfony\symfony\src\Symfony\Component\Security\Http\Firewall\AccessListener.phpwhich is understandable, but I hopedExceptionListenerwould have been called priorAccessListener``, but that’s a whole other issue.

the only possible workaround to this is to implement entry_point of a firewall.

<?php
namespace Acme\ApiBundle\Security\Firewall;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;

class EntryPoint implements AuthenticationEntryPointInterface{
  public function start(Request $request, AuthenticationException $authException = null){
      $response = new Response(
        '{"error":{"code":'.Response::HTTP_FORBIDDEN.',"message":"Access Denied"}}',
        Response::HTTP_FORBIDDEN,
        array('Content-Type'=>'application/json'));
      return $response;
  }
}