ficus
ficus

Reputation: 194

zfcuser - whitelist routes and all childroutes

I'am using ZfcUser module in my application to protect access to /admin route. As I want to block all childroutes of /admin, except for /login, /register etc.

In order to do so, I've added a code from accepted answer here - Zend Framework 2 - Global check for authentication with ZFCUser

protected $whitelist = array('zfcuser/login', 'default');

  public function onBootstrap($e)
  {
      $app = $e->getApplication();
      $em  = $app->getEventManager();
      $sm  = $app->getServiceManager();

      $list = $this->whitelist;
      $auth = $sm->get('zfcuser_auth_service');

      $em->attach(MvcEvent::EVENT_ROUTE, function($e) use ($list, $auth) {
          $match = $e->getRouteMatch();

          // No route match, this is a 404
          if (!$match instanceof RouteMatch) {
              return;
          }

          // Route is whitelisted
          $name = $match->getMatchedRouteName();
          if (in_array($name, $list)) {
              return;
          }

          // User is authenticated
          if ($auth->hasIdentity()) {
              return;
          }

          // Redirect to the user login page, as an example
          $router   = $e->getRouter();
          $url      = $router->assemble(array(), array(
              'name' => 'zfcuser/login'
          ));

          $response = $e->getResponse();
          $response->getHeaders()->addHeaderLine('Location', $url);
          $response->setStatusCode(302);

          return $response;
      }, -100);
  }

It works, however it also block access to root routes - and as there is plenty of them, I do not really want to add every single route to whitelist. Is there any way to restrict access only to /admin routes?

Upvotes: 0

Views: 178

Answers (3)

Adam Lundrigan
Adam Lundrigan

Reputation: 598

I suggest taking a look at ZfcRbac. It has a "guards" functionality that I think is exactly what you're looking for:

return [
    'zfc_rbac' => [
        'guards' => [
            'ZfcRbac\Guard\RouteGuard' => [
                'admin*' => ['admin']
            ]
        ]
    ]
];

This would restrict any route starting with admin to users in the admin role. Since the default operation mode is blacklist-based ("protection mode" is "allow"), you only need to specify rules for the routes you want to restrict access to. Any route not matching a RouteGuard will be publicly-accessible.

Upvotes: 1

unclexo
unclexo

Reputation: 3941

You may protect access to admin area by checking each controller name instead of checking route names. Thus you may control user's accessibility with less effort and it is more portable than checking route names.

List your controllers where you want to limit accesses. So everything related to a controller should be restricted. Wherever you need to restrict access just list them here. You do not need to make your hands dirty with onBootstrap() method anymore.

protected $whitelist = array(
    'ZfcUser\Controller\User', // or use 'zfcuser'
); 

Put right controller name in the $whitelist. You can get that by echoing $controller in the onBootstrap() method. Please check out the commented area below.

Next catch up the controller name and then check whether that is listed in your list or not.

public function onBootstrap(MvcEvent $e)
{
    $app = $e->getApplication();
    $em  = $app->getEventManager();
    $sm  = $app->getServiceManager();

    $list = $this->whitelist;
    $auth = $sm->get('zfcuser_auth_service');

    $em->attach(MvcEvent::EVENT_ROUTE, function($e) use ($list, $auth) {

        // get the current route
        $route = $e->getRouteMatch()->getMatchedRouteName();

        // check for 'zfcuser/login' and 'zfcuser/register' routes
        if (in_array($route, array('zfcuser/login', 'zfcuser/register'))) {
            return;
        }   

        // get the current controller name
        $controller = $e->getRouteMatch()->getParam('controller');

        // Check the right controller name by echoing 
        // echo $controller;         

        // check if a user has access on the current controller 
        if (in_array($controller, $list)) {

            if(! $auth->hasIdentity()) {

                $router = $e->getRouter();
                $url = $router->assemble(array(), array(
                    'name' => 'zfcuser/login'
                ));

                $response = $e->getResponse();
                $response->getHeaders()->addHeaderLine('Location', $url);
                $response->setStatusCode(302);

                return $response;
            }
        }

    }, -100);
}    

Let us know if it helps you!

Upvotes: 1

AlexP
AlexP

Reputation: 9857

Is there any way to restrict access only to /admin routes?

That would really mean that rather than a whitelist you would need a blacklist or change the logic of the conditional check.

Depending on your requirements, you could check just part of the route, something like this.

$this->whitelist = [
    'zfcuser/login', 
    'default'
];

// Route is whitelisted
$currentRoute = $match->getMatchedRouteName();

foreach($this->whitelist as $route) {
    if (0 === strpos($currentRoute, $route)) {
        // we matched the start of the route,
        // e.g every route under 'default' would match this
        return;
    }
}

Upvotes: 1

Related Questions