Search code examples
mysqlsecurityauthenticationldapsymfony-3.3

LDAP with Guard Authentication System in Symfony 3


What I'm pretending to do is to include the LDAP for internal users in a Guard Authentication System configured by ddbb. I already have build my Guard Authentication System and works really nice thanks to https://knpuniversity.com/screencast/symfony-security.

But I need also to try to log in previously via LDAP mode. More precisely, the functionality must be like this:

The user try to log in on the Guard System Authentication configured with a database from MySQL and:

1- Check if exist the user in the table User from MySQL. If exist, we go to step 2. If not exist return false to the authentication with the error message.

2-Check if the user exist in the LDAP mode. If exist go to the step 3. If not exist go to the step 4.

3-Try to log in via LDAP with the username and password. If the authentication is ok, it's logged in. If can't match the password via LDAP, return false to the authentication with the error message.

4-After checking the LDAP option, we will just try to log in via Guard Authentication System. If the authentication it's ok, the user is logged in. If can't match the password via Guard with the MySQL users table, return false to the authentication with the error message.


Solution

  • In the LoginFormAuthenticator file I finally could manage this behavior I want as shows the next code.

    <?php
    
    namespace AppBundle\Security;
    
    use ...
    use Zend\Ldap\Ldap;
    use Zend\Ldap\Exception\LdapException;
    
    class LoginFormAuthenticator extends AbstractFormLoginAuthenticator
    {
        use TargetPathTrait;
    
        private $em;
        private $router;
        private $passwordEncoder;
        private $csrfTokenManager;
    
        public function __construct(...
        }
    
        public function getCredentials(Request $request)
        {
        ...
        }
    
        public function getUser($credentials, UserProviderInterface $userProvider)
        {
            $username = $credentials['username'];
            $ldapPassword = $credentials['password'];
            $ldaphost = 'ldap.example.com';    // your ldap servers
            $baseDn = 'dc=example,dc=es';
    
            $options = [
                'host'              => $ldaphost,
                'username'          => $username,
                'password'          => $ldapPassword,
                'bindRequiresDn'    => false,
                'accountDomainName' => 'example.es',
                'baseDn'            => $baseDn,
            ];
    
    
            $userInterface = $this->em->getRepository('AppBundle:User')
                ->findOneBy(['email' => $username]);
            $ldap = new Ldap($options);
    
            try {
                $ldap->bind();
                $userInterface->setIsAuthenticationLDAP(true);
            } catch (LdapException $zle){
                $userInterface->setIsAuthenticationLDAP(false);
            }
    
            return $userInterface;
        }
    
        public function checkCredentials($credentials, UserInterface $user)
        {
            $password = $credentials['password'];
    
            if($user->isAuthenticationLDAP()){
                $user->setLoginAttempts(0);
                $this->em->persist($user);
                $this->em->flush();
                return true;
            } else {
               if($this->passwordEncoder->isPasswordValid($user, $password)) {
                   $user->setLoginAttempts(0);
                   $this->em->persist($user);
                   $this->em->flush();
                   return true;
               } else {
                   if($user->getLoginAttempts() == '0') $user->setFirstLoginAttempt(new \DateTime('now'));
                   $user->setLoginAttempts($user->getLoginAttempts() + 1);
                   if($user->getLoginAttempts() >= 5) {
                       $user->setLockedDateTime(new \DateTime('now'));
                       $user->setLoginAttempts(0);
                   }
                   $this->em->persist($user);
                   $this->em->flush();
               }
           }
    
           return false;
        }
    
        public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey)
        {
           ....
        }
    
        protected function getLoginUrl()
        {
            return $this->router->generate('fos_user_security_login');
        }
    }
    

    I hope anyone can enjoy this answer.