Tuesday, October 20, 2009

Securing the application

Lets say we have two different applications which are part of bigger system so they have the same set of users. If it is some closed system you will probably want to restrict some groups of users from accessing one o the applications (ie. client didn't buy that feature so his users shouldn't use it). If you wanted to use the standard credentials system implemented in the symfony, you'd have to check in each action if user have a proper credential.  In our system we have hundreds of actions so it'd be a real nightmare. Especially you'd have to do it for both apps.


The best solution would be setting an access on the applications level but unfortunately security.yml in the app config directory doesn't allow it.

apps/app1/config/security.yml
//it won't work!
all:
  is_secure: on
  credentials: [[admin, app1]]

The solution is custom filter which will parse that yaml for us. So first, lets setup the security.yml so it could be understood by our filter:

all:
  is_secure: off
  credentials: [[admin, app1]]

The "is_secure: off" value is needed to disable default symfony behaviour. Next, we have to create a mySecurityFilter.php file in apps/app1/lib directory.

class mySecurityFilter extends sfGuardBasicSecurityFilter
{
  public function execute($filterChain)
  {
    if ($this->isFirstCall()) 
    {
      $context    = $this->getContext();
      $user       = $context->getUser();
      $strModule  = $context->getModuleName();
      $controller = $context->getController();
      $action     = $context->getActionName();
       
      if($user->isAuthenticated())
      {
       if($action!='signout' && $action!='noauth')
       {
         $config = sfYaml::load(SF_ROOT_DIR.'/apps/app1/config/security.yml');
         if(!empty($config))
         {
           if(array_key_exists($strModule,$config))
           {
             if($user->hasCredential($config[$strModule]['credentials']))
             {
               $filterChain->execute();
               return;
             }
             else
             {
              $controller->forward('errorPage', 'noauth');
              throw new sfStopException();
             }
           }         
           elseif(array_key_exists('all',$config))
           {
             if($user->hasCredential($config['all']['credentials']))
             {
               $filterChain->execute();
               return;
             }
             else
             {
               $controller->forward('errorPage', 'noauth');
               throw new sfStopException();
             }
           }
          }
        }
       }
       else 
       {
         // the user is not authenticated
         $controller->forward(sfConfig::get('sf_login_module'),sfConfig::get('sf_login_action'));

        throw new sfStopException();
       }
    }
    $filterChain->execute();
  }
}

The last step is to notice symfony about existence of our filter and when it should be launched:

apps/app1/config/filters.yml
mySecurityFilter:
  class: mySecurityFilter
rendering: ~
web_debug: ~
security: ~
cache: ~
common: ~
flash: ~
execution: ~ 
Now clear cache and that's all, now only users with credentials specified in the app security.yml will have access to actions in that application!

No comments:

Post a Comment