I’ve totally forgot that at the end of post Extra questions and solutions for sfGuardPlugin we have promised to write how to implement complicated user statuses for sfGuardPlugin. Sorry Hugo (one of our commenters), you was hoping it will be quickly but only now we have got a chance to write next post about extending sfGuardPlugin.
Generally, it’s simple but you should either modify existing sfGuardPlugin (so it’s hack and it’s bad because you will have problems with plugin upgrades) or override sfGuardPlugin with overwriting some functions.
I’m going to propose here hack version and if you want you always can use the same code for overriding. As you remember we used sfGuardPluginExtra for extending purposes. So now we need to add to sf_guard_user_profile new field which is called “user_status_id” and it’s responsible for user statuses (e.g. 1 = pending, 2 = active, 3 = frozen, 4 = deleted). There are actually 2 ways – either we use user_status_id only as informative field and allow/block user access based on original is_active field boolean value in sfGuardUser table. I bet in most cases it’s enough. Because if user pending or frozen or deleted he does not have access to system so is_active is false. But I can believe that in some cases we may need is_partially_active status or something like that 🙂
This or other way this hack may shed some light on sfGuardAuth mechanisms (it’s good to know how we can improve is_active).
So let me provide you a small code quotation from sfGuardPlugin/lib/validator/sfGuardUserValidator.class.php
$user = sfGuardUserPeer::retrieveByUsername($username);
// user exists?
if ($user)
{
// password is ok?
if ($user->checkPassword($password))
{
$this->getContext()->getUser()->signIn($user, $remember);return true;
}
}
This is core of authentification for sfGuardPlugin. Lets stick a knife into this heart with our piece of code 🙂
// user status is ok?
if (!$user->checkStatus($user->getProfile()->getStatusId())) {
$error = $this->getParameterHolder()->get(‘userstatus_error’);
return false;
}
It means we are going additionaly check user status before even allow system to identify the password. Of course function $user->checkStatus we need to additionaly define in sfGuardUser.php class:
public function checkStatus($status_id)
{
if ($status_id == SF_GUARD_USER_PROFILE_STATUS_ID_ACTIVE)
return true;
else return false;
}
Here we use only simple constant SF_GUARD_USER_PROFILE_STATUS_ID_ACTIVE and we can have more complicated conditions of course.
Let me provide full piece of code fore user validator with included our hack code:
// user exists?
if ($user)
{
// user status is ok?
if (!$user->checkStatus($user->getProfile()->getStatusId())) {
$error = $this->getParameterHolder()->get(‘userstatus_error’);
return false;
}// password is ok?
if ($user->checkPassword($password))
{
$this->getContext()->getUser()->signIn($user, $remember);return true;
}
}
Would be interesting to hear which other code hacks were done by you.
I tried a quick search in symfony forum and found something related to hacks here:
http://www.symfony-project.org/forum/index.php/m/39682/?srch=hack+sfguardplugin#msg_39682
Have a great non hacked weekend!
One reply on “Extending sfGuardPlugin (part 2)”
I am working on an application where I extend sfGuard (or rather sfGuardDoctrine) to accommodate permissions per account.
I explain: There is a user table an account table, permission table and a ternary relationship in the permitting table with user_id, account_id and permission_id.
For example a certain user can have blog-admin permission for account 1.
The difficulty is that the credentials needed for an action cannot be set in security.yml because they dependent on the account the action acts on.
So what I do is:
– In the signin method of SecurityUser, I store the credential as a string of the form: permission|account_id for example blog-admin|1.
– I override the getCredential method of each module to protect, adding the account specific credentials (like blog-admin|1) to the ones defined in the security.yml file.
Any other ideas if anyone has been implementing that case?