Question

As title said I need to modify sfDoctrineGuard validators to allow login based on credentials. I've this users and credentials:

username           credential
administrator      super admin
user1              public_access
user2              
user3              public_access

I've also two applications: admin and site. So based on this data I need to achieve this:

  • user1 and user3 could login in site app but not in admin
  • user2 couldn't login in site and either in admin
  • administrator could login in admin but not in site

Any help?

Was it helpful?

Solution

First you should copy the sfGuardValidatorUser class from plugins/sfDoctrineGuardPlugin/lib/validator into lib/validator and clear the cache.

Than modify it's doClean method to check if a user has the required permission.

class sfGuardValidatorUser extends sfValidatorBase
{
  // ...

  protected function doClean($values)
  {
    $username = isset($values[$this->getOption('username_field')]) ? $values[$this->getOption('username_field')] : '';
    $password = isset($values[$this->getOption('password_field')]) ? $values[$this->getOption('password_field')] : '';

    $callable = sfConfig::get('app_sf_guard_plugin_retrieve_by_username_callable');

    if ($username && $callable)
    {
      $user = call_user_func_array($callable, array($username));
    }
    elseif ($username)
    {
      $user = $this->getTable()->retrieveByUsername($username);
    }
    else
    {
      $user = false;
    }

    /** @var $user sfGuardUser */
    if ($user && $user->isAllowedToLogIn(sfConfig::get('sf_app'), $password))
    {
      return array_merge($values, array('user' => $user));
    }

    if ($this->getOption('throw_global_error'))
    {
      throw new sfValidatorError($this, 'invalid');
    }

    throw new sfValidatorErrorSchema($this, array($this->getOption('username_field') => new sfValidatorError($this, 'invalid')));
  }

  // ...
}

Than add isAllowedToLogIn method to the sfGuardUser class:

public function isAllowedToLogIn($app, $password)
{
  if ('admin' == $app)
  {
    $hasPermission = $this->getIsSuperAdmin() || $this->hasPermission('admin');
  }
  elseif ('site' == $app)
  {
    $hasPermission = $this->hasPermission('public_access');
  }
  else
  {
    $hasPermission = true;
  }

  return $this->getIsActive() && $this->checkPassword($password) && $hasPermission;
}

Modify the permission check part if needed.

I recommend to add an admin group and permission as well and if you can don't use the is_super_admin flag.

OTHER TIPS

You are mixing two things here - authentication and authorisation of users.

Authentication means that your users can log into the website, and you have a confirmation that this the right person.

Authorisation filters which content is available to which users (authenticated or not).

So what you are looking for here is to block access to users who should not be able to see the admin app, not block the login.

If you block the login part (using validators, your own signing action or whatever) you will only block anonymous users who will want to see your admin app. When they try to log in they will be rejected because they are not admins. But if the user logs in to the site app and then goes to admin there will no additional login required and the user will be granted access (unless you set the proper authorisation).

So what you need is to add a security.yml file to your apps/admin/config folder with this content:

all:
  is_secure: true
  credentials: super_admin

If a 'normal' user logs in and tries to navigate to admin app he will be denied access.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top