Search code examples
symfonyldap

Symfony 5.4 LDAP and User-Entity Password mixed


Is ist possible to configure user authentification for Symfony 5.4 using either User/Password stored in the User entity oder LDAP depending on a boolean field or the password being null in the User entity?

I need to create some users that have to log on but are not contained in the customers LDAP structure. LDAP is more a comfort thing (single credentials for all apps) here than a security one (no one may logon if not defined in LDAP).

Perhaps I can get around programming the security things from the scatch and just combine two different providers.


Solution

  • Meanwhile I solved it and it was quite easy by using the "normal" password authenticator and modifying a bit of code. The strategy is:

    1. Check if its an LDAP user. If not, use password authentication
    2. Search the user in the LDAP directory
    3. Bail out if not found
    4. Bail out if not unique
    5. Check credentials

    The steps I took:

    1. I added a boolean field to the entity USER called ldap_flag

    2. I added variables to .env to specify the LDAP parameters

    3. I modified Security/LoginFormAuthenticator:checkCredentials like this:

      if ($user->getLDAPFlag()) {
      
          if ($conn = ldap_connect($_ENV['LDAP_HOST'])) {
              ldap_set_option($conn, LDAP_OPT_PROTOCOL_VERSION, $_ENV['LDAP_PROTOCOL_VERSION']);
              ldap_set_option($conn, LDAP_OPT_REFERRALS, 0);
              if ($_ENV['LDAP_CERT_CHECK'] == 0)
                  ldap_set_option($conn, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER);
              $dn = $_ENV['LDAP_BIND_DN'];
              $pw = $_ENV['LDAP_BIND_PW'];
              if (ldap_bind($conn, $dn, $pw)) {
                  // Search user
                  $res = ldap_search($conn, $_ENV['LDAP_SEARCH_DN'], "(&(uid=" . $user->getUserName() . ")(objectClass=inetOrgPerson))", array('dn'));
                  $entries = ldap_get_entries($conn, $res);
                  if ($entries["count"] == 1)
                      return ldap_bind($conn, $entries[0]['dn'], $credentials['password']);
                  else if ($entries["count"] > 0)
                      throw new CustomUserMessageAuthenticationException('Benutzer im LDAP nicht eindeutig!');
                  else
                      throw new CustomUserMessageAuthenticationException('Benutzer auf dem LDAP Server nicht gefunden!');
              } else
                  // cannot bind
                  throw new CustomUserMessageAuthenticationException('Kann nicht an LDAP-Server binden!');
              ldap_unind($conn);
          } else {
              // no LDAP Connection
              throw new CustomUserMessageAuthenticationException('Keine Verbindung zum LDAP-Server');
          }
      } else
          // internal password-check
          return $this->passwordEncoder->isPasswordValid($user, $credentials['password']);
      

      }

    The error messages are in German but it should be easy to adapt them to an other language as they explain within their context.