A while ago I needed to hook up symfony’s excellent sfGuard plugin to some LDAP functionality. There are a couple of issues with the plugin and the readme which I think need fixing. In particular, there is no support for checking both LDAP and standard sfGuard passwords. This is absolutely essential (eg an admin user or guest users who aren’t in LDAP), and I’m somewhat amazed that there’s no provision for this. Moreover, the plugin structure generally makes it seemingly impossible (or if it is possible it’s just too horrible to contemplate) to write your own checkPassword() which does do both sorts of checking.
Anyway this post is partly an attempt for me to get my head round something which I’ve either totally misunderstood, or just isn’t well documented.
The README file that comes with the plugin is great, but it’s a little confusing for explaining how you might override its own way of checking passwords with something that’s LDAP-based. It’s really very simple to do when written out in plain English:
1. Make a file called myLDAP.class.php in your application’s lib folder. Put this in it:
class myLDAP extends sfGuardSecurityUser
2. Now put a method inside the class you just created:
public static function checkLDAPPassword($username, $password)
// put your preferred LDAP-checking code in here
// should return true or false
3. Add this to your application’s app.yml file:
check_password_callable: [myLDAP, checkLDAPPassword]
where myLDAP is the file called myLDAP.class.php that you created in step 1 above. checkLDAPPassword is the method you made inside myLDAP.class.php that you made in step 2.
And there you have it. Basic LDAP password checking.
How does checkPassword() actually work?
The above code is all very well, but what’s really going on?
Well, there are a couple of steps which I managed to work out:
sfGuardUserValidator contains a call to
$user is a result of
BasesfGuardUser) has a method called
checkPassword() too. This calls the method you listed in your app.yml file (
checkLDAPPassword in this case), or does a standard sfGuard password check (
checkPasswordByGuard) if you didn’t specify anything:
public function checkPassword($password)
if ($callable = sfConfig::get('app_sf_guard_plugin_check_password_callable'))
return call_user_func_array($callable, array($this->getUsername(), $password));
Which it does depends on how you set up your app.yml file (see Step 3 above).
At this point, if you set up your app.yml correctly you’ll be in your custom
checkLDAPPassword() method, which will do whatever you want it to do to check LDAP passwords. So long as it returns true or false depending on whether the check was successful or not, you’ll be ok.
sfGuardSecurityUser class also contains a
checkPassword() method. This basically does the same thing as the in
sfGuardUserValidator, but in a slightly different way, and allows access to
checkPassword() in templates and controllers through the
$sf_user object. The important thing to realise is that both pieces of code end up calling the same
checkPassword() method in
So how about LDAP and sfGuard checking?
Now the fun begins. The problem is that it’s seemingly impossible to call
checkPasswordByGuard() yourself from inside your custom-built
checkLDAPPassword() method. Why would you want to do this? Because that way you can do some standard password checking first to see if your user is in fact a sfGuard user and not an LDAP user. Only if that failed would you do LDAP checking (I suppose you could do it the other way round if you wanted.) Even better, you wouldn’t need to alter
So why is it impossible to call
checkPasswordByGuard() ‘by hand’? As far as I can see, it assumes that you’re not in a static context, and that you have some kind of user object available. But of course, my
checkLDAPPassword() is in a static context. It had to be that way because it was called by
call_user_func_array() which uses the output of
sfConfig::get() as an argument.
If you find a way of doing this, please let me know. Losing the will to live is merely one of the symptoms of battling with this sort of thing. I have a life to live.
All I can suggest to you in the meantime is to modify your copy of
PluginsfGuardUser.php to allow both sorts of password checking. That’s what I did and it worked for me. It’s just a pity that you can’t override the
checkPasswordByGuard() method in some way without changing the core of the plugin.