Projet

Général

Profil

Paste
Télécharger (14,2 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ldap / ldap_test / LdapServerTest.class.php @ bc175c27

1
<?php
2

    
3
/**
4
 * @file
5
 * Simpletest ldapServer class for testing without an actual ldap server
6
 *
7
 */
8

    
9
/**
10
 * LDAP Server Class
11
 *
12
 *  This class is used to create, work with, and eventually destroy ldap_server
13
 * objects.
14
 *
15
 * @todo make bindpw protected
16
 */
17

    
18
ldap_servers_module_load_include('php', 'ldap_servers', 'LdapServer.class');
19

    
20
class LdapServerTest extends LdapServer {
21

    
22
  public $entries;
23
  public $methodResponses;
24
  public $searchResults;
25
  public $binddn = FALSE; // Default to an anonymous bind.
26
  public $bindpw = FALSE; // Default to an anonymous bind.
27

    
28
  /**
29
   * Constructor Method
30
   *
31
   * can take array of form property_name => property_value
32
   * or $sid, where sid is used to derive the include file.
33
   */
34
  function __construct($sid) {
35
    if (!is_scalar($sid)) {
36
      $test_data = $sid;
37
      $sid = $test_data['sid'];
38
    }
39
    else {
40
      $test_data = variable_get('ldap_test_server__' . $sid, array());
41
    }
42

    
43
    $bindpw = (isset($test_data['bindpw'])) ? $test_data['bindpw'] : 'goodpwd';
44
    $this->sid = $sid;
45
    $this->refreshFakeData();
46
    $this->initDerivedProperties($bindpw);
47
  }
48

    
49
  public function refreshFakeData() {
50
    $test_data = variable_get('ldap_test_server__' . $this->sid, array());
51
    $this->methodResponses = (is_array($test_data) && isset($test_data['methodResponses'])) ? $test_data['methodResponses'] : array();
52
    $this->entries = (is_array($test_data) && isset($test_data['ldap'])) ? $test_data['ldap'] : array();
53
    $this->searchResults = (isset($test_data['search_results'])) ? $test_data['search_results'] : array();
54
    $this->detailedWatchdogLog = variable_get('ldap_help_watchdog_detail', 0);
55
    foreach ($test_data['properties'] as $property_name => $property_value ) {
56
      $this->{$property_name} = $property_value;
57
    }
58
  //  $this->basedn = unserialize($this->basedn);
59
    if (isset($test_data['bindpw']) && $test_data['bindpw'] != '') {
60
      $this->bindpw = ldap_servers_decrypt($this->bindpw);
61
    }
62
  }
63

    
64
  /**
65
   * Destructor Method
66
   */
67
  function __destruct() {
68
     // if alterations to server configuration must be maintained throughout simpletest, variable_set('ldap_authorization_test_server__'. $sid, array());
69
  }
70

    
71
  /**
72
   * Connect Method
73
   */
74
  function connect() {
75
    return $this->methodResponses['connect'];
76
  }
77

    
78

    
79
  function bind($userdn = NULL, $pass = NULL, $anon_bind = FALSE) {
80
    $userdn = ($userdn != NULL) ? $userdn : $this->binddn;
81
    $pass = ($pass != NULL) ? $pass : $this->bindpw;
82

    
83
    if (! isset($this->entries[$userdn])) {
84
      $ldap_errno = LDAP_NO_SUCH_OBJECT;  // 0x20 or 32
85
      if (function_exists('ldap_err2str')) {
86
        $ldap_error = ldap_err2str($ldap_errno);
87
      }
88
      else {
89
        $ldap_error = "Failed to find $userdn in LdapServerTest.class.php";
90
      }
91
    }
92
    elseif (isset($this->entries[$userdn]['password'][0]) && $this->entries[$userdn]['password'][0] == $pass && $pass) {
93
      return LDAP_SUCCESS;
94
    }
95
    else {
96
      if (!$pass) {
97
        debug("Simpletest failure for $userdn.  No password submitted");
98
      }
99
      if (! isset($this->entries[$userdn]['password'][0])) {
100
        debug("Simpletest failure for $userdn.  No password in entry to test for bind"); debug($this->entries[$userdn]);
101
      }
102
      $ldap_errno = LDAP_INVALID_CREDENTIALS;
103
      if (function_exists('ldap_err2str')) {
104
        $ldap_error = ldap_err2str($ldap_errno);
105
      }
106
      else {
107
        $ldap_error = "Credentials for $userdn failed in LdapServerTest.class.php";
108
      }
109
    }
110

    
111
    $watchdog_tokens = array('%user' => $userdn, '%errno' => $ldap_errno, '%error' => $ldap_error);
112
    watchdog('ldap_servers', "LDAP bind failure for user %user. Error %errno: %error", $watchdog_tokens);
113
    return $ldap_errno;
114

    
115
  }
116

    
117
  /**
118
   * Disconnect (unbind) from an active LDAP server.
119
   */
120
  function disconnect() {
121

    
122
  }
123

    
124
  /**
125
   * Perform an LDAP search.
126
   *
127
   * @param string $filter
128
   *   The search filter. such as sAMAccountName=jbarclay
129
   * @param string $basedn
130
   *   The search base. If NULL, we use $this->basedn
131
   * @param array $attributes
132
   *   List of desired attributes. If omitted, we only return "dn".
133
   *
134
   * @return
135
   *   An array of matching entries->attributes, or FALSE if the search is
136
   *   empty.
137
   */
138
  function search($base_dn = NULL, $filter, $attributes = array(), $attrsonly = 0, $sizelimit = 0, $timelimit = 0, $deref = LDAP_DEREF_NEVER, $scope = LDAP_SCOPE_SUBTREE) {
139

    
140
    $lcase_attribute = array();
141
    foreach ($attributes as $i => $attribute_name) {
142
      $lcase_attribute[] = drupal_strtolower($attribute_name);
143
    }
144
    $attributes = $lcase_attribute;
145

    
146
    $filter = trim(str_replace(array("\n", "  "), array('', ''), $filter)); // for test matching simplicity remove line breaks and tab spacing
147

    
148
    if ($base_dn == NULL) {
149
      if (count($this->basedn) == 1) {
150
        $base_dn = $this->basedn[0];
151
      }
152
      else {
153
        return FALSE;
154
      }
155
    }
156

    
157
    /**
158
     * Search CASE 1: for some mock ldap servers, a set of fixed ldap filters
159
     * are prepolulated in test data
160
     */
161
    if (isset($this->searchResults[$filter][$base_dn])) {
162
      $results = $this->searchResults[$filter][$base_dn];
163
      foreach ($results as $i => $entry) {
164
        if (is_array($entry) && isset($entry['FULLENTRY'])) {
165
          unset($results[$i]['FULLENTRY']);
166
          $dn = $results[$i]['dn'];
167
          $results[$i] = $this->entries[$dn];
168
          $results[$i]['dn'] = $dn;
169
        }
170
      }
171
      return $results;
172
    }
173

    
174
    /**
175
     * Search CASE 2: attempt to programmatically evaluate ldap filter
176
     * by looping through fake ldap entries
177
     */
178
    $base_dn = drupal_strtolower($base_dn);
179
    $filter = trim($filter, "()");
180
    $subqueries = array();
181
    $operand = FALSE;
182

    
183
    if (strpos($filter, '&') === 0) {
184
     /**
185
     * case 2.A.: filter of form (&(<attribute>=<value>)(<attribute>=<value>)(<attribute>=<value>))
186
     *  such as (&(samaccountname=hpotter)(samaccountname=hpotter)(samaccountname=hpotter))
187
     */
188
      $operand = '&';
189
      $filter = substr($filter, 1);
190
      $filter = trim($filter, "()");
191
      $parts = explode(')(', $filter);
192
      foreach ($parts as $i => $pair) {
193
        $subqueries[] = explode('=', $pair);
194
      }
195
    }
196
    elseif (strpos($filter, '|') === 0) {
197
     /**
198
     * case 2.B: filter of form (|(<attribute>=<value>)(<attribute>=<value>)(<attribute>=<value>))
199
     *  such as (|(samaccountname=hpotter)(samaccountname=hpotter)(samaccountname=hpotter))
200
     */
201
      $operand = '|';
202
      $filter = substr($filter, 1);
203
      $filter = trim($filter, "()");
204
      $parts = explode(')(', $filter);
205
      $parts = explode(')(', $filter);
206
      foreach ($parts as $i => $pair) {
207
        $subqueries[] = explode('=', $pair);
208
      }
209
    }
210
    elseif (count(explode('=', $filter)) == 2) {
211
     /**
212
     * case 2.C.: filter of form (<attribute>=<value>)
213
     *  such as (samaccountname=hpotter)
214
     */
215
      $operand = '|';
216
      $subqueries[] = explode('=', $filter);
217
    }
218
    else {
219
      return FALSE;
220
    }
221

    
222

    
223

    
224

    
225
    // need to perform feaux ldap search here with data in
226
    $results = array();
227

    
228
    if ($operand == '|') {
229
      foreach ($subqueries as $i => $subquery) {
230
        $filter_attribute = drupal_strtolower($subquery[0]);
231
        $filter_value = $subquery[1];
232
        foreach ($this->entries as $dn => $entry) {
233
          $dn_lcase = drupal_strtolower($dn);
234

    
235
          // if not in basedn, skip
236
          // eg. basedn ou=campus accounts,dc=ad,dc=myuniversity,dc=edu
237
          // should be leftmost string in:
238
          // cn=jdoe,ou=campus accounts,dc=ad,dc=myuniversity,dc=edu
239
          //$pos = strpos($dn_lcase, $base_dn);
240
          $substring = strrev(substr(strrev($dn_lcase), 0, strlen($base_dn)));
241
          $cascmp = strcasecmp($base_dn, $substring);
242
          if ($cascmp !== 0) {
243

    
244
            continue; // not in basedn
245
          }
246
          // if doesn't filter attribute has no data, continue
247
          $attr_value_to_compare = FALSE;
248
          foreach ($entry as $attr_name => $attr_value) {
249
            if (drupal_strtolower($attr_name) == $filter_attribute) {
250
              $attr_value_to_compare = $attr_value;
251
              break;
252
            }
253
          }
254
          if (!$attr_value_to_compare || drupal_strtolower($attr_value_to_compare[0]) != $filter_value) {
255
            continue;
256
          }
257

    
258
          // match!
259
          $entry['dn'] = $dn;
260
          if ($attributes) {
261
            $selected_data = array();
262
            foreach ($attributes as $i => $attr_name) {
263
              $selected_data[$attr_name] = (isset($entry[$attr_name])) ? $entry[$attr_name] : NULL;
264
            }
265
            $results[] = $selected_data;
266
          }
267
          else {
268
            $results[] = $entry;
269
          }
270
        }
271
      }
272
    }
273
    elseif ($operand == '&') { // reverse the loops
274
      foreach ($this->entries as $dn => $entry) {
275
        $dn_lcase = drupal_strtolower($dn);
276
        $match = TRUE; // until 1 subquery fails
277
        foreach ($subqueries as $i => $subquery) {
278
          $filter_attribute = drupal_strtolower($subquery[0]);
279
          $filter_value = $subquery[1];
280

    
281
          $substring = strrev(substr(strrev($dn_lcase), 0, strlen($base_dn)));
282
          $cascmp = strcasecmp($base_dn, $substring);
283
          if ($cascmp !== 0) {
284
            $match = FALSE;
285
            break; // not in basedn
286
          }
287
          // if doesn't filter attribute has no data, continue
288
          $attr_value_to_compare = FALSE;
289
          foreach ($entry as $attr_name => $attr_value) {
290
            if (drupal_strtolower($attr_name) == $filter_attribute) {
291
              $attr_value_to_compare = $attr_value;
292
              break;
293
            }
294
          }
295
          if (!$attr_value_to_compare || drupal_strtolower($attr_value_to_compare[0]) != $filter_value) {
296
            $match = FALSE;
297
            break; // not in basedn
298
          }
299

    
300
        }
301
        if ($match === TRUE) {
302
          $entry['dn'] = $dn;
303
          if ($attributes) {
304
            $selected_data = array();
305
            foreach ($attributes as $i => $attr_name) {
306
              $selected_data[$attr_name] = (isset($entry[$attr_name])) ? $entry[$attr_name] : NULL;
307
            }
308
            $results[] = $selected_data;
309
          }
310
          else {
311
            $results[] = $entry;
312
          }
313
        }
314
      }
315
    }
316

    
317
    $results['count'] = count($results);
318
    return $results;
319
  }
320

    
321
/**
322
 * does dn exist for this server?
323
 *
324
 * @param string $dn
325
 * @param enum $return = 'boolean' or 'ldap_entry'
326
 *
327
 * @param return FALSE or ldap entry array
328
 */
329
  function dnExists($find_dn, $return = 'boolean', $attributes = array('objectclass')) {
330
    $this->refreshFakeData();
331
    $test_data = variable_get('ldap_test_server__' . $this->sid, array());
332
    foreach ($this->entries as $entry_dn => $entry) {
333
      $match = (strcasecmp($entry_dn, $find_dn) == 0);
334

    
335
      if ($match) {
336
        return ($return == 'boolean') ? TRUE : $entry;
337
      }
338
    }
339
    return FALSE; // not match found in loop
340

    
341
  }
342

    
343
  public function countEntries($ldap_result) {
344
    return ldap_count_entries($this->connection, $ldap_result);
345
  }
346

    
347

    
348
  public static function getLdapServerObjects($sid = NULL, $type = NULL, $flatten = FALSE) {
349
    $servers = array();
350
    if ($sid) {
351
      $servers[$sid] = new LdapServerTest($sid);
352
    }
353
    else {
354
      $server_ids = variable_get('ldap_test_servers', array());
355
      foreach ($server_ids as $sid => $_sid) {
356
        $servers[$sid] = new LdapServerTest($sid);
357
      }
358
    }
359

    
360
    if ($flatten && $sid) {
361
      return $servers[$sid];
362
    }
363
    else {
364
      return $servers;
365
    }
366
  }
367

    
368

    
369
  /**
370
   * create ldap entry.
371
   *
372
   * @param array $ldap_entry should follow the structure of ldap_add functions
373
   *   entry array: http://us.php.net/manual/en/function.ldap-add.php
374
        $attributes["attribute1"] = "value";
375
        $attributes["attribute2"][0] = "value1";
376
        $attributes["attribute2"][1] = "value2";
377
   * @return boolean result
378
   */
379

    
380
  public function createLdapEntry($ldap_entry, $dn = NULL) {
381
    $result = FALSE;
382
    $test_data = variable_get('ldap_test_server__' . $this->sid, array());
383

    
384
    if (isset($ldap_entry['dn'])) {
385
      $dn = $ldap_entry['dn'];
386
      unset($ldap_entry['dn']);
387
    }
388

    
389
    if ($dn && !isset($test_data['entries'][$dn])) {
390
      $test_data['entries'][$dn] = $ldap_entry;
391
      $test_data['ldap'][$dn] = $ldap_entry;
392
      variable_set('ldap_test_server__' . $this->sid, $test_data);
393
      $this->refreshFakeData();
394
      $result = TRUE;
395
    }
396
    return $result;
397
  }
398

    
399
  function modifyLdapEntry($dn, $attributes = NULL, $old_attributes = FALSE) {
400
    if (!$attributes) {
401
      $attributes = array();
402
    }
403
    $test_data = variable_get('ldap_test_server__' . $this->sid, array());
404
    if (!isset($test_data['entries'][$dn])) {
405
      return FALSE;
406
    }
407
    $ldap_entry = $test_data['entries'][$dn];
408

    
409
    foreach ($attributes as $key => $cur_val) {
410
      if ($cur_val == '') {
411
        unset($ldap_entry[$key]);
412
      }
413
      elseif (is_array($cur_val)) {
414
        foreach ($cur_val as $mv_key => $mv_cur_val) {
415
          if ($mv_cur_val == '') {
416
            unset($ldap_entry[$key][$mv_key]);
417
          }
418
          else {
419
            if (is_array($mv_cur_val)) {
420
              $ldap_entry[$key][$mv_key] = $mv_cur_val;
421
            }
422
            else {
423
              $ldap_entry[$key][$mv_key][] = $mv_cur_val;
424
            }
425
          }
426
        }
427
        unset($ldap_entry[$key]['count']);
428
        $ldap_entry[$key]['count'] = count($ldap_entry[$key]);
429
      }
430
      else {
431
        $ldap_entry[$key][0] = $cur_val;
432
        $ldap_entry[$key]['count'] = count($ldap_entry[$key]);
433
      }
434
    }
435

    
436
    $test_data['entries'][$dn] = $ldap_entry;
437
    $test_data['ldap'][$dn] = $ldap_entry;
438
    variable_set('ldap_test_server__' . $this->sid, $test_data);
439
    $this->refreshFakeData();
440
    return TRUE;
441

    
442
  }
443

    
444
    /**
445
   * Perform an LDAP delete.
446
   *
447
   * @param string $dn
448
   *
449
   * @return boolean result per ldap_delete
450
   */
451

    
452
  public function delete($dn) {
453

    
454
    $test_data = variable_get('ldap_test_server__' . $this->sid, array());
455
    $deleted = FALSE;
456
    foreach (array('entries', 'users', 'groups', 'ldap') as $test_data_sub_array) {
457
      if (isset($test_data[$test_data_sub_array][$dn])) {
458
        unset($test_data[$test_data_sub_array][$dn]);
459
        $deleted = TRUE;
460
      }
461
    }
462
    if ($deleted) {
463
      variable_set('ldap_test_server__' . $this->sid, $test_data);
464
      $this->refreshFakeData();
465
      return TRUE;
466
    }
467
    else {
468
      return FALSE;
469
    }
470

    
471
  }
472

    
473
}