You are here

class LdapServerTest in Lightweight Directory Access Protocol (LDAP) 8.2

Same name and namespace in other branches
  1. 7.2 ldap_test/LdapServerTest.class.php \LdapServerTest
  2. 7 ldap_servers/tests/LdapServerTest.class.php \LdapServerTest

Hierarchy

Expanded class hierarchy of LdapServerTest

File

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

View source
class LdapServerTest extends LdapServer {
  public $entries;
  public $methodResponses;
  public $searchResults;
  public $binddn = FALSE;

  // Default to an anonymous bind.
  public $bindpw = FALSE;

  // Default to an anonymous bind.

  /**
   * Constructor Method
   *
   * can take array of form property_name => property_value
   * or $sid, where sid is used to derive the include file.
   */
  function __construct($sid) {
    if (!is_scalar($sid)) {
      $test_data = $sid;
      $sid = $test_data['sid'];
    }
    else {
      $test_data = variable_get('ldap_test_server__' . $sid, array());
    }
    $bindpw = isset($test_data['bindpw']) ? $test_data['bindpw'] : 'goodpwd';
    $this->sid = $sid;
    $this
      ->refreshFakeData();
    $this
      ->initDerivedProperties($bindpw);
  }
  public function refreshFakeData() {

    // debug("refreshFakeData sid=". $this->sid);
    $test_data = variable_get('ldap_test_server__' . $this->sid, array());
    $this->methodResponses = is_array($test_data) && isset($test_data['methodResponses']) ? $test_data['methodResponses'] : array();
    $this->entries = is_array($test_data) && isset($test_data['ldap']) ? $test_data['ldap'] : array();

    //  debug('this->entries');debug($this->entries);
    $this->searchResults = isset($test_data['search_results']) ? $test_data['search_results'] : array();
    $this->detailedWatchdogLog = config('ldap_help.settings')
      ->get('watchdog_detail');
    foreach ($test_data['properties'] as $property_name => $property_value) {
      $this->{$property_name} = $property_value;
    }

    //  $this->basedn = unserialize($this->basedn);
    if (isset($test_data['bindpw']) && $test_data['bindpw'] != '') {
      $this->bindpw = ldap_servers_decrypt($this->bindpw);
    }
  }

  /**
   * Destructor Method
   */
  function __destruct() {

    // if alterations to server configuration must be maintained throughout simpletest, variable_set('ldap_authorization_test_server__'. $sid, array());
  }

  /**
   * Connect Method
   */
  function connect() {
    return $this->methodResponses['connect'];
  }
  function bind($userdn = NULL, $pass = NULL, $anon_bind = FALSE) {
    $userdn = $userdn != NULL ? $userdn : $this->binddn;
    $pass = $pass != NULL ? $pass : $this->bindpw;
    if (!isset($this->entries[$userdn])) {
      $ldap_errno = LDAP_NO_SUCH_OBJECT;

      // 0x20 or 32
      if (function_exists('ldap_err2str')) {
        $ldap_error = ldap_err2str($ldap_errno);
      }
      else {
        $ldap_error = "Failed to find {$userdn} in LdapServerTest.class.php";
      }
    }
    elseif (isset($this->entries[$userdn]['password'][0]) && $this->entries[$userdn]['password'][0] == $pass && $pass) {
      return LDAP_SUCCESS;
    }
    else {
      if (!$pass) {
        debug("Simpletest failure for {$userdn}.  No password submitted");
      }
      if (!isset($this->entries[$userdn]['password'][0])) {
        debug("Simpletest failure for {$userdn}.  No password in entry to test for bind");
        debug($this->entries[$userdn]);
      }
      $ldap_errno = LDAP_INVALID_CREDENTIALS;
      if (function_exists('ldap_err2str')) {
        $ldap_error = ldap_err2str($ldap_errno);
      }
      else {
        $ldap_error = "Credentials for {$userdn} failed in LdapServerTest.class.php";
      }
    }
    $watchdog_tokens = array(
      '%user' => $userdn,
      '%errno' => $ldap_errno,
      '%error' => $ldap_error,
    );
    watchdog('ldap', "LDAP bind failure for user %user. Error %errno: %error", $watchdog_tokens);
    return $ldap_errno;
  }

