Search code examples
phpsymfonysecuritysessionsilex

Responding with HTTP_UNAUTHORIZED/Redirect on session expiration


In my application I have a before() hook defined inside the routes.php file:

$app->before(function(Request $request) use($app) {

    $authAnon = $app['security']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');

    if(!$request->getSession()->get('username') && $authAnon) {

        if($request->isXmlHttpRequest()) {
            // return 401/HTTP_UNAUTHORIZED response
            $response = new Response();
            $response->setStatusCode(Response::HTTP_UNAUTHORIZED);
            $response->headers->set('Reason', 'SESSION_EXPIRED');
            $response->headers->set('WWW-Authenticate', 'MyAuthScheme realm="app:login"');
            return $response;
        }

        return new RedirectResponse('login', 301);

    }

}

But this results in $app['security'] not being found/defined:

InvalidArgumentException in Container.php line 96: Identifier "security" is not defined.

My security setup looks like this:

$app->register(new Silex\Provider\SecurityServiceProvider(), array(
    'security.firewalls' => array(
        'login' => array(
            'pattern' => '^/login$',
        ),
        'secured' => array(
            'pattern' => '^.*$',
            'form' => array('login_path' => '/login', 'check_path' => '/login_check'),
            'logout' => array('logout_path' => '/logout', 'invalidate_session' => true),
            'users' => array(
                'admin' => array('ROLE_ADMIN', 'hashed_pwd'),
                'user' => array('ROLE_USER', 'hashed_pwd'),
            ),
        ),
    )
));

$app['security.role_hierarchy'] = array(
    'ROLE_ADMIN' => array('ROLE_USER'),
);

$app['security.access_rules'] = array(
    array('^/admin', 'ROLE_ADMIN'),
    array('^.*$', ['ROLE_USER']),
);

The order the session & security providers are registered looks as follows:

$config_path = __DIR__.'/../app/config/';
require_once $config_path.'session.php';
require_once $config_path.'security.php';
require_once $config_path.'routes/routes.php';

$app->run();

What am I doing wrong?

Edit

Please take a look at my answer below to see what I ended up with.


Solution

  • My guess is that you're using a version of the Symfony Security Component >= 2.6+ right now, so according to the Silex docs you can't use the service security directly (as in $app['security']) and you have to use authorization checker service ($app['security.authorization_checker']):

    <?php
    
    $app->before(function(Request $request) use($app) {
    
      // This won't work with Symfony Security Component < 2.6
      // $authAnon = $app['security']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
    
      // Under Symfony 2.6+
      $authAnon = $app['security.authorization_checker']->isGranted('IS_AUTHENTICATED_ANONYMOUSLY');
      // ...
    }