Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony2: use both LDAP (Active directory) and DB for user authentication

I'm using Symfony framework v 2.4.2 to update an existing website which performs a double check to log users in:

  1. first, it checks if the username and password belong to a valid Active Directory user (using PHP's ldap_bind() function);
  2. if so, it checks the username only against a DB table (no password is stored in the DB);
  3. if the username is found in the DB table, the website loads the user profile from DB, and the user is authenticated.

How can I replicate this auth process in Symfony2?

So far, I got stuck with FOSUserBundle and FR3DLdapBundle: I managed to use chained providers (ldap and db), but seemingly LDAP credentials are completely ignored: users can login with the credentials stored in the DB, even if the ldap_bind() fails - which is the exact opposite of points 1 & 2.

Besides, when using FOSUserBundle, it seems to be mandatory to store passwords inside the DB.

Please pay attention to point no. 2: users must be free to change their LDAP password from outside the website (that is, from Active Directory), and then log in with the new credentials- without any update to the website's users database.

Any solution is welcome, I'm not so much in love with FOSUserBundle and even less with FR3DLdapBundle.

like image 560
Paolo Stefan Avatar asked Mar 19 '14 09:03

Paolo Stefan


2 Answers

I worked it out like this:

  1. created a custom user entity based on the FOSUSerBundle User model;
  2. created a custom user provider (see Javad answer to this question), registered it as a service and added it to my providers section in app/config/security.yml;
  3. from v2.4 on, Symfony (luckily) offers a simplified authentication system that does not force you to go through all the custom authentication provider stuff (which IMHO was a real pain): it's called Authenticator and it's documented here. I implemented my own Authenticator class and performed the double check using my custom UserProvider class.
like image 195
Paolo Stefan Avatar answered Nov 15 '22 21:11

Paolo Stefan


You need to define a CustomUserProvider for LDAP which will find the user in AD and in your security.yml you need to set this provider (Custom User Provider)

providers:
    ldap_provider:
        id: myprovider.security.user.provider   # as you know when you create a custom web service provider you need to define it as a service and use the ID of the service here #

You also need to enable your service in your firewall
Next step is to create custom Authentication Provider for LDAP which authenticate the user and password through LDAP and return the user object from DB (Custom Authentication Provider)

Base on this process first it will try to find user in LDAP if it exists it will continue authenticating through LDAP and if user is authenticated it will return the User Object from DB

Here is a sample for custom user provider

public function loadUserByUsername($username)
{
   $ldap_obj = new adLDAP('exampl.ldapdircetory.com', 'prot', 'Base_DN', 'ldap_admin_user', 'ldap_admin_pass'));
   $filter = "( &(objectclass=person)( |(uid=".$username.")(cn=".$username.")(mail=".$username.") ) )";
   $info = $ldap_obj->search_user($filter);
   if ($info['count'] != 0) {
      // create temp User instance of UserInterface base on the returned info
      $user = new User();
      ...
      return $user
   }
   else {
      throw new UsernameNotFoundException('No match username was found.');
   }

I assume you have adLDAP class to authenticate user(s) through LDAP

like image 32
Javad Avatar answered Nov 15 '22 22:11

Javad