Active Directory Validation is Slow in PHP

So I'm validating username, password, and group membership in active directory like so:

function validate($username, $password, $groupname = null) {
  if ($username && $password) {
    $link = ldap_connect($domain);
    if ($link) {
      ldap_set_option($link, LDAP_OPT_PROTOCOL_VERSION, 3);
      $bind = ldap_bind($link, $username, $password);
      if ($bind) {
        if ($groupname) {
          $filter  = "(samAccountName=".$username.")";
          $attrs   = array("memberOf");
          $res     = ldap_search($link, $baseDN, $filter, $attrs);
          $entries = ldap_get_entries($link, $res);
          $isMember = false;
          if ($entries && $entries[0] && $entries[0]['memberof']) {
            $arr = $entries[0]['memberof'];
            foreach ($arr as $key => $value) {
              if ($key != 'count') {
                $isMember = $isMember || preg_match("|".preg_quote($groupname)."|", $value);
              }
            }
          }
          return $isMember;
        } else {
          return true;
        }
      } else {
        return false;
      }
    } else {
      error_log("Could not connect to Active Directory");
      return false;
    }
  } else {
    error_log("Username or password missing");
    return false;
  }
}

This works correctly, but is painfully slow, taking as much as 2~3 minutes to validate that a user is a member of a group.. If I omit the group membership check it runs almost instantaneously. How can I speed this up (without caching)?

EDIT

since it was not clear from the question, the bottle neck is the ldap_search function which takes ~127 seconds, rest of the program runs in less than a second. Should also add that we only have about 20 AD users and 10ish groups.

Answers


Ar first it looked to me like the foreach-loop with a preg_match inside takes some time. Especially if there are a lot of groups to check.

But then it became clear that there were only 10 groups and about 20 users in the AD, so it had to be something different.

In the end it was an issue with missing timeouts. Adding ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, 10); right before the ldap_search() cured the issue.

It looks as if in that special case a connection to the LDAP-Server has been opened but the LDAP-Server didn't respond correctly and therefore the client was waiting for an answer until the timeout was hit. Setting this timeout to a much smaller value than the default (which is indefinite) caused the ldap_search to return much earlier as it needs no longer to wait.

AFAIK this has been fixed in PHP-5.6.14 and PHP-7.0.0


Need Your Help

Random access gzip stream

language-agnostic compression gzip large-files random-access

I'd like to be able to do random access into a gzipped file.

Define missing symbols in Clojure

macros clojure symbols

I am trying to write a macro that, given a form, defines all missing symbols as themselve.