You are here

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

Same name and namespace in other branches
  1. 7.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 140
Simpletest ldapServer class for testing without an actual ldap server

Class

LdapServerTest

Code

function search($base_dn = NULL, $filter, $attributes = array(), $attrsonly = 0, $sizelimit = 0, $timelimit = 0, $deref = LDAP_DEREF_NEVER, $scope = LDAP_SCOPE_SUBTREE) {

  // debug("ldap test server search base_dn=$base_dn, filter=$filter");
  $lcase_attribute = array();
  foreach ($attributes as $i => $attribute_name) {
    $lcase_attribute[] = drupal_strtolower($attribute_name);
  }
  $attributes = $lcase_attribute;
  $filter = trim(str_replace(array(
    "\n",
    "  ",
  ), array(
    '',
    '',
  ), $filter));

  // for test matching simplicity remove line breaks and tab spacing
  if ($base_dn == NULL) {
    if (count($this->basedn) == 1) {
      $base_dn = $this->basedn[0];
    }
    else {

      // debug("fail basedn: ldap test server search base_dn=$base_dn, filter=$filter");
      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])) {

    //   debug("case1 filter= $filter   base_dn=$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;
      }
    }

    //   debug($results);
    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 = array();
  $operand = FALSE;
  if (strpos($filter, '&') === 0) {

    //   debug('2.A.');

    /**
     * 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) {

    //debug('2.B.');

    /**
     * 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);
    }

    // debug("operand=$operand, filter=$filter subqueries"); debug($subqueries);
    // debug($this->entries['cn=hpotter,ou=people,dc=hogwarts,dc=edu']);
    // debug($this->entries['cn=clone0,ou=people,dc=hogwarts,dc=edu']);
  }
  elseif (count(explode('=', $filter)) == 2) {

    // debug('2.C.');

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

    //  debug('no case');
    return FALSE;
  }

  // need to perform feaux ldap search here with data in
  $results = array();
  if ($operand == '|') {
    foreach ($subqueries as $i => $subquery) {
      $filter_attribute = drupal_strtolower($subquery[0]);
      $filter_value = $subquery[1];

      //  debug("filter_attribute=$filter_attribute, filter_value=$filter_value");
      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

        //$pos = strpos($dn_lcase, $base_dn);
        $substring = strrev(substr(strrev($dn_lcase), 0, strlen($base_dn)));
        $cascmp = strcasecmp($base_dn, $substring);

        //debug("dn_lcase=$dn_lcase, base_dn=$base_dn,pos=$pos,substring=$substring,cascmp=$cascmp");
        if ($cascmp !== 0) {
          continue;

          // not in basedn
        }

        // 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;
          }
        }

        // debug("filter value=$filter_value, attr_value_to_compare="); debug($attr_value_to_compare);
        if (!$attr_value_to_compare || drupal_strtolower($attr_value_to_compare[0]) != $filter_value) {
          continue;
        }

        // match!
        // debug("match"); debug($attr_value); debug($attributes);
        $entry['dn'] = $dn;
        if ($attributes) {
          $selected_data = array();
          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 == '&') {

    // reverse the loops
    foreach ($this->entries as $dn => $entry) {
      $dn_lcase = drupal_strtolower($dn);
      $match = TRUE;

      // until 1 subquery fails
      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);

        //debug("dn_lcase=$dn_lcase, base_dn=$base_dn,pos=$pos,substring=$substring,cascmp=$cascmp");
        if ($cascmp !== 0) {
          $match = FALSE;
          break;

          // not in basedn
        }

        // 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;
          }
        }

        // debug("filter value=$filter_value, attr_value_to_compare="); debug($attr_value_to_compare);
        if (!$attr_value_to_compare || drupal_strtolower($attr_value_to_compare[0]) != $filter_value) {
          $match = FALSE;
          break;

          // not in basedn
        }
      }
      if ($match === TRUE) {
        $entry['dn'] = $dn;
        if ($attributes) {
          $selected_data = array();
          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);

  //  debug("ldap test server search results"); debug($results);
  return $results;
}