  /**
   * Disconnect (unbind) from an active LDAP server.
   */
  function disconnect() {
  }

  /**
   * Perform an LDAP search.
   *
   * @param string $filter
   *   The search filter. such as sAMAccountName=jbarclay
   * @param string $basedn
   *   The search base. If NULL, we use $this->basedn
   * @param array $attributes
   *   List of desired attributes. If omitted, we only return "dn".
   *
   * @return
   *   An array of matching entries->attributes, or FALSE if the search is
   *   empty.
   */
  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;
  }

  /**
   * does dn exist for this server?
   *
   * @param string $dn
   * @param enum $return = 'boolean' or 'ldap_entry'
   *
   * @param return FALSE or ldap entry array
   */
  function dnExists($find_dn, $return = 'boolean', $attributes = array(
    'objectclass',
  )) {
    $this
      ->refreshFakeData();
    $test_data = variable_get('ldap_test_server__' . $this->sid, array());
    foreach ($this->entries as $entry_dn => $entry) {
      $match = strcasecmp($entry_dn, $find_dn) == 0;
      if ($match) {

        //  debug("testserver:dnExists,match=$match, entry_dn=$entry_dn, find_dn=$find_dn"); debug($entry);
        return $return == 'boolean' ? TRUE : $entry;
      }
    }

    // debug("testserver:dnExists, no match");
    return FALSE;

    // not match found in loop
  }
  public function countEntries($ldap_result) {
    return ldap_count_entries($this->connection, $ldap_result);
  }
  public static function getLdapServerObjects($sid = NULL, $type = NULL, $flatten = FALSE) {
    $servers = array();
    if ($sid) {
      $servers[$sid] = new LdapServerTest($sid);
    }
    else {
      $server_ids = variable_get('ldap_test_servers', array());
      foreach ($server_ids as $sid => $_sid) {
        $servers[$sid] = new LdapServerTest($sid);
      }
    }
    if ($flatten && $sid) {
      return $servers[$sid];
    }
    else {
      return $servers;
    }
  }

  /**
  * create ldap entry.
  *
  * @param array $ldap_entry should follow the structure of ldap_add functions
  *   entry array: http://us.php.net/manual/en/function.ldap-add.php
       $attributes["attribute1"] = "value";
       $attributes["attribute2"][0] = "value1";
       $attributes["attribute2"][1] = "value2";
  * @return boolean result
  */
  public function createLdapEntry($ldap_entry, $dn = NULL) {
    $result = FALSE;
    $test_data = variable_get('ldap_test_server__' . $this->sid, array());
    if (isset($ldap_entry['dn'])) {
      $dn = $ldap_entry['dn'];
      unset($ldap_entry['dn']);
    }
    if ($dn && !isset($test_data['entries'][$dn])) {
      $test_data['entries'][$dn] = $ldap_entry;
      $test_data['ldap'][$dn] = $ldap_entry;
      variable_set('ldap_test_server__' . $this->sid, $test_data);
      $this
        ->refreshFakeData();
      $result = TRUE;
    }
    return $result;
  }
  function modifyLdapEntry($dn, $attributes = NULL, $old_attributes = FALSE) {
    if (!$attributes) {
      $attributes = array();
    }
    $test_data = variable_get('ldap_test_server__' . $this->sid, array());
    if (!isset($test_data['entries'][$dn])) {
      return FALSE;
    }
    $ldap_entry = $test_data['entries'][$dn];
    foreach ($attributes as $key => $cur_val) {
      if ($cur_val == '') {
        unset($ldap_entry[$key]);
      }
      elseif (is_array($cur_val)) {
        foreach ($cur_val as $mv_key => $mv_cur_val) {
          if ($mv_cur_val == '') {
            unset($ldap_entry[$key][$mv_key]);
          }
          else {
            if (is_array($mv_cur_val)) {
              $ldap_entry[$key][$mv_key] = $mv_cur_val;
            }
            else {
              $ldap_entry[$key][$mv_key][] = $mv_cur_val;
            }
          }
        }
        unset($ldap_entry[$key]['count']);
        $ldap_entry[$key]['count'] = count($ldap_entry[$key]);
      }
      else {
        $ldap_entry[$key][0] = $cur_val;
        $ldap_entry[$key]['count'] = count($ldap_entry[$key]);
      }
    }
    $test_data['entries'][$dn] = $ldap_entry;
    $test_data['ldap'][$dn] = $ldap_entry;

    //  debug("modifyLdapEntry:server test data before save $dn"); debug($test_data['entries'][$dn]);
    variable_set('ldap_test_server__' . $this->sid, $test_data);
    $this
      ->refreshFakeData();
    return TRUE;
  }

  /**
   * Perform an LDAP delete.
   *
   * @param string $dn
   *
   * @return boolean result per ldap_delete
   */
  public function delete($dn) {
    $test_data = variable_get('ldap_test_server__' . $this->sid, array());

    // debug("test ldap server, delete=$dn, test data="); debug(array_keys($test_data['users']));
    $deleted = FALSE;
    foreach (array(
      'entries',
      'users',
      'groups',
      'ldap',
    ) as $test_data_sub_array) {
      if (isset($test_data[$test_data_sub_array][$dn])) {
        unset($test_data[$test_data_sub_array][$dn]);
        $deleted = TRUE;
      }
    }
    if ($deleted) {
      variable_set('ldap_test_server__' . $this->sid, $test_data);
      $this
        ->refreshFakeData();
      return TRUE;
    }
    else {
      return FALSE;
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
LdapServer::$account_name_attr public property
LdapServer::$address public property
LdapServer::$basedn public property
LdapServer::$bind_method public property
LdapServer::$connection public property
LdapServer::$detailedWatchdogLog public property Error methods and properties.
LdapServer::$detailed_watchdog_log public property
LdapServer::$editPath public property
LdapServer::$groupDeriveFromDn public property
LdapServer::$groupDeriveFromDnAttr public property
LdapServer::$groupFunctionalityUnused public property
LdapServer::$groupGroupEntryMembershipsConfigured public property
LdapServer::$groupMembershipsAttr public property
LdapServer::$groupMembershipsAttrMatchingUserAttr public property
LdapServer::$groupNested public property
LdapServer::$groupObjectClass public property
LdapServer::$groupTestGroupDn public property
LdapServer::$groupTestGroupDnWriteable public property
LdapServer::$groupUserMembershipsAttr public property
LdapServer::$groupUserMembershipsAttrExists public property
LdapServer::$groupUserMembershipsConfigured public property
LdapServer::$group_properties private property
LdapServer::$inDatabase public property
LdapServer::$ldapToDrupalUserPhp public property
LdapServer::$ldap_type public property
LdapServer::$mail_attr public property
LdapServer::$mail_template public property
LdapServer::$name public property
LdapServer::$numericSid public property
LdapServer::$paginationEnabled public property
LdapServer::$picture_attr public property
LdapServer::$port public property
LdapServer::$queriableWithoutUserCredentials public property
LdapServer::$searchPageEnd public property
LdapServer::$searchPageSize public property
LdapServer::$searchPageStart public property
LdapServer::$searchPagination public property
LdapServer::$sid public property
LdapServer::$status public property
LdapServer::$testingDrupalUserDn public property
LdapServer::$testingDrupalUsername public property
LdapServer::$tls public property
LdapServer::$unique_persistent_attr public property
LdapServer::$unique_persistent_attr_binary public property
LdapServer::$userAttributeNeededCache public property
LdapServer::$user_attr public property
LdapServer::$user_dn_expression public property
LdapServer::$_errorMsg protected property
LdapServer::$_errorName protected property
LdapServer::$_hasError protected property
LdapServer::clearError public function
LdapServer::connectAndBindIfNotAlready public function
LdapServer::dnArrayToLowerCase public function
LdapServer::errorMsg public function
LdapServer::errorName public function
LdapServer::field_to_properties_map public static function
LdapServer::groupAddGroup public function NOT TESTED add a group entry
LdapServer::groupAddMember public function NOT TESTED add a member to a group
LdapServer::groupAllMembers public function @todo: NOT IMPLEMENTED: nested groups
LdapServer::groupIsMember public function Is a user a member of group?
LdapServer::groupMembershipsFromEntryResursive public function recurse through all groups, adding parent groups to $all_group_dns array.
LdapServer::groupMembershipsFromUser public function get list of all groups that a user is a member of.
LdapServer::groupMembersResursive public function NOT IMPLEMENTED recurse through all child groups and add members.
LdapServer::groupRemoveGroup public function NOT TESTED remove a group entry
LdapServer::groupRemoveMember public function NOT TESTED remove a member from a group
LdapServer::groupUserMembershipsFromDn public function get "groups" from derived from DN. Has limited usefulness
LdapServer::groupUserMembershipsFromEntry public function get list of all groups that a user is a member of by querying groups
LdapServer::groupUserMembershipsFromUserAttr public function get list of all groups that a user is a member of by using memberOf attribute first, then if nesting is true, using group entries to find parent groups
LdapServer::hasError public function
LdapServer::initDerivedProperties protected function this method sets properties that don't directly map from db record. it is split out so it can be shared with ldapServerTest.class.php
LdapServer::ldapErrorNumber public function
LdapServer::ldapQuery function execute ldap query and return ldap records
LdapServer::LDAP_CONNECT_ERROR constant
LdapServer::LDAP_OPERATIONS_ERROR constant
LdapServer::LDAP_PROTOCOL_ERROR constant
LdapServer::LDAP_SUCCESS constant
LdapServer::pagedLdapQuery public function execute a paged ldap query and return entries as one aggregated array
LdapServer::removeUnchangedAttributes public static function given 2 ldap entries, old and new, removed unchanged values to avoid security errors and incorrect date modifieds
LdapServer::searchAllBaseDns public function Perform an LDAP search on all base dns and aggregate into one result
LdapServer::setError public function
LdapServer::userEmailFromLdapEntry public function
LdapServer::userPictureFromLdapEntry public function *
LdapServer::userPuidFromLdapEntry public function
LdapServer::userUserEntityFromPuid public function
LdapServer::userUsernameFromDn public function
LdapServer::userUsernameFromLdapEntry public function
LdapServer::userUserNameToExistingLdapEntry function Queries LDAP server for the user.
LdapServer::userUsernameToLdapNameTransform function
LdapServer::userUserToExistingLdapEntry public function
LdapServer::user_lookup public function
LdapServer::__invoke function Invoke Method
LdapServerTest::$binddn public property Overrides LdapServer::$binddn
LdapServerTest::$bindpw public property Overrides LdapServer::$bindpw
LdapServerTest::$entries public property
LdapServerTest::$methodResponses public property
LdapServerTest::$searchResults public property
LdapServerTest::bind function * Bind (authenticate) against an active LDAP database. * * Overrides LdapServer::bind
LdapServerTest::connect function Connect Method Overrides LdapServer::connect
LdapServerTest::countEntries public function Overrides LdapServer::countEntries
LdapServerTest::createLdapEntry public function create ldap entry. Overrides LdapServer::createLdapEntry
LdapServerTest::delete public function Perform an LDAP delete. Overrides LdapServer::delete
LdapServerTest::disconnect function Disconnect (unbind) from an active LDAP server. Overrides LdapServer::disconnect
LdapServerTest::dnExists function does dn exist for this server? Overrides LdapServer::dnExists
LdapServerTest::getLdapServerObjects public static function
LdapServerTest::modifyLdapEntry function modify attributes of ldap entry Overrides LdapServer::modifyLdapEntry
LdapServerTest::refreshFakeData public function
LdapServerTest::search function Perform an LDAP search. Overrides LdapServer::search
LdapServerTest::__construct function Constructor Method Overrides LdapServer::__construct
LdapServerTest::__destruct function Destructor Method Overrides LdapServer::__destruct