You are here

public function LdapServerTest::search in Lightweight Directory Access Protocol (LDAP) 7.2

Same name and namespace in other branches
  1. 8.2 ldap_test/LdapServerTest.class.php \LdapServerTest::search()
  2. 7 ldap_servers/tests/LdapServerTest.class.php \LdapServerTest::search()

Perform an LDAP search.

Parameters

string $filter: The search filter. such as sAMAccountName=jbarclay.

string $basedn: The search base. If NULL, we use $this->basedn.

array $attributes: List of desired attributes. If omitted, we only return "dn".

Return value

An array of matching entries->attributes, or FALSE if the search is empty.

Overrides LdapServer::search

File

ldap_test/LdapServerTest.class.php, line 152
Simpletest ldapServer class for testing without an actual ldap server.

Class

LdapServerTest

Code

public function search($base_dn = NULL, $filter, $attributes = [], $attrsonly = 0, $sizelimit = 0, $timelimit = 0, $deref = LDAP_DEREF_NEVER, $scope = LDAP_SCOPE_SUBTREE) {
  $lcase_attribute = [];
  foreach ($attributes as $i => $attribute_name) {
    $lcase_attribute[] = drupal_strtolower($attribute_name);
  }
  $attributes = $lcase_attribute;

  // For test matching simplicity remove line breaks and tab spacing.
  $filter = trim(str_replace([
    "\n",
    "  ",
  ], [
    '',
    '',
  ], $filter));
  if ($base_dn == NULL) {
    if (count($this->basedn) == 1) {
      $base_dn = $this->basedn[0];
    }
    else {
      return FALSE;
    }
  }

  /**
   * Search CASE 1: for some mock ldap servers, a set of fixed ldap filters
   * are prepolulated in test data
   */
  if (isset($this->searchResults[$filter][$base_dn])) {
    $results = $this->searchResults[$filter][$base_dn];
    foreach ($results as $i => $entry) {
      if (is_array($entry) && isset($entry['FULLENTRY'])) {
        unset($results[$i]['FULLENTRY']);
        $dn = $results[$i]['dn'];
        $results[$i] = $this->entries[$dn];
        $results[$i]['dn'] = $dn;
      }
    }
    return $results;
  }

  /**
   * Search CASE 2: attempt to programmatically evaluate ldap filter
   * by looping through fake ldap entries
   */
  $base_dn = drupal_strtolower($base_dn);
  $filter = trim($filter, "()");
  $subqueries = [];
  $operand = FALSE;
  if (strpos($filter, '&') === 0) {

    /**
     * case 2.A.: filter of form (&(<attribute>=<value>)(<attribute>=<value>)(<attribute>=<value>))
     *  such as (&(samaccountname=hpotter)(samaccountname=hpotter)(samaccountname=hpotter))
     */
    $operand = '&';
    $filter = substr($filter, 1);
    $filter = trim($filter, "()");
    $parts = explode(')(', $filter);
    foreach ($parts as $i => $pair) {
      $subqueries[] = explode('=', $pair);
    }
  }
  elseif (strpos($filter, '|') === 0) {

    /**
     * case 2.B: filter of form (|(<attribute>=<value>)(<attribute>=<value>)(<attribute>=<value>))
     *  such as (|(samaccountname=hpotter)(samaccountname=hpotter)(samaccountname=hpotter))
     */
    $operand = '|';
    $filter = substr($filter, 1);
    $filter = trim($filter, "()");
    $parts = explode(')(', $filter);
    $parts = explode(')(', $filter);
    foreach ($parts as $i => $pair) {
      $subqueries[] = explode('=', $pair);
    }
  }
  elseif (count(explode('=', $filter)) == 2) {

    /**
     * case 2.C.: filter of form (<attribute>=<value>)
     *  such as (samaccountname=hpotter)
     */
    $operand = '|';
    $subqueries[] = explode('=', $filter);
  }
  else {
    return FALSE;
  }

  // Need to perform feaux ldap search here with data in.
  $results = [];
  if ($operand == '|') {
    foreach ($subqueries as $i => $subquery) {
      $filter_attribute = drupal_strtolower($subquery[0]);
      $filter_value = $subquery[1];
      foreach ($this->entries as $dn => $entry) {
        $dn_lcase = drupal_strtolower($dn);

        // If not in basedn, skip
        // eg. basedn ou=campus accounts,dc=ad,dc=myuniversity,dc=edu
        // should be leftmost string in:
        // cn=jdoe,ou=campus accounts,dc=ad,dc=myuniversity,dc=edu.
        $substring = strrev(substr(strrev($dn_lcase), 0, strlen($base_dn)));
        $cascmp = strcasecmp($base_dn, $substring);
        if ($cascmp !== 0) {

          // Not in basedn.
          continue;
        }

        // If doesn't filter attribute has no data, continue.
        $attr_value_to_compare = FALSE;
        foreach ($entry as $attr_name => $attr_value) {
          if (drupal_strtolower($attr_name) == $filter_attribute) {
            $attr_value_to_compare = $attr_value;
            break;
          }
        }
        if (!$attr_value_to_compare || drupal_strtolower($attr_value_to_compare[0]) != $filter_value) {
          continue;
        }

        // match!
        $entry['dn'] = $dn;
        if ($attributes) {
          $selected_data = [];
          foreach ($attributes as $i => $attr_name) {
            $selected_data[$attr_name] = isset($entry[$attr_name]) ? $entry[$attr_name] : NULL;
          }
          $results[] = $selected_data;
        }
        else {
          $results[] = $entry;
        }
      }
    }
  }
  elseif ($operand == '&') {
    foreach ($this->entries as $dn => $entry) {
      $dn_lcase = drupal_strtolower($dn);

      // Until 1 subquery fails.
      $match = TRUE;
      foreach ($subqueries as $i => $subquery) {
        $filter_attribute = drupal_strtolower($subquery[0]);
        $filter_value = $subquery[1];
        $substring = strrev(substr(strrev($dn_lcase), 0, strlen($base_dn)));
        $cascmp = strcasecmp($base_dn, $substring);
        if ($cascmp !== 0) {
          $match = FALSE;

          // Not in basedn.
          break;
        }

        // If doesn't filter attribute has no data, continue.
        $attr_value_to_compare = FALSE;
        foreach ($entry as $attr_name => $attr_value) {
          if (drupal_strtolower($attr_name) == $filter_attribute) {
            $attr_value_to_compare = $attr_value;
            break;
          }
        }
        if (!$attr_value_to_compare || drupal_strtolower($attr_value_to_compare[0]) != $filter_value) {
          $match = FALSE;

          // Not in basedn.
          break;
        }
      }
      if ($match === TRUE) {
        $entry['dn'] = $dn;
        if ($attributes) {
          $selected_data = [];
          foreach ($attributes as $i => $attr_name) {
            $selected_data[$attr_name] = isset($entry[$attr_name]) ? $entry[$attr_name] : NULL;
          }
          $results[] = $selected_data;
        }
        else {
          $results[] = $entry;
        }
      }
    }
  }
  $results['count'] = count($results);
  return $results;
